Hi, I am currently working on small project which I need to generate some arbitrary signal using DAC inside STM32G431KB.
Code is shown below.
#include "main.h"
#include "SysClockConfig.h"
uint16_t Output_Buffer[10] = {2048,2048,2048,2048,2048,2048,2048,2048,2048,2048};
void Initialization()
{
//----------Clock Config----------//
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN; //Enable Timer 2 Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMAMUX1EN; //Enable DMA
RCC->AHB2ENR |= RCC_AHB2ENR_DAC3EN | RCC_AHB2ENR_GPIOAEN; //Enable DAC3 and GPIOA
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Enable SysCfg for OPAMP
//----------GPIO Config----------//
GPIOA->MODER |= GPIO_MODER_MODE2; //Analog Mode
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPD2); //No PU-PD
//----------OPAMP Config----------//
OPAMP1->CSR &= ~(OPAMP_CSR_OPAMPxEN); //Disable OPAMP
OPAMP1->CSR |= OPAMP_CSR_VPSEL; //Connect DAC3_CH1 to VINP
OPAMP1->CSR |= OPAMP_CSR_VMSEL; // Follower Mode
OPAMP1->CSR |= OPAMP_CSR_HIGHSPEEDEN; // Enable High-Speed Mode
OPAMP1->CSR &= ~(OPAMP_CSR_OPAMPINTEN); //Output connected to pin
OPAMP1->CSR |= OPAMP_CSR_OPAMPxEN; //Enable OPAMP
//----------Timer Config----------//
TIM2->CR1 &= ~(TIM_CR1_CEN); //Counter disable
TIM2->PSC = 149; //
TIM2->ARR = 2000000; //
TIM2->CR1 |= TIM_CR1_URS; //Only counter overflow/underflow generates an update
TIM2->CR2 |= (0b010<<TIM_CR2_MMS_Pos); //The update event is selected as a trigger output
TIM2->EGR |= TIM_EGR_UG; //Update generation
//----------DAC Config-----------//
DAC3->CR &= ~(DAC_CR_EN1); //Disable DAC
DAC3->CR |= DAC_CR_DMAEN1; //Enable DMA on DAC Ch1
DAC3->CR &= ~(DAC_CR_WAVE1); //Wave Generation Disabled
DAC3->CR |= (4 << DAC_CR_TSEL1_Pos); //Trigger Channel 4 = Timer TRGO 2
DAC3->MCR |= (0b011 << DAC_MCR_MODE1_Pos);//Normal Mode DAC Channel 1 is connected to on chip peripherals with Buffer disabled.
DAC3->MCR |= (0b01 << DAC_MCR_HFSEL_Pos); //High frequency interface mode compatible to AHB>80 MHz enabled
DAC3->CR |= DAC_CR_TEN1; //Channel Trigger Enable
DAC3->CR |= DAC_CR_EN1; //Enable DAC
while(!(DAC3->SR & DAC_SR_DAC1RDY)); //Wait Until DAC is ready
//----------DMA1 Channel1 Configuration----------//
DMA1_Channel1->CNDTR = 10; //Set number of data to be sent
DMA1_Channel1->CPAR = (uint32_t) &DAC3->DHR12R1; //Peripheral address
DMA1_Channel1->CMAR = (uint32_t) Output_Buffer; //Data Buffer address
// VHigh Priority 16bit Data size 16bit Data size Memory Inc. Circular Mode Memory2Perip
DMA1_Channel1->CCR |= (0b11 << DMA_CCR_PL_Pos) | (0b01 << DMA_CCR_MSIZE_Pos) | (0b01 << DMA_CCR_PSIZE_Pos) | DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_DIR ;
DMAMUX1_Channel0->CCR |= (102 << DMAMUX_CxCR_DMAREQ_ID_Pos); //Connect DAC3_CH1 to DMA channel 1
DMA1_Channel1->CCR |= DMA_CCR_EN; //Enable Channel
}
int main(void)
{
HAL_Init();
SystemClock_Config();
Initialization();
//DAC3->DHR12R1 = 2048;
TIM2->CR1 |= TIM_CR1_CEN; //Counter enable
while (1)
{
}
}
void Error_Handler(void)
{
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
RCC_OscInitStruct.PLL.PLLN = 75;
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)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
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_7) != HAL_OK)
{
Error_Handler();
}
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk);
}
The code works if I don't use DMA. I can see the expected Output on PA2. However, when I tried to use DMA the output stays at 0V and I get DMA underrun bit set in DAC_SR register.
My timer is really slow 150MHz/150 = 1MHz/2000000= 2seconds. I can't see why this happens since underrun caused when DMA can't keep up with the DAC trigger speed.
I suspect that DMA do not work at start and thus giving underrun error at beginning.
Has anyone encountered something like this?
Thank you.