1

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

  1. 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);
  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.

  1. I have checked that it has no chance to get into the I2C_EV_IRQHandler or I2C_ER_IRQHandlerin debug mode to change the status or increase the TX count.
BF_zub
  • 11
  • 1
  • You could try doing single reads in a loop to see on which byte it gets blocked. Are there other devices on the bus? – Nicolas Jul 31 '22 at 21:11
  • Address is `0x50` for EEPROM, `0xa0` is the one with R/W bit cleared. Are you sure that your API expects the 8-bit template address? – 0andriy Jul 31 '22 at 21:50
  • @0andriy I think you are right, address should be 0x50. I will try to do with this adress with cmsis driver. – BF_zub Aug 01 '22 at 02:49
  • Can you post the content of I2C SR/ISR register? (the one with flags) when you get into this busy? I had something of that sort once, turned out, I needed to clear transmission complete flag, I think. And, maybe, stop/start bit detection, whichever needed clearing. They need to be clear before the transmission begins. After this change things just worked for me (I wrote my own CMSIS I2C driver too) – Ilya Aug 01 '22 at 14:49

0 Answers0