cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f4 adc dma 14 analog inputs

oli
Associate II
Posted on February 20, 2015 at 20:02

Hello

It seems that I do have huge challange.

I need 14 analog inputs working continuously.

According this I'm using DMA transmission.

I've setup the GPIO config

I've setup the DMA config.

I've setup the ADC1 config.for all 14 analog inputs

I've compared these config with some of the examples here at this forum.

All of them show me differences in particular. But what ever I configure at DMA and ADC it will not work.

The ADC gets one time a value and seems then to be stuck. The DMA does nothing. The memory array is empty all the time.

I've check the configuration more times and found some faults due my own settings. But still the same problem like described above.

Does anyone know whether there is a matching example anywhere or can giv eme a hint what I hav eto take care for e.g. for the deployment of the 14 analog inputs etc.?
9 REPLIES 9
Posted on February 20, 2015 at 20:44

As entertaining as it is to guess what you've done wrong, I'll post this, and you can provide your code here, or via email, and I'll try an identify what's going on.

// STM32 ADC Sample 4x at 160 KHz STM32F4 Discovery - sourcer32@gmail.com
// (C) Copyright 2013-2014, All Rights Reserved
// Assumptions per system_stm32f4xx.c CPU @ 4 MHz, APB2 @ 2 MHz (/2), APB1 @ 6 MHz (/4)
// PLL ((HSI / 25) * 320) / 2, where HSI is ~0 MHz
// or
// ((HSE / 4) * 160) / 2, where HSE is 5.120 MHz
// ((HSE / 8) * 160) / 2, where HSE is 240 MHz
// ((HSE / 16) * 160) / 2, where HSE is 480 MHz
#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);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* ADC Channel 10 -> PC0 - Clashes USB PowerOn
ADC Channel 11 -> PC1
ADC Channel 12 -> PC2
ADC Channel 13 -> PC3 - Clashes DOUT
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &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; // 2,4,6,8
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 5-20 if interleave mode
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 4 Channels
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Back-to-Back, maximal rate
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel 11 configuration */
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_28Cycles); // 3,15,28,56,84,112,144,480
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,2,ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_12,3,ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_13,4,ADC_SampleTime_28Cycles);
// Conversion time is 12 cycles, per manual
// (2 MHz / 2) / (12 + 28) = 640 KHz (1.5625 us)
/* 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 8
__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 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 160 KHz, LED Toggles at 80 KHz
{
/* 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)
}
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LEDs to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on */
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
while(1); // Don't want to exit
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 20, 2015 at 20:49

I know I built a 13-UP example for someone, it don't have it to hand on this system.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
oli
Associate II
Posted on February 22, 2015 at 12:59

Many thanks for the example.

It is although a bit a Problem for me to put the code here because of confidential requirements. But I'll compare your example to find out what is wrong. It can't be more than just a register bit. 

Posted on February 23, 2015 at 04:04

Makes for a bit of a one-way street...

