Author Topic: STM32 DAC DMA Underrun problem  (Read 3062 times)

0 Members and 1 Guest are viewing this topic.

Offline syntax333Topic starter

  • Regular Contributor
  • *
  • Posts: 158
  • Country: 00
STM32 DAC DMA Underrun problem
« on: July 16, 2020, 05:17:11 am »
Hi, I am currently working on small project which I need to generate some arbitrary signal using DAC inside STM32G431KB.
Code is shown below.

Code: [Select]

#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.
 

Offline syntax333Topic starter

  • Regular Contributor
  • *
  • Posts: 158
  • Country: 00
Re: STM32 DAC DMA Underrun problem
« Reply #1 on: July 16, 2020, 06:57:11 am »
Also I tried using timer interrupt to send data into "DAC3->DHR12R1" register. I set timer to 2.5MHz and used internal OPAMP(follower) to route DAC3 output to external pin. Code works fine but it seems like output is limited to 1Msps even though in datasheet it says that DAC3 can output at 15Msps. Is this normal?
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4288
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: STM32 DAC DMA Underrun problem
« Reply #2 on: July 16, 2020, 07:08:59 am »
Quote
DAC registers
Refer to Section 1 on page 72 for a list of abbreviations used in register descriptions.
The peripheral registers have to be accessed by words (32-bit).

Quote
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 ;
That's 16 bit.
Don't you get a busfault?

edit: I just though that the DMA may not be able to cause an exception in the arm cortex... the transaction will just.. fail.. and that's it. Maybe this is wrong though.
« Last Edit: July 16, 2020, 11:18:15 am by Jeroen3 »
 
The following users thanked this post: syntax333

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 9780
  • Country: fi
Re: STM32 DAC DMA Underrun problem
« Reply #3 on: July 16, 2020, 07:10:16 am »
You have configured DAC as the DMA request source. Isn't your intention to use the timer as the DMA request source?
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3468
  • Country: gb
Re: STM32 DAC DMA Underrun problem
« Reply #4 on: July 16, 2020, 08:49:09 am »
Also I tried using timer interrupt to send data into "DAC3->DHR12R1" register. I set timer to 2.5MHz and used internal OPAMP(follower) to route DAC3 output to external pin. Code works fine but it seems like output is limited to 1Msps even though in datasheet it says that DAC3 can output at 15Msps. Is this normal?

That'll most likely be a code speed limitation, not the DAC itself.

You have configured DAC as the DMA request source. Isn't your intention to use the timer as the DMA request source?

Well there's your problem lady!
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1850
  • Country: se
Re: STM32 DAC DMA Underrun problem
« Reply #5 on: July 16, 2020, 09:22:44 am »
You have configured DAC as the DMA request source. Isn't your intention to use the timer as the DMA request source?

Well there's your problem lady!

Nope, the idea is correct.
The DAC will issue a DMA request when it receives an HW trigger, when DMA_ENx is set.
See the reference manual chapter 22.4.8

I think Jeroen3 might be correct.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline syntax333Topic starter

  • Regular Contributor
  • *
  • Posts: 158
  • Country: 00
Re: STM32 DAC DMA Underrun problem
« Reply #6 on: July 16, 2020, 11:01:36 am »
Quote
DAC registers
Refer to Section 1 on page 72 for a list of abbreviations used in register descriptions.
The peripheral registers have to be accessed by words (32-bit).

Quote
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 ;
That's 16 bit.
Don't you get a busfault?

Yes the problem was transfer size. After setting "0b10 <<DMA_CCR_PSIZE_Pos" which corresponds to 32 bit code now works as expected. Also now DAC can go beyond 1Msps. Thank you!
 
The following users thanked this post: SiliconWizard


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf