cancel
Showing results for 
Search instead for 
Did you mean: 

Help with simple ADC on STM32F4

willschneider
Associate II
Posted on July 17, 2013 at 16:46

Hi all,

I'm trying to get a simple ADC working on the stm32f4 discoveryboard. At the moment I simply want to obtain an input value(ConvertedValue) as a variable rather than saving to memory inDMA.

I'm struggling with the pins - some of them give me a littlefunctionality and others none at all. I cant get any port to workproperly. PIN0 will work to an extent - it will read a changingvalue, but it is also outputting a voltage of 2 volts which I've nottold it to - and so any readings it gets are somewhat distorted.

I'd really appreciate anyone taking a look at the code im using(its mostly taken from various sources around the web - not really myown)

Sorry for the poor/lack of formatting <code>

<
pre
><
font
size
=
''1''
>#include ''stm32f4xx_adc.h''
#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_rcc.h''
#include ''led.h''
#include ''stm32f4_discovery.h''
#include ''stm32f4xx_tim.h''
#include ''stm32f4xx_dac.h''
int ConvertedValue = 0; //Converted value read from ADC1
</
font
><
font
size
=
''1''
>
void adc_configure(){
ADC_InitTypeDef ADC_init_structure; //Structure for adc confguration
GPIO_InitTypeDef GPIO_initStructre; //Structure for analog input pin
//Clock configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//The ADC1 is connected the APB2 peripheral bus thus we will use its clock source
RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN,ENABLE);//Clock for the ADC port!! Do not forget about this one ;)
//Analog pin configuration
GPIO_StructInit(&GPIO_initStructre);
GPIO_initStructre.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0
GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode
GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down
GPIO_Init(GPIOE,&GPIO_initStructre);//Affecting the port with the initialization structure configuration
//ADC structure configuration
ADC_DeInit();
ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Right;//data converted will be shifted to right
ADC_init_structure.ADC_Resolution = ADC_Resolution_12b;//Input voltage is converted into a 12bit number giving a maximum value of 4096
ADC_init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once
ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1 (actually I'm not sure about this one :/)
ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion
ADC_init_structure.ADC_NbrOfConversion = 1;//I think this one is clear :p
ADC_init_structure.ADC_ScanConvMode = DISABLE;//The scan is configured in one channel
ADC_Init(ADC1,&ADC_init_structure);//Initialize ADC with the previous configuration
//Enable ADC conversion
ADC_Cmd(ADC1,ENABLE);
//Select the channel to be read from
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_144Cycles);
}
int adc_convert(){
ADC_SoftwareStartConv(ADC1);//Start the conversion
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion
return ADC_GetConversionValue(ADC1); //Return the converted data
}
int main(void){
adc_configure();//Start configuration
//dac_configure();
while(1)
{//loop while the board is working
ConvertedValue = adc_convert();//Read the ADC converted value
//DAC_Ch1_WaveConfig();
}
}</
font
>
</
pre
>

</code>
38 REPLIES 38
willschneider
Associate II
Posted on July 19, 2013 at 11:11

Here is my first attempt at getting the output on a DAC

