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 */
  }
}

 

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