DSP 基于 TMS320F2803x 的 I2C 上的 PMBus 的软件应用

参考手册:Software Implementation of PMBus Over I2C for TMS320F2803x.pdf

例程代码下载地址在参考手册内。

一、PMBus 概览

1、PMbus 特点

PMBus的基本硬件协议是 I2C 协议,这是一种广泛使用的2线协议。 此外,PMBus还指定了另外两个可选线:控制和警报。 从机使用警报线来通知主机故障,而主机将控制线用作片选线以打开或关闭从机。 这些线是可选的; 如果需要,PMBus可以仅通过时钟和数据线作为2线协议运行。

有几个可选功能为PMBus规范增加了鲁棒性,这对于关键系统来说很重要。 像SMBus一样,PMBus实现超时功能。 如果时钟保持低电平的时间超过超时间隔,则设备必须在指定的时间段内重置通信。 强烈建议使用可提高鲁棒性的可选功能是数据包错误检查(PEC)。 PEC通过循环冗余校验8(CRC-8)算法来检查收到的数据包的有效性。

2、PMBus 格式

PMBus事务遵循以下六种格式之一:发送字节,读取字节,写入字节,读取/写入字节,读取字和读取/写入字。 对于所有事务,将首先发送每个字节的MSB(最高有效位)。

2.1 Send Byte 发送字节

2.2 Read Byte 读取字节

2.3 Write Byte 写入字节

2.4 Read/Write Byte 读取/写入字节

读/写字节命令用于在从设备中读或写一个字节的信息。 这些命令遵循读字节或写字节格式,读/写位确定事务处理方向。 通常,读/写字节命令用于访问可写入或读取的寄存器或参数。

2.5 Read Word 读取字

2.6 Read/Write Word 读取/写入字

读/写字命令用于将信息的一个字(两个字节)读取或写入从设备。 主机使用I2C传输命令字节,然后根据事务的方向向从设备读取或向从设备写入两个数据字节。

2.7 Packet Error Checking Protocol 错包检查协议

使用数据包错误检查时,在每个事务中的停止字节之前会添加一个附加字节。 对于读取,PEC 字节从从机读取,而主机将其与自己计算的 PEC 字节进行比较。 对于写操作,PEC 字节从主机发送到从机,从机将其与自己计算的 PEC 字节进行比较。

比较之后,如果 PEC 字节不同,则从设备将检测到 PEC 错误。 PMBus 协议中的首选响应是发送 NACK,通常针对硬件PMBus 和PEC 实现来完成。 但是, 由于此实现是通过 I2C 硬件而非专用 PMBus 硬件上的软件完成的,因此它无法及时计算和检查 NACK 的 PEC 字节,因此此处 PMBus 协议不需要NACK,而是根据PMBus规范采取以下措施:

  • 不响应命令或不执行命令
  • 刷新命令代码和所有收到的数据
  • 置位 STATUS_BYTE 寄存器中的 CML 位(此实现中的变量Status_Byte)
  • 置位 STATUS_CML 寄存器中的 PEC 失败位(此实现中的变量Status_Cml)
  • 通过将警报线拉低来通知主机故障情况

二、Scope and User Implementation

1、应用检查清单:

编写用户应用程序时,应对例程代码进行一些修改:

  • 更改PMBus.h中定义的PEC的值。 PEC = 0 不支持错包检查,PEC = 1 支持错包检查。
  • 正确选择设备的构建配置:master 主设备 或 slave 从设备。
  • 根据 PMBus 规范为应用选择合适的主频率,介于10 kHz至400 kHz之间。 应相应设置所需的预分频值(请参见 I2CMaster_Init()的功能描述)。
  • 您应该更改用于警报和控制线的GPIO,以匹配应用中使用的引脚。 对于主设备,警报线当前触发 xint1。 请参阅设备文档以正确配置所需的GPIO来触发 xint1。
  • 若要将C2000™设备用作 PMBus 从设备,代码中的某些部分标记为用户代码(User Code), 这些部分应根据为特定应用程序实现的PMBus 命令进行修改。
  • 虽然在PMBus.h文件中定义了所有PMBus命令的命令字节,但未响应命令执行的动作。 这取决于用户的应用程序和 PMBus 命令集。 对于从设备,必须更改代码以提供正确的数据字节,以便在被请求时发送给主设备,并采取适当的措施以响应收到的命令。 对于主设备,您必须添加代码以存储从从设备接收到的所有数据,并采取相应的措施。

2、实施准则