// Assumptions per system_stm32f4xx.c CPU @ 168 MHz, APB2 @ 84 MHz (/2), APB1 @ 42 MHz (/4)
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* DMA1 clock and GPIOA clock enable (to be used with DAC) */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE);
/* DAC Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 11 -> PC1
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//GPIO_InitTypeDef GPIO_InitStructure2;
/* DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_15Cycles); // PC1
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE 400 // 200KHz x2 HT/TC at 1KHz
__IO uint16_t ADCConvertedValues[BUFFERSIZE];
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
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_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* Enable DMA Stream Half / Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (84000000 / 200000) - 1; // 200 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 TRGO selection */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void DMA2_Stream0_IRQHandler(void) // Called at 1 KHz for 200 KHz sample rate, LED Toggles at 500 Hz
{
/* Test on DMA Stream Half Transfer interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
/* Turn LED3 off: Half Transfer */
STM_EVAL_LEDOff(LED3);
// Add code here to process first half of buffer (ping)
}
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
/* Turn LED3 on: End of Transfer */
STM_EVAL_LEDOn(LED3);
// Add code here to process second half of buffer (pong)
}
}
void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* TIM6 Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (84000000 / 200000);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
/* TIM6 TRGO selection */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
/* TIM6 enable counter */
TIM_Cmd(TIM6, ENABLE);
}
#define DAC_DHR12R2_ADDRESS 0x40007414
void DAC_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
/* DAC channel2 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_2, &DAC_InitStructure);
/* DMA1_Stream5 channel7 configuration **************************************/
DMA_DeInit(DMA1_Stream5);
DMA_InitStructure.DMA_Channel = DMA_Channel_7; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
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_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &DMA_InitStructure);
/* Enable DMA1_Stream5 */
DMA_Cmd(DMA1_Stream5, ENABLE);
/* Enable DAC Channel2 */
DAC_Cmd(DAC_Channel_2, ENABLE);
/* Enable DMA for DAC Channel2 */
DAC_DMACmd(DAC_Channel_2, ENABLE);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
TIM6_Config();
DAC_Config();
NVIC_Configuration();
TIM2_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 500 Hz means it working */
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(1); // Don't want to exit
}

Posted on July 19, 2013 at 12:02

Honestly I think you could use the T2_TRGO (TIM2 Trigger) as a common source for the ADC and DAC. Observe how I define the trigger to the ADC as the timer, and dial the timer to pace the start of conversion. You'd have to dig into the tables in the RM0090 Reference Manual, or look at the library source, to understand the available options and routing of such signals.

[DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/ADC%20and%20DMA%2c%20again&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=237]https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Discovery%2FADC%20and%20DMA%2C%20again&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=237

In retrospect the IQ example used PC0 as an input, the code was from another board I use which I back ported to the STM32F4-Discovery that others actually have.

I'm seem to recall either manifesting, or thinking about, channeling 2 samples from the ADC to the DAC, although most people want to process the data.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
willschneider
Associate II
Posted on July 19, 2013 at 12:36

OK, Thanks, I'll take a look.

I will be processing my signal, however I want to get my ADC/DAC working first :)

willschneider
Associate II
Posted on July 19, 2013 at 13:17

I've cleaned up my code, and I think i've covered all the bases. However I'm not getting any DAC output. Do I need to be wary of reading from the DMA at the same time it is being written to? May that be my problem?

// Assumptions per system_stm32f4xx.c CPU @ 168 MHz, APB2 @ 84 MHz (/2), APB1 @ 42 MHz (/4)
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* DMA1 clock and GPIOA clock enable (to be used with DAC) */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE);
/* DAC Periph clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
}
/**************************************************************************************/
void GPIO_ADC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 11 -> PC1
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void GPIO_DAC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//GPIO_InitTypeDef GPIO_InitStructure2;
/* DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration */
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);
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 1 Channel
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Conversions Triggered
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_15Cycles); // PC1
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
}
/**************************************************************************************/
#define BUFFERSIZE 400 // 200KHz x2 HT/TC at 1KHz
__IO uint16_t ADCConvertedValues[BUFFERSIZE];
static void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE; // Count of 16-bit words
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_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* Enable DMA Stream Half / Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = (84000000 / 200000) - 1; // 200 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 TRGO selection */
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
void DMA2_Stream0_IRQHandler(void) // Called at 1 KHz for 200 KHz sample rate, LED Toggles at 500 Hz
{
/* Test on DMA Stream Half Transfer interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
/* Turn LED3 off: Half Transfer */
STM_EVAL_LEDOff(LED3);
// Add code here to process first half of buffer (ping)
}
/* Test on DMA Stream Transfer Complete interrupt */
if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
/* Turn LED3 on: End of Transfer */
STM_EVAL_LEDOn(LED3);
// Add code here to process second half of buffer (pong)
}
}
#define DAC_DHR8R1_ADDRESS 0x40007410
void DAC_Config(void)
{
DAC_InitTypeDef DAC_InitStructure;
/* DAC channel2 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
}
void DAC_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA1_Stream5 channel7 configuration **************************************/
DMA_DeInit(DMA1_Stream5);
DMA_InitStructure.DMA_Channel = DMA_Channel_7; 
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE;
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_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &DMA_InitStructure);
/* Enable DMA1_Stream5 */
DMA_Cmd(DMA1_Stream5, ENABLE);
/* Enable DAC Channel2 */
DAC_Cmd(DAC_Channel_1, ENABLE);
/* Enable DMA for DAC Channel2 */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_ADC_Configuration();
GPIO_DAC_Configuration();
DAC_Config();
DAC_DMA_Config();
NVIC_Configuration();
TIM2_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 500 Hz means it working */
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(1); // Don't want to exit
}

