2020-09-15 01:16 AM
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();
}
}