以下准则应有助于将示例代码与用户应用程序集成:

  • PMBus.h 文件包含所有 256 个 PMBus 命令的索引的符号定义,与 PMBus 规范第II部分中的命令名称匹配。 调用PMBusMaster_Transmit()函数时应使用这些索引。
    示例:PMBusMaster(STATUS_TEMPERATURE,…,…,…)
  • PMBus.h 文件还包含 PMBus 状态寄存器的结构,这些结构的位定义与 PMBus 规范第II部分一致。 这些寄存器以与 C280x C / C ++ 头文件相同的样式实现,以便轻松地访问寄存器中的每个位。 以这种方式进行定义还允许 Code Composer Studio™ 自动完成功能,从而使代码开发更加容易。 可以复制相同的结构来实现应用程序所需的任何其他 PMBus 寄存器。
  • 尽管可以与多个从设备进行通信,但示例代码的主设备侧旨在与一个从设备进行通信-通过调用具有下一个从设备地址的功能 PMBusMaster_Init(),主设备可以切换其所命令的从设备。
  • 在通信线路上选择适当的上拉电阻以及其他硬件注意事项,完全由用户决定。 请注意,C2000 GPIO上的内部上拉电阻不满足该要求,应添加外部上拉电阻。
  • GPIO配置为控制线。 但是,根据PMBus规范,控制线功能的真正实现是它对某些PMBus命令的影响。 由于这是应用程序层的一部分,因此由您自己决定将此功能作为命令实现的一部分来实现。 有关控制线如何使用不同命令进行操作的更多信息,请参见 http://pmbus.org。

三、函数描述

PMBusMaster.c 和 PMBusSlave.c 文件包含用于将PMBus实施为主设备或从设备的代码。 通过将 PMBus.h 中的 PEC 定义为0或1,可以构建带有或不带有 PEC 功能的实现。

1、主设备函数

以下描述适用于 PMBusMaster.c 文件中的功能。

1.1 PMBusMaster_Init(PMBusMaster_SlaveAddress, PMBusMaster_Prescale)

这个函数应该在 PMBus 操作开始前被调用。设备使用 I2CMaster_Init()  函数配置基础 I2C,并为警报和控制线配置另外两个GPIO引脚。警报线引脚也被配置为触发 XINT1 中断。 可以针对特定于应用程序的警报线响应修改中断 xint1_isr。PMBusMaster_Prescale 通过在初始化基础 I2C 时传递此值来配置主机以所需的频率进行通信。有关选择预分频值的建议,请参见 I2CMaster_Init()  。退出功能之前,主设备通过调用 I2CMaster_SlavePresent() 函数等待从设备准备就绪。

PMBusMaster_Init() 参数描述
参数名描述
PMBusMaster_SlaveAddress从设备地址
PMBusMaster_Prescale达到所需主频率的预分频值
void PMBusMaster_Init(unsigned char PMBusMaster_SlaveAddress, unsigned char PMBusMaster_Prescale)
{
	// Control Line functionality GPIO0
	GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;	//Enable pullup on GPIO0
	GpioDataRegs.GPASET.bit.GPIO0 = 1;	//Drive line high
	GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0;	//GPIO0 = GPIO0
	GpioCtrlRegs.GPADIR.bit.GPIO0 = 1;	//GPIO0 = output
	  
	// SMBUS Alert functionality (GPIO2 = Alert line)
	GpioCtrlRegs.GPAPUD.bit.GPIO2 = 0;		//Enable pullup on GPIO2
	GpioDataRegs.GPASET.bit.GPIO2 = 1;		//Drive line high
	GpioCtrlRegs.GPAQSEL1.bit.GPIO2 = 0;	//SYNC to SYSCLKOUT
	GpioCtrlRegs.GPACTRL.bit.QUALPRD0 = 0;	//no qualification (SYNC to SYSCLKOUT)
	GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0;		//GPIO2 = GPIO2
	GpioCtrlRegs.GPADIR.bit.GPIO2 = 0;		//GPIO2 = input
	  
	//setup interrupt triggered by Alert line 
	EALLOW;									// This is needed to write to EALLOW protected registers
	PieVectTable.XINT1 = &xint1_isr;
	EDIS;									// This is needed to disable write to EALLOW protected registers 
	GpioIntRegs.GPIOXINT1SEL.all = 2;		//Make GPIO2 input source for XINT1
	XIntruptRegs.XINT1CR.bit.POLARITY = 2;	//XINT1 triggered by falling edge (high-to-low-transition)
	  
	slave_address = PMBusMaster_SlaveAddress;
	I2CMaster_Init(PMBusMaster_SlaveAddress, PMBusMaster_Prescale);		// Initialize USCI module
	while(!I2CMaster_SlavePresent(slave_address));		//check if slave device present
	 
	// Enable Alert line interrupt
	XIntruptRegs.XINT1CR.bit.ENABLE = 1;	//Enable XINT1 interrupt  
	// Enable XINT1 interrupt in the PIE: Group 1 interrupt 4
	PieCtrlRegs.PIEIER1.bit.INTx4 = 1;
	// Enable CPU INT1 which is connected to PIE group 1
	IER |= M_INT1;
	  
	while (I2CMaster_NotReady());           // Is the bus free?
}

 

