之前使用I2C是在CS43L22或者DCMI下用过,不过,实际上,我们用的效率比较低,只是为了实现某些功能而已,实际上并不是需要这样的.先计算一下,I2C的时序,以及事件.
首先读时序,对于I2C,先是读写时序.
- 第一步是I2C_GenerateSTART,这个会发生I2C_EVENT_MASTER_MODE_SELECT事件.
- 第二步是I2C_Send7bitAddress,发送从机地址,以及读写状态.这时候会发生I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED事件.
- 第三步是I2C_SendData,发送的是从寄存器地址,这三步,读写一致,会发生I2C_EVENT_MASTER_BYTE_TRANSMITTED事件.
- 针对写入时序,会反复进入I2C_EVENT_MASTER_BYTE_TRANSMITTING,直到发送结束.
- 针对读取时序,重新执行第一第二步,然后反复进入I2C_EVENT_MASTER_BYTE_TRANSMITTING.
那么,我们就可以开I2C事件中断,查询我们事件,因为整个I2C生命周期里面,我们就不再干预了,所以,最好是有个类似标志位的东西. 我们需要知道的是,当前I2C时候空闲,在做Read还是Write.目标设备的地址DeviceAddress,目标寄存器地址DeviceRegister,需要传输的长度BufferLen,以及我用到的pBuff,另外再传输过程需要记录,还需要PointerIndex,另外I2C只有事件中断,我们中断逻辑内应该是读写分离的,读时候不写,写时候不读,读取时序其实是写-读,写入时序是写.所以我捏造了两个人工中断.I2C1_RX_IRQHandler和I2C1_TX_IRQHandler.定义结构体.
typedef struct { __IO uint8_t IDLE: 1; uint8_t RW: 1; uint8_t DeviceAddress; uint8_t DeviceRegister; volatile uint8_t PointerIndex; uint8_t BufferLen; volatile uint8_t * pBuff; void (* IRQn)(); } I2C1_Hal_Def;
初始化就和普通I2C初始化没什么区别,只需要多加一个中断.
void I2C1_Hal_Init(void) { I2C_InitTypeDef I2C_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; I2C_Cmd(I2C1, DISABLE); I2C_DeInit(I2C1); /* Connect I2C_SCL*/ GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); /* Connect I2C_SDA*/ GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1); /* Configure I2C pins: SCL and SDA ---------------------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_Init(GPIOB, &GPIO_InitStructure); /* DISABLE I2C event and buffer interrupt */ I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE); /* I2C configuration -----------------------------------------------------*/ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x32; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 400000; I2C_Init(I2C1, &I2C_InitStructure); /* Configure and enable I2C interrupt ------------------------------------*/ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Enable I2C ------------------------------------------------------------*/ I2C_Cmd(I2C1, ENABLE); }
但是,写入读出函数,就是需要填充刚才的结构体,然后发送一个Start,马上就能进入中断.
uint32_t I2C1_Hal_Write(uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint16_t writeLen) { if (I2C_Hal_Status.IDLE != 0) return I2C1_FAIL; I2C_Hal_Status.IDLE = 1; I2C_Hal_Status.DeviceAddress = i2cSaleAddress; I2C_Hal_Status.DeviceRegister = writeAddress; I2C_Hal_Status.PointerIndex = 0; I2C_Hal_Status.RW = 0; I2C_Hal_Status.BufferLen = writeLen; I2C_Hal_Status.pBuff = buff; I2C_Hal_Status.IRQn = (void ( *)( ))I2C1_TX_IRQHandler; I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); /* Send I2C START condition */ I2C_GenerateSTART(I2C1, ENABLE); return I2C1_OK; }
这个函数,执行后马上就返回了, 并不阻塞任何的应用.在Start传输后,会马上进入中断,在中断内进行事务传输.
static void I2C1_TX_IRQHandler(void) { switch (I2C_GetLastEvent(I2C1)) { /* Test on I2Cx EV5 and clear it */ case I2C_EVENT_MASTER_MODE_SELECT: I2C_Send7bitAddress(I2C1, I2C_Hal_Status.DeviceAddress, I2C_Direction_Transmitter); break; /* Test on I2Cx EV6 and first EV8 and clear them */ case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: /* Send the first data */ I2C_SendData(I2C1, I2C_Hal_Status.DeviceRegister); /* EV8 just after EV6 */ break; case I2C_EVENT_MASTER_BYTE_TRANSMITTING: if((I2C_Hal_Status.PointerIndex < I2C_Hal_Status.BufferLen) && (I2C_Hal_Status.RW == 0)) { /* Transmit buffer data */ I2C_SendData(I2C1, I2C_Hal_Status.pBuff[I2C_Hal_Status.PointerIndex++]); } else { I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE); } break; /* Test on I2Cx EV8 and clear it */ case I2C_EVENT_MASTER_BYTE_TRANSMITTED: if (I2C_Hal_Status.RW != 0) { I2C_Hal_Status.IRQn = (void ( *)(void *))I2C1_RX_IRQHandler; I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE); I2C_GenerateSTART(I2C1, ENABLE); } else { I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE); I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); I2C_Hal_Status.IDLE = 0; } break; } }
在Read的时候也同理,但是Read函数一样是进入I2C1_TX_IRQHandler,不过,RW位不一样,如果是RW为读,那么,再次发送Start,否则,在传输后,就发送STOP了.当然,既然非阻塞,也就是传说中的异步,那么,必然有异步的查询,查一下东西好了没,于是做一个函数,查BUSY位和用户BUSY.
uint32_t I2C1_Hal_Poll(void) { return (I2C_Hal_Status.IDLE || I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); }
测试方法:
I2C1_Hal_Init(); aBuffer[0] = 0x01; for(;;) { I2C1_Hal_Write(aBuffer, 0xA6, 0x2F, 3); while(I2C1_Hal_Poll()); I2C1_Hal_Read(aBuffer, 0xA6, 0x2F, 3); while(I2C1_Hal_Poll()); I2C1_Hal_Write(aBuffer, 0xA6, 0x2F, 0); while(I2C1_Hal_Poll()); I2C1_Hal_Read(aBuffer, 0xA6, 0x2F, 0); while(I2C1_Hal_Poll()); }
完整C代码:
#include#include #include "I2C.h" static void I2C1_RX_IRQHandler(void); static void I2C1_TX_IRQHandler(void); static I2C1_Hal_Def I2C_Hal_Status; void I2C1_Hal_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; GPIOB_B->AFRL.AFR6 = 0x04; //AF_I2C GPIOB_B->AFRH.AFR9 = 0x04; GPIOB_B->MODER.MODER6 = 0x02; GPIOB_B->MODER.MODER9 = 0x02; GPIOB_B->OSPEEDR.OSPEEDR6 = 0x02; GPIOB_B->OSPEEDR.OSPEEDR9 = 0x02; GPIOB_B->OTYPER.OT6 = 0x01; GPIOB_B->OTYPER.OT9 = 0x01; I2C1->CR1 = 0x00000001; I2C1->CR2 = 0x0000002A; I2C1->CCR = 0x00008023; I2C1->TRISE = 0x0000000D; /* Configure and enable I2C interrupt ------------------------------------*/ NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } uint32_t I2C1_Hal_Write(uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint8_t writeLen) { if (I2C_Hal_Status.IDLE != 0) return I2C1_FAIL; I2C_Hal_Status.IDLE = 1; I2C_Hal_Status.DeviceAddress = i2cSaleAddress; I2C_Hal_Status.DeviceRegister = writeAddress; I2C_Hal_Status.PointerIndex = 0; I2C_Hal_Status.RW = 0; I2C_Hal_Status.BufferLen = writeLen; I2C_Hal_Status.pBuff = buff; I2C_Hal_Status.IRQn = (void ( *)( ))I2C1_TX_IRQHandler; I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE); I2C1_B->CR1.ACK = 1; I2C1_B->CR1.START = 1; return I2C1_OK; } uint32_t I2C1_Hal_Read(uint8_t *pBuff, uint16_t DeviceAddress, uint8_t DeviceRegister, uint8_t BufferLen) { if (I2C_Hal_Status.IDLE != 0) return I2C1_FAIL; I2C_Hal_Status.IDLE = 1; I2C_Hal_Status.DeviceAddress = DeviceAddress; I2C_Hal_Status.DeviceRegister = DeviceRegister; I2C_Hal_Status.PointerIndex = 0; I2C_Hal_Status.RW = 1; I2C_Hal_Status.BufferLen = BufferLen; I2C_Hal_Status.pBuff = pBuff; I2C_Hal_Status.IRQn = (void ( *)())I2C1_TX_IRQHandler; I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, ENABLE); I2C1_B->CR1.ACK = 1; I2C1_B->CR1.START = 1; return I2C1_OK; } uint32_t I2C1_Hal_Poll(void) { return (I2C_Hal_Status.IDLE || I2C1_B->SR2.BUSY ); } static void I2C1_TX_IRQHandler(void) { switch (I2C_GetLastEvent(I2C1)) { /* Test on I2Cx EV5 and clear it */ case I2C_EVENT_MASTER_MODE_SELECT: I2C_Send7bitAddress(I2C1, I2C_Hal_Status.DeviceAddress, I2C_Direction_Transmitter); break; /* Test on I2Cx EV6 and first EV8 and clear them */ case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: /* Send the first data */ I2C_SendData(I2C1, I2C_Hal_Status.DeviceRegister); /* EV8 just after EV6 */ break; case I2C_EVENT_MASTER_BYTE_TRANSMITTING: if((I2C_Hal_Status.PointerIndex < I2C_Hal_Status.BufferLen) && (I2C_Hal_Status.RW == 0)) { /* Transmit buffer data */ I2C_SendData(I2C1, I2C_Hal_Status.pBuff[I2C_Hal_Status.PointerIndex++]); } else { I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE); } break; /* Test on I2Cx EV8 and clear it */ case I2C_EVENT_MASTER_BYTE_TRANSMITTED: if (I2C_Hal_Status.RW != 0) { I2C_Hal_Status.IRQn = (void ( *)(void *))I2C1_RX_IRQHandler; I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE); I2C_GenerateSTART(I2C1, ENABLE); } else { I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE); I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); I2C_Hal_Status.IDLE = 0; } break; } } static void I2C1_RX_IRQHandler(void) { switch (I2C_GetLastEvent(I2C1)) { /* Test on I2Cx EV5 and clear it */ case I2C_EVENT_MASTER_MODE_SELECT: /* Send I2Cx slave Address for write */ I2C_Send7bitAddress(I2C1, I2C_Hal_Status.DeviceAddress, I2C_Direction_Receiver); break; /* Test on I2Cx EV6 and first EV8 and clear them */ case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: if (I2C_Hal_Status.PointerIndex == (I2C_Hal_Status.BufferLen - 1)) { I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); } break; /* Test on I2Cx EV2 and clear it */ case I2C_EVENT_MASTER_BYTE_RECEIVED: I2C_Hal_Status.pBuff[I2C_Hal_Status.PointerIndex++] = I2C_ReceiveData(I2C1); if (I2C_Hal_Status.PointerIndex == (I2C_Hal_Status.BufferLen - 1)) { I2C_AcknowledgeConfig(I2C1, DISABLE); I2C_GenerateSTOP(I2C1, ENABLE); } else if (I2C_Hal_Status.PointerIndex >= I2C_Hal_Status.BufferLen) { I2C_Hal_Status.IRQn = (void ( *)(void *))I2C1_TX_IRQHandler; //??????? I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE); I2C_Hal_Status.IDLE = 0; } break; } } void I2C1_EV_IRQHandler(void) { if (I2C_Hal_Status.IRQn) { I2C_Hal_Status.IRQn(); } }
完整头文件:
#ifndef _USER_I2C_H_ #define _USER_I2C_H_ #include "stm32f4xx.h" #define I2C1_FAIL 1 #define I2C1_OK 0 typedef struct { __IO uint8_t IDLE: 1; uint8_t RW: 1; uint8_t DeviceAddress; uint8_t DeviceRegister; volatile uint8_t PointerIndex; uint8_t BufferLen; volatile uint8_t * pBuff; void (* IRQn)(); } I2C1_Hal_Def; void I2C1_Hal_Init(void); uint32_t I2C1_Hal_Write(uint8_t *buff, uint16_t i2cSaleAddress, uint8_t writeAddress, uint8_t writeLen); uint32_t I2C1_Hal_Read(uint8_t *buff, uint16_t i2cSaleAddress, uint8_t readAddress, uint8_t readLen); uint32_t I2C1_Hal_Poll(void); #endif