cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 - Sending Sine Wave with DAC and DMA

kl4971tse
Associate II
Posted on November 29, 2016 at 05:51

Hello!

I am currently trying to send a sine wave through the DAC. I've tried both using the std peripheral libraries and stm32cube, but to no avail. The frequencies and amplitude of the measured sine wave don't correspond to the values that I have calculated. I've been referring to note AN3126 and have modified the example provided by the std peripheral libraries. Would anyone have any advice for this? Thank you!

/* Includes ------------------------------------------------------------------*/
#include ''main.h''
/** @addtogroup STM32F30x_StdPeriph_Examples
* @{
*/
/** @addtogroup DAC_SignalsGeneration
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DAC_DHR12R2_ADDRESS 0x40007414
#define DAC_DHR8R1_ADDRESS 0x40007410
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
const uint16_t Sine12bit[128] = {
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, 100, 87, 79, 75, 76, 82, 93, 109, 
129, 154, 184, 218, 257, 300, 347, 399, 455, 514, 
577, 644, 714, 788, 865, 944, 1026, 1111, 1198, 1287, 
1378, 1471, 1565, 1660, 1756, 1853, 1950, 2047 }; 
/* Private function prototypes -----------------------------------------------*/
static void DAC_Config(void);
static void TIM_Config(void);
static void GPIO_Config(void);
static void DMA_Config(void); 
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured, 
this is done through SystemInit() function which is called from startup
file (startup_stm32f30x.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f30x.c file
*/
/* Preconfiguration before using DAC----------------------------------------*/
GPIO_Config();
DMA_Config();
DAC_Config();
/* TIM2 configuration to trigger DAC */
TIM_Config();
/* Configures Key Button EXTI Line */
/* Infinite loop */
/* The sine wave and the escalator wave has been selected */
/* Sine Wave generator ---------------------------------------------*/
/* DAC channel2 Configuration */
while (1)
{ 
}
}
/**
* @brief TIM2 configuration to trigger DAC conversion 
* @param None
* @retval None
*/
static void TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* TIM2 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
TIM_TimeBaseStructure.TIM_Period = (800000/(1000*128))-1; // originally 0xFF 
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; 
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 TRGO selection */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
/**
* @brief DAC channels configurations (PA4 and PA5 in analog,
* enable DAC clock, enable DMA2 clock)
* @param None
* @retval None
*/
static void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure PA.04 (DAC_OUT1) as analog */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static void DAC_Config(void){
/* DAC Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_Buffer_Switch = DAC_BufferSwitch_Disable;
/* DAC Channel2 Init */
DAC_Init(DAC1, DAC_Channel_2, &DAC_InitStructure);
/* Enable DAC Channel2 */
DAC_Cmd(DAC1, DAC_Channel_2, ENABLE);
/* Enable DMA for DAC Channel2 */
DAC_DMACmd(DAC1, DAC_Channel_2, ENABLE);
}
static void DMA_Config(void){
/* DMA2 clock enable (to be used with DAC) */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); 
/* DMA2 channel3 configuration */
DMA_DeInit(DMA1_Channel5); 
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 128;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
/* Enable DMA2 Channel3 */
DMA_Cmd(DMA1_Channel5, ENABLE);
} 

4 REPLIES 4
Walid FTITI_O
Senior II
Posted on November 29, 2016 at 10:39

Hi Aurora,

For the case of sine wave generation using DAC , you would refer to the example descibed in application note 

http://www.st.com/content/ccc/resource/technical/document/application_note/6f/35/61/e9/8a/28/48/8c/DM00129215.pdf/files/DM00129215.pdf/jcr:content/translations/en.DM00129215.pdf

''Extending the DAC performance of STM32 microcontrollers ''. The example of the high speed use of the DAC is based on STM32F407, it shows how togenerate a 200 kHz sine wave by the DAC operating at 5 Msps.

-Hannibal-

AvaTar
Lead
Posted on November 29, 2016 at 12:00

> The frequencies and amplitude of the measured sine wave don't correspond to the values that I have calculated.

 

For the amplitudes, have you observed the DAC output impedance(s) in the datasheet ?

Check that you measuring device does not overload it.

For the frequency, do you have a proper '

HSE_VALUE

' definition visible in the

stm32f3xx.h

header file ?

Otherwise it falls back to a default value, which is most probably incorrect for your hardware.

(The same issues as often occured in connection with UART baudrates ...).

Posted on December 10, 2016 at 19:05

What frequency are you trying to create?

