cancel
Showing results for 
Search instead for 
Did you mean: 

3 channels on ADC1 and DMA

fabricepeden
Associate II
Posted on April 10, 2013 at 07:59

Hi Everbody,

I'm trying to configure 3 channels of the ADC (Vbat, Temp and another analog input). Yesterday, I managed to read the value of Vbat. Now I would to read the value of the three channels, but I have '0' in my array. I have started to initialize the DMA. I'm using DMA2 stream 0 (for ADC1 in the datasheet).

/* Initialize the DMA1 Channel1 according to the DMA_InitStructure members */
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* Enable peripheral clocks *************************************************/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x4001204C;//ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)&ADCConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 3;
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_Init(DMA2_Stream0, &DMA_InitStructure);
/* Enable DMA1 Channel1 */
DMA_Cmd(DMA2_Stream0, ENABLE);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Enabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_ScanConvMode = ENABLE; 
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel18 (VBAT) configuration ******************************/
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, 1, ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 2, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 3, ADC_SampleTime_15Cycles);
/* Enable VBAT channel */
ADC_VBATCmd(ENABLE); 
/* Enable Temp channel */
ADC_TempSensorVrefintCmd(ENABLE);
/* Enable ADC1 DMA transfer */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
/* Enable ADC1 **************************************************************/
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConv(ADC1);

Have you some ideas to suggest to me to help me to solve this problem ? Thank you in advance,
16 REPLIES 16
raptorhal2
Lead
Posted on January 30, 2014 at 17:12

Even the temperature sensor results are strange. The conversion should be equivalent to approximately 1.4 volts. Both the temp sensor and VBAT require a minimum of 2.2 usec sampling time. Use the 480 cycles sampling time recommended in clive1's code.

You can avoid pitfalls like this by reading the data sheet and reference manual.

Cheers, Hal

oyakovlev
Associate II
Posted on January 30, 2014 at 18:30

Hi Baird,

Thanks for your comment, but I've read lot of manuals, blogs and forums before ask here. Also I've made lot of experiments with board too.

Unfortunately, it can't influence to results so hard. I get normal values if I will use only one channel in ADC & DMA.

Thanks

Posted on January 30, 2014 at 19:17