1.2 PMBusMaster(PMBusMaster_CommandByte, PMBusMaster_RWFlag, PMBusMaster_Message,*PMBusMaster_ReceivedValue)

该函数通过 I2C 硬件作为主机执行 PMBus 事务。

PMBusMaster_CommandByte 包含PMBus命令的索引。该索引用于确定要发送的 PMBus 命令字节,以及确定需要哪种类型的命令(读字节,写字节等),并因此确定通过 I2C 发送和接收的字节数。 对于读/写命令,参数 PMBusMaster_RWFlag 确定主机是在读取还是在写从机。对于写命令,PMBusMaster_Message 包含要发送的消息; 它是 int 类型的,因此它可以包含一个或两个字节的消息,具体取决于命令。 对于读取命令,*PMBusMaster_ReceivedValue 是将存储读取的数据并将其传递回应用程序级别的指针。

如果将 PEC 定义为 1,则在 PMBusMaster() 中实现数据包错误检查功能。 请注意,在主 switch 语句中,有些部分以 #if !PEC 和 #else 开头。 这些部分分别实现了不使用 PEC 和使用 PEC 的功能。如果实现了PEC,则此功能将根据其自身在读命令中的计算结果来检查从机中的 PEC,并在写命令时发送一个要由从机检查的 PEC 字节。 该函数将命令字节、从机地址、读/写标志以及发送或接收的任何字节传递给 PMBusMaster_CRC8MakeBitwise(),以进行 PEC 字节计算。 该函数返回 PEC 比较的结果(1 =成功,0 =失败)。

