cancel
Showing results for 
Search instead for 
Did you mean: 

I2C DMA synchronization not triggering

dryet
Associate II

Hi guys,

I am trying to run a demo on STM32U083C-DK board. 

This demo consists of LPTIMER generating PWM that is used for synchronization of I2C read from on-board temperature sensor. Rising edge writes the addres of read and falling edge reads data. The main issue I have encountered is that my synchronization setup works perfectly with UART transmit but with I2C no matter what I try I don't ever get transmit on the I2C bus.

What I checked:

- LPTIMER NVIC is on and is able to start UART synchronization

- I2C DMA works when software triggered. (with synchronization disabled)

DMA setup for I2C DMA:

dryet_0-1724843526621.png

dryet_1-1724843567189.png

dryet_2-1724843593231.png

LPTIMER config:

dryet_3-1724843626795.png

dryet_4-1724843641187.png

Logic analyzer output:

dryet_5-1724843706033.png

Where D0 is SDA, D1 is SCL and D2 is LPTIMER output

This is the main and initialisation of I2C:

I2C_HandleTypeDef hi2c1; DMA_HandleTypeDef hdma_i2c1_tx; DMA_HandleTypeDef hdma_i2c1_rx; LPTIM_HandleTypeDef hlptim1; union { uint8_t temp_raw_8[2]; int16_t temp_raw_16; }temp_raw; uint8_t stts22h_temp_l_out = STTS22H_TEMP_L_OUT; STTS22H_IO_t stts22h_io; STTS22H_Object_t stts22h_obj; int main(void) { MX_GPIO_Init(); MX_DMA_Init(); MX_USART2_UART_Init(); MX_I2C1_Init(); MX_LPTIM1_Init(); /* USER CODE BEGIN 2 */ HAL_I2C_Master_Transmit_DMA(&hi2c1, STTS22H_I2C_ADD_L, &stts22h_temp_l_out, 1); HAL_I2C_Master_Receive_DMA(&hi2c1, STTS22H_I2C_ADD_L, &temp_raw.temp_raw_8[0], 2); HAL_LPTIM_PWM_Start_IT(&hlptim1, LPTIM_CHANNEL_1); /* USER CODE END 2 */ } void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) { GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_DMA_MuxSyncConfigTypeDef pSyncConfig; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; if(hi2c->Instance==I2C1) { /* USER CODE BEGIN I2C1_MspInit 0 */ /* USER CODE END I2C1_MspInit 0 */ /** Initializes the peripherals clocks */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1; PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2C1 GPIO Configuration PB7 ------> I2C1_SDA PB8 ------> I2C1_SCL */ GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* Peripheral clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); /* I2C1 DMA Init */ /* I2C1_TX Init */ hdma_i2c1_tx.Instance = DMA1_Channel1; hdma_i2c1_tx.Init.Request = DMA_REQUEST_I2C1_TX; hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_i2c1_tx.Init.Mode = DMA_CIRCULAR; hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_MEDIUM; if (HAL_DMA_Init(&hdma_i2c1_tx) != HAL_OK) { Error_Handler(); } pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM1_OUT; pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_RISING; pSyncConfig.SyncEnable = ENABLE; pSyncConfig.EventEnable = ENABLE; pSyncConfig.RequestNumber = 1; if (HAL_DMAEx_ConfigMuxSync(&hdma_i2c1_tx, &pSyncConfig) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(hi2c,hdmatx,hdma_i2c1_tx); /* I2C1_RX Init */ hdma_i2c1_rx.Instance = DMA1_Channel2; hdma_i2c1_rx.Init.Request = DMA_REQUEST_I2C1_RX; hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR; hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_MEDIUM; if (HAL_DMA_Init(&hdma_i2c1_rx) != HAL_OK) { Error_Handler(); } pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM1_OUT; pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_FALLING; pSyncConfig.SyncEnable = ENABLE; pSyncConfig.EventEnable = ENABLE; pSyncConfig.RequestNumber = 2; if (HAL_DMAEx_ConfigMuxSync(&hdma_i2c1_rx, &pSyncConfig) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(hi2c,hdmarx,hdma_i2c1_rx); /* I2C1 interrupt Init */ HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(I2C1_IRQn); /* USER CODE BEGIN I2C1_MspInit 1 */ /* USER CODE END I2C1_MspInit 1 */ } }
View more

 

If I am missing something please let me know but I feel like I am either using wrong function to call I2C receive and transmit (which I doubt) or there is a bug.

Thank you in advance for answers.

1 ACCEPTED SOLUTION

Accepted Solutions

The example you linked uses UART. You are using I2C which is more complicated in its usage. You will need to initiate each I2C transaction with a call to HAL_I2C_Master_Receive_DMA. Perhaps put this in a timer interrupt callback which is called periodically.

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

View solution in original post

4 REPLIES 4
TDK
Guru

The basic premise of the program isn't valid. You can't use the HAL DMA routines like this. Look at the code within HAL_I2C_Master_Receive_DMA to see how it starts the transfer. Only after the transfer is started can DMA be used.

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

Could you please elaborate on your answer? How could I otherwise you the synchronization of I2C? 

I am basically trying the same thing as in: https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Projects/STM32H743I-EVAL/Examples/DMA/DMAMUX_SYNC

 

The example you linked uses UART. You are using I2C which is more complicated in its usage. You will need to initiate each I2C transaction with a call to HAL_I2C_Master_Receive_DMA. Perhaps put this in a timer interrupt callback which is called periodically.

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

Okay, thank you. 

In my excercise I wanted to make I2C read to my memory completely automatic in the backround using DMA so it updates temperature values automatically without any MCU work and I can get the latest value in my code. 

I will continue to work on my example and I will try to come up with a way to make it work