I'm willing to bet the input frequency to the TIM is not 800 KHz

If you want 1 KHz out with 128 samples, you need to get a period of 128 KHz from a source clock with is more likely 36 or 72 MHz

ie Period = (72000000 / 128000) - 1; // Although not cleanly divisible

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on December 10, 2016 at 18:50

 ,

 ,

Some checklist in my mind:

Use a real Timer trigger GPIO pin

Use a DAC input real trigger pin (short to the Timer CC trigger pin)

==>, This way, you can look at the sampling rate.

Also, make sure the DAC buffer is activated and the analog supply pins of the STM32 are connected to the supply.

When testing, the DAC output should not drive analog components (no load)

Good luck!

Here are some pseudo code (in case it gives some general clues) used on STM32F437 to generate waveforms

 ,

♯ include '...'

 ,

♯ include 'math.h'

//const u32 DACn_DHR_Adr[3] = { 0, DAC_DHR12R1_ADDRESS, DAC_DHR12R2_ADDRESS },

 ,

const u32 DACn_DHR_Adr[3] = { 0, DAC_DHR12L1_ADDRESS, DAC_DHR12L2_ADDRESS },

 ,

const u32 DAC_Channels[3] = { 0, DAC_Channel_1, DAC_Channel_2 },

static u32 DAC_Get_n_From_PinName(PinNameDef N) {

 ,

 ,

if(N==PA4) return 1,

 ,

if(N==PA5) return 2,

 ,

 ,

while(1), // this is NOT a DAC output pin

 ,

 ,

}

 ,

void NewDAC_Pin_Buffer_VRef_mV(DAC_t* D, u32 PPP, IO_Pin_t* DacPin, FunctionalState BufferEnable, u16 VRef_mV) {

if(PPP==0) while(1),

 ,

if(DacPin==0) while(1), // no DAC output pin?

// Initialise the structure

 ,

D->,VRef_mV = VRef_mV,

 ,

D->,PPP = PPP,

 ,

D->,n = DAC_Get_n_From_PinName(DacPin->,Name),

 ,

D->,AnalogOutPin = DacPin,

 ,

 ,

ClockGateEnable_PPP((u32)D->,PPP, ENABLE), // Clock enable the peripheral

DAC_DeInit(),

 ,

DAC_StructInit(&,D->,InitStructure), // Initialize the structure, can be edited outside this function

 ,

D->,InitStructure.DAC_OutputBuffer = BufferEnable ? DAC_OutputBuffer_Enable : DAC_OutputBuffer_Disable,

 ,

D->,InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None,

 ,

}

void SetDAC_Waveform(DAC_t* D, u32 Adr, u32 Size) {

 ,

 ,

u8 n = D->,n,

if(Size>,1) { // DMA will be used for the transfer

 ,

D->,SampleAdr = Adr,

 ,

D->,SampleSize = Size,

ClockGateEnable_PPP((u32)DMA1, ENABLE), // Clock enable DMA here

 ,

//RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE),

 ,

 ,

DMA_StreamChannelInfo_t* DMA_Info = Get_pStreamChannelForPPP_Signal((u32)DAC, DAC1_ANALOG, DMA_DIR_MemoryToPeripheral),

 ,

D->,DMA_TX = Get_pDMA_Info(DMA_Info->,Stream),

 ,

D->,TX_Channel = DMA_Info->,Channel,

DMA_DeInit(DMA_Info->,Stream), // DACn

 ,

DMA_InitTypeDef DMAI,

 ,

DMAI.DMA_Channel = DMA_Info->,Channel, // DACn

 ,

DMAI.DMA_PeripheralBaseAddr = (u32)DACn_DHR_Adr[n],

 ,

DMAI.DMA_Memory0BaseAddr = (u32)D->,SampleAdr, // n = 1 or 2

 ,

DMAI.DMA_DIR = DMA_DIR_MemoryToPeripheral,

 ,

DMAI.DMA_BufferSize = D->,SampleSize,

 ,

DMAI.DMA_PeripheralInc = DMA_PeripheralInc_Disable,

 ,

DMAI.DMA_MemoryInc = DMA_MemoryInc_Enable,

 ,

DMAI.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord,

 ,

DMAI.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord,

 ,

DMAI.DMA_Mode = DMA_Mode_Circular,

 ,

DMAI.DMA_Priority = DMA_Priority_High,

 ,

DMAI.DMA_FIFOMode = DMA_FIFOMode_Disable,

 ,

DMAI.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull,

 ,

DMAI.DMA_MemoryBurst = DMA_MemoryBurst_Single,

 ,

DMAI.DMA_PeripheralBurst = DMA_PeripheralBurst_Single,

 ,

DMA_Init(DMA_Info->,Stream, &,DMAI),

 ,

return,

 ,

}

 ,

 ,

while(1), // not supported for now

 ,

}