PMBusMaster() 参数描述
参数名描述
PMBusMaster_CommandByte 从 PMBus.h 中定义的命令列表(例如STATUS_WORD)中传递的 PMBus 命令。 这是包含 PMBus 规范中定义的包含 PMBus 命令代码的表的索引。
PMBusMaster_RWFlag达到所需主频率的预分频值
PMBusMaster_MessagePMBus读/写标志。 读/写字节和读/写字命令仅需要指示主机是从从机读取还是向从机写入。
0:写
1:读
*PMBusMaster_ReceivedValue对于读取功能,这是指向包含从设备接收的字节的数组的指针。
unsigned char PMBusMaster(unsigned char PMBusMaster_CommandByte, unsigned char PMBusMaster_RWFlag, unsigned int PMBusMaster_Message,unsigned char *PMBusMaster_ReceivedValue)
{	  
	unsigned char PMBusMaster_TransmitBuffer[4];
	unsigned char PMBusMaster_ReceiveBuffer[5];
	unsigned char PMBusMaster_RxCount = 0;
	unsigned int PMBusMaster_Temp = 0;
	unsigned char PMBusMaster_Index;
	unsigned char PMBusMaster_CommandGroup;
	
	#if PEC  //PEC variables
		unsigned char PMBusMaster_CrcMsgSize = 0;
		unsigned char PMBusMaster_CrcMsg[5];
		unsigned char PMBusMaster_CrcMasterGenerated = 0;
		unsigned char PMBusMaster_CrcSlaveGenerated = 0;
		unsigned char PMBusMaster_Result = 0;
		
		PMBusMaster_CrcMsg[0] = slave_address << 1;		// 1st CRC byte = slave address...
	#endif
	  
	PMBusMaster_Index = PMBusMaster_CommandByte;                     	// Store PMBus command byte as ...
	PMBusMaster_TransmitBuffer[0] = PMBus_Commands[PMBusMaster_Index];	//...1st byte in Tx buffer	
	PMBusMaster_Temp = PMBusMaster_Message;
	  
	PMBusMaster_TransmitBuffer[1] = PMBusMaster_Message & 0x00FF;	//store lower byte of message
	PMBusMaster_Temp = (PMBusMaster_Message) >> 8;
	PMBusMaster_TransmitBuffer[2] = PMBusMaster_Temp;				// store higher byte of message
	
	if(PMBusMaster_Index > 0 && PMBusMaster_Index < 13)			//read byte from slave device
	    PMBusMaster_CommandGroup = READBYTE;
	if(PMBusMaster_Index > 12 && PMBusMaster_Index < 40)		// read word from slave device
	    PMBusMaster_CommandGroup = READWORD;
	if(PMBusMaster_Index > 39 && PMBusMaster_Index < 44)		// write byte to slave device
	    PMBusMaster_CommandGroup = WRITEBYTE;
	if(PMBusMaster_Index > 43 && PMBusMaster_Index < 49)		// send byte to slave device
	    PMBusMaster_CommandGroup = SENDBYTE;
	/* Read or write one byte of data. R/W oprn. decided based on RWFlag *******/
	if(PMBusMaster_Index > 48 && PMBusMaster_Index < 69) 
	{
		if (PMBusMaster_RWFlag == 0)				// write byte
			PMBusMaster_CommandGroup = WRITEBYTE;
		else										// read byte
			PMBusMaster_CommandGroup = READBYTE;
	}
	/* Read or write one word of data. R/W oprn. decided based on RWFlag *******/
	if(PMBusMaster_Index > 68 && PMBusMaster_Index < 120)		// R/W Word
	{
		if (PMBusMaster_RWFlag == 0)             	// write word (new command group)
	    	PMBusMaster_CommandGroup = WRITEWORD;
	    else                                    	// read word
	    	PMBusMaster_CommandGroup = READWORD; 
    }
	if(PMBusMaster_Index >= 120)
		while(1);						//illegal index - invalid command trap
	
	switch(PMBusMaster_CommandGroup)
	{
		#if !PEC
			case READBYTE: // read byte
	        		PMBusMaster_RxCount = 1;
	        		while (I2CMaster_NotReady());
	        		I2CMaster_Transmit(1,PMBusMaster_TransmitBuffer,1,PMBusMaster_ReceiveBuffer);      
	        		break;           
	           
			case READWORD:  // read word
					PMBusMaster_RxCount = 2;
					while (I2CMaster_NotReady());
					I2CMaster_Transmit(1,PMBusMaster_TransmitBuffer,2,PMBusMaster_ReceiveBuffer);                         
			        break;
			        
			case WRITEBYTE: // write byte
					while (I2CMaster_NotReady() );
					I2CMaster_Transmit(2,PMBusMaster_TransmitBuffer,0,0);        
			        break;
			case SENDBYTE:  // send byte   
					while (I2CMaster_NotReady());
					I2CMaster_Transmit(1,PMBusMaster_TransmitBuffer,0,0);       
			        break;
			case WRITEWORD:  // write word
					while (I2CMaster_NotReady());
					I2CMaster_Transmit(3,PMBusMaster_TransmitBuffer,0,0);      
			        break;
		#else
			case READBYTE:					// read byte
		            PMBusMaster_RxCount = 1;
		            while (I2CMaster_NotReady());
		            I2CMaster_Transmit(1,PMBusMaster_TransmitBuffer,2,PMBusMaster_ReceiveBuffer);  
		            
		            /* Assembling bit stream for CRC check*/
		            PMBusMaster_CrcMsg[1] = PMBusMaster_TransmitBuffer[0];  		// store first tx byte
		            PMBusMaster_CrcMsg[2] = (slave_address << 1) + 1;				// store slave addres + R/W=1
		            PMBusMaster_CrcMsg[3] = PMBusMaster_ReceiveBuffer[0];   		// store rx byte 1
		            PMBusMaster_CrcSlaveGenerated = PMBusMaster_ReceiveBuffer[1]; 	//store PEC byte from slave
		            PMBusMaster_CrcMsgSize = 4;                 					// # of bytes
		            
		            /* CRC function call, generate CRC byte to compare with slave CRC*/
		            PMBusMaster_CrcMasterGenerated = PMBusMaster_Crc8MakeBitwise(CRC8_INIT_REM,CRC8_POLY,PMBusMaster_CrcMsg,PMBusMaster_CrcMsgSize);
		            if (PMBusMaster_CrcMasterGenerated == PMBusMaster_CrcSlaveGenerated)	//compare the PEC bytes
		            	PMBusMaster_Result = PEC_PASS;            // PEC byte was validated
		            else
		            	PMBusMaster_Result = PEC_FAIL;            // failed PEC test   
					break;           
	           
	  		case READWORD:						// read word
		            PMBusMaster_RxCount = 2;
		            while (I2CMaster_NotReady());
		            I2CMaster_Transmit(1,PMBusMaster_TransmitBuffer,3,PMBusMaster_ReceiveBuffer);  
		            
		            /* Assembling bit stream for CRC check*/
		            PMBusMaster_CrcMsg[1] = PMBusMaster_TransmitBuffer[0];
		            PMBusMaster_CrcMsg[2] = (slave_address << 1) + 1;				// store slave address + R/W=1
		            PMBusMaster_CrcMsg[3] = PMBusMaster_ReceiveBuffer[0];
		            PMBusMaster_CrcMsg[4] = PMBusMaster_ReceiveBuffer[1];
		            PMBusMaster_CrcSlaveGenerated = PMBusMaster_ReceiveBuffer[2];	//store PEC byte from slave
		            PMBusMaster_CrcMsgSize = 5;
		            
		            /* CRC function call, generate CRC byte to compare with slave CRC*/
		            PMBusMaster_CrcMasterGenerated = PMBusMaster_Crc8MakeBitwise(CRC8_INIT_REM,CRC8_POLY,PMBusMaster_CrcMsg,PMBusMaster_CrcMsgSize);	            
		            if (PMBusMaster_CrcMasterGenerated == PMBusMaster_CrcSlaveGenerated)
		                 PMBusMaster_Result = PEC_PASS;
		            else
		                 PMBusMaster_Result = PEC_FAIL;                       
					break;
	          
			case WRITEBYTE:						// write byte
		  			/* CRC function call, generate CRC byte to transmit to slave device*/
		            PMBusMaster_CrcMsg[1] = PMBusMaster_TransmitBuffer[0];
		            PMBusMaster_CrcMsg[2] = PMBusMaster_TransmitBuffer[1];
		            PMBusMaster_CrcMsgSize = 3;
		            PMBusMaster_CrcMasterGenerated = PMBusMaster_Crc8MakeBitwise(CRC8_INIT_REM,CRC8_POLY,PMBusMaster_CrcMsg,PMBusMaster_CrcMsgSize);
		            PMBusMaster_TransmitBuffer[2] = PMBusMaster_CrcMasterGenerated;
		            
		            while (I2CMaster_NotReady() );
		            I2CMaster_Transmit(3,PMBusMaster_TransmitBuffer,0,0); 
		            
		            //check if the slave verified the PEC byte
		            if(alert == 0)	
		            	PMBusMaster_Result = PEC_PASS;
		            else
		            	PMBusMaster_Result = PEC_FAIL;              
					break;
	          
	  		case SENDBYTE:						// send byte  
		  			/* CRC function call, generate CRC byte to transmit to slave device*/
		            PMBusMaster_CrcMsg[1] = PMBusMaster_TransmitBuffer[0];
		            PMBusMaster_CrcMsgSize = 2;
		            PMBusMaster_CrcMasterGenerated = PMBusMaster_Crc8MakeBitwise(CRC8_INIT_REM,CRC8_POLY,PMBusMaster_CrcMsg,PMBusMaster_CrcMsgSize);
		            PMBusMaster_TransmitBuffer[1] = PMBusMaster_CrcMasterGenerated; 
		            
		            while (I2CMaster_NotReady());
		            I2CMaster_Transmit(2,PMBusMaster_TransmitBuffer,0,0);  
	 
		            //check if the slave verified the PEC byte
		            if(alert == 0)	
		            	PMBusMaster_Result = PEC_PASS;
		            else
		            	PMBusMaster_Result = PEC_FAIL; 
					break;
	          
			case WRITEWORD:						// write word
		  			/* CRC function call, generate CRC byte to transmit to slave device*/
		            PMBusMaster_CrcMsg[1] = PMBusMaster_TransmitBuffer[0];
		            PMBusMaster_CrcMsg[2] = PMBusMaster_TransmitBuffer[1];
		            PMBusMaster_CrcMsg[3] = PMBusMaster_TransmitBuffer[2];
		            PMBusMaster_CrcMsgSize = 4;
		            PMBusMaster_CrcMasterGenerated = PMBusMaster_Crc8MakeBitwise(CRC8_INIT_REM,CRC8_POLY,PMBusMaster_CrcMsg,PMBusMaster_CrcMsgSize);
		            PMBusMaster_TransmitBuffer[3] = PMBusMaster_CrcMasterGenerated;
		            
		            while (I2CMaster_NotReady());
		            I2CMaster_Transmit(4,PMBusMaster_TransmitBuffer,0,0);
		            
		            //check if the slave verified the PEC byte
		            if(alert == 0)	
		            	PMBusMaster_Result = PEC_PASS;
		            else
		            	PMBusMaster_Result = PEC_FAIL; 
					break;
		#endif
			    
		default:
				break;
	}
	if (PMBusMaster_ReceivedValue !=0)
	{
		*PMBusMaster_ReceivedValue++ = PMBusMaster_ReceiveBuffer[0];
		if (PMBusMaster_RxCount > 1)
			*PMBusMaster_ReceivedValue = PMBusMaster_ReceiveBuffer[1];
	}
	#if PEC
		return PMBusMaster_Result;	//When PEC is implemented, return the result of the packet error checking (0 = failure, 1 = success)
	#else
		return 1;	//When PEC is not implemented, return a 1 for completed communication
	#endif
}

