cancel
Showing results for 
Search instead for 
Did you mean: 

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

SMond
Associate

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?

5 REPLIES 5
Uwe Bonnes
Principal III

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

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
Up vote any posts that you find helpful, it shows what's working..

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.

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
Up vote any posts that you find helpful, it shows what's working..
S.Ma
Principal

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.