I tried to learn the CMSIS driver in I2C. I have STM32F407VGT6 and EEPROM at24c256 as test hardware. First, create the I2C environment with CubeMX to config the I2C. https://i.stack.imgur.com/qnm5J.jpg https://i.stack.imgur.com/FA8un.jpg then I followed the arm example from the arm-cmsis driver website. https://arm-software.github.io/CMSIS_5/Driver/html/group__i2c__interface__gr.html
#include "Driver_I2C.h"
#define EEPROM_I2C_ADDR 0xA0 /* EEPROM I2C address */
/* I2C driver instance */
extern ARM_DRIVER_I2C Driver_I2C1;
static ARM_DRIVER_I2C *I2Cdrv = &Driver_I2C1;
static volatile uint32_t I2C_Event;
/* I2C Signal Event function callback */
void I2C_SignalEvent (uint32_t event) {
/* Save received events */
I2C_Event |= event;
/* Optionally, user can define specific actions for an event */
if (event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) {
/* Less data was transferred than requested */
}
if (event & ARM_I2C_EVENT_TRANSFER_DONE) {
/* Transfer or receive is finished */
}
if (event & ARM_I2C_EVENT_ADDRESS_NACK) {
/* Slave address was not acknowledged */
}
if (event & ARM_I2C_EVENT_ARBITRATION_LOST) {
/* Master lost bus arbitration */
}
if (event & ARM_I2C_EVENT_BUS_ERROR) {
/* Invalid start/stop position detected */
}
if (event & ARM_I2C_EVENT_BUS_CLEAR) {
/* Bus clear operation completed */
}
if (event & ARM_I2C_EVENT_GENERAL_CALL) {
/* Slave was addressed with a general call address */
}
if (event & ARM_I2C_EVENT_SLAVE_RECEIVE) {
/* Slave addressed as receiver but SlaveReceive operation is not started */
}
if (event & ARM_I2C_EVENT_SLAVE_TRANSMIT) {
/* Slave addressed as transmitter but SlaveTransmit operation is not started */
}
}
/* Read I2C connected EEPROM (event driven example) */
int32_t EEPROM_Read_Event (uint16_t addr, uint8_t *buf, uint32_t len) {
uint8_t a[2];
a[0] = (uint8_t)(addr >> 8);
a[1] = (uint8_t)(addr & 0xFF);
/* Clear event flags before new transfer */
I2C_Event = 0U;
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
/* Wait until transfer completed */
while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
/* Check if all data transferred */
if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U) return -1;
/* Clear event flags before new transfer */
I2C_Event = 0U;
I2Cdrv->MasterReceive (EEPROM_I2C_ADDR, buf, len, false);
/* Wait until transfer completed */
while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
/* Check if all data transferred */
if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U) return -1;
return 0;
}
/* Read I2C connected EEPROM (pooling example) */
int32_t EEPROM_Read_Pool (uint16_t addr, uint8_t *buf, uint32_t len) {
uint8_t a[2];
a[0] = (uint8_t)(addr >> 8);
a[1] = (uint8_t)(addr & 0xFF);
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
/* Wait until transfer completed */
while (I2Cdrv->GetStatus().busy);
/* Check if all data transferred */
if (I2Cdrv->GetDataCount () != len) return -1;
I2Cdrv->MasterReceive (EEPROM_I2C_ADDR, buf, len, false);
/* Wait until transfer completed */
while (I2Cdrv->GetStatus().busy);
/* Check if all data transferred */
if (I2Cdrv->GetDataCount () != len) return -1;
return 0;
}
/* Initialize I2C connected EEPROM */
int32_t EEPROM_Initialize (bool pooling) {
int32_t status;
uint8_t val;
if (pooling == true) {
I2Cdrv->Initialize (NULL);
} else {
I2Cdrv->Initialize (I2C_SignalEvent);
}
I2Cdrv->PowerControl (ARM_POWER_FULL);
I2Cdrv->Control (ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
I2Cdrv->Control (ARM_I2C_BUS_CLEAR, 0);
/* Check if EEPROM can be accessed */
if (pooling == true) {
status = EEPROM_Read_Pool (0x00, &val, 1);
} else {
status = EEPROM_Read_Event (0x00, &val, 1);
}
return (status);
}
above was the code example from cmsis-driver website. I have modified the EEPROM_I2C_ADDR to 0xA0(for AT24C256 EEPROM).
then I try to run main() with function
EEPROM_Initialize(true)
then this function will get into EEPROM_Read_Pool()
but the test always stuck in
while (I2Cdrv->GetStatus().busy);
after I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
。
I have tried
- use HAL library to run MEM_Write, MEM_Read with the EEPROM, and make sure the EEPROM could work.
HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDRESS, 0, 0xff, &data_to_write, 1,10);
HAL_Delay(10);
uint8_t data_read = 60;
HAL_I2C_Mem_Read(&hi2c1,EEPROM_ADDRESS,0,0xff,&data_to_read,1,1);
- I have checked the return value of all below
I2Cdrv->PowerControl (ARM_POWER_FULL);
I2Cdrv->Control (ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
I2Cdrv->Control (ARM_I2C_BUS_CLEAR, 0);
I2Cdrv->MasterTransmit (EEPROM_I2C_ADDR, a, 2, true);
all the return value are 0x00000000(seems running ok).But still have no idea why the status is always busy.
- I have checked that it has no chance to get into the
I2C_EV_IRQHandler
orI2C_ER_IRQHandler
in debug mode to change the status or increase the TX count.