1.3 xint1_isr

外部中断“ 1”配置为在警报线下降至低压状态时触发。 您可以根据应用程序的所需功能更改此中断服务例程,以服务警报线。

2 从设备函数

2.1 PMBusSlave_Init(PMBusSlave_DeviceAddress)

这个函数应该在 PMBus 操作开始前被调用。该函数使用参数 PMBusSlave_DeviceAddress 指定的设备地址将基础 I2C 配置为从设备。 它还设置了用于I2C操作以及警报和控制线功能的 GPIO。 

void PMBusSlave_Init(unsigned char PMBusSlave_DeviceAddress)
{	
	StatusRegs.StatusWord.all = 0;			//Clear status bits for the status registers we are using
	StatusRegs.StatusCml.all = 0;
	
	// Control Line functionality GPIO0
	GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0;		//Enable pullup on GPIO0
	GpioDataRegs.GPASET.bit.GPIO0 = 1;		//Drive line high
	GpioCtrlRegs.GPAQSEL1.bit.GPIO0 = 0;	//SYNC to SYSCLKOUT
	GpioCtrlRegs.GPACTRL.bit.QUALPRD0 = 0;	//no qualification (SYNC to SYSCLKOUT)
	GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0;		//GPIO0 = GPIO0
	GpioCtrlRegs.GPADIR.bit.GPIO0 = 0;		//GPIO0 = input
	 
	// SMBUS Alert functionality (GPIO2 = Alert line)
	GpioCtrlRegs.GPAPUD.bit.GPIO2 = 0;		//Enable pullup on GPIO2
	GpioDataRegs.GPASET.bit.GPIO2 = 1;		//Drive line high
	GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0;		//GPIO2 = GPIO2
	GpioCtrlRegs.GPADIR.bit.GPIO2 = 1;		//GPIO2 = output
	
	slave_address = PMBusSlave_DeviceAddress;
	I2CSlave_Init(slave_address);     // Initialize USCI module
}

