2023-02-22 03:58 AM
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
2023-02-22 08:17 AM
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 ?
2023-02-22 08:28 AM
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