在网上总看到有人说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 }