2.2 PMBusSlave_DecodeCommand(PMBusSlave_RxCommand)

一旦接收到从主机发送的命令字节,就会从PMBusSlave() 函数调用此函数。 该函数在表中查找命令字节并确定命令的类型(读取字节,写入字节等)。 它还确定该命令是否是从设备支持的命令,并在必要时准备要发送的信息。

 用户应该更改标记为“用户代码”的代码部分,以实施特定于应用程序的命令。

USER CODE
#warn "User should change code to implement their application's supported PMBus commands."
switch (PMBusSlave_Index) //should include all user supported commands
{
case STATUS_TEMPERATURE:
PMBusSlave_TransmitBuffer[0] = Temperature;
break;
...
default:
PMBusSlave_DummyCommand = 1; //command not supported by this slave
break;
}
参数名描述
PMBusSlave_RxCommand从设备收到的命令字节
unsigned char PMBusSlave_DecodeCommand(unsigned char PMBusSlave_RxCommand)
{
	unsigned char PMBusSlave_CommandGroup;	
	
	for(PMBusSlave_Index = 0; PMBusSlave_Index < 120; PMBusSlave_Index++)
	{
		if(PMBus_Commands[PMBusSlave_Index] == PMBusSlave_RxCommand)
			break;
	}
	
	USER CODE
	#warn	"User should change code to implement their application's supported PMBus commands."
	switch (PMBusSlave_Index)	//should include all user supported commands
	{
		case STATUS_TEMPERATURE:
				PMBusSlave_TransmitBuffer[0] = Temperature;
				break;
		case STORE_DEFAULT_CODE:
				break;
		case OPERATION:
				PMBusSlave_TransmitBuffer[0] = Operation;
				break;
		case STATUS_WORD:
				PMBusSlave_TransmitBuffer[0] = Status_Word;	//lower byte
				PMBusSlave_TransmitBuffer[1] = Status_Word >> 8;	//upper byte
				break;
		case VOUT_COMMAND:
				PMBusSlave_TransmitBuffer[0] = Vout_Command;	//lower byte
				PMBusSlave_TransmitBuffer[1] = Vout_Command >> 8;	//upper byte
				break;
		default:
				PMBusSlave_DummyCommand = 1;	//command not supported by this slave
				break;
	}
	END USER CODE	
	
	if(PMBusSlave_Index == 0)//dummy byte to check if slave is present
		PMBusSlave_DummyCommand = 1;
	if(PMBusSlave_Index > 0 && PMBusSlave_Index < 13)                  //read byte from slave device
		PMBusSlave_CommandGroup = READBYTE;
	if(PMBusSlave_Index > 12 && PMBusSlave_Index < 40)                 // read word from slave device
		PMBusSlave_CommandGroup = READWORD;
	if(PMBusSlave_Index > 39 && PMBusSlave_Index < 44)                 // write byte to slave device
		PMBusSlave_CommandGroup = WRITEBYTE;
	if(PMBusSlave_Index > 43 && PMBusSlave_Index < 49)                 // send byte to slave device
		PMBusSlave_CommandGroup = SENDBYTE;
	/* Read or write one byte of data. R/W oprn. decided based on RWFlag *******/
	if(PMBusSlave_Index > 48 && PMBusSlave_Index < 69) 
	{
	    PMBusSlave_CommandGroup = RWBYTE;
	}
	/* Read or write one word of data. R/W oprn. decided based on RWFlag *******/
	if(PMBusSlave_Index > 68 && PMBusSlave_Index < 120)                // R/W Word
	{
	    PMBusSlave_CommandGroup = RWWORD;
	}
	if(PMBusSlave_Index >= 120)
		while(1);                               //illegal index - invalid command trap
		
	return PMBusSlave_CommandGroup;
}

