cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 LL I2C DMA - AT24C32 EEPROM read/write

PTiha
Senior

Hi!

I created a simple test project based on the example "I2C_OneBoard_AdvCommunication_DMAAndIT" found in the STM32Cube_FW_F4_V1.25.2 package.

The project basically works, but I have to take the number of data to be sent one more than the amount to be actually sent.

So when I want to read from the EEPROM and have to send out the start address, I have to set the DMA transmission to 3 bytes instead of two.

It's just a quick and dirty project to help me understanding the basics...

Thanks for any help!

My main.c (I've deleted irrelevant parts...):

uint8_t rd_value[20] = {0};
uint8_t wr_value[20] = {0x14,0x13,0x12,0x11,0x10,
                        0x0F,0x0E,0x0D,0x0C,0x0B,
                        0x0A,0x09,0x08,0x07,0x06,
                        0x05,0x04,0x03,0x02,0x01};
 
uint8_t tx_buffer[32] = {};
uint8_t* tx_data_buffer = tx_buffer + 2;
uint8_t rx_buffer[34] = {};
 
__IO uint8_t  ubMasterRequestDirection  = 0;
__IO uint8_t  ubMasterNbDataToReceive   = 0;
__IO uint8_t  ubMasterNbDataToTransmit  = 0;
__IO uint8_t  ubMasterTransferComplete  = 0;
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_DMA_Init();
//  MX_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_I2C2_Init();
 
  Configure_DMA();
  Activate_I2C_Master();
 
  for (int i = 0; i < 20; ++i)
  {
    tx_data_buffer[i] = wr_value[i];
  }
//  dsrtc_eeprom_write(0x0000, 0x00, 20);
  dsrtc_eeprom_read(0x0000, 0x00, 20);
 
  while (1)
  {
  }
}
 
void Configure_DMA(void)
{
  // TX
  LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_7,
      (uint32_t)tx_buffer,
      (uint32_t)LL_I2C_DMA_GetRegAddr(I2C2),
      LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_7)
      );
 
  // RX
  LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_2,
      (uint32_t)LL_I2C_DMA_GetRegAddr(I2C2),
      (uint32_t)rx_buffer,
      LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_2)
      );
 
  /* (5) Enable DMA1 interrupts complete/error */
  // TX
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_7);
  LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_7);
  // RX
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_2);
  LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_2);
}
 
void Activate_I2C_Master(void)
{
  LL_I2C_Enable(I2C2);
  LL_I2C_EnableIT_EVT(I2C2);
  LL_I2C_EnableIT_ERR(I2C2);
}
 
int dsrtc_eeprom_write(uint16_t address, uint8_t *data, uint16_t size_of_data)
{
  tx_buffer[0] = (address >> 8) & 0xFF;
  tx_buffer[1] = address & 0xFF;
  ubMasterNbDataToTransmit = 2 + size_of_data;
 
  SEGGER_RTT_printf(0, "Write:");
  for (int i = 0; i < ubMasterNbDataToTransmit; ++i)
  {
    SEGGER_RTT_printf(0, " %02X", tx_buffer[i]);
    rx_buffer[i] = 0;
  }
  SEGGER_RTT_printf(0, "\r\n");
 
  /* (1) Configure DMA parameters for Command Code transfer *******************/
  LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_7, (uint32_t)(tx_buffer));
  LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_7, ubMasterNbDataToTransmit);
 
  /* (2) Enable DMA transfer **************************************************/
  LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_7);
  /* (3) Prepare acknowledge for Master data reception ************************/
  LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_ACK);
 
  /* (4) Initiate a Start condition to the Slave device ***********************/
  /* Master Request direction WRITE */
  ubMasterRequestDirection = I2C_REQUEST_WRITE;
 
  /* Master Generate Start condition */
  LL_I2C_GenerateStartCondition(I2C2);
 
  /* (5) Loop until end of transfer completed (DMA TC raised) *****************/
 
  /* Loop until DMA transfer complete event */
  while(!ubMasterTransferComplete)
  {
  }
 
  /* (6) Generate a Stop condition to the Slave device ************************/
  LL_I2C_GenerateStopCondition(I2C2);
 
  /* (7) Clear pending flags, Data Command Code are checking into Slave process */
  /* End of Master Process */
  LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_7);
 
  /* Clear and Reset process variables and arrays */
  ubMasterTransferComplete = 0;
  ubMasterNbDataToTransmit = 0;
 
  return 0;
}
 
