在網上總看到有人說STM32的硬件IIC不好用,可到底哪不好用,也一直沒找到問題點。
最近有空看了一下STM32的硬件IIC,里面很多EV5/EV6等事件的概念是有些別扭,不過不影響使用。
寫了一個簡單的polling模式下的數據讀寫,也能正常實現功能。但是在單步調試時發現了一些問題,先上代碼:
1 void STM32F407_IIC_readNByte(u8 addr, u8 * pdata, u8 length) 2 { 3 u8 i = 0; 4 I2C_GenerateSTART(I2C1, ENABLE); 5 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 6 7 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 8 // I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED); 9 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 10 I2C_SendData(I2C1, addr); 11 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 12 I2C_GenerateSTART(I2C1, ENABLE); 13 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 14 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver); 15 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //EV6 16 17 for(i = 0; i < length; i++) 18 { 19 if(i == 6) 20 { 21 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7_1 22 *pdata = I2C_ReceiveData(I2C1); 23 I2C_AcknowledgeConfig(I2C1, DISABLE); 24 I2C_GenerateSTOP(I2C1, ENABLE); 25 pdata++; 26 } 27 else 28 { 29 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7 30 *pdata = I2C_ReceiveData(I2C1); 31 pdata++; 32 } 33 } 34 35 }
上述代碼第5行是在循環查詢EV5事件是否發生,EV5事件是SB==1,可通過先讀取SR1,在寫DR寄存器來清除SB的狀態,單步調試也是如此。
第9行是在循環查詢EV6事件是否發生,EV6事件是ADDR==1,可通過先讀取SR1,再讀取SR2清除ADDR的狀態。但是代碼在全速運行時可正常執行,在單步調試時,發現還未讀取SR1/SR2,ADDR的狀態就已清0,導致第九行的while循環檢測不到EV6事件,不知此問題是否是STM32硬件IIC的一個bug,但此問題不影響正常使用
一般IIC器件的讀是可以連續讀的,但寫時一次最多只能寫一個page,寫下一個page,需要重新發送起始位,要寫入的地址等,經測試,如下代碼可實現正常讀寫(polling模式下):

1 #include <sys.h> 2 #include "delay.h" 3 #include "STM32_IIC.h" 4 5 #define AT24C02_PAGE_SIZE 8 6 7 void STM32F407_IIC_Init() 8 { 9 GPIO_InitTypeDef GPIO_InitStructure; 10 I2C_InitTypeDef I2C_InitStructure; 11 12 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 13 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 14 15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; 16 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 17 GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; 18 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 19 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 20 GPIO_Init(GPIOB, &GPIO_InitStructure); 21 22 GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1); 23 GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1); 24 25 I2C_InitStructure.I2C_ClockSpeed = 100000; 26 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; 27 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; 28 I2C_InitStructure.I2C_OwnAddress1 = 0x44; 29 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; 30 I2C_InitStructure.I2C_DutyCycle = 0; 31 I2C_Init(I2C1, &I2C_InitStructure); 32 I2C_AcknowledgeConfig(I2C1, ENABLE); 33 I2C_StretchClockCmd(I2C1, DISABLE); 34 } 35 36 u8 STM32F407_IIC_randomReadByte(u8 addr) 37 { 38 u8 retvalue = 0; 39 I2C_GenerateSTART(I2C1, ENABLE); 40 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 41 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 42 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 43 I2C_SendData(I2C1, addr); 44 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); 45 I2C_GenerateSTART(I2C1, ENABLE); 46 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 47 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver); 48 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); 49 I2C_AcknowledgeConfig(I2C1, DISABLE); 50 while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)); 51 retvalue = I2C_ReceiveData(I2C1); 52 I2C_GenerateSTOP(I2C1, DISABLE); 53 return retvalue; 54 } 55 56 u8 STM32F407_IIC_readCurrentByte() 57 { 58 u8 retvalue = 0; 59 while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); 60 I2C_GenerateSTART(I2C1, ENABLE); 61 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 62 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver); 63 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //EV6 64 retvalue = I2C_ReceiveData(I2C1); 65 I2C_AcknowledgeConfig(I2C1, DISABLE); 66 while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)); 67 retvalue = I2C_ReceiveData(I2C1); 68 I2C_GenerateSTOP(I2C1, DISABLE); 69 return retvalue; 70 } 71 72 void STM32F407_IIC_randomWriteByte(u8 addr, u8 value) 73 { 74 I2C_GenerateSTART(I2C1, ENABLE); 75 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); 76 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 77 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 78 I2C_SendData(I2C1, addr); 79 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); 80 I2C_SendData(I2C1, value); 81 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); 82 I2C_GenerateSTOP(I2C1, ENABLE); 83 } 84 85 void STM32F407_IIC_readNByte(u8 addr, u8 * pdata, u8 length) 86 { 87 u8 i = 0; 88 I2C_GenerateSTART(I2C1, ENABLE); 89 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 90 91 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 92 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 93 I2C_SendData(I2C1, addr); 94 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 95 I2C_GenerateSTART(I2C1, ENABLE); 96 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 97 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Receiver); 98 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //EV6 99 100 for(i = 0; i < length; i++) 101 { 102 if(i == length - 2) 103 { 104 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7_1 105 *pdata = I2C_ReceiveData(I2C1); 106 I2C_AcknowledgeConfig(I2C1, DISABLE); 107 I2C_GenerateSTOP(I2C1, ENABLE); 108 pdata++; 109 } 110 else 111 { 112 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7 113 *pdata = I2C_ReceiveData(I2C1); 114 pdata++; 115 } 116 } 117 } 118 119 120 /* This function will not roll over if the program address is out of current page boundary */ 121 void STM32F407_IIC_writePage(u8 addr, u8 *pdata, u8 length) 122 { 123 u8 i = 0; 124 u8 remainToWrite = ((AT24C02_PAGE_SIZE - (addr % 8)) > length) ? length : (AT24C02_PAGE_SIZE - (addr % 8)); 125 126 I2C_GenerateSTART(I2C1, ENABLE); 127 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 128 129 I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 130 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 131 I2C_SendData(I2C1, addr); 132 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 133 for(i = 0; i < remainToWrite; i++) 134 { 135 I2C_SendData(I2C1, *pdata); 136 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 137 pdata++; 138 } 139 I2C_GenerateSTOP(I2C1, ENABLE); 140 } 141 142 143 /* This function will roll over if the program address is out of current page boundary */ 144 //void STM32F407_IIC_writePage(u8 addr, u8 *pdata, u8 length) 145 //{ 146 // u8 i = 0; 147 // I2C_GenerateSTART(I2C1, ENABLE); 148 // while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5 149 // 150 // I2C_Send7bitAddress(I2C1, 0xA0, I2C_Direction_Transmitter); 151 // while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //EV6 152 // I2C_SendData(I2C1, addr); 153 // while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 154 // for(i = 0; i < length; i++) 155 // { 156 // I2C_SendData(I2C1, *pdata); 157 // while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING)); //EV8 158 // pdata++; 159 // } 160 // I2C_GenerateSTOP(I2C1, ENABLE); 161 //} 162 163 void STM32F407_IIC_writeNByte(u8 addr, u8 *pdata, u8 length) 164 { 165 u8 actualWriteByte = 0; 166 while(length > 0) 167 { 168 actualWriteByte = ((AT24C02_PAGE_SIZE - (addr % 8)) > length) ? length : (AT24C02_PAGE_SIZE - (addr % 8)); 169 STM32F407_IIC_writePage(addr, pdata, length); 170 addr += actualWriteByte; 171 pdata += actualWriteByte; 172 length -= actualWriteByte; 173 delay_ms(5); 174 } 175 }