2.3 PMBusSlave()

该功能等待主机发送PMBus命令字节,然后执行PMBus读取和写入操作。

 

3 PMBus With PEC

3.1 PMBusMaster_Crc8MakeBitwise(PMBusMaster_CRC, PMBusMaster_Poly, *PMBusMaster_Pmsg, PMBusMaster_MsgSize)

此函数根据* PMBusMaster_Pmsg上的字节,根据PMBus规范生成 PEC 字节并返回 PEC 字节。

参数名描述
PMBusMaster_CRCCRC 计算的初始值
PMBusMaster_Poly多项式
*PMBusMaster_Pmsg指向要在 CRC 计算中使用的数据的指针。 这应该包括从机地址,读/写位,命令字节以及主机刚刚发送或接收的所有数据字节。
PMBusMaster_MsgSizeCRC 计算中使用的数据字节数
static unsigned char PMBusMaster_Crc8MakeBitwise(unsigned char PMBusMaster_CRC, unsigned char PMBusMaster_Poly, unsigned char *PMBusMaster_Pmsg, unsigned int PMBusMaster_MsgSize)
{
    unsigned int i, j, carry;
    unsigned char msg;

    PMBusMaster_CRC = *PMBusMaster_Pmsg++;			// first byte loaded in "crc"		
    for(i = 0 ; i < PMBusMaster_MsgSize-1 ; i ++)
    {
        msg = *PMBusMaster_Pmsg++;					// next byte loaded in "msg"
        
		for(j = 0 ; j < 8 ; j++)
    	{
	    	carry = PMBusMaster_CRC & 0x80;								// check if MSB=1			
	        PMBusMaster_CRC = (PMBusMaster_CRC << 1) | (msg >> 7);		// Shift 1 bit of next byte into crc
	        if(carry) PMBusMaster_CRC ^= PMBusMaster_Poly;      		// If MSB = 1, perform XOR
				msg <<= 1;                  							// Shift left msg byte by 1
				msg &= 0x00FF;
        }
    }
	// The previous loop computes the CRC of the input bit stream. To this, 
    // 8 trailing zeros are padded and the CRC of the resultant value is 
    // computed. This gives the final CRC of the input bit stream.
	for(j = 0 ; j < 8 ; j++)
    {
		carry = PMBusMaster_CRC & 0x80;
		PMBusMaster_CRC <<= 1;
		if(carry) PMBusMaster_CRC ^= PMBusMaster_Poly;
    }
    
    PMBusMaster_CRC &= 0x00FF;		//We only want one byte (lower)
    
    return(PMBusMaster_CRC);
}

 

3.2 PMBusSlave_Crc8MakeBitwise(PMBusSlave_CRC, PMBusSlave_Poly, *PMBusSlave_Pmsg, PMBusSlave_MsgSize)

