2020-07-18 11:30 PM
Hi Everyone,
My problem relates to I2C communication when trying to send bytes to a display on address 0x78. First I tried with the plain I2C HAL function(blocking), but I realised that the MCU gets frozen because of the huge amount of data to be sent (8192 bytes). At that point I decided to go for using DMA.
Type of the MCU: STM32L471ZGT6
Init of I2C:
I2C_InitTypeDef i2cInstanceInit;
// STM32 Cube generated value
// I2C Speed frequency = 100kHz
// Rise time = 1000ns
// Fall time = 300ns
i2cInstanceInit.Timing = 0x60E32C34;
i2cInstanceInit.OwnAddress1 = 0xFF;
i2cInstanceInit.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
i2cInstanceInit.DualAddressMode = I2C_DUALADDRESS_DISABLE;
i2cInstanceInit.OwnAddress2 = 0xFF;
i2cInstanceInit.GeneralCallMode = I2C_GENERALCALL_DISABLE;
i2cInstanceInit.NoStretchMode = I2C_NOSTRETCH_DISABLE;
i2cConfigure(I2C3, &i2cInstanceInit);
i2cConfigure method:
void i2cConfigure(I2C_TypeDef* i2cInstance, I2C_InitTypeDef* i2cInstanceInit)
...
} else if (i2cInstance == I2C3) {
i2c3Handle.Instance = i2cInstance;
i2c3Handle.Init = *i2cInstanceInit;
if (HAL_I2C_Init(&i2c3Handle) != HAL_OK) {
recordErrorActivityC("I2C3 initialization failed!", -1);
}
...
HAL_I2C_MspInit is invoked from HAL_I2C_Init function:
...
DMA_HandleTypeDef hdmaI2C;
...
void HAL_I2C_MspInit(I2C_HandleTypeDef *i2cHandle)
{
...
else if (i2cHandle->Instance == I2C3) {
/* Configure the I2C clock source. The clock is derived from the SYSCLK */
RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
RCC_PeriphCLKInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_SYSCLK;
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
__HAL_RCC_I2C3_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_FLASH_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(ZS4v0_I2C3_SDA_PORT, &GPIO_InitStruct);
HAL_NVIC_SetPriority(I2C3_ER_IRQn, 4, 0);
HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
/* Peripheral DMA TX init*/
hdmaI2C.Instance = DMA1_Channel2;
hdmaI2C.Init.Request = DMA_REQUEST_3;
hdmaI2C.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdmaI2C.Init.PeriphInc = DMA_PINC_DISABLE;
hdmaI2C.Init.MemInc = DMA_MINC_ENABLE;
hdmaI2C.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;
hdmaI2C.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdmaI2C.Init.Mode = DMA_NORMAL;
hdmaI2C.Init.Priority = DMA_PRIORITY_HIGH;
__HAL_LINKDMA(i2cHandle,hdmatx,hdmaI2C);
HAL_DMA_DeInit(&hdmaI2C);
HAL_DMA_Init(&hdmaI2C);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* Peripheral DMA RX init*/
hdmaI2C.Instance = DMA1_Channel3;
hdmaI2C.Init.Request = DMA_REQUEST_3;
hdmaI2C.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdmaI2C.Init.PeriphInc = DMA_PINC_DISABLE;
hdmaI2C.Init.MemInc = DMA_MINC_ENABLE;
hdmaI2C.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;
hdmaI2C.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdmaI2C.Init.Mode = DMA_NORMAL;
hdmaI2C.Init.Priority = DMA_PRIORITY_HIGH;
__HAL_LINKDMA(i2cHandle,hdmarx,hdmaI2C);
HAL_DMA_DeInit(&hdmaI2C);
HAL_DMA_Init(&hdmaI2C);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
...
}
Since I just want to transmit bytes to the display I set up DMA1 channel 2(given by Cube MX correspondingly to I2C3) but later while trying to find out what the issue is, I added I2C3 Rx too on DMA1 Channel 3.
Interrupt handler file(stm32l4x_it.c):
...
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(i2c3Handle.hdmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(i2c3Handle.hdmarx);
}
void I2C2_ER_IRQHandler(void)
{
HAL_I2C_ER_IRQHandler(&i2c2Handle);
}
void I2C3_ER_IRQHandler(void)
{
HAL_I2C_ER_IRQHandler(&i2c3Handle);
}
...
uint8_t buffer[5];
memset(buffer, 1,5);
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit_DMA(&i2c3Handle, 0x78, buffer, sizeof(buffer)); //S2ST(1)
Above you can see that I've crated a short snippet to check whether those five bytes are sent out well, but the outcome was different.
All in all I always experience that only the address bytes is sent out and SCL channel remains low, in addition to that I saw during debug that the I2C transmit is still taking place, like it was waiting for bytes to send out but nothing comes.
I had no opportunity in the past to deal with DMA so probably I am missing out on something.
Thank you for your help in advance!
2020-07-19 09:00 AM
Your scope trace shows you're writing to slave address 0b0111100 = 0x3C, not 0x78. Address should be shifted left one bit. I'm not sure why the plot says "Address write: 78". Seems misleading.