cancel
Showing results for 
Search instead for 
Did you mean: 

Trying to setup DMA for I2C on STM32L4R

MGode
Associate

Hi,

I'm trying to set up DMA transfers for I2C sensors on STM32L4R9 MCU.

I've followed the documentation and analyzed the HAL implementation, but the DMA channel IRQ handler is never triggered.

Here's the specific sequence of steps that I'm performing:

First, I initialize the I2C peripheral, using a Cube-generated configuration. (The configuration is known to work properly for the polling variants of HAL_I2C_Master_Transmit and HAL_I2C_Master_Receive):

    hi2c4.Instance = I2C4;
    hi2c4.Init.Timing = 0x00303D5B;
 
    hi2c4.Init.OwnAddress1 = 0;
    hi2c4.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c4.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c4.Init.OwnAddress2 = 0;
    hi2c4.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    hi2c4.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c4.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c4) != HAL_OK) {
        Error_Handler();
    }
    /* Configure Analogue filter */
    if (HAL_I2CEx_ConfigAnalogFilter(&hi2c4, I2C_ANALOGFILTER_ENABLE) != HAL_OK) {
        Error_Handler();
    }
    /* Configure Digital filter  */
    if (HAL_I2CEx_ConfigDigitalFilter(&hi2c4, 0) != HAL_OK) {
        Error_Handler();
    }

ABP1, ABP2, AHB and the core are all driven from the 16MHz onboard HSI oscillator. I2C is also clocked from HSI.

Subsequently, I enable the clocks of DMA1 and DMAMUX1 as well as the DMA1_Channel1_IRQ:

    __HAL_RCC_DMAMUX1_CLK_ENABLE();
    __HAL_RCC_DMA1_CLK_ENABLE();
 
    HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, IRQ_PRIORITY_DMA, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

Lastly, I configure the DMA registers, DMAMUX control register and I2C registers in the following manner:

    DMAMUX1_Channel0->CCR = DMA_REQUEST_I2C4_TX;
 
    DMA1_Channel1->CCR &= ~DMA_CCR_EN;
    DMA1_Channel1->CNDTR = 2;
    DMA1_Channel1->CPAR = (uint32_t) &I2C4->TXDR;
    DMA1_Channel1->CMAR = (uint32_t) data;
    DMA1_Channel1->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_TEIE;
    DMA1_Channel1->CCR |= DMA_CCR_EN;
 
    I2C4->CR2 = (2 << I2C_CR2_NBYTES_Pos)
        | (saddr << (I2C_CR2_SADD_Pos + 1))
        | I2C_CR2_AUTOEND
        | I2C_CR2_START
        | 0x80000000UL; // from  I2C_GENERATE_START_WRITE in stm32l4xx_hal_i2c.h
 
    I2C4->CR1 |= I2C_CR1_TXDMAEN;

where `saddr` is the address of the I2C slave device, and `data` is a two-element buffer that I'm trying to send to the device.

I'd expect the `DMA1_Channel1_IRQHandler` to be triggered after the signal is generated on the I2C interface (the code follows HAL's implementation of HAL_I2C_Master_Transmit_DMA): I enter HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI), waiting for a wakeup from some event (I have a global volatile variable, and each ISR sets a flag into that variable. I can generate events which wake up the core, but the flag that is supposed to be written from the `DMA1_Channel1_IRQHandler` is never written. If I make a spinlock instead of going to sleep, the result is the same)

Is there anything important that I'm missing here?

0 REPLIES 0