void UseDAC_Trigger(DAC_t* D, IO_Pin_t* Trigger, u32 InternalTrigger) { // DAC_InitStructure.DAC_Trigger = DAC_Trigger_T3_TRGO,

 ,

 ,

if(Trigger) { // Physical Trigger Pin (can be probed by oscilloscope)

 ,

if((Trigger->,Name &, 0xF)!=9) while(1),

 ,

D->,TriggerPin = Trigger,

 ,

InternalTrigger = DAC_Trigger_Ext_IT9, // override the internal trigger

 ,

},

 ,

 ,

D->,InitStructure.DAC_Trigger = InternalTrigger,

 ,

}

void ConfigureDAC(DAC_t* D) {

 ,

 ,

u8 n = D->,n,

 ,

// configure the analog output pin

 ,

ConfigurePinAsAnalog(D->,AnalogOutPin),

 ,

 ,

// configure the external trigger pin, if non NULL

 ,

if(D->,TriggerPin) {

 ,

ConfigurePinAsInputTrigger(D->,TriggerPin),

 ,

EXTI_SetEdgesEnable(D->,TriggerPin->,Name, ENABLE, DISABLE), // Rising Edge is the trigger/event

 ,

EXTI_SetEvent(D->,TriggerPin->,Name &, 0xF, ENABLE), // no checks on overbooking here...

 ,

},

 ,

 ,

DAC_Init(DAC_Channels[n], &,D->,InitStructure),

 ,

if(D->,DMA_TX) { // if DMA is defined (needed)

 ,

DMA_Cmd(D->,DMA_TX->,Stream, ENABLE),

 ,

BookDMA_Stream(D->,DMA_TX->,Stream),

 ,

DAC_DMACmd(DAC_Channels[n], ENABLE),

 ,

},

 ,

}

void EnableDAC(DAC_t* D) { // Finally activate the DAC (HW configuration can be altered between Configure and Enable

 ,

 ,

u8 n = D->,n,

 ,

DAC_Cmd(DAC_Channels[n], ENABLE),

 ,

}

// helper functions

void SetDAC_Lsb(DAC_t* D, u32 Lsb) {

 ,

 ,

u32 n = D->,n,

 ,

u16* DR = (u16*) DACn_DHR_Adr[n],

 ,

*DR = Lsb,

 ,

DAC->,SWTRIGR = 1<,<,(n-1), // push the data out right now

 ,

}

 ,

u16 DAC_mV_ToLsb(DAC_t* D, u32 mV) {

 ,

 ,

u32 Lsb = Interpolate_s32 (0, D->,VRef_mV, 0, 0xFFF0, mV),

 ,

return mV,

 ,

}

♯ define myPI 3.14159265359

 ,

void DAC_WaveGeneratePredefined(u16* pu16, u8 WaveName, u16 size) {

 ,

 ,

u16 i,

 ,

u16 data,

 ,

 ,

for(i=0,i<,size,i++) {

 ,

 ,

switch(WaveName) {

 ,

 ,

case 0: data = 0,break,

 ,

case 1: data = i*4096/size,break, // rising values

 ,

case 2: data = 4095-i*4096/size,break, // falling values

 ,

case 11: data = (u16)(2048+2047*sin(1*2*i*myPI/size)),break,

 ,

case 12: data = (u16)(2048+2047*sin(2*2*i*myPI/size)),break,

 ,

case 13: data = (u16)(2048+2047*sin(3*2*i*myPI/size)),break,

 ,

case 14: data = (u16)(2048+2047*sin(4*2*i*myPI/size)),break,

 ,

case 15: data = (u16)(2048+2047*sin(5*2*i*myPI/size)),break,

 ,

case 16: data = (u16)(2048+2047*sin(6*2*i*myPI/size)),break,

 ,

case 17: data = (u16)(2048+2047*sin(7*2*i*myPI/size)),break,

 ,

case 18: data = (u16)(2048+2047*sin(8*2*i*myPI/size)),break,

 ,

default:data = (i<,(size>,>,1))?1024:2048, // square wave, not full amplitude

 ,

}

 ,

 ,

pu16[i] = data<,<,4, // make it 16 bit format

 ,

 ,

}

 ,

}