参数名描述
PMBusSlave_CRCCRC 计算的初始值
PMBusSlave_Poly多项式
*PMBusSlave_Pmsg指向要在CRC计算中使用的数据的指针。 这应该包括从机地址,读/写位,命令字节以及从机刚刚发送或接收的所有数据字节。
PMBusSlave_MsgSizeCRC 计算中使用的数据字节数
static unsigned short PMBusSlave_Crc8MakeBitwise(unsigned char PMBusSlave_CRC, unsigned char PMBusSlave_Poly, unsigned char *PMBusSlave_Pmsg, unsigned int PMBusSlave_MsgSize)
{
    unsigned int i, j, carry;
    unsigned char msg;

    PMBusSlave_CRC = *PMBusSlave_Pmsg++;        	// first byte loaded in "crc"		
    for(i = 0 ; i < PMBusSlave_MsgSize-1 ; i ++)
    {
        msg = *PMBusSlave_Pmsg++;                   // next byte loaded in "msg"
        
		for(j = 0 ; j < 8 ; j++)
	    {
	  		carry = PMBusSlave_CRC & 0x80;               			// check if MSB=1			
          	PMBusSlave_CRC = (PMBusSlave_CRC << 1) | (msg >> 7);    // Shift 1 bit of next byte into crc
            if(carry) PMBusSlave_CRC ^= PMBusSlave_Poly;      		// If MSB = 1, perform XOR
			msg <<= 1;                  							// Shift left msg byte by 1
			msg &= 0x00FF;
        }
    }
	// The previous loop computes the CRC of the input bit stream. To this, 
    // 8 trailing zeros are padded and the CRC of the resultant value is 
    // computed. This gives the final CRC of the input bit stream.
	for(j = 0 ; j < 8 ; j++)
    {
		carry = PMBusSlave_CRC & 0x80;
		PMBusSlave_CRC <<= 1;
		if(carry) PMBusSlave_CRC ^= PMBusSlave_Poly;
    }	
        
    PMBusSlave_CRC &= 0x00FF;	//We only want one byte (lower)
    
    return(PMBusSlave_CRC);
}

 

4 底层功能说明 —— I2C

PMBus的这种软件实现依赖于控制硬件的底层 I2C 层。 I2CMaster.c 文件包含控制 I2C 层的功能,而 PMBusSlave.c 文件包含用于初始化从属端 I2C 层的功能。

4.1 I2C主机

4.1.1 I2CMaster_Init(I2CMaster_SlaveAddress, I2CMaster_Prescale)

此功能将I2C模块配置为I2C主设备,将两个GPIO配置为I2C时钟和数据线,并设置适当的 I2C 中断。 它使用 I2CMaster_Prescale 为所需的通信频率设置模块时钟。

I2CMaster_Prescale中传递的值与主通信频率之间的关系可以用以下公式表示:

4.1.2 I2CMaster_Transmit(I2CMaster_ByteCountTx, *I2CMaster_TxArray, I2CMaster_ByteCountRx,
*I2CMaster_RxArray)

每当主机进行I2C事务时,都应调用此函数。 该函数从* I2CMaster_TxArray传递的结构中的数据中发送指定数量的字节,然后从从设备接收由* I2CMaster_RxArray传递的结构中的指定字节数。

参数名描述
I2CMaster_ByteCountTx要发送的字节数
*I2CMaster_TxArray指向发送缓冲区的指针
I2CMaster_ByteCountRx要接收的字节数
*I2CMaster_RxArray指向接收缓冲区的指针

4.1.3 I2CMaster_SlavePresent(I2CMaster_SlaveAddress)

此功能检查是否有 I2C 从设备连接到时钟和数据线。 它通过向从机发送一个虚拟字节并获取其 ACK 状态来实现。 如果接收到 ACK,则函数返回“ 1”;如果接收到 NACK,则函数返回“ 0”。

4.1.4 I2CMaster_NotReady()

此函数返回繁忙位的值(I2caCtrlRegs.I2CSTR.bit.BB)。

4.1.5 I2CMaster_Wait()

从 I2CMaster_Transmit() 函数中调用此函数。它通过轮询停止位和繁忙位(I2caRegs.I2CSTR.bit.STP 和 I2caRegs.I2CSTR.bit.BB)来等待主服务器完成事务。

4.1.6 i2c_master_int1a_isr

这是 I2C 主中断服务程序。 当主机从机接收数据时,它由读-就绪(RRDY)中断触发。 它将数据存储在位于* I2CMaster_ReceiveField 的接收缓冲区中,并递增指针。

4.2  I2C 从机

4.2.1  I2CSlave_Init(I2CSlave_OwnAddress)

此功能将I2C模块配置为I2C从设备,将两个GPIO配置为I2C时钟和数据线,并设置适当的I2C中断。 它将从站的地址设置为I2CSlave_OwnAddress。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值