DAC with DMA: DMA interrupt not working

Post here first, or if you can't find a relevant section!
Post Reply
whemak
Posts: 5
Joined: Sun May 24, 2020 9:52 am

DAC with DMA: DMA interrupt not working

Post by whemak »

Hi everyone,

I need to run the DAC with DMA on the Arduino IDE. I have an STM32L4R5ZI and a Cube IDE project that works fine so I tried to redo the same things on Arduino IDE. I understand STM32duino does not support DAC+DMA (?!) and to make it work I had to push things a bit (see code).

So question 1: is there a better way to proceed? I could not understand exactly what is supported and what not. Is DAC+DMA maybe supported already?!

My next problem is the following. My code works on Arduino IDE and I can get up to about 10MS/s, but if DMA interrupts are enabled, the code in "loop()" get stuck as soon as DMA reaches the first half-complete buffer event: DMA keeps running forvever, all the rest stops! :evil: Without DMA interrupt, everything works fine and the loop code keeps on being executed as expected (flashing LED here, just for debugging). It looks like there is a problem with the NVIC and when the interrupt fires the main execution jumps who knows where and gets stuck. I tried to the define the standard "DMA1_Channel1_IRQHandler()" but I do not think it is getting linked in any way. I had a look at the NVIC table and the entry for DMA1 channel1 at 0x6C does not seem correct.

Question 2: what's wrong here? How can I fix this? Is there a good way to change entries in the NVIC? The DMA interrupt is not absolutely necessary but it would be nice to have.

My code. It is broken down in three files. The sketch:

Code: Select all

/*
 * DAC with DMA
 */
#include "utils.h"

DAC_HandleTypeDef hdac1;
DMA_HandleTypeDef hdma_dac1_ch1;
TIM_HandleTypeDef htim2;

#define TT   100  /* period in usec (multiples of 10 pls) */
#define NSAM 100
/* Sine 100 pt */
uint32_t sine_val[NSAM] =
{
  0x800,0x874,0x8E7,0x959,0x9CA,0xA3A,0xAA7,0xB11,0xB78,0xBDC,
  0xC3B,0xC97,0xCEE,0xD40,0xD8C,0xDD3,0xE14,0xE4F,0xE84,0xEB2,
  0xED9,0xEF9,0xF13,0xF25,0xF30,0xF33,0xF30,0xF25,0xF13,0xEF9,
  0xED9,0xEB2,0xE84,0xE4F,0xE14,0xDD3,0xD8C,0xD40,0xCEE,0xC97,
  0xC3B,0xBDC,0xB78,0xB11,0xAA7,0xA3A,0x9CA,0x959,0x8E7,0x874,
  0x800,0x78C,0x719,0x6A7,0x636,0x5C6,0x559,0x4EF,0x488,0x424,
  0x3C5,0x369,0x312,0x2C0,0x274,0x22D,0x1EC,0x1B1,0x17C,0x14E,
  0x127,0x107,0x0ED,0x0DB,0x0D0,0x0CD,0x0D0,0x0DB,0x0ED,0x107,
  0x127,0x14E,0x17C,0x1B1,0x1EC,0x22D,0x274,0x2C0,0x312,0x369,
  0x3C5,0x424,0x488,0x4EF,0x559,0x5C6,0x636,0x6A7,0x719,0x78C
};

#define msec 500;
uint32_t counts = (uint32_t)2*TT/10;

void setup() 
{
  pinMode(LED_RED,OUTPUT);
  pinMode(LED_GREEN,OUTPUT);
  pinMode(LED_BLUE,OUTPUT);
  
  Serial.begin(9600);

  MX_DMA_Init(); 
  MX_DAC1_Init();  
  MX_TIM2_Init();
  HAL_TIM_Base_Start(&htim2);
  HAL_DAC_Start_DMA(&hdac1,DAC1_CHANNEL_1,sine_val,NSAM,DAC_ALIGN_12B_R);  
    
}

void loop() 
{ 
  digitalWrite(LED_GREEN,0);
  delay(msec);
  digitalWrite(LED_GREEN,1);
  delay(msec);   
}
Then "utils.h"

Code: Select all

#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_dac.h"
#include "stm32l4xx_hal_dma.h"
#include "stm32l4xx_hal_dma_ex.h"
#include "stm32l4xx_hal_tim.h"

static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_DAC1_Init(void);
static void MX_TIM2_Init(void);
and "utils.cpp"

Code: Select all

#include "utils.h"

extern DAC_HandleTypeDef hdac1;
extern DMA_HandleTypeDef hdma_dac1_ch1;
extern TIM_HandleTypeDef htim2;
extern uint32_t counts;

/*=[HAL]=================================================*/
void HAL_MspInit(void)
{
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();
}
/*=[CLOCK]=================================================*/
void SystemClock_Config(void)
{
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST) != HAL_OK) { /* errror */ }
  /* Internal Oscillator Configuration: MSI@4MHz PLL x30 total */
  RCC_OscInitTypeDef RCC_OscInitStruct = {};
  RCC_OscInitStruct.OscillatorType      = RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.MSIState            = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange       = RCC_MSIRANGE_6;
  RCC_OscInitStruct.PLL.PLLState        = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource       = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM            = 1;
  RCC_OscInitStruct.PLL.PLLN            = 60;
  RCC_OscInitStruct.PLL.PLLP            = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ            = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR            = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* errror */ }
  /* Internal Clock Configuration: from PLL, no division on buses */
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource        = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider       = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider      = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider      = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { /* errror */ }
}
/*=[DAC]=================================================
 *
 * here I had to tweak things a bit since I needed a different version 
 * of HAL_DAC_MspInit() 
 *
 */
static void MX_DAC1_Init(void)
{
  DAC_ChannelConfTypeDef sConfig = {};
  hdac1.Instance = DAC1;
  /* DAC Initialization */
  if (myHAL_DAC_Init(&hdac1) != HAL_OK) /* <= modified */
  /* DAC Configuration */
  sConfig.DAC_SampleAndHold           = DAC_SAMPLEANDHOLD_DISABLE;
  sConfig.DAC_Trigger                 = DAC_TRIGGER_T2_TRGO;
  sConfig.DAC_HighFrequency           = DAC_HIGH_FREQUENCY_INTERFACE_MODE_DISABLE;
  sConfig.DAC_OutputBuffer            = DAC_OUTPUTBUFFER_ENABLE;
  sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_ENABLE;
  sConfig.DAC_UserTrimming            = DAC_TRIMMING_FACTORY;
  if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_1) != HAL_OK) { /* errror */ }
}
HAL_StatusTypeDef myHAL_DAC_Init(DAC_HandleTypeDef *hdac)
{
  if (hdac->State == HAL_DAC_STATE_RESET)
  {
    hdac->Lock = HAL_UNLOCKED;
    myHAL_DAC_MspInit(hdac); /* <= modified */
  }
  hdac->State     = HAL_DAC_STATE_BUSY; 
  hdac->ErrorCode = HAL_DAC_ERROR_NONE;
  hdac->State     = HAL_DAC_STATE_READY;
  return HAL_OK;
}
void myHAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
  /* Setup GPIO pin */
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_DAC1_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* Setup DMA */
  hdma_dac1_ch1.Instance                 = DMA1_Channel1;
  hdma_dac1_ch1.Init.Request             = DMA_REQUEST_DAC1_CH1;
  hdma_dac1_ch1.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  hdma_dac1_ch1.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_dac1_ch1.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_dac1_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_dac1_ch1.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  hdma_dac1_ch1.Init.Mode                = DMA_CIRCULAR;
  hdma_dac1_ch1.Init.Priority            = DMA_PRIORITY_LOW;
  if (HAL_DMA_Init(&hdma_dac1_ch1) != HAL_OK) { /* errror */ }
  __HAL_LINKDMA(hdac,DMA_Handle1,hdma_dac1_ch1);
}
/*=[TIMER2]=================================================*/
static void MX_TIM2_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim2.Instance                    = TIM2;
  htim2.Init.Prescaler              = 6-1; 
  htim2.Init.CounterMode            = TIM_COUNTERMODE_UP;
  htim2.Init.Period                 = counts-1; 
  htim2.Init.ClockDivision          = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload      = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { }
  sClockSourceConfig.ClockSource    = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode     = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { }
}
/*=[DMA]=================================================*/
void DMA1_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_dac1_ch1);
}
void HAL_DAC_ConvHalfCpltCallback(DMA_HandleTypeDef* hdma)
{
  /* nothing */
}
void HAL_DAC_ConvCpltCallback(DMA_HandleTypeDef* hdma)
{
  /* nothing */
}
static void MX_DMA_Init(void) 
{
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  /* 
   * If enabled, main loop gets stuck after half buffer is used
   */
  //HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

Thank you! S
by stas2z » Sun May 24, 2020 12:09 pm

Code: Select all

extern "C" void DMA1_Channel1_IRQHandler(void)
Go to full post
stas2z
Posts: 131
Joined: Mon Feb 24, 2020 8:17 pm
Answers: 8

Re: DAC with DMA: DMA interrupt not working

Post by stas2z »

Code: Select all

extern "C" void DMA1_Channel1_IRQHandler(void)
Post Reply

Return to “General discussion”