• STM32实现PMBus从机程序


    最近在野火的STM32F103VET6开发板上实现PMBus从机程序,这个程序参考了以下这篇博客的关于使用中断法实现I2C从机程序:STM32设置为I2C从机模式_iic从机_柒壹漆的博客-CSDN博客 ,实测这个程序是可以正常运行的,感谢博主的分享!

    另外我还参考了德州仪器的一篇基于TMS320F2803x系列单片机PMBus协议的实现,包括主机和从机程序(源程序和文档下载地址:http://www.ti.com/lit/zip/SPRABJ6,文档的截图如下)。

     PMBus协议的详细内容我就不说了,这里我主要说下PMBusSlave.c这个文件,代码和主要函数如下:

    1、PMBusSlave_Init:初始化I2C,这里使用STM32的硬件I2C,主要配置好引脚模式为开漏输出,时钟为100K-400K之间都可以,还有从机地址和中断,另外要使能自动应答,这样从机在收到每个数据时在第9个时钟周期会把SDA拉低作为应答。

    2、PMBusSlave_DecodeCommand:该函数主要是根据主机发送来的命令在数组中找到对应的命令索引从而对命令进行分组处理。如果发送的命令无效,则根据自己程序的需要进行异常处理。

    3、PMBusSlave_Crc8MakeBitwise:因为绝大部分PMBus通信都使用CRC8校验,这个函数的用于检测接收到的数据是否CRC校验正确以及对发送的数据进行CRC计算。

    4、I2C1_EV_IRQHandler:I2C的事件中断处理程序,这是最主要最核心的部分,绝大部分的PMBus的收发都是在此进行的。主要的几个事件分别介绍如下:

    a) I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED(0x00020002):

    这是主机在发出START信号后,接着发送I2C从机地址(从机地址+最低位的读写位置0),如果发送的地址与当前从机的地址匹配则会产生此中断事件,此处基本不用处理,根据需要做一些变量的初始化也是可以的。

    b) I2C_EVENT_SLAVE_BYTE_RECEIVED(0x00020040):

    这是主机要写数据到从机时,从机接收到了数据就会产生此中断事件。在此处我们应该调用I2C_ReceiveData(I2Cx)函数保存所接收到的数据。如果主机有多个数据要发送,这个事件会多次触发。总之这个地方的主要工作就将数据保存在数据缓冲中。

    c) I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED(0x00060082):

    当主机发送读操作指令时(从机地址+最低位的读写位置1),如果地址与本机地址匹配则会产生该中断事件,在该事件中我们可以开始调用函数I2C_SendData(I2Cx, data[ptr++]);发送第一个数据(可能有多个数据要发送)。此时对发送数据指针进行适当调整,以便后面的中断事件中继续发送数据。

    d) I2C_EVENT_SLAVE_BYTE_TRANSMITTED(0x00060084):

    当主机需要读到多个数据并且从机成功发送了一个数据后就会产生此中断事件,此处我们就根据数据指针继续调用函数2C_SendData(I2Cx, data[ptr++]发送数据,直到所有的数据都发送完成。

    e) I2C_EVENT_SLAVE_STOP_DETECTED(0x00000010):

    当从机检测到主机发送了STOP信号后就会产生该中断事件。此中断中一般会根据主机发送的写指令和要写入的数据进行相应的操作,例如:主机发送VOUT_COMMAND(0x21)对电源的输出电压进行设置,另外当主机读取完所有数据后也会发送STOP信号,此处我们可以对发送操作做一些清理工作,主要看自己程序的要求。

    其实程序中最主要的是要知道在哪个中断事件编写相应的代码,其他像PMBus协议稍微看下资料就明白了,如果不使用STM32,换了一个别的单片机,只需要按照单片机对应的寄存器和事件处理程序写程序就可以了。之前我也写过ATmega16A和PIC16F系列的I2C从机程序,大同小异。

    这个程序有一个问题我一直不明白,就是当主机(我使用的USB转I2C设备)进行从机扫描时会出现多个从机地址,可我明明只连接了一个I2C从机,而且执行主机扫描之后这个程序会死机,我调试发现主机发送从机扫描时,I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED中断事件产生了,不明白为何这里会死机,到时我再调试下卡在哪里了。下图显示的就是主机扫描时出现的多个从机地址(我的从机地址是0x54,7位地址格式)。

    main函数中只需要调用PMBusSlave_Init函数进行初始化设置就可以进入while循环,等待中断事件触发了。

    好了,欢迎大家指出我的代码中存在的问题,我好改进,使程序更加健壮可靠。

    1. /*******************************************************************************
    2. *
    3. * PMBusSlave.c - This program is a software implementation of PMBus over I2C,
    4. * with the Piccolo device acting as the PMBus slave.
    5. *
    6. * Copyright (c) 2011 Texas Instruments Incorporated. All rights reserved.
    7. * Software License Agreement
    8. *
    9. * Texas Instruments (TI) is supplying this software for use solely and
    10. * exclusively on TI's microcontroller products. The software is owned by
    11. * TI and/or its suppliers, and is protected under applicable copyright
    12. * laws. You may not combine this software with "viral" open-source
    13. * software in order to form a larger program.
    14. *
    15. * THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    16. * NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    17. * NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    18. * A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    19. * CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    20. * DAMAGES, FOR ANY REASON WHATSOEVER.
    21. *
    22. ******************************************************************************/
    23. //#include "DSP2803x_Device.h" // DSP280x Headerfile Include File
    24. //#include "DSP2803x_Examples.h" // DSP280x Examples Include File
    25. //#include "DSP2803x_I2C_defines.h"
    26. #include "stm32f10x.h"
    27. #include "stm32f10x_gpio.h"
    28. #include "stm32f10x_i2c.h"
    29. #include "PMBusSlave.h"
    30. #include "PMBus.h"
    31. #include "i2c_slave.h"
    32. #define I2C1_CLOCK_FRQ 100000 // I2C-Frq in Hz (100 kHz)
    33. struct STATUS_REGS StatusRegs;
    34. //This array contains all of the PMBus command bytes (according to the PMBus spec)
    35. //indexed by the command indeces defined in PMBus.h
    36. const unsigned char PMBus_Commands[120] =
    37. {
    38. 0x00, // dummy byte
    39. 0x19,0x78,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x80,0x81,0x82,0x98,
    40. 0x79,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,
    41. 0x93,0x94,0x95,0x96,0x97,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,
    42. 0xA7,0xA8,0xA9,0x13,0x14,0x17,0x18,0x3 ,0x11,0x12,0x15,0x16,
    43. 0x0 ,0x1 ,0x2 ,0x4 ,0x10,0x20,0x3A,0x3D,0x41,0x45,0x47,0x49,
    44. 0x4C,0x50,0x54,0x56,0x5A,0x5C,0x63,0x69,0x21,0x22,0x23,0x24,
    45. 0x25,0x26,0x27,0x28,0x29,0x2A,0x31,0x32,0x33,0x35,0x36,0x37,
    46. 0x38,0x39,0x3B,0x3C,0x3E,0x3F,0x40,0x42,0x43,0x44,0x46,0x48,
    47. 0x4A,0x4B,0x4F,0x51,0x52,0x53,0x55,0x57,0x58,0x59,0x5B,0x5D,
    48. 0x5E,0x5F,0x60,0x61,0x62,0x64,0x65,0x66,0x68,0x6A,0x6B
    49. };
    50. static unsigned char slave_address;
    51. static uint8_t i2c1_mode = I2C1_MODE_WAITING;
    52. //static uint8_t i2c_rcv_finish_flag = 0;//got received all data
    53. static uint8_t i2c_rcv_cnt = 0;
    54. static uint8_t i2c_transmit_cnt = 0;
    55. unsigned char PMBusSlave_ReceiveBuffer[4] = {0,0,0,0};
    56. unsigned char PMBusSlave_TransmitBuffer[5] = {0xDF,0xC5,0x18,0x9F,0xB7};
    57. unsigned char PMBusSlave_Index = 0;
    58. unsigned char PMBusSlave_DummyCommand = 0;
    59. USER CODE
    60. //Example variables, should be changed by user to be application specific
    61. #warning "User should declare application specific PMBus registers or variables."
    62. //initial values
    63. unsigned char Temperature = 0x88; //0x12,STATUS_TEMPERATURE command (R byte)
    64. unsigned char Default_Code = 0; //STORE_DEFAULT_CODE command (W byte)
    65. unsigned char Operation = 0x34; //OPERATION command (R/W byte)
    66. unsigned int Status_Word = 0x5678; //STATUS_WORD command (R word)
    67. unsigned char Status_Byte = 0x00; //STATUS_BYTE command (R byte)
    68. unsigned char Status_Cml = 0x00; //STATUS_CML command (R byte)
    69. unsigned int Vout_Command = 0x90AB; //VOUT_COMMAND command (R/W word)
    70. END USER CODE
    71. /***************************************************************************//**
    72. * @brief Initialize I2C module in slave mode.
    73. * @param I2CSlave_OwnAddress The slave device's own address.
    74. * @return None
    75. ******************************************************************************/
    76. void I2CSlave_Init(uint16_t I2CSlave_OwnAddress)
    77. {
    78. GPIO_InitTypeDef GPIO_InitStructure;
    79. NVIC_InitTypeDef NVIC_InitStructure;
    80. I2C_InitTypeDef I2C_InitStructure;
    81. RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    82. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    83. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    84. /* Configure I2C_EE pins: SCL and SDA */
    85. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    86. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    87. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    88. GPIO_Init(GPIOB, &GPIO_InitStructure);
    89. /* Configure the I2C event priority */
    90. NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
    91. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    92. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    93. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    94. NVIC_Init(&NVIC_InitStructure);
    95. /* Configure I2C error interrupt to have the higher priority */
    96. NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
    97. NVIC_Init(&NVIC_InitStructure);
    98. /* I2C configuration */
    99. I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    100. I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    101. I2C_InitStructure.I2C_OwnAddress1 = I2CSLAVE_ADDR;
    102. I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    103. I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    104. I2C_InitStructure.I2C_ClockSpeed = I2C1_CLOCK_FRQ;
    105. //I2C_OwnAddress2Config(I2C1, 0x00);//configure the second I2C address
    106. /* I2C Peripheral Enable */
    107. I2C_Cmd(I2C1, ENABLE);
    108. /* Apply I2C configuration after enabling it */
    109. I2C_Init(I2C1, &I2C_InitStructure);
    110. I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE); //Part of the STM32 I2C driver
    111. I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
    112. I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE); //Part of the STM32 I2C driver
    113. //======================= the original codes ============================
    114. /*
    115. //Setup Cpu Timer 0 interrupt
    116. EALLOW; // This is needed to write to EALLOW protected registers
    117. PieVectTable.TINT0 = &cpu_timer0_isr;
    118. EDIS; // This is needed to disable write to EALLOW protected registers
    119. // Enable TINT0 in the PIE: Group 1 interrupt 7
    120. PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    121. // Enable CPU int1 which is connected to CPU-Timer 0
    122. IER |= M_INT1;
    123. InitI2CGpio();
    124. InitCpuTimers();
    125. ConfigCpuTimer(&CpuTimer0, 60, 35000); //CPU Timer 0 interrupt after 35 ms (at 60MHz CPU freq.)
    126. // Initialize I2C
    127. I2caRegs.I2COAR = I2CSlave_OwnAddress; // Own address
    128. I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clk
    129. I2caRegs.I2CCLKL = 10; // NOTE: must be non zero
    130. I2caRegs.I2CCLKH = 5; // NOTE: must be non zero
    131. I2caRegs.I2CIER.all = 0x00; // Clear interrupts - polling based method
    132. I2caRegs.I2CMDR.all = 0x0020; // Take I2C out of reset
    133. // Stop I2C when suspended
    134. return;
    135. */
    136. }
    137. /***************************************************************************//**
    138. * @brief Configure the C2000 device as a PMBus slave.
    139. * @param PMBusSlave_DeviceAddress The slave device's own address.
    140. * @return None
    141. ******************************************************************************/
    142. #warning "Change the GPIOs used for Alert and Control lines to match the desired GPIOs for the application."
    143. void PMBusSlave_Init(unsigned char PMBusSlave_DeviceAddress)
    144. {
    145. StatusRegs.StatusWord.all = 0; //Clear status bits for the status registers we are using
    146. StatusRegs.StatusCml.all = 0;
    147. /*
    148. // Control Line functionality GPIO0
    149. GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0; //Enable pullup on GPIO0
    150. GpioDataRegs.GPASET.bit.GPIO0 = 1; //Drive line high
    151. GpioCtrlRegs.GPAQSEL1.bit.GPIO0 = 0; //SYNC to SYSCLKOUT
    152. GpioCtrlRegs.GPACTRL.bit.QUALPRD0 = 0; //no qualification (SYNC to SYSCLKOUT)
    153. GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; //GPIO0 = GPIO0
    154. GpioCtrlRegs.GPADIR.bit.GPIO0 = 0; //GPIO0 = input
    155. // SMBUS Alert functionality (GPIO2 = Alert line)
    156. GpioCtrlRegs.GPAPUD.bit.GPIO2 = 0; //Enable pullup on GPIO2
    157. GpioDataRegs.GPASET.bit.GPIO2 = 1; //Drive line high
    158. GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0; //GPIO2 = GPIO2
    159. GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; //GPIO2 = output
    160. */
    161. slave_address = PMBusSlave_DeviceAddress;
    162. I2CSlave_Init(PMBusSlave_DeviceAddress); // Initialize USCI module
    163. }
    164. /***************************************************************************//**
    165. * @brief Determine what type of PMBus command was received from the master.
    166. *
    167. * The function also prepares data in the transmit buffer to send to
    168. * the master for supported READ and READ/WRITE commands. Users should modify
    169. * the code to implement their application's supported PMBus commands.
    170. * @param PMBusSlave_RxCommand The command byte received from the master.
    171. * @return Command group of the received command.
    172. ******************************************************************************/
    173. unsigned char PMBusSlave_DecodeCommand(unsigned char PMBusSlave_RxCommand)
    174. {
    175. unsigned char PMBusSlave_CommandGroup;
    176. for(PMBusSlave_Index = 0; PMBusSlave_Index < 120; PMBusSlave_Index++)
    177. {
    178. if(PMBus_Commands[PMBusSlave_Index] == PMBusSlave_RxCommand)
    179. break;
    180. }
    181. USER CODE
    182. #warning "User should change code to implement their application's supported PMBus commands."
    183. switch (PMBusSlave_Index) //should include all user supported commands
    184. {
    185. case STATUS_TEMPERATURE:
    186. PMBusSlave_TransmitBuffer[0] = Temperature;
    187. break;
    188. case READ_POUT://output power for example
    189. PMBusSlave_TransmitBuffer[0] = Vout_Command; //lower byte
    190. PMBusSlave_TransmitBuffer[1] = Vout_Command >> 8; //upper byte
    191. break;
    192. case STORE_DEFAULT_CODE:
    193. break;
    194. case OPERATION:
    195. PMBusSlave_TransmitBuffer[0] = Operation;
    196. break;
    197. case STATUS_WORD:
    198. PMBusSlave_TransmitBuffer[0] = Status_Word; //lower byte
    199. PMBusSlave_TransmitBuffer[1] = Status_Word >> 8; //upper byte
    200. break;
    201. case VOUT_COMMAND://0x21 command
    202. PMBusSlave_TransmitBuffer[0] = Vout_Command; //lower byte
    203. PMBusSlave_TransmitBuffer[1] = Vout_Command >> 8; //upper byte
    204. break;
    205. default:
    206. PMBusSlave_DummyCommand = 1; //command not supported by this slave
    207. break;
    208. }
    209. END USER CODE
    210. if(PMBusSlave_Index == 0)//dummy byte to check if slave is present
    211. PMBusSlave_DummyCommand = 1;
    212. if(PMBusSlave_Index > 0 && PMBusSlave_Index < 13) //read byte from slave device
    213. PMBusSlave_CommandGroup = READBYTE;
    214. if(PMBusSlave_Index > 12 && PMBusSlave_Index < 40) // read word from slave device
    215. PMBusSlave_CommandGroup = READWORD;
    216. if(PMBusSlave_Index > 39 && PMBusSlave_Index < 44) // write byte to slave device
    217. PMBusSlave_CommandGroup = WRITEBYTE;
    218. if(PMBusSlave_Index > 43 && PMBusSlave_Index < 49) // send byte to slave device
    219. PMBusSlave_CommandGroup = SENDBYTE;
    220. /* Read or write one byte of data. R/W oprn. decided based on RWFlag *******/
    221. if(PMBusSlave_Index > 48 && PMBusSlave_Index < 69)
    222. {
    223. PMBusSlave_CommandGroup = RWBYTE;
    224. }
    225. /* Read or write one word of data. R/W oprn. decided based on RWFlag *******/
    226. if(PMBusSlave_Index > 68 && PMBusSlave_Index < 120) // R/W Word
    227. {
    228. PMBusSlave_CommandGroup = RWWORD;
    229. }
    230. //*****************************************
    231. //illegal index - invalid command trap
    232. //===Here we don't enter dead loop===
    233. //if(PMBusSlave_Index >= 120)
    234. //while(1);
    235. //*****************************************
    236. return PMBusSlave_CommandGroup;
    237. }
    238. static void PMBus_ClearFlag(void)
    239. {
    240. /* ADDR Flag clear */
    241. while((I2C1->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR)
    242. {
    243. I2C1->SR1;
    244. I2C1->SR2;
    245. }
    246. /* STOPF Flag clear */
    247. while((I2C1->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF)
    248. {
    249. I2C1->SR1;
    250. I2C1->CR1 |= 0x1;
    251. }
    252. }
    253. void I2C1_ER_IRQHandler(void)
    254. {
    255. if (I2C_GetITStatus(I2C1, I2C_IT_AF))
    256. {
    257. I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    258. }
    259. }
    260. /***************************************************************************//**
    261. * @brief Receives a command from the master and performs reads and writes accordingly.
    262. *
    263. * This function should be modified by the user for their application's
    264. * supported commands to make function calls to carry out the commands
    265. * (e.g. adjusting fan speed)
    266. * @param None
    267. * @return None
    268. ******************************************************************************/
    269. //void PMBusSlave(void)
    270. void I2C1_EV_IRQHandler(void)
    271. {
    272. unsigned char PMBusSlave_Command = 0, PMBusSlave_CommandType = 0;
    273. uint8_t wert;
    274. uint32_t event;
    275. unsigned char PMBusSlave_CrcMsgSize = 0;
    276. unsigned char PMBusSlave_CrcMsg[5];
    277. unsigned char PMBusSlave_CrcMasterGenerated = 0;
    278. unsigned char PMBusSlave_CrcSlaveGenerated = 0;
    279. PMBusSlave_CrcMsg[0] = slave_address << 1;
    280. //Reading last event
    281. event = I2C_GetLastEvent(I2C1);
    282. switch(event)
    283. {
    284. //Master has sent the slave address and prepared to send data to the slave
    285. //and the slave address is matched the slave device.
    286. //There is a problem that once the master sends out a broadcast address,
    287. //this system is halted on this event.
    288. case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:
    289. i2c1_mode = I2C1_MODE_SLAVE_ADR_WR;
    290. break;
    291. // Master has sent a byte to the slave
    292. case I2C_EVENT_SLAVE_BYTE_RECEIVED:
    293. wert = I2C_ReceiveData(I2C1);
    294. PMBusSlave_ReceiveBuffer[i2c_rcv_cnt] = wert;
    295. i2c_rcv_cnt++;
    296. break;
    297. //Master has sent the slave address(R) and the slave prepares to send data to the master
    298. case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:
    299. i2c1_mode = I2C1_MODE_SLAVE_ADR_RD;
    300. PMBusSlave_ReceiveBuffer[0] = I2C_ReceiveData(I2C1);
    301. PMBusSlave_Command = PMBusSlave_ReceiveBuffer[0]; //get register value received prior to this step
    302. PMBusSlave_CommandType = PMBusSlave_DecodeCommand(PMBusSlave_Command);
    303. switch(PMBusSlave_CommandType)
    304. {
    305. //Implementation with Packet Error Checking
    306. case READBYTE: // master reading byte from slave
    307. //setup PEC byte
    308. i2c_transmit_cnt = 0;
    309. PMBusSlave_TransmitBuffer[0] = 0x99;//example data
    310. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    311. PMBusSlave_CrcMsg[2] = (slave_address << 1) + 1; // store slave address + R/W=1
    312. PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0]; // store tx byte 1
    313. PMBusSlave_CrcMsgSize = 4;
    314. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    315. PMBusSlave_TransmitBuffer[1] = PMBusSlave_CrcSlaveGenerated;
    316. I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    317. i2c_transmit_cnt++;
    318. break;
    319. case READWORD: // master reading word from slave
    320. //setup PEC byte
    321. i2c_transmit_cnt = 0;
    322. PMBusSlave_TransmitBuffer[0] = 0xAB; //lower byte
    323. PMBusSlave_TransmitBuffer[1] = 0x90; //upper byte
    324. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    325. PMBusSlave_CrcMsg[2] = (slave_address << 1) + 1; // store slave address + R/W=1
    326. PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0]; // store tx byte 1
    327. PMBusSlave_CrcMsg[4] = PMBusSlave_TransmitBuffer[1]; // store tx byte 2
    328. PMBusSlave_CrcMsgSize = 5;
    329. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    330. PMBusSlave_TransmitBuffer[2] = PMBusSlave_CrcSlaveGenerated;
    331. I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    332. i2c_transmit_cnt++;
    333. break;
    334. case RWWORD: //read/write word
    335. //setup PEC byte
    336. i2c_transmit_cnt = 0;
    337. PMBusSlave_TransmitBuffer[0] = 0xF8; //lower byte of example data
    338. PMBusSlave_TransmitBuffer[1] = 0xD9; //upper byte
    339. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    340. PMBusSlave_CrcMsg[2] = (slave_address << 1) + 1; // store slave address + R/W=1
    341. PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0]; // store tx byte 1
    342. PMBusSlave_CrcMsg[4] = PMBusSlave_TransmitBuffer[1]; // store tx byte 2
    343. PMBusSlave_CrcMsgSize = 5;
    344. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    345. PMBusSlave_TransmitBuffer[2] = PMBusSlave_CrcSlaveGenerated;
    346. I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    347. i2c_transmit_cnt++;
    348. break;
    349. //used to send error message if the command can't be recognized
    350. default:
    351. //setup PEC byte
    352. i2c_transmit_cnt = 0;
    353. PMBusSlave_TransmitBuffer[0] = 0xFF; //lower byte
    354. PMBusSlave_TransmitBuffer[1] = 0xEE; //upper byte
    355. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    356. PMBusSlave_CrcMsg[2] = (slave_address << 1) + 1; // store slave address + R/W=1
    357. PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0]; // store tx byte 1
    358. PMBusSlave_CrcMsg[4] = PMBusSlave_TransmitBuffer[1]; // store tx byte 2
    359. PMBusSlave_CrcMsgSize = 5;
    360. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    361. PMBusSlave_TransmitBuffer[2] = PMBusSlave_CrcSlaveGenerated;
    362. I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    363. i2c_transmit_cnt++;
    364. break;
    365. }
    366. break;
    367. //The slave device has to send the next byte to the master if needed
    368. case I2C_EVENT_SLAVE_BYTE_TRANSMITTED:
    369. //I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    370. //i2c_transmit_cnt++;
    371. i2c1_mode = I2C1_MODE_DATA_BYTE_RD;
    372. if(i2c_transmit_cnt < sizeof(PMBusSlave_TransmitBuffer))
    373. {
    374. I2C_SendData(I2C1, PMBusSlave_TransmitBuffer[i2c_transmit_cnt]);
    375. i2c_transmit_cnt++;
    376. }
    377. else
    378. {
    379. i2c_transmit_cnt = 0;
    380. }
    381. break;
    382. //The slave has received all data from the master and then prepares to write data or other operations accordingly.
    383. case I2C_EVENT_SLAVE_STOP_DETECTED:
    384. if(i2c_rcv_cnt > 0)
    385. {
    386. PMBusSlave_Command = PMBusSlave_ReceiveBuffer[0]; //get the received data
    387. PMBusSlave_CommandType = PMBusSlave_DecodeCommand(PMBusSlave_Command);
    388. switch(PMBusSlave_CommandType)
    389. {
    390. case WRITEWORD: // master writing word to slave
    391. PMBusSlave_CrcMasterGenerated = PMBusSlave_ReceiveBuffer[3]; //get the received PEC byte from master
    392. //calculate PEC byte for comparison
    393. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    394. PMBusSlave_CrcMsg[2] = PMBusSlave_ReceiveBuffer[1]; // store rx byte
    395. PMBusSlave_CrcMsg[3] = PMBusSlave_ReceiveBuffer[2]; // store rx byte
    396. PMBusSlave_CrcMsgSize = 4; // # of bytes
    397. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    398. //if the bytes do not match, respond according to the PMBus Spec.
    399. if(PMBusSlave_CrcSlaveGenerated != PMBusSlave_CrcMasterGenerated) //compare received PEC byte with calculated PEC byte
    400. {
    401. //Flush the received command byte and any received data
    402. PMBusSlave_Command = 0; //flush command byte
    403. PMBusSlave_Index = 0; //clear index so no data is stored
    404. PMBusSlave_ReceiveBuffer[0] = 0; //flush received data bytes
    405. PMBusSlave_ReceiveBuffer[1] = 0;
    406. PMBusSlave_ReceiveBuffer[2] = 0;
    407. PMBusSlave_ReceiveBuffer[3] = 0;
    408. //ERROR process if needed
    409. }
    410. break;
    411. case RWWORD: //read/write word
    412. //while(!I2caRegs.I2CSTR.bit.AAS); //wait until addressed by master
    413. //if (I2caRegs.I2CSTR.bit.SDIR == 0) //determine if slave should send/receive
    414. { //slave receiver
    415. PMBusSlave_CrcMasterGenerated = PMBusSlave_ReceiveBuffer[3];//get the received PEC byte from master
    416. //calculate PEC byte for comparison
    417. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    418. PMBusSlave_CrcMsg[2] = PMBusSlave_ReceiveBuffer[1]; // store rx byte
    419. PMBusSlave_CrcMsg[3] = PMBusSlave_ReceiveBuffer[2]; // store rx byte
    420. PMBusSlave_CrcMsgSize = 4; // # of bytes
    421. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    422. //if the bytes do not match, respond according to the PMBus Spec.
    423. if(PMBusSlave_CrcSlaveGenerated != PMBusSlave_CrcMasterGenerated) //compare received PEC byte with calculated PEC byte
    424. {
    425. //Flush the received command byte and any received data
    426. PMBusSlave_Command = 0; //flush command byte
    427. PMBusSlave_Index = 0; //clear index so no data is stored
    428. PMBusSlave_ReceiveBuffer[0] = 0; //flush received data bytes
    429. PMBusSlave_ReceiveBuffer[1] = 0;
    430. PMBusSlave_ReceiveBuffer[2] = 0;
    431. PMBusSlave_ReceiveBuffer[3] = 0;
    432. //ERROR process if needed
    433. }
    434. else//TODO according to the command
    435. {
    436. switch(PMBusSlave_Command)
    437. {
    438. default:
    439. break;
    440. }
    441. }
    442. }
    443. break;
    444. case WRITEBYTE: // master writing single byte to slave
    445. PMBusSlave_CrcMasterGenerated = PMBusSlave_ReceiveBuffer[2]; //get the received PEC byte from master
    446. //calculate PEC byte for comparison
    447. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    448. PMBusSlave_CrcMsg[2] = PMBusSlave_ReceiveBuffer[1]; // store rx byte
    449. PMBusSlave_CrcMsgSize = 3; // # of bytes
    450. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    451. //if the bytes do not match, respond according to the PMBus Spec.
    452. if(PMBusSlave_CrcSlaveGenerated != PMBusSlave_CrcMasterGenerated) //compare received PEC byte with calculated PEC byte
    453. {
    454. //Flush the received command byte and any received data
    455. PMBusSlave_Command = 0; //flush command byte
    456. PMBusSlave_Index = 0; //clear index so no data is stored
    457. PMBusSlave_ReceiveBuffer[0] = 0; //flush received data bytes
    458. PMBusSlave_ReceiveBuffer[1] = 0;
    459. PMBusSlave_ReceiveBuffer[2] = 0;
    460. //ERROR process if needed
    461. }
    462. break;
    463. case SENDBYTE: //we already received the command.
    464. //while(!I2caRegs.I2CSTR.bit.RRDY); //wait for the data
    465. //PMBusSlave_CrcMasterGenerated = I2caRegs.I2CDRR; //get the received PEC byte from master
    466. //StopCpuTimer0(); //No timeout, so stop the timer
    467. //ReloadCpuTimer0(); //Reload the period value (35 ms timeout)
    468. //calculate PEC byte for comparison
    469. PMBusSlave_CrcMsg[1] = PMBusSlave_Command; // store first rx byte
    470. PMBusSlave_CrcMsgSize = 2; // # of bytes
    471. PMBusSlave_CrcSlaveGenerated = PMBusSlave_Crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);
    472. //if the bytes do not match, respond according to the PMBus Spec.
    473. if(PMBusSlave_CrcSlaveGenerated != PMBusSlave_CrcMasterGenerated) //compare received PEC byte with calculated PEC byte
    474. {
    475. //Flush the received command byte
    476. PMBusSlave_Command = 0; //flush command byte
    477. PMBusSlave_Index = 0; //clear index so no data is stored
    478. //Set status bits
    479. //StatusRegs.StatusWord.StatusByte.bit.CML = 1; //set the CML bit
    480. //StatusRegs.StatusCml.bit.PACKET_ERROR_CHECK_FAILED = 1; //set the PEC failed bit
    481. //signal the master via the Alert line
    482. //GpioDataRegs.GPACLEAR.bit.GPIO2 = 1; //Drive line low
    483. }
    484. break; //User could insert handling code here.
    485. default:
    486. break;
    487. }
    488. i2c_rcv_cnt = 0;
    489. }
    490. PMBus_ClearFlag();
    491. i2c1_mode = I2C1_MODE_WAITING;
    492. break;
    493. default:
    494. break;
    495. }
    496. // //Event handle
    497. // if(event == I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED)
    498. // {
    499. // // Master has sent the slave address to send data to the slave
    500. // i2c1_mode = I2C1_MODE_SLAVE_ADR_WR;
    501. // }
    502. // else if(event == I2C_EVENT_SLAVE_BYTE_RECEIVED)
    503. // {
    504. // // Master has sent a byte to the slave
    505. // wert = I2C_ReceiveData(I2C1);
    506. // PMBusSlave_ReceiveBuffer[i2c_rcv_cnt] = wert;
    507. // i2c_rcv_cnt++;
    508. //
    509. // /*=========== the old statements ================
    510. // // Check address
    511. // if(i2c1_mode == I2C1_MODE_SLAVE_ADR_WR)
    512. // {
    513. // i2c1_mode = I2C1_MODE_ADR_BYTE;
    514. // // Set current ram address
    515. // i2c1_ram_adr = wert;
    516. // }
    517. // else
    518. // {
    519. // i2c1_mode = I2C1_MODE_DATA_BYTE_WR;
    520. // // Store data in RAM
    521. // Set_I2C1_Ram(i2c1_ram_adr, wert);
    522. // // Next ram adress
    523. // i2c1_ram_adr++;
    524. // }*/
    525. // }
    526. // else if(event == I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED)
    527. // {
    528. // // Master has sent the slave address to read data from the slave
    529. // i2c1_mode = I2C1_MODE_SLAVE_ADR_RD;
    530. // // Read data from RAM
    531. // wert = Get_I2C1_Ram(i2c1_ram_adr);
    532. // // Send data to the master
    533. // I2C_SendData(I2C1, wert);
    534. // // Next ram adress
    535. // i2c1_ram_adr++;
    536. // }
    537. // else if(event == I2C_EVENT_SLAVE_BYTE_TRANSMITTED)
    538. // {
    539. // // Master wants to read another byte of data from the slave
    540. // i2c1_mode = I2C1_MODE_DATA_BYTE_RD;
    541. // // Read data from RAM
    542. // wert = Get_I2C1_Ram(i2c1_ram_adr);
    543. // // Send data to the master
    544. // I2C_SendData(I2C1, wert);
    545. // // Next ram adress
    546. // i2c1_ram_adr++;
    547. // }
    548. // else if(event == I2C_EVENT_SLAVE_STOP_DETECTED)
    549. // {
    550. // // Master has STOP sent
    551. // if(i2c_rcv_cnt)
    552. // {
    553. // i2c_rcv_finish_flag = 1;
    554. // }
    555. // PMBus_ClearFlag();
    556. // i2c1_mode = I2C1_MODE_WAITING;
    557. // }
    558. //I2C error check
    559. if (I2C_GetITStatus(I2C1, I2C_IT_AF))
    560. {
    561. I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    562. //i2c_rcv_finish_flag = 0;
    563. }
    564. USER CODE
    565. //contains what actions to take after getting information from the master,
    566. //usually where to store received data and what functions to call in response
    567. #warning "User should modify code to implement their application's supported PMBus commands."
    568. switch (PMBusSlave_Index) //should include all user supported commands
    569. {
    570. case STATUS_TEMPERATURE:
    571. break;
    572. case STORE_DEFAULT_CODE:
    573. Default_Code = PMBusSlave_ReceiveBuffer[0];
    574. break;
    575. case OPERATION:
    576. Operation = PMBusSlave_ReceiveBuffer[0];
    577. break;
    578. case STATUS_WORD:
    579. break;
    580. case VOUT_COMMAND:
    581. Vout_Command = (PMBusSlave_ReceiveBuffer[1] << 8) | PMBusSlave_ReceiveBuffer[0];
    582. break;
    583. default: //command not supported by this slave
    584. break;
    585. }
    586. END USER CODE
    587. }
    588. #if PEC
    589. /***************************************************************************//**
    590. * @brief Calculate the Packet Error Checking byte.
    591. * @param PMBusSlave_CRC Initial value.
    592. * @param PMBusSlave_Poly The polynomial to use for the calculation.
    593. * @param *PMBusSlave_PMsg Pointer to the bytes from the PMBus transaction.
    594. * @param PMBusSlave_MsgSize Number of bytes in the last transaction.
    595. * @return The PEC byte.
    596. ******************************************************************************/
    597. static unsigned short PMBusSlave_Crc8MakeBitwise(unsigned char PMBusSlave_CRC, unsigned char PMBusSlave_Poly, unsigned char *PMBusSlave_Pmsg, unsigned int PMBusSlave_MsgSize)
    598. {
    599. unsigned int i, j, carry;
    600. unsigned char msg;
    601. PMBusSlave_CRC = *PMBusSlave_Pmsg++; // first byte loaded in "crc"
    602. for(i = 0 ; i < PMBusSlave_MsgSize-1 ; i ++)
    603. {
    604. msg = *PMBusSlave_Pmsg++; // next byte loaded in "msg"
    605. for(j = 0 ; j < 8 ; j++)
    606. {
    607. carry = PMBusSlave_CRC & 0x80; // check if MSB=1
    608. PMBusSlave_CRC = (PMBusSlave_CRC << 1) | (msg >> 7); // Shift 1 bit of next byte into crc
    609. if(carry) PMBusSlave_CRC ^= PMBusSlave_Poly; // If MSB = 1, perform XOR
    610. msg <<= 1; // Shift left msg byte by 1
    611. msg &= 0x00FF;
    612. }
    613. }
    614. // The previous loop computes the CRC of the input bit stream. To this,
    615. // 8 trailing zeros are padded and the CRC of the resultant value is
    616. // computed. This gives the final CRC of the input bit stream.
    617. for(j = 0 ; j < 8 ; j++)
    618. {
    619. carry = PMBusSlave_CRC & 0x80;
    620. PMBusSlave_CRC <<= 1;
    621. if(carry) PMBusSlave_CRC ^= PMBusSlave_Poly;
    622. }
    623. PMBusSlave_CRC &= 0x00FF; //We only want one byte (lower)
    624. return(PMBusSlave_CRC);
    625. }
    626. #endif
    627. /***************************************************************************//**
    628. * @brief Handles timeouts. Triggered if clock held low > 35ms.
    629. * @param None
    630. * @return None
    631. ******************************************************************************/
    632. /*
    633. interrupt void cpu_timer0_isr(void)
    634. {
    635. // Timed out. Reset module.
    636. I2caRegs.I2CMDR.bit.IRS = 0; //reset
    637. // Acknowledge this interrupt to receive more interrupts from group 1
    638. PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
    639. }
    640. */

  • 相关阅读:
    夜天之书 #68 开源码力圆桌文字稿
    Chrome访问剪切板实现右键复制粘贴
    使用CountDownLatch解决接口循环网络请求造成的耗时问题
    vue实现轮播图详解
    uniapp实现多行文本溢出超过指定行数 展开 收起
    用python的mako模板库写一个自动生成.c/.h文件generate_code功能
    Unity-特殊文件夹
    Redis缓存篇:高频问题横扫核心知识点,面试高级工程师必备知识体系
    工商银行卡安全码怎么看
    游戏道具平台|基于Springboot+Vue实现游戏道具平台系统
  • 原文地址:https://blog.csdn.net/jmmx/article/details/133039123