// STM32 ADC Triple Channel STM32F3-Discovery - sourcer32@gmail.com
/**************************************************************************************/
// ADC1 ADC2 ADC3 ADC4
// IN1 PA0* PA4 PB1 PE14*
// IN2 PA1 PA5* PE9* PE15*
// IN3 PA2 PA6* PE13* PB12
// IN4 PA3 PA7* --- PB14
// IN5 PF4 PC4 PB13 PB15
//
// *Used on STM32F3-Discovery
// Free pins located in STM32F3-Discovery manual, UM1570
// ADC1/2 Trigger EXT3 TIM2_CC2
// Pins for this example VBAT TEMP PA1(IN2)
/**************************************************************************************/
#include ''stm32f3_discovery.h''
#include ''stm32f30x.h''
#include <
stdio.h
>
/**************************************************************************************/
#define BUFSIZE 10
volatile uint16_t ADCConvertedValues[3 * BUFSIZE];
uint16_t CalibrationValue;
/**************************************************************************************/
void ADC_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA and GPIOB Periph clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* ADC Channels configuration */
/* Configure as analog input */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC12_DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA configuration */
/* DMA1 Channel1 Init Test */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // The register of a singular ADC
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BUFSIZE * 3;
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_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure); // ADC1
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
volatile int i;
/* Configure the ADC clocks */
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
/* Enable ADC1/2 clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
/* ADC GPIO configuration */
ADC_GPIO_Configuration();
/* ADC DMA Channel configuration */
ADC12_DMA_Configuration();
/* ADC Calibration procedure */
ADC_VoltageRegulatorCmd(ADC1, ENABLE);
/* Insert delay equal to 10 µs */
for(i=0; i<
10000
; i++);
ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) != RESET);
CalibrationValue
= 
ADC_GetCalibrationValue
(ADC1);
/* ADC configuration */
ADC_CommonInitStructure.ADC_Mode
= 
ADC_Mode_Independent
;
ADC_CommonInitStructure.ADC_Clock
= 
ADC_Clock_AsynClkMode
;
ADC_CommonInitStructure.ADC_DMAAccessMode
= 
ADC_DMAAccessMode_Disabled
; // Not Multi Mode
ADC_CommonInitStructure.ADC_DMAMode
= 
ADC_DMAMode_Circular
;
ADC_CommonInitStructure.ADC_TwoSamplingDelay
= 
10
;
ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
/* */
ADC_InitStructure.ADC_ContinuousConvMode
= 
ADC_ContinuousConvMode_Disable
; // Triggered
ADC_InitStructure.ADC_Resolution
= 
ADC_Resolution_12b
;
ADC_InitStructure.ADC_ExternalTrigEventEdge
= 
ADC_ExternalTrigEventEdge_RisingEdge
;
ADC_InitStructure.ADC_DataAlign
= 
ADC_DataAlign_Right
;
ADC_InitStructure.ADC_OverrunMode
= 
ADC_OverrunMode_Disable
;
ADC_InitStructure.ADC_AutoInjMode
= 
ADC_AutoInjec_Disable
;
ADC_InitStructure.ADC_NbrOfRegChannel
= 
3
;
ADC_InitStructure.ADC_ExternalTrigConvEvent
= 
ADC_ExternalTrigConvEvent_3
; // ADC1 EXT3 TIM2_CC2
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, 1, ADC_SampleTime_61Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 2, ADC_SampleTime_61Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_61Cycles5); // PA1
/* Enable VBAT channel */
ADC_VrefintCmd(ADC1, ENABLE);
/* Enable Temp channel */
ADC_TempSensorCmd(ADC1, ENABLE);
/* Configures the ADC DMA */
ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
/* Enable the ADC DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* wait for ADC1 ADRDY */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
/* Enable the DMA channel */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* Start ADC1 Software Conversion */
ADC_StartConversion(ADC1);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Enable TIM2 Peripheral clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler
= 
0
;
TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 50) - 1; // 50 Hz Sample Rate
TIM_TimeBaseStructure.TIM_ClockDivision
= 
TIM_CKD_DIV1
;
TIM_TimeBaseStructure.TIM_CounterMode
= 
TIM_CounterMode_Up
;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OCMode
= 
TIM_OCMode_PWM1
;
TIM_OCInitStructure.TIM_OutputState
= 
TIM_OutputState_Enable
;
TIM_OCInitStructure.TIM_Pulse
= 
10
; // Some arbitary width
TIM_OCInitStructure.TIM_OCPolarity
= 
TIM_OCPolarity_High
;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
void DMA1_Channel1_IRQHandler(void) // 5 Hz
{
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_IT_TC1))
{
/* Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_GL1);
STM_EVAL_LEDToggle(LED3); // 2.5 Hz
}
}
/**************************************************************************************/
void TIM2_IRQHandler(void) // 50 Hz
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
STM_EVAL_LEDToggle(LED4); // 25 Hz
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA1 CH1 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel
= 
DMA1_Channel1_IRQn
;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority
= 
0
;
NVIC_InitStructure.NVIC_IRQChannelSubPriority
= 
1
;
NVIC_InitStructure.NVIC_IRQChannelCmd
= 
ENABLE
;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel
= 
TIM2_IRQn
;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
/* Initialize LEDs available on STM32F-Discovery board */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* Turn on LD3 */
STM_EVAL_LEDOn(LED3);
STM_EVAL_LEDOn(LED4);
NVIC_Configuration();
TIM2_Configuration();
ADC_Configuration();
/* Enable DMA1 Channel1 Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* TIM Interrupts enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
while(1) // Don't want to exit
{
if (ADCConvertedValues[0] != 0xFFFF)
{
printf(''%03X %03X %03
X'', ADCConvertedValues[0], ADCConvertedValues[1], ADCConvertedValues[2]);
ADCConvertedValues[0] = 0xFFFF;
}
}
}
//******************************************************************************
// Rough SWV support in Keil, STM32F3-Discovery, Make SB10 to connect PB3/SWO
//******************************************************************************
#include <rt_misc.h>
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
ITM_SendChar(ch);
return(ch);
}
int fgetc(FILE *f)
{
char ch;
ch = 1;
return((int)ch);
}
int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int ch)
{
ITM_SendChar(ch);
}
void _sys_exit(int return_code)
{
label: goto label; /* endless loop */
}
//******************************************************************************
#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..
oyakovlev
Associate II
Posted on January 30, 2014 at 19:50

Hi Clive,

Thanks a lot for your help!

I've understood my mistakes:

1. Wrong ADC data register - it's a differ for cascade and single modes as it turned out

2. Wrong DMA mode for ADC

Last point was not so obviously from reference manual for me...  

Thanks you for your kind assistance!

 

aliansari91
Associate
Posted on March 06, 2014 at 16:30

Can I use this Code for STM32 F101C8 ?? 

Posted on March 06, 2014 at 18:11

Can I use this Code for STM32F101C8 ??

I'm guessing you can't, you'd need to port it and tailor it to suit the part you are using. The code I've posted is from a clear and systematic understanding of the part documentation as expressed in the Data Sheet, Reference Manual, and board User Manuals.

In the general sense the concepts expressed in the code are applicable to your part, it's the details that will differ.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
aliansari91
Associate
Posted on March 07, 2014 at 18:10

Okiess.. Thank You.. Clive