willschneider
Associate II
Posted on July 22, 2013 at 11:47

I'm now having a nightmare trying to get a DAC working. Could anybody please point me towards any working examples of a simple DAC outputting using DMA?

I've been looking at the ST DAC_SignalsGeneration example which outputs different waves from DMA, however whenever I try to remove the selection code so that it only outputs a sine wave, it dies altogether.

Posted on July 23, 2013 at 05:50

This is a blind build, need to try with a scope

// STM32F4-Discovery Dual DAC 6.25 KHz Sine - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************/
const uint16_t Sine12bit[32] = {
2047, 2447, 2831, 3185,
3498, 3750, 3939, 4056,
4095, 4056, 3939, 3750,
3495, 3185, 2831, 2447,
2047, 1647, 1263, 909,
599, 344, 155, 38,
0, 38, 155, 344,
599, 909, 1263, 1647};
uint16_t SineTable[64];
/**************************************************************************/
void RCC_Config(void)
{
/* DMA1 clock and GPIOA clock enable (to be used with DAC) */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE);
/* DAC and TIM6 Peripheral clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);
}
/**************************************************************************/
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* DAC channel 1 & 2 (DAC_OUT1 = PA.4)(DAC_OUT2 = PA.5) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************/
void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
int Period;
Period = ((SystemCoreClock / 2) / 200000); // 200 KHz timebase, 6.25 KHz Sine
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = Period - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
/* TIM6 TRGO selection */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
/* TIM6 enable counter */
TIM_Cmd(TIM6, ENABLE);
}
/**************************************************************************/
#define DAC_DHR12RD_ADDRESS 0x40007428 // Right Align 12-bit Dual
void DAC_Config(void)
{
DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* DAC channel 1 and 2 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Init(DAC_Channel_2, &DAC_InitStructure);
/* DMA1_Stream5 channel7 configuration **************************************/
DMA_DeInit(DMA1_Stream5);
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&SineTable[0];
DMA_InitStructure.DMA_BufferSize = 32; // 16-bit x 64 / 2
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; // 32-bit 16x2
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &DMA_InitStructure);
/* Enable DMA1_Stream5 */
DMA_Cmd(DMA1_Stream5, ENABLE);
/* Enable DAC Channel 1 and 2 */
DAC_Cmd(DAC_Channel_1, ENABLE);
DAC_Cmd(DAC_Channel_2, ENABLE);
/* Enable DMA for DAC Channel1 */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
/**************************************************************************/
int main(void)
{
int i, j;
j = 0;
for(i=0; i<32; i++)
{
SineTable[j++] = Sine12bit[i];
SineTable[j++] = Sine12bit[(i + 8) % 32]; // 90 degree phase shift on Channel 2
}
RCC_Config();
GPIO_Config();
TIM6_Config();
DAC_Config();
while(1); // Do not exit
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
willschneider
Associate II
Posted on July 23, 2013 at 10:16

Thanks clive1, much appreciated.

willschneider
Associate II
Posted on July 23, 2013 at 15:45

Concerning DSP, i'm trying to include the math.h file but i'm hitting a bag of errors.

I'm using what I think is the correct include -

#include ''stm32f4_discovery.h''
#define ARM_MATH_CM4
#include <
arm_math.h
>

And the ..\..\..\..\Libraries\CMSIS\Include path is correctly in the include paths. However, using the following example code -

int busyflag =0;
uint32_t fftSize = 1024; 
uint32_t ifftFlag = 0; 
uint32_t doBitReverse = 1; 
void Processing(uint16_t Values[])
{
#define TEST_LENGTH_SAMPLES 2048 
/* ------------------------------------------------------------------- 
* External Input and Output buffer Declarations for FFT Bin Example 
* ------------------------------------------------------------------- */ 
extern float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES]; 
static float32_t testOutput[TEST_LENGTH_SAMPLES/2]; 
/* ------------------------------------------------------------------ 
* Global variables for FFT Bin Example 
* ------------------------------------------------------------------- */ 
/* Reference index at which max energy of bin ocuurs */ 
uint32_t refIndex = 213, testIndex = 0; 
//FFT
arm_status status; 
arm_cfft_radix4_instance_f32 S; 
float32_t maxValue; 
status = ARM_MATH_SUCCESS; 
/* Initialize the CFFT/CIFFT module */ 
status = arm_cfft_radix4_init_f32(&S, fftSize, ifftFlag, doBitReverse); 
/* Process the data through the CFFT/CIFFT module */ 
arm_cfft_radix4_f32(&S, testInput_f32_10khz); 
/* Process the data through the Complex Magnitude Module for 
calculating the magnitude at each bin */ 
arm_cmplx_mag_f32(testInput_f32_10khz, testOutput, fftSize); 
/* Calculates maxValue and returns corresponding BIN value */ 
arm_max_f32(testOutput, fftSize, &maxValue, &testIndex); 
if(testIndex != refIndex) 
{ 
status = ARM_MATH_TEST_FAILURE; 
} 
/* ---------------------------------------------------------------------- 
** Loop here if the signals fail the PASS check. 
** This denotes a test failure 
** ------------------------------------------------------------------- */ 
if( status != ARM_MATH_SUCCESS) 
{ 
while(1); 
} 
while(1); /* main function does not return */
}