// STM32F4-Discovery ADC1x13 (13UP) - sourcer32@gmail.com
// (C) Copyright 2013-2015, All Rights Reserved
#define SAMPLES 13
#include <
stdio.h
>
#include <
stdlib.h
>
#include <
string.h
>
#include ''stm32f4xx.h''
//****************************************************************************
volatile uint16_t ADCConvertedValues[SAMPLES];
//****************************************************************************
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE);
/* Configure ADC1 Channel 0 pin as analog input PA0 *****************************/
/* Configure ADC1 Channel 4 pin as analog input PA4 *****************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure ADC1 Channel 8 pin as analog input PB0 *****************************/
/* Configure ADC1 Channel 9 pin as analog input PB1 *****************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure ADC1 Channel 10 pin as analog input PC0 *****************************/
/* Configure ADC1 Channel 11 pin as analog input PC1 *****************************/
/* Configure ADC1 Channel 12 pin as analog input PC2 *****************************/
/* Configure ADC1 Channel 13 pin as analog input PC3 *****************************/
/* Configure ADC1 Channel 14 pin as analog input PC4 *****************************/
/* Configure ADC1 Channel 15 pin as analog input PC5 *****************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
//****************************************************************************
void ADC1_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
int i;
/* Enable peripheral clocks *************************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
/* DMA2_Stream0 channel0 configuration **************************************/
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = SAMPLES;
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(DMA2_Stream0, &DMA_InitStructure);
/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);
/* 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);
/* ADC1 Init ****************************************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // Multiple Channels
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Keep Sampling
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = SAMPLES;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel configuration ******************************/
i = 1;
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, i++, ADC_SampleTime_480Cycles); // PA0
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, i++, ADC_SampleTime_480Cycles); // PA4
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, i++, ADC_SampleTime_480Cycles); // PC4
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, i++, ADC_SampleTime_480Cycles); // PC5
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, i++, ADC_SampleTime_480Cycles); // PB0
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, i++, ADC_SampleTime_480Cycles); // PB1
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, i++, ADC_SampleTime_480Cycles); // PC0
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, i++, ADC_SampleTime_480Cycles); // PC1
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, i++, ADC_SampleTime_480Cycles); // PC2
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, i++, ADC_SampleTime_480Cycles); // PC3
ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, i++, ADC_SampleTime_480Cycles); // 16
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, i++, ADC_SampleTime_480Cycles); // 17
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, i++, ADC_SampleTime_480Cycles); // 18
/* Enable TempSensor and Vrefint */
ADC_TempSensorVrefintCmd(ENABLE);
/* Enable VBAT channel */
ADC_VBATCmd(ENABLE);
/* 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);
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
}
//****************************************************************************
int main(void)
{
GPIO_Configuration();
ADC1_Configuration();
while(1) /* Infinite loop */
{
if (ADCConvertedValues[SAMPLES-1] != 0xFFFF) // Check for new values loaded
{
int i;
for(i=0; i<
SAMPLES
; i++)
{
printf(''%03X '', ADCConvertedValues[i]);
}
printf(''

'');
ADCConvertedValues[SAMPLES-1] = 0xFFFF; // Invalidate
}
}
}
//****************************************************************************
// Hosting of stdio functionality through SWD (Keil)
//****************************************************************************
/* Implementation of putchar (also used by printf function to output data) */
int SendChar(int ch) /* Write character to Serial Port */
{
ITM_SendChar(ch); // From core_cm4.c
return(ch);
}
//****************************************************************************
#include <rt_misc.h>
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
int fputc (int ch, FILE *f) { return (SendChar(ch)); }
int ferror (FILE *f) {
/* Your implementation of ferror */
return EOF;
}
void _ttywrch (int ch) { SendChar(ch); }
void _sys_exit (int return_code) { for (;;); }
//****************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
while (1)
{}
}
#endif
//****************************************************************************

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
oli
Associate II
Posted on February 23, 2015 at 08:39

Thanks Clive.

Going thru your example this morning I've seen some errors.

Setting the DMA configuration via #defines I had wrong values for DMA_BufferSize and NbrOfConversion (3 instead of 14).

And while reorganisation of the ADC-Software module for new requirements I've made a copy and paste error so the structure for the ADC_Init(...) was not initialized correct.

Sometimes it is better to stop working in the night and start a new trial in the morning.

But for all of that stupid faults I hope I can ask you in the future again.

Bye

Oliver

oli
Associate II
Posted on February 25, 2015 at 17:03

Hello

I'm now testing the ADC with the configuration above.

But the values the ADC offers are not like expected.

The input signal moves in range of 120mV at an offset of 2 volts. The ADC values move within a range of 250mV

The Vref has 3.3V and according the oszilloscope is this voltage clear and stabil.

  *        SYSCLK(Hz)                             | 168000000

  *-----------------------------------------------------------------------------

  *        HCLK(Hz)                               | 168000000

  *-----------------------------------------------------------------------------

  *        AHB Prescaler                          | 1

  *-----------------------------------------------------------------------------

  *        APB1 Prescaler                         | 4

  *-----------------------------------------------------------------------------

  *        APB2 Prescaler                         | 4

Has anyone an idea what the reason for these behaviour could be?

Oliver

shoaib
Associate II
Posted on March 08, 2016 at 13:18

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6Zi&d=%2Fa%2F0X0000000br1%2FoEcrGr1te.IY06i2M2FzoXi9oBVpASCLCUQaNMcX_UQ&asPdf=false
shoaib
Associate II
Posted on March 08, 2016 at 13:25

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6jb&d=%2Fa%2F0X0000000buD%2Fpq1XG3sVoUObPu7Fo36RmZ8_NCVj.R4jCaqIVEMC_0w&asPdf=false
Posted on March 08, 2016 at 14:41

Can we please stick to one thread. Ideally if discussing your own code, do so in your own thread.

[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/ADC%20trigger%20on%20timer%20update&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/AllItems.aspx&currentviews=3631]Other thread, cross posted

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..