cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 communication with a display via I2C over DMA

DJuko.1
Associate

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.

0693W000001t9dLQAQ.png

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!

1 REPLY 1
TDK
Guru

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.

If you feel a post has answered your question, please click "Accept as Solution".