2014-11-27 06:45 AM
I am using the STM32L Discovery Board (STML152RB chip on board). The IDE is Emblocks. I was trying to generate a sawtooth wave signal using DAC and DMA but it does not work. I was able to make the same program without DMA (by triggering an interrupt at regular time with a timer and updating the DAC value inside the interrup handler) but with DMA it does not work. Below is the code I use. Anyone can help to fix it?
#include ''stm32l1xx_conf.h''#include <stm32l1xx.h>#include <stm32l1xx_rcc.h>#include <stm32l1xx_gpio.h>#include <stm32l1xx_tim.h>#include <stm32l1xx_dac.h>#include <stm32l1xx_dma.h>#include <misc.h>#include <math.h>#define WAVE_FREQ 5000#define WAVE_POINTS 100#define TIMER_PERIOD 9uint16_t wave_array[100];uint8_t j;float pi_greco = 3.14159;int timervalue;void GPIO_initialize(void){ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitTypeDef gpioStructure; gpioStructure.GPIO_Pin = GPIO_Pin_5; gpioStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpioStructure);}void DAC_initialize(void){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); RCC_APB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitTypeDef DMA_Structure; DMA_Structure.DMA_PeripheralBaseAddr = (uint32_t) &DAC->DHR12R2; DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array; DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_Structure.DMA_BufferSize = WAVE_POINTS; DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_Structure.DMA_Mode = DMA_Mode_Circular; DMA_Structure.DMA_Priority = DMA_Priority_High; DMA_Structure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_Structure); DAC_InitTypeDef DAC_Structure; DAC_Structure.DAC_Trigger = DAC_Trigger_T6_TRGO; DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_2, &DAC_Structure); DMA_Cmd(DMA1_Channel1, ENABLE); DAC_DMACmd(DAC_Channel_2, ENABLE); DAC_Cmd(DAC_Channel_2, ENABLE);}void TIM6_initialize(void){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef timerInitStructure; timerInitStructure.TIM_Prescaler = 319; timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure.TIM_Period = TIMER_PERIOD; timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM6, &timerInitStructure); TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); TIM_Cmd(TIM6, ENABLE);}int main(void){ for(j=0; j<100; j++) { wave_array[j] = (uint16_t)(500 + 20*j); } GPIO_initialize(); TIM6_initialize(); DAC_initialize(); while(1) { }}2014-11-27 06:58 AM
According RM0038, DAC_channel2 trigs DMA1_channel3. I do not catch why DAC_ch2 is associated with TIM7, but if I were you I will use TIM7 instead of TIM6.
Or you can use the DAC_Channel1/TIM6/DMA1_Channel2 combination as well.2014-11-27 07:10 AM
Changed DMA_Channel1 with DMA_Channel3 and TIM6 with TIM7 but again it is not working
2014-11-27 07:22 AM
Does it still work with TIM7 and no DMA ?
2014-11-27 09:15 AM
Yes. It works also with TIM7. However with the no DMA version there is also another difference: the event that triggers the DAC update is TIM_IT_Update with no DMA and
TIM_TRGOSource_Update with DMA (since this was used in a code I found on the web).
2014-11-27 09:16 AM
#include ''stm32l1xx_conf.h''
#include <
stm32l1xx.h
>
#include <
stm32l1xx_rcc.h
>
#include <
stm32l1xx_gpio.h
>
#include <
stm32l1xx_tim.h
>
#include <
stm32l1xx_dac.h
>
#include <
stm32l1xx_dma.h
>
#include <
misc.h
>
#include <
math.h
>
#define WAVE_FREQ 5000
#define WAVE_POINTS 100
#define TIMER_PERIOD 10
uint16_t wave_array[100];
uint8_t j;
float pi_greco = 3.14159;
int timervalue;
void GPIO_initialize(void)
{
GPIO_InitTypeDef gpioStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
gpioStructure.GPIO_Pin = GPIO_Pin_5;
gpioStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &gpioStructure);
}
void DAC_initialize(void)
{
DMA_InitTypeDef DMA_Structure;
DAC_InitTypeDef DAC_Structure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel3); // DAC2 -> DMA1 Ch3
DMA_Structure.DMA_PeripheralBaseAddr = (uint32_t) &DAC->DHR12R2;
DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array[0];
DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_Structure.DMA_BufferSize = WAVE_POINTS;
DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_Structure.DMA_Mode = DMA_Mode_Circular;
DMA_Structure.DMA_Priority = DMA_Priority_High;
DMA_Structure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_Structure);
DAC_Structure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_2, &DAC_Structure);
DMA_Cmd(DMA1_Channel3, ENABLE);
DAC_DMACmd(DAC_Channel_2, ENABLE);
DAC_Cmd(DAC_Channel_2, ENABLE);
}
void TIM6_initialize(void)
{
TIM_TimeBaseInitTypeDef timerInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
timerInitStructure.TIM_Prescaler = 320-1;// 32MHz -> 100KHz
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = TIMER_PERIOD - 1; // DIV10, 100KHz -> 10KHz
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM6, &timerInitStructure);
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
TIM_Cmd(TIM6, ENABLE);
}
int main(void)
{
for(j=0; j<100; j++)
{
wave_array[j] = (uint16_t)(500 + 20*j);
}
GPIO_initialize();
TIM6_initialize();
DAC_initialize();
while(1)
{
}
}
2014-11-27 09:41 AM
RCC_APB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
of course this is the best candidate to explain why it does not work.2014-11-28 01:17 AM
Used the code suggested by clive1 and also fixed the RCC statement
RCC_AHB1PeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
withRCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
but the code still does not work.2014-11-28 04:46 AM
Yes did this all blind, I don't have any boards/scopes with me right now.
Could confirm timer is firing using TIM interrupt and/or toggling LED or pin.2014-11-28 08:36 AM
Now it seems to work. I have found some code on the web and replicated it with minor changes. Following is the working code. Moved to TIM2 but I do not think this is the problem. Maybe DAC definition should be made just after GPIO definition and both defined after DMA definition. Not sure.
#include ''stm32l1xx_conf.h''#include <stm32l1xx.h>#include <stm32l1xx_rcc.h>#include <stm32l1xx_gpio.h>#include <stm32l1xx_tim.h>#include <stm32l1xx_dac.h>#include <stm32l1xx_dma.h>#include <misc.h>#include <math.h>#define WAVE_FREQ 5000#define WAVE_POINTS 100#define TIMER_PERIOD 10#define DAC_DHR12RD_Address 0x40007420uint16_t wave_array[100];uint16_t j;float pi_greco = 3.14159;int timervalue;void DAC_initialize(void){ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); GPIO_InitTypeDef gpioStructure; gpioStructure.GPIO_Pin = GPIO_Pin_5; gpioStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &gpioStructure); DAC_InitTypeDef DAC_Structure; DAC_Structure.DAC_Trigger = DAC_Trigger_T2_TRGO; DAC_Structure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_Structure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_2, &DAC_Structure); DAC_Cmd(DAC_Channel_2, ENABLE); DAC_DMACmd(DAC_Channel_2, ENABLE);}void DMA_initialize(void){ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(DMA1_Channel3); DMA_InitTypeDef DMA_Structure; DMA_Structure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address; DMA_Structure.DMA_MemoryBaseAddr = (uint32_t) &wave_array; DMA_Structure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_Structure.DMA_BufferSize = WAVE_POINTS; DMA_Structure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Structure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Structure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_Structure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_Structure.DMA_Mode = DMA_Mode_Circular; DMA_Structure.DMA_Priority = DMA_Priority_High; DMA_Structure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel3, &DMA_Structure); DMA_Cmd(DMA1_Channel3, ENABLE);}void TIM2_initialize(void){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef timerInitStructure; timerInitStructure.TIM_Prescaler = 320-1; timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure.TIM_Period = TIMER_PERIOD-1; timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, &timerInitStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_Cmd(TIM2, ENABLE);}int main(void){ for(j=0; j<100; j++) { wave_array[j] = (uint16_t)(2000 + 1500*sin((2*pi_greco*j)/100)); // wave_array[j] = (uint16_t)(500+20*j); } DMA_initialize(); DAC_initialize(); TIM2_initialize(); while(1) { }}