Skip to main content
malehakim
Associate III
February 22, 2023
Question

Not getting desired frequency from DAC output pin

  • February 22, 2023
  • 2 replies
  • 917 views

Hi,

am having an STM32F303K8 and using its DAC to generate a sinewave of a given frequency. Am using TIM6 update event to effect the results on the DAC periphery.

AM running the APB1 bus at 16MHz, and my sinewave table has 256 samples. I set my prescalar to 0 and ARR to 2, and the closest i can produce is about 940Hz on the scope. I want to generate a Sinewave of 40KHz. I dont know what am doing wrong. Here are the relevenat pieces of my code.

// DAC variables
#define SINE_TABLE_SIZE 256
static uint16_t sinetable[SINE_TABLE_SIZE];
 
void generateSineTable(void)
{
 for (int i = 0; i < SINE_TABLE_SIZE; i++)
 {
 sinetable[i] = (uint16_t)(2047.5 * (sinf(2 * M_PI * i / SINE_TABLE_SIZE) + 1.0));
 }
}
 
void configureDAC(void)
{
 // Enable DAC clock
 RCC->APB1ENR |= RCC_APB1ENR_DAC1EN;
 
 // Enable GPIOA clock
 RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
 
 // Configure PA4 as analog mode
 GPIOA->MODER |= GPIO_MODER_MODER4;
 
 // Enable DAC channel 1
 DAC->CR |= DAC_CR_EN1;
}
 
void configureTimer6(void)
{
 // Enable Timer 6 clock
 RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
 
 // Set Timer 6 prescaler to 0
 TIM6->PSC = 0;
 
 // Set Timer 6 auto-reload value
 TIM6->ARR = 2;
 
 // Enable update interrupt
 TIM6->DIER |= TIM_DIER_UIE;
 
 // Set Timer 6 interrupt priority to highest
 NVIC_SetPriority(TIM6_DAC_IRQn, 0);
 
 // Enable Timer 6 interrupt
 NVIC_EnableIRQ(TIM6_DAC_IRQn);
 
 TIM6->CR2 |= TIM_CR2_MMS_2; // set TIM6_TRGO as trigger output
 
 TIM6->CR1 |= TIM_CR1_CEN; // enable timer 6
}
 
void TIM6_DAC_IRQHandler(void)
{
 static uint32_t sine_index = 0;
 uint16_t dac_output;
 
 // Check if update interrupt flag is set
 if (TIM6->SR & TIM_SR_UIF)
 {
 // Reset interrupt flag.
 	// According to the datasheet, it should be cleared by software
 TIM6->SR &= ~TIM_SR_UIF;
 
 // Get DAC output value from lookup table
 dac_output = sinetable[sine_index];
 
 // Update DAC output
 DAC->DHR12R1 = dac_output;
 
 // Update sine wave index
 sine_index++;
 
 if (sine_index >= SINE_TABLE_SIZE)
 {
 sine_index = 0;
 }
 }
}
 
int main(void)
{
 // Configure system clock
 SystemClock_Config();
 
 // Generate sine wave lookup table
 generateSineTable();
 
 // Configure DAC
 configureDAC();
 
 // Configure Timer6
 configureTimer6();
 
 // Start Timer6
 TIM6->CR1 |= TIM_CR1_CEN;
 
 // Main loop
 while (1)
 {
 // Do nothing
 }
}
 
 

I also want the Sinewave to be centered on the 0 voltage mark on the oscilloscope, so that half of it lies above the mark and half of it below. I've been really defeated by that part.

I am including a snapshot of the debug status of my APB1 clock, verifying that am running it at 16MHz

0693W00000aHPn1QAG.png

    This topic has been closed for replies.

    2 replies

    S.Ma
    Principal
    February 22, 2023

    Reverse thinking:

    40 kHz period with say a DAC with 1 MHz sample rate, that makes 25 samples for one sine period.

    Check the max slew rate (assumed here to be 45 degree slope, not the worst case of a square wave).

    Am I wrong ?

    KnarfB
    Super User
    February 22, 2023

    Your interrupt rate is pretty high. 940Hz * 256 samples/period == 240640 interrupts/s. Try to increase APB1 freq. and/or higher code optimization.

    Anyway, it will be a waste of CPU cycles. Try timer driver DMA to DAC.

    [Edit] A good check that the Core is not overrun is by putting some code in the while loop like a counter and see if/how many iterations per second the IRQ load leaves for normal operation.

    hth

    KnarfB