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!

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);
}
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);
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);
}