Multiple DMAs conflicts Topic is solved

Discussions and support about ChibiOS/HAL, the MCU Hardware Abstraction Layer.
Post Reply
blackberryer
Posts: 24
Joined: Sat Apr 05, 2025 6:52 pm
Been thanked: 4 times

Multiple DMAs conflicts

Post by blackberryer »

OS : ChibiOS-21.11.3
MCU : STM32F405VGT6

BUZZER : PB0 TIM1_CH2N STM32_DMA2_STREAM5

I use pwm in combination with dma to drive the buzzer, but it conflicts with I2C until I disable I2C's DMA(see viewtopic.php?t=4167), the buzzer works fine, why?

Code: Select all

void buzzer_init(void)
{
  // Configure pin as AF output. Initialize the output low.
  palSetPadMode(PORT_BUZZER, PIN_BUZZER, PAL_MODE_ALTERNATE(BUZZER_AF) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_PUPDR_PULLDOWN);

  // Initialize frame buffer
  last_buzzer_dutycycle = BUZZER_DUTYCYCLE;
  uint32_t i;
  for (i = 0; i < BUZZER_DATA_BIT_N; i++)    buzzer_frame_buffer[i]                       = last_buzzer_dutycycle; // All bits are zero duty cycle
  for (i = 0; i < BUZZER_RESET_BIT_N; i++)   buzzer_frame_buffer[i + BUZZER_DATA_BIT_N]   = 0; // All bits are zero duty cycle
  rccEnableDMA_buzzer(false);
  (BUZZER_DMA_STREAM)->stream->PAR  = (uint32_t)(&(BUZZER_PWMD.tim->CCR[BUZZER_TIM_CH]));
  (BUZZER_DMA_STREAM)->stream->M0AR = (uint32_t)(&buzzer_frame_buffer);//uint32_t match STM32_DMA_CR_MSIZE_WORD
  (BUZZER_DMA_STREAM)->stream->NDTR = (uint32_t)(BUZZER_BUFF_BIT_N);//sizeof(buzzer_frame_buffer)/sizeof(uint8_t));//
  (BUZZER_DMA_STREAM)->stream->CR   = 0;
  (BUZZER_DMA_STREAM)->stream->CR  |= (uint32_t)( STM32_DMA_CR_PL(BUZZER_DMA_PRIORITY) | STM32_DMA_CR_CHSEL(BUZZER_DMA_CHANNEL) |
                                                  STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | //0x00000000U |//STM32_DMA_CR_RESET_VALUE |
                                                  STM32_DMA_CR_MSIZE_WORD | STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE );//| STM32_DMA_CR_CIRC );//
 
  // Start DMA
  (BUZZER_DMA_STREAM)->stream->CR  |= ((uint32_t)0x00000001);//STM32_DMA_CR_EN;//dmaStreamEnable(BUZZER_DMA_STREAM);
  nvicEnableVector(BUZZER_DMA_STREAM_IRQ, BUZZER_PWM_IRQ_PRIORITY);

  pwmStart(&BUZZER_PWMD, &buzzer_pwm_config);
  pwmEnableChannel(&BUZZER_PWMD, BUZZER_TIM_CH, 5000);     // Initial period is 0; output will be low until first duty cycle is DMA'd in
  //pwmEnableChannel(&BUZZER_PWMD, BUZZER_TIM_CH, PWM_PERCENTAGE_TO_WIDTH(&BUZZER_PWMD, 5000));
}


1.Why does I2C use DMA by default? Isn't there an option?
2.How to avoid conflicts and make them work?
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Multiple DMAs conflicts

Post by Giovanni »

Hi,

There is no option to disable use of DMA in that driver. Can you use another DMA channel for your buzzer?

Giovanni
blackberryer
Posts: 24
Joined: Sat Apr 05, 2025 6:52 pm
Been thanked: 4 times

Re: Multiple DMAs conflicts

Post by blackberryer »

Giovanni wrote:Hi,

There is no option to disable use of DMA in that driver. Can you use another DMA channel for your buzzer?

Giovanni


The other channel has the same result, using TIM3 and using STM32_DMA1_STREAM2, but the result will conflict, the program is stuck, I use vscode, I can't use the debugger at the moment, so I don't know where the program crashes, but it is clear that I2C will conflict with buzzer's DMA when using DMA.
the other IO PB1, controls WS2812, PB0 and PB1 don't conflict when they use DMA respectively.
blackberryer
Posts: 24
Joined: Sat Apr 05, 2025 6:52 pm
Been thanked: 4 times

Re: Multiple DMAs conflicts

Post by blackberryer »

Giovanni wrote:Hi,

There is no option to disable use of DMA in that driver. Can you use another DMA channel for your buzzer?

Giovanni


I guess I understand the error, I set the TCIE interrupt, but I'm not doing the processing in the OSAL_IRQ_HANDLER function.
When I set up I2C without DMA, I misunderstood commented out the OSAL_IRQ_HANDLER function, and an error also occurs at this time. When I turn on OSAL_IRQ_HANDLER function and clean up the flag operation(The most important thing is that I did buzzer_stop()), the error disappears.

How do I operate the OSAL_IRQ_HANDLER function corresponding to buzzer when I use I2C with DMA?

Because when I enable I2C DMA, the OSAL_IRQ_HANDLER function I wrote myself will conflict with the system and make it impossible to compile(multiple definition of `Vector74' or `Vector150' ).

Code: Select all

//  DMA2 stream 5 shared interrupt handler.
#if 1//0
OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) {
  uint32_t flags = DMA2->HISR; DMA2->HIFCR = flags;

  if (flags & DMA_HISR_TCIF5_Msk) DMA2_CH5_HANDLER_FUNC(flags); // DMA2 Channel 5 handler
}
#endif


