cancel
Showing results for 
Search instead for 
Did you mean: 

Not getting desired frequency from DAC output pin

malehakim
Associate III

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

2 REPLIES 2
S.Ma
Principal

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
Principal III

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