Skip to main content
SMond
Associate
August 17, 2019
Question

How use two periphrals with DMA which are in same DMA stream but in diffrent DMA channel?

  • August 17, 2019
  • 5 replies
  • 1197 views

Hi, I have a problem in DMA with stm32f4XX. I need to use two peripherals i2c3 for IMU and UART4 for gps, I setup the base code and its working fine when one of the peripheral DMA initialisation is disable. 

Here is my code:-

void GPIO_I2C3_Init(void)

{

GPIO_InitTypeDef GPIO_Init;

static DMA_HandleTypeDef hdma2_tx;

static DMA_HandleTypeDef hdma2_rx;

__HAL_RCC_GPIOC_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();

__HAL_RCC_I2C3_CLK_ENABLE();

__HAL_RCC_I2C3_FORCE_RESET(); 

HAL_Delay(10);

__HAL_RCC_I2C3_RELEASE_RESET();

__HAL_RCC_DMA1_CLK_ENABLE();

GPIO_Init.Pin = GPIO_PIN_8;

GPIO_Init.Mode = GPIO_MODE_AF_OD;

GPIO_Init.Pull = GPIO_PULLUP;

GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;

GPIO_Init.Alternate = GPIO_AF4_I2C3;

HAL_GPIO_Init(GPIOA,&GPIO_Init);

GPIO_Init.Pin = GPIO_PIN_9;

GPIO_Init.Mode = GPIO_MODE_AF_OD;

GPIO_Init.Pull = GPIO_PULLUP;

GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;

GPIO_Init.Alternate = GPIO_AF4_I2C3;

HAL_GPIO_Init(GPIOC,&GPIO_Init);

i2c3_cfg.Instance = I2C3;

i2c3_cfg.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;

i2c3_cfg.Init.ClockSpeed = 400000;

i2c3_cfg.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;

i2c3_cfg.Init.DutyCycle = I2C_DUTYCYCLE_2;

i2c3_cfg.Init.GeneralCallMode = I2C_GENERALCALL_ENABLE;

i2c3_cfg.Init.OwnAddress1 = 0;

i2c3_cfg.Init.OwnAddress2 = 0;

i2c3_cfg.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

hdma2_tx.Instance         = DMA1_Stream4;

 hdma2_tx.Init.Channel       = DMA_CHANNEL_3;

 hdma2_tx.Init.Direction      = DMA_MEMORY_TO_PERIPH;

 hdma2_tx.Init.PeriphInc      = DMA_PINC_DISABLE;

 hdma2_tx.Init.MemInc       = DMA_MINC_ENABLE;

 hdma2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

 hdma2_tx.Init.MemDataAlignment  = DMA_MDATAALIGN_BYTE;

 hdma2_tx.Init.Mode        = DMA_NORMAL;

 hdma2_tx.Init.Priority      = DMA_PRIORITY_LOW;

hdma2_tx.Init.FIFOMode      = DMA_FIFOMODE_DISABLE;     

 hdma2_tx.Init.FIFOThreshold    = DMA_FIFO_THRESHOLD_FULL;

 hdma2_tx.Init.MemBurst      = DMA_MBURST_INC8;

 hdma2_tx.Init.PeriphBurst     = DMA_PBURST_INC8;

  

 HAL_DMA_Init(&hdma2_tx);

__HAL_LINKDMA(&i2c3_cfg, hdmatx, hdma2_tx);

  

hdma2_rx.Instance         = DMA1_Stream2;  

 hdma2_rx.Init.Channel       = DMA_CHANNEL_3;

 hdma2_rx.Init.Direction      = DMA_PERIPH_TO_MEMORY;

 hdma2_rx.Init.PeriphInc      = DMA_PINC_DISABLE;

 hdma2_rx.Init.MemInc       = DMA_MINC_ENABLE;

 hdma2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

 hdma2_rx.Init.MemDataAlignment  = DMA_MDATAALIGN_BYTE;

 hdma2_rx.Init.Mode        = DMA_NORMAL;

 hdma2_rx.Init.Priority      = DMA_PRIORITY_HIGH;

 hdma2_rx.Init.FIFOMode      = DMA_FIFOMODE_DISABLE;     

 hdma2_rx.Init.FIFOThreshold    = DMA_FIFO_THRESHOLD_FULL;

 hdma2_rx.Init.MemBurst      = DMA_MBURST_INC8;

 hdma2_rx.Init.PeriphBurst     = DMA_PBURST_INC8; 

 HAL_DMA_Init(&hdma2_rx);

__HAL_LINKDMA(&i2c3_cfg, hdmarx, hdma2_rx);

 HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);

HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);  

 HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);

HAL_NVIC_SetPriority(I2C3_ER_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);

 HAL_NVIC_SetPriority(I2C3_EV_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);

HAL_I2C_Init(&i2c3_cfg);

}

void GPIO_UART4_Init(void)

{

GPIO_InitTypeDef GPIO_Init;

static DMA_HandleTypeDef hdma1_rx;

__HAL_RCC_GPIOA_CLK_ENABLE();

__HAL_RCC_UART4_CLK_ENABLE();

__HAL_RCC_DMA1_CLK_ENABLE();

GPIO_Init.Pin  = GPIO_PIN_0|GPIO_PIN_1;

 GPIO_Init.Pull  = GPIO_PULLUP;

GPIO_Init.Mode = GPIO_MODE_AF_PP; //uart4 tx pin as pushpull

GPIO_Init.Alternate = GPIO_AF8_UART4;

 GPIO_Init.Speed = GPIO_SPEED_HIGH;

HAL_GPIO_Init(GPIOA, &GPIO_Init);

GPS_Uart.Instance = UART4;

GPS_Uart.Init.BaudRate = 9600;

GPS_Uart.Init.StopBits = UART_STOPBITS_1;

GPS_Uart.Init.WordLength = UART_WORDLENGTH_8B;

GPS_Uart.Init.Mode = UART_MODE_TX_RX;

GPS_Uart.Init.Parity = UART_PARITY_NONE;

GPS_Uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;

GPS_Uart.Init.OverSampling = UART_OVERSAMPLING_16;

HAL_UART_Init(&GPS_Uart);

hdma1_rx.Instance         = DMA1_Stream2;  

 hdma1_rx.Init.Channel       = DMA_CHANNEL_4;

 hdma1_rx.Init.Direction      = DMA_PERIPH_TO_MEMORY;

 hdma1_rx.Init.PeriphInc      = DMA_PINC_DISABLE;

 hdma1_rx.Init.MemInc       = DMA_MINC_ENABLE;

 hdma1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

 hdma1_rx.Init.MemDataAlignment  = DMA_MDATAALIGN_BYTE;

 hdma1_rx.Init.Mode        = DMA_CIRCULAR;

 hdma1_rx.Init.Priority      = DMA_PRIORITY_HIGH;

 hdma1_rx.Init.FIFOMode      = DMA_FIFOMODE_DISABLE;     

 hdma1_rx.Init.FIFOThreshold    = DMA_FIFO_THRESHOLD_FULL;

hdma1_rx.Init.MemBurst      = DMA_MBURST_INC8;

 hdma1_rx.Init.PeriphBurst     = DMA_PBURST_INC8; 

 HAL_DMA_Init(&hdma1_rx);

__HAL_LINKDMA(&GPS_Uart, hdmarx, hdma1_rx);

HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);  

 HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);

HAL_NVIC_SetPriority(UART4_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(UART4_IRQn);

__HAL_UART_ENABLE_IT(&GPS_Uart,UART_IT_IDLE);

 __HAL_DMA_ENABLE_IT(&hdma1_rx,DMA_IT_TC);

}

and IRQs :-

void DMA1_Stream2_IRQHandler(void)

{

flag_g=~flag_g;

if(flag_g)

HAL_DMA_IRQHandler(i2c3_cfg.hdmarx);

else

  HAL_DMA_IRQHandler(GPS_Uart.hdmarx); //UART4

}

void DMA1_Stream4_IRQHandler(void)

{

 HAL_DMA_IRQHandler(i2c3_cfg.hdmatx);

}

void UART4_IRQHandler(void)

{

 HAL_UART_IRQHandler(&GPS_Uart);

}

void I2C3_EV_IRQHandler(void)

{

 HAL_I2C_EV_IRQHandler(&i2c3_cfg);

}

void I2C3_ER_IRQHandler(void)

{

 HAL_I2C_ER_IRQHandler(&i2c3_cfg);

}

The main probleam is i2c3 and uart4 is in same dma stream-> dma_stream2, but in diffrent channel. So is there any way use two periphral with DMA which are in same stream?

This topic has been closed for replies.

5 replies

Uwe Bonnes
Chief
August 17, 2019

There is no way. That is wy the DMAMUX in newer families comes handy.

Tesla DeLorean
Guru
August 17, 2019

You'll likely need to live with a simple UART4 RX interrupt handler.

Review if alternate pin muxing, or other usage might accommodate your needs.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
SMond
SMondAuthor
Associate
August 17, 2019

Yes , right.

And it's working​ nice with simple uart interrupt. I wondering that while using dma transfer cmplt call back it's effting rtos timing, but with interrupt it's fine no latency.

Tesla DeLorean
Guru
August 17, 2019

Well for there to be any point of using DMA, you'd need a deeper buffer, and this might not cleanly align with data bursting from a GPS receiver.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal
August 17, 2019

I2C can be implemented by SW bit banging, and 400 kbps is easily done by SW.

USART is not, so just use DMA for this only exclusively.

The SW will be easier to maintain than acrobatically hop between 2 channels.