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.
12 REPLIES 12

It's apparently consequence of incorrectly handled/misunderstood remark from the RM:

waclawekjan_0-1692284143462.png

The delay according to 'G431 DS is:

waclawekjan_1-1692284532642.png

but, as the highlighted remark above indicates, this delay is only in the analog part, nothing prevents the digital part to work normally.

So, to generate a quasi-continuous waveform, it's not just matter of removing the delay, but you should also avoid switching the DMA [EDIT see post below] DAC [/EDIT] off and on.

But, at the end of the day, this is just another case to repeat my mantra: Cube/HAL - as inevitably any "library" - implements only a miniscule fraction of what the hardware is capable of, the arguable "usual cases". And Cube/HAL specifically is primarily a vehicle to allow clicky configuration in CubeMX. If your use case is outside of these "usual cases", Cube/HAL gets into way more than helps. This is not fault of Cube/HAL; it is what it is and using it you agreed to accept its shortcomings.

If you mean developing with STM32 seriously, you are better off using registers directly (no, not Cube/LL, that's mostly just renaming registers thus another unnecessary obstacle). DAC is trivial, timers are relatively easy, DMA/DMAMUX is maybe a bit more involved but in the long run the investment in learning pays off.

JW


@waclawek.jan wrote:
So, to generate a quasi-continuous waveform, it's not just matter of removing the delay, but you should also avoid switching the DMA off and on.

I disagree! It's normal to turn Off and On DMA, especially when transfer completed.
It's impossible to change configuration without turning DMA off (memory address / size / etc).
And there are DMA callbacks (interrupts) of Half Complete/Complete, to prepare new data, to switch buffers, etc.

I would agree the same about DAC , it's better to initialize / turn it on once and later update values when needed, or add wait check for DAC become ready after turning it on.

@waclawek.jan 
Thank you for pointing right way DACxRDY in DAC_SR register for implementing delay instead of insane 1 SysTick 😀

Sorry, my bad, I meant, you should not switch *DAC* off/on (i.e. you should remove __HAL_DAC_ENABLE() / __HAL_DAC_DISABLE() from the functions you are using to start/stop DMA). I've corrected above.

Btw. I went through the Cubes and I found the delay only in 'G4 and 'U5 HAL, whereas the analog part setting (tWAKEUP) is - logically - present and of similar duration in other STM32 families which have DAC, too.

JW