cancel
Showing results for 
Search instead for 
Did you mean: 

DMA to DAC transfer in normal mode too slow

fedeparkour
Associate II

Hi,

I'm using STM32G431RB on the NUCLEO-G431RB developement board.

I want to generate a signal from an array each time an external trigger is received.

The signal is sampled with the TIMER6 trigger, which is rised every 1us. (MCU clock is 170MHz, TIMER6 PSC is 0 and ARR is 170-1).

TIMER6 configurationTIMER6 configuration

The DMA is set to normal mode (because I want to generate a signal only when the trigger comes, and not continuously)

DAC DMA configurationDAC DMA configuration

 The DAC is configured like this:

DAC configurationDAC configuration

 I'm calling the HAL_DAC_Start_DMA function each time the external trigger rises, but, even if the trigger is repeated each 1ms, the signal is generated each 2ms. The minimum interval between a signal generation and another one is 2ms and basically I need to reduce it as much as possible.

SignalSignal

 

Here the trigger is faster than 2ms but the signal is generated each 2msHere the trigger is faster than 2ms but the signal is generated each 2ms

 The code:

/* Private variables ---------------------------------------------------------*/

DAC_HandleTypeDef hdac1;

DMA_HandleTypeDef hdma_dac1_ch1;

TIM_HandleTypeDef htim6;

/* USER CODE BEGIN PV */
uint8_t dac_flag = 0;
uint32_t data[41] = {2048, 2148, 2248, 2348, 2448, 2548, 2648, 2748, 2848, 2948, 3048, 2948, 2848, 2748, 2648, 2548, 2448, 2348, 2248, 2148, 2048, 1948, 1848, 1748, 1648, 1548, 1448, 1348, 1248, 1148, 1048, 1148, 1248, 1348, 1448, 1548, 1648, 1748, 1848, 1948, 2048}; //Signal lookup table
/* USER CODE END PV */

int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* Configure the system clock */
SystemClock_Config();

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_DAC1_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim6);

//Initial value 
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 2048);
HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);

 

while (1)
  {
     if(dac_flag)
    {
        dac_flag = 0;
        HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, data, 41, DAC_ALIGN_12B_R);
     }
  }
 
...
 
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
   if(GPIO_Pin == STAGE_TRIG_Pin)
  { 
      dac_flag = 1;
  }
}
 
It seems that the DMA "recharge" is blocking the next transfer. Is there something to do in order to speed up this process?
 
Thank you in advance.
1 ACCEPTED SOLUTION

Accepted Solutions

I see. Still there is option to set HAL_DAC_DMA only ones ( assuming it's most slow subroutine) , and in the interrupt do start/stop Timer-6. Or even better configure tim-6 to trigger on external event in one time mode or with one more timer as 50 usec pulse generator for tim-6 waiting in Gated-mode.

View solution in original post

12 REPLIES 12
MasterT
Senior III

"The DMA is set to normal mode (because I want to generate a signal only when the trigger comes, and not continuously)"

I see misunderstanding how dma works. DMA is not a master, but submissive in this configuration. TIM -> DAC - DMA.

So, dma is waiting request from the dac, and setting "circular" mode is the right way to do . Than you start all process only ones, speed limits I tested with G-474re about ~14 msps with 170MHz clock

Thank you MasterT for your answer.

By setting the DMA in circular mode I don't obtain the wanted behaviour. I mean: I don't want to generate continuously the waveform, I want to generate the signal only when the external trigger rises. The signal duration is about 50 us, and the trigger can come in any moment. Actually if the trigger comes before 2ms from another one it will be ignored which is bad form my application.

Set a GPIO pin when you set dac_flag, and clear it in main() when you test it; and observe.

An interesting test might be also to toggle a pin in the main() loop and observe.

JW

I tried to continuously call HAL_DAC_Start_DMA in the while loop followed by a HAL_GPIO_TogglePin and the result is:

0.PNG

 

1.PNG

 

> I tried to continuously call HAL_DAC_Start_DMA in the while loop followed by a HAL_GPIO_TogglePin 

How? I don't understand. Please post relevant code.

JW

I see. Still there is option to set HAL_DAC_DMA only ones ( assuming it's most slow subroutine) , and in the interrupt do start/stop Timer-6. Or even better configure tim-6 to trigger on external event in one time mode or with one more timer as 50 usec pulse generator for tim-6 waiting in Gated-mode.

DMA in continuous mode, timer6 start when trigger comes and timer6 stop when DMA DAC transfer completed works fine!

Thank you!

MMatj.1
Associate II

Hi!

I had this problem also and it is because of insane 1ms(SysTick) delay ( ! BUG ! ) in HAL_DAC_Start_DMA() !
This bug even prevent using this function in interrupt with higher priority than SysTick .. 
I had to use own copy implementation of this function with commented out "HAL_Delay(1);".
It allowed me to start next DAC DMA transfer in transfer completed callback without any noticeable delay in output signal.

 

 

 

...
  if (status == HAL_OK)
  {
    /* Enable the Peripheral */
    __HAL_DAC_ENABLE(hdac, Channel);
    /* Ensure minimum wait before using peripheral after enabling it */
    // HAL_Delay(1);   // Commented out insane delay !
  }
  else
  {
    hdac->ErrorCode |= HAL_DAC_ERROR_DMA;
  }
...

 

 

 

 

WHAT?

@Amel NASRI, can this please be explained/fixed?

Thanks,

JW