I'm getting these errors - .\ADC_Interleaved_DMAmode2\ADC_Interleaved_DMAmode2.axf: Error: L6218E: Undefined symbol arm_cfft_radix4_f32 (referred from main.o). .\ADC_Interleaved_DMAmode2\ADC_Interleaved_DMAmode2.axf: Error: L6218E: Undefined symbol arm_cfft_radix4_init_f32 (referred from main.o). .\ADC_Interleaved_DMAmode2\ADC_Interleaved_DMAmode2.axf: Error: L6218E: Undefined symbol arm_cmplx_mag_f32 (referred from main.o). .\ADC_Interleaved_DMAmode2\ADC_Interleaved_DMAmode2.axf: Error: L6218E: Undefined symbol arm_max_f32 (referred from main.o). .\ADC_Interleaved_DMAmode2\ADC_Interleaved_DMAmode2.axf: Error: L6218E: Undefined symbol testInput_f32_10khz (referred from main.o).
Posted on July 23, 2013 at 16:06

Looks to be more of a linker error complaining about the lack of a library in the project. Remember #include files define the interface, the code has to come from some place else. Something like fftmath.a, fftmath.lib, or whatever

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
willschneider
Associate II
Posted on July 23, 2013 at 16:20

Perhaps the C:\Keil\ARM\CMSIS\DSP_Lib\Source\TransformFunctions folder?

However, linking this path aswell makes no difference.