I don't know how to use STM32_DMA2_CH5_HANDLER of the system, because the system's callback function is 'dma.streams[13].func', I don't know how to set it

Code: Select all

/**
 * @brief   DMA2 stream 5 shared interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) {
  uint32_t flags;

  OSAL_IRQ_PROLOGUE();

  flags = (DMA2->HISR >> 6U) & STM32_DMA_ISR_MASK;
  DMA2->HIFCR = flags << 6U;
  if (dma.streams[13].func)
    dma.streams[13].func(dma.streams[13].param, flags);

  OSAL_IRQ_EPILOGUE();
}
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Multiple DMAs conflicts

Post by Giovanni »

Hi,

The problem is that you should not touch DMA registers directly but use the DMA driver functions, you can see an example of DMA driver use (and callback use) in any driver using DMA, see the SPI driver for example.

Giovanni
blackberryer
Posts: 24
Joined: Sat Apr 05, 2025 6:52 pm
Been thanked: 4 times

Re: Multiple DMAs conflicts

Post by blackberryer »

Giovanni wrote:Hi,

The problem is that you should not touch DMA registers directly but use the DMA driver functions, you can see an example of DMA driver use (and callback use) in any driver using DMA, see the SPI driver for example.

Giovanni


I modified my program and used the following code, but in fact, the callback function was triggered for the first time, and the callback function was not triggered afterwards

Code: Select all

void buzzer_init(void)
{
  // Configure pin as AF output. Initialize the output low.
  palSetPadMode(PORT_BUZZER, PIN_BUZZER, PAL_MODE_ALTERNATE(BUZZER_AF) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_PUPDR_PULLDOWN);
  // Initialize frame buffer
  last_buzzer_dutycycle = BUZZER_DUTYCYCLE;
  uint32_t i;
  for (i = 0; i < BUZZER_DATA_BIT_N; i++)    buzzer_frame_buffer[i]                       = last_buzzer_dutycycle; // All bits are zero duty cycle
  for (i = 0; i < BUZZER_RESET_BIT_N; i++)   buzzer_frame_buffer[i + BUZZER_DATA_BIT_N]   = 0; // All bits are zero duty cycle
  buzzer_dma = dmaStreamAlloc(BUZZER_DMA_STREAM, BUZZER_PWM_IRQ_PRIORITY, (stm32_dmaisr_t)buzzer_tx_complete_interrupt, (void *)BUZZER_DMA_STREAM);
  dmaStreamSetPeripheral(buzzer_dma, &(BUZZER_PWMD.tim->CCR[BUZZER_TIM_CH]));
  dmaStreamSetMemory0(buzzer_dma, buzzer_frame_buffer);
  dmaStreamSetTransactionSize(buzzer_dma, BUZZER_BUFF_BIT_N);
  // TCIE mode, select channel BUZZER_DMA_CHANNEL
  dmaStreamSetMode( buzzer_dma,
                    STM32_DMA_CR_PL(BUZZER_DMA_PRIORITY) | STM32_DMA_CR_CHSEL(BUZZER_DMA_CHANNEL) |
                    STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD |
                    STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE );// | STM32_DMA_CR_CIRC );//
  // init FIFO to 0 aka only one element
  //dmaStreamSetFIFO(buzzer_dma, STM32_DMA_FCR_FTH_1Q);
  dmaStreamEnable(buzzer_dma);
  pwmStart(&BUZZER_PWMD, &buzzer_pwm_config);
  pwmEnableChannel(&BUZZER_PWMD, BUZZER_TIM_CH, 5000);     // Initial period is 0; output will be low until first duty cycle is DMA'd in
  //pwmEnableChannel(&BUZZER_PWMD, BUZZER_TIM_CH, PWM_PERCENTAGE_TO_WIDTH(&BUZZER_PWMD, 5000));
}


Code: Select all

void buzzer_tx_complete_interrupt(uint32_t flags)
{
  //(void)flags;
  #if BUZZER_TIM_N == 1
  if (flags & DMA_HISR_TCIF5)
  {
    //flags &= ~DMA_HISR_TCIF5;
    palTogglePad(GPIOC, GPIOC_LED);
    buzzer_stop();
  }
  #elif BUZZER_TIM_N == 3
  if (flags & DMA_LISR_TCIF2)
  {
    //flags &= ~DMA_LISR_TCIF5;
    palTogglePad(GPIOC, GPIOC_LED);
    buzzer_stop();
  }
  #endif
}


Code: Select all

void buzzer_stop(void)
{
  // Stop DMA
  #if 1
  dmaStreamDisable(buzzer_dma);
  //dmaStreamFree(buzzer_dma);
  #else
  //dmaStreamDisable(BUZZER_DMA_STREAM);
  (BUZZER_DMA_STREAM)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE |
                                       STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE | STM32_DMA_CR_EN);
 
  nvicDisableVector(BUZZER_DMA_STREAM_IRQ);
  //rccDisableDMA2();
  #endif
  // Stop PWM
  //pwmStop(&BUZZER_PWMD);
  //pwmDisableChannel(&BUZZER_PWMD, BUZZER_TIM_CH);
}
blackberryer
Posts: 24
Joined: Sat Apr 05, 2025 6:52 pm
Been thanked: 4 times

Re: Multiple DMAs conflicts

Post by blackberryer »

It's been solved, thanks

flags pre-shifted content of the xISR register, the bits are aligned to bit zero

Code: Select all

void buzzer_tx_complete_interrupt(void *param, uint32_t flags)
{
  //(void)flags;
  if (flags & (0x01 << 5))
  {
    //flags &= ~DMA_HISR_TCIF5;
    palTogglePad(GPIOC, GPIOC_LED);
    buzzer_stop();
  }
}
Post Reply