int dsrtc_eeprom_read(uint16_t address, uint8_t *data, uint16_t size_of_data)
{
  tx_buffer[0] = (address >> 8) & 0xFF;
  tx_buffer[1] = address & 0xFF;
  ubMasterNbDataToTransmit = 2;
  ubMasterNbDataToReceive = size_of_data;
 
  /* (1) Configure DMA parameters for Command Code transfer *******************/
  LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_7, (uint32_t)(tx_buffer));
  LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_7, ubMasterNbDataToTransmit);
 
  /* (2) Enable DMA transfer **************************************************/
  LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_7);
  /* (3) Prepare acknowledge for Master data reception ************************/
  LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_ACK);
 
  /* (4) Initiate a Start condition to the Slave device ***********************/
  /* Master Request direction WRITE */
  ubMasterRequestDirection = I2C_REQUEST_WRITE;
 
  /* Master Generate Start condition */
  LL_I2C_GenerateStartCondition(I2C2);
 
  /* (5) Loop until end of transfer completed (DMA TC raised) *****************/
 
  /* Loop until DMA transfer complete event */
  while(!ubMasterTransferComplete)
  {
  }
 
  /* Reset ubMasterTransferComplete flag */
  ubMasterTransferComplete = 0;
 
 
  LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_7);
  LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_2, ubMasterNbDataToReceive);
  LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_2);
 
  /* (6) Prepare acknowledge for Master data reception ************************/
  LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_ACK);
 
  /* (7) Initiate a ReStart condition to the Slave device *********************/
  /* Master Request direction READ */
  ubMasterRequestDirection = I2C_REQUEST_READ;
 
  /* Master Generate ReStart condition */
  LL_I2C_GenerateStartCondition(I2C2);
 
  /* (8) Loop until end of transfer completed (DMA TC raised) *****************/
 
  /* Loop until DMA transfer complete event */
  while(!ubMasterTransferComplete)
  {
  }
  /* (9) Generate a Stop condition to the Slave device ************************/
  LL_I2C_GenerateStopCondition(I2C2);
 
  /* (10) Clear pending flags, Data Command Code are checking into Slave process */
  /* Disable Last DMA bit */
  LL_I2C_DisableLastDMA(I2C2);
 
  /* Disable acknowledge for Master next data reception */
  LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_NACK);
 
  /* End of Master Process */
  LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_2);
  /* Display through external Terminal IO the Slave Answer received */
 
  /* Clear and Reset process variables and arrays */
  ubMasterTransferComplete = 0;
  ubMasterNbDataToTransmit = 0;
 
  for (int i = 0; i < size_of_data; ++i)
  {
    SEGGER_RTT_printf(0, " %02X", rx_buffer[i]);
    rx_buffer[i] = 0;
  }
  SEGGER_RTT_printf(0, "\r\n");
  return 0;
}
 
void Transfer_Complete_Callback()
{
  /* DMA transfer completed */
  ubMasterTransferComplete = 1;
}
 
void Transfer_Error_Callback()
{
  /* Disable DMA1_Stream7_IRQn */
  NVIC_DisableIRQ(DMA1_Stream7_IRQn);
}

Interrupt handlers:

void DMA1_Stream2_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream2_IRQn 0 */
  if(LL_DMA_IsActiveFlag_TC2(DMA1))
  {
    LL_DMA_ClearFlag_TC2(DMA1);
    Transfer_Complete_Callback();
  }
  else if(LL_DMA_IsActiveFlag_TE2(DMA1))
  {
    Transfer_Error_Callback();
  }
}
 
void I2C2_EV_IRQHandler(void)
{
  /* Check SB flag value in ISR register */
  if(LL_I2C_IsActiveFlag_SB(I2C2))
  {
    /* Send Slave address with a 7-Bit SLAVE_OWN_ADDRESS for a ubMasterRequestDirection request */
    LL_I2C_TransmitData8(I2C2, SLAVE_OWN_ADDRESS | ubMasterRequestDirection);
  }
  /* Check ADDR flag value in ISR register */
  else if(LL_I2C_IsActiveFlag_ADDR(I2C2))
  {
    /* Verify the transfer direction */
    if(LL_I2C_GetTransferDirection(I2C2) == LL_I2C_DIRECTION_READ)
    {
      if(ubMasterNbDataToReceive == 1)
      {
        /* Prepare the generation of a Non ACKnowledge condition after next received byte */
        LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_NACK);
 
        /* Enable DMA transmission requests */
        LL_I2C_EnableDMAReq_RX(I2C2);
      }
      else if(ubMasterNbDataToReceive == 2)
      {
        /* Prepare the generation of a Non ACKnowledge condition after next received byte */
        LL_I2C_AcknowledgeNextData(I2C2, LL_I2C_NACK);
 
        /* Enable Pos */
        LL_I2C_EnableBitPOS(I2C2);
      }
      else
      {
        /* Enable Last DMA bit */
        LL_I2C_EnableLastDMA(I2C2);
 
        /* Enable DMA transmission requests */
        LL_I2C_EnableDMAReq_RX(I2C2);
      }
    }
    else
    {
      /* Enable DMA transmission requests */
      LL_I2C_EnableDMAReq_TX(I2C2);
    }
 
    /* Clear ADDR flag value in ISR register */
    LL_I2C_ClearFlag_ADDR(I2C2);
  }
}
 
void I2C2_ER_IRQHandler(void)
{
  Error_Handler();
}
 
void DMA1_Stream7_IRQHandler(void)
{
  if(LL_DMA_IsActiveFlag_TC7(DMA1))
  {
    LL_DMA_ClearFlag_TC7(DMA1);
    Transfer_Complete_Callback();
  }
  else if(LL_DMA_IsActiveFlag_TE7(DMA1))
  {
    Transfer_Error_Callback();
  }
}

0 REPLIES 0