STM32 F4 DAC DMA waveform Generator
Goal: generating an arbitrary periodic waveform using a DACS with DMA and TIM6 as a trigger.
Agenda:
- Modeling a waveform in MATLAB and getting the waveform data
- Studying the DAC, DMA, and TIM6 to see how it can is used to generate a waveform
- Coding and testing a couple of functions
Percent generating an Nbit sine wave%modifiable Parameters:step, bits, offsetclose; clear; Clc;points= -; % number of points between sin (0) to Sin (2*pi) Bits= A; % A-bit sine Wave for A-bit Dacoffset= the; %limiting DAC output voltaget=0:((2*pi/(points-1))):(2*PI); % Creating a vector from 0To2*Piy= sin (t); %getting the sine valuesy= y +1; % getting rid of negative values (shifting up by1) y= Y* ((2^bits-1)-2*offset)/2+offset; % limiting the range (0+offset) to (2^bits-offset) y= Round (y); %rounding the Valuesplot (t, y); Grid% plotting forVisual confirmationfprintf ('%d,%d,%d,%d,%d,%d,%d, %d,%d,%d, \ n', y);
There ' s a trade-off between the sine wave resolution (number of points from sin (0) to sin (2*pi)), Output frequency range, and precision of the output frequency (e.g. we want a 20kHz wave, but we can only get 19.8kHz or 20.2kHz because the step is 0.4kHz). The output frequency is a non-linear function with multiple variables. To complicate it further, some of these variables must is integers within 1 to 65535 range which makes it impossible to OU Tput certain frequencies precisely.
Although precise frequency control is terribly hard (if not impossible), one feature does stand out-ability to generate a periodic waveform of any shape.
Below is the code for mediocre range/precision/resolution but excellent versatility in terms of shaping the output wavefor M.
@input-uint16_t Function[waveform_resolution]
@output-PA4 in analog configuration
@parameters-out_freq, Sin_res
To tailor other parameters, study the DAC channel block diagram, electrical characteristics, timing diagrams, etc. To switch DAC channels, see memory Map, specifically DAC DHRX Register for DMA writes.
#include <stm32f4xx.h>#include"other_stuff.h"#defineOut_freq 5000//Output Waveform Frequency#defineSine_res 128//Waveform Resolution#defineDac_dhr12r1_addr 0x40007408//DMA writes into this reg on every request#defineCnt_freq 42000000//TIM6 counter Clock (prescaled APB1)#defineTim_period ((Cnt_freq)/((sine_res) * (out_freq)))//autoreload reg ValueConstuint16_t Function[sine_res] = {2048,2145,2242,2339,2435,2530,2624,2717,2808,2897, 2984,3069,3151,3230,3307,3381,3451,3518,3581,3640, 3696,3748,3795,3838,3877,3911,3941,3966,3986,4002, 4013,4019,4020,4016,4008,3995,3977,3954,3926,3894, 3858,3817,3772,3722,3669,3611,3550,3485,3416,3344, 3269,3191,3110,3027,2941,2853,2763,2671,2578,2483, 2387,2291,2194,2096,1999,1901,1804,1708,1612,1517, 1424,1332,1242,1154,1068,985,904,826,751,679, 610,545,484,426,373,323,278,237,201,169, 141,118, -, the, -, the, the, the, the,109, 129,154,184,218,257, -,347,399,455,514, 577,644,714,788,865,944,1026,1111,1198,1287, 1378,1471,1565,1660,1756,1853,1950,2047 }; Static voidTim6_config (void);Static voidDac1_config (void); intMain () {gpio_inittypedef gpio_a; Rcc_ahb1periphclockcmd (Rcc_ahb1periph_gpioa, ENABLE); Rcc_apb1periphclockcmd (RCC_APB1PERIPH_DAC, ENABLE); Rcc_ahb1periphclockcmd (RCC_AHB1PERIPH_DMA1, ENABLE); Gpio_a.gpio_pin=Gpio_pin_4; Gpio_a.gpio_mode=Gpio_mode_an; GPIO_A.GPIO_PUPD=Gpio_pupd_nopull; Gpio_init (Gpioa,&gpio_a); Tim6_config (); Dac1_config (); while(1) { } }Static voidTim6_config (void) {tim_timebaseinittypedef tim6_timebase; Rcc_apb1periphclockcmd (RCC_APB1PERIPH_TIM6, ENABLE); Tim_timebasestructinit (&tim6_timebase); Tim6_timebase.tim_period=(uint16_t) tim_period; Tim6_timebase.tim_prescaler=0; Tim6_timebase.tim_clockdivision=0; Tim6_timebase.tim_countermode=tim_countermode_up; Tim_timebaseinit (TIM6,&tim6_timebase); Tim_selectoutputtrigger (TIM6, tim_trgosource_update); Tim_cmd (TIM6, ENABLE);}Static voidDac1_config (void) {dac_inittypedef dac_init; Dma_inittypedef Dma_init; Dac_init. Dac_trigger=Dac_trigger_t6_trgo; Dac_init. Dac_wavegeneration=Dac_wavegeneration_none; Dac_init. Dac_outputbuffer=dac_outputbuffer_enable; Dac_init (Dac_channel_1,&dac_init); Dma_deinit (DMA1_STREAM5); Dma_init. Dma_channel=dma_channel_7; Dma_init. Dma_peripheralbaseaddr=(uint32_t) dac_dhr12r1_addr; Dma_init. Dma_memory0baseaddr= (uint32_t) &function; Dma_init. Dma_dir=dma_dir_memorytoperipheral; Dma_init. Dma_buffersize=Sine_res; Dma_init. Dma_peripheralinc=dma_peripheralinc_disable; Dma_init. Dma_memoryinc=dma_memoryinc_enable; Dma_init. Dma_peripheraldatasize=Dma_peripheraldatasize_halfword; Dma_init. Dma_memorydatasize=Dma_memorydatasize_halfword; Dma_init. Dma_mode=Dma_mode_circular; Dma_init. Dma_priority=Dma_priority_high; Dma_init. Dma_fifomode=dma_fifomode_disable; Dma_init. Dma_fifothreshold=Dma_fifothreshold_halffull; Dma_init. Dma_memoryburst=Dma_memoryburst_single; Dma_init. Dma_peripheralburst=Dma_peripheralburst_single; Dma_init (DMA1_STREAM5,&dma_init); Dma_cmd (DMA1_STREAM5, ENABLE); Dac_cmd (Dac_channel_1, ENABLE); Dac_dmacmd (Dac_channel_1, ENABLE);}
Using The code above we is supposed to get a 5kHz sine wave constructed with + points (for better quality, consider USI ng more points).
Here's a picture of the what we actually get (off by 25Hz, not too bad).
And here ' s the cool sinc (x) function. To generate other functions, model it in MATLAB, cast to 12-bit, STM32F4 does the rest.
STM32 F4 DAC DMA waveform Generator