Skip to main content
Visitor II
September 15, 2020
Question

STM32F4 LL I2C DMA - AT24C32 EEPROM read/write

  • September 15, 2020
  • 0 replies
  • 2478 views

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();
 }
}

    This topic has been closed for replies.