cancel
Showing results for 
Search instead for 
Did you mean: 

ADC3 converting 3 inputs + display

patrick_seeboerger
Associate II
Posted on January 26, 2014 at 14:45

The original post was too long to process during our migration. Please click on the attachment to read the original post.
10 REPLIES 10
raptorhal2
Lead
Posted on January 26, 2014 at 16:08

See Table 6 in the Discovery User manual. PC1 and 2 are not free IOs.

Edit: ...and as you will discover, there are only 3 free ADC channels, only two of which are on ADC3, and no one ADC has all 3 free channels. O joy!

Cheers, Hal

Posted on January 26, 2014 at 16:18

uwVoltage1 = (ADCConvertedValues[0])/1000; //PC3
uwMVoltage1 = (ADCConvertedValues[0]%1000)/100; //PC3
uwVoltage2 = (ADCConvertedValues[0])/1000; //PC2
uwMVoltage2 = (ADCConvertedValues[0]%1000)/100; //PC2
uwVoltage3 = (ADCConvertedValues[0])/1000; //PC1
uwMVoltage3 = (ADCConvertedValues[0]%1000)/100; //PC1

So probably not all stored in index zero? And not voltages
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
patrick_seeboerger
Associate II
Posted on January 31, 2014 at 19:20

Ok. thank you.

I had a look on the manual and now I prefer to program the following:

- ADC3 converts PC3 and PF6

- ADC1 converts PA5

The ADCs shall work in regular simultaneous mode.

I have already programmed them but I think there are still some

errors...

Do you know any example for this mode or can you tell me the exact procedure of that mode

step by step?

In the attachment you can find what I have already implemented.

Maybe you also know a user manual for the keil debugger to debug the

Discovery board quite well?

Thanks.

Best regards,

Patrick

________________

Attachments :

ADC_main.c.txt : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I04o&d=%2Fa%2F0X0000000bT8%2FqVR0LYcvsLffV_zOSEqulatc3NpUkRKiEodXsHZDkzk&asPdf=false
Posted on January 31, 2014 at 20:59

Well there's a whole bunch of non-sense going on it there, where do I start...

You shouldn't program ADC3 to be doing two conflicting things, if you want it to read 2 channels configure it to do that, not program it twice to do 1 channel each time.

The address of the data register in the DMA configuration needs to point at the ADC you're trying to read. Right now they all point to one register and I'm not sure which one it ends up reading.

Do you want all THREE channels to sample at the exactly same time? Because to do that you'd need to configure ADC1, ADC2 and ADC3

I've posted dozen examples, for a slew of STM32 parts. You could try the search on the forum, or perhaps more effectively with Google.

Keil's debugger documentation should describe the functionality in a fairly generic and board agnostic fashion.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 31, 2014 at 22:08

// STM32 ADC Triple Channel STM32F429I-DISCO - sourcer32@gmail.com
// Limited ADC Resource
// PA.05 ADC12_IN5 ADC1
// PC.03 ADC123_IN13 ADC2
// PF.06 ADC3_IN4 ADC3
#include <
stdio.h
>
#include <
stdlib.h
>
#include ''stm32f429i_discovery.h''
//****************************************************************************
void RCC_Configuration(void)
{
/* Enable peripheral clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOF |
RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_ADC3 ,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
//****************************************************************************
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
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 GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// PA.05 ADC12_IN5 ADC1
// PC.03 ADC123_IN13 ADC2
// PF.06 ADC3_IN4 ADC3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOF, &GPIO_InitStructure);
}
//******************************************************************************
#define BUFFERSIZE (200 * 3 * 2) // 200 Hz x3 x2 HT/TC at 1Hz
volatile uint16_t ADCTripleConvertedValues[BUFFERSIZE]; // Filled as ADC1, ADC2, ADC3
//******************************************************************************
#define ADC_CDR_ADDRESS ((uint32_t)0x40012308) // Common Data Register
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA2 Stream0 channel0 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCTripleConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = BUFFERSIZE / 2; // 32-bit words not 16-bit
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
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);
/* 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 ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* ADC Common configuration *************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2; // 2 - 16-bit pairs, 1 - 32-bit x3
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
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);
ADC_Init(ADC2, &ADC_InitStructure); // Mirror on ADC2
ADC_Init(ADC3, &ADC_InitStructure); // Mirror on ADC3
/* ADC1 regular channel 5 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_84Cycles); // PA5
/* ADC2 regular channel 13 configuration */
ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 1, ADC_SampleTime_84Cycles); // PC3
/* ADC3 regular channel 4 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 1, ADC_SampleTime_84Cycles); // PF6
/* Enable DMA request after last transfer (multi-ADC mode) ******************/
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
/* Enable ADC1 **************************************************************/
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC2 **************************************************************/
ADC_Cmd(ADC2, ENABLE);
/* Enable ADC3 **************************************************************/
ADC_Cmd(ADC3, ENABLE);
}
//******************************************************************************
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Time base configuration for 5 ms (200 Hz) */
TIM_TimeBaseStructure.TIM_Prescaler = ((SystemCoreClock / 2) / 1000000) - 1; // 1 MHz
TIM_TimeBaseStructure.TIM_Period = (1000000 / 200) - 1; // 1 MHz to 200 Hz
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);
}
//******************************************************************************
volatile uint16_t *BufferReady;
void DMA2_Stream0_IRQHandler(void)
{
/* 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)
BufferReady = (uint16_t *)&ADCTripleConvertedValues[0];
}
/* 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)
BufferReady = (uint16_t *)&ADCTripleConvertedValues[BUFFERSIZE / 2];
}
}
//****************************************************************************
int main(void)
{
RCC_Configuration();
NVIC_Configuration();
DMA_Configuration();
GPIO_Configuration();
TIM_Configuration(); /* 200 KHz Time Base */
ADC_Configuration();
STM_EVAL_LEDInit(LED3); /* Configure LED to monitor program status */
STM_EVAL_LEDOn(LED3); /* Turn LED3 on, 0.5 Hz means it working */
puts(''ADC 3UP STM32F429I-DISCO'');
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConv(ADC1);
BufferReady = NULL;
while(1)
{
uint16_t *BufferNow;
while(BufferReady == NULL); // Wait for DMA interrupt to signal next available block
BufferNow = (uint16_t *)BufferReady; // 1 Hz
BufferReady = NULL;
printf(''%04X %04X %04
X'', BufferNow[0], BufferNow[1], BufferNow[2]);
}
}
//****************************************************************************
// Rough SWV support in Keil, STM32F429I-DISCO, Make SB9 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..
patrick_seeboerger
Associate II
Posted on February 07, 2014 at 17:57

Thank you Clive for the program. I am quite sure that it works at your surrounding, 

but when I try to debug the program, debugging stops always at line 

while(BufferReady == NULL); // Wait for DMA interrupt to signal next available block

so I do not get any interrupt in that case!?

Why?

Thanks.

Posted on February 07, 2014 at 18:21

Don't know, try turning optimization off, the newer versions of Keil v4.7x seem to have issues with correctly interpreting ''volatile''

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
patrick_seeboerger
Associate II
Posted on February 11, 2014 at 21:02

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=0680X000006I6m8&d=%2Fa%2F0X0000000bv6%2FwglBvHXkNTx4GtInNDgnNbmsTSKZNASbGsoNJsr1nFQ&asPdf=false
Posted on February 11, 2014 at 22:51

For what I am waiting there exactly?

It's waiting for the DMA half/complete interrupt to occur, which fills the pointer with the location of the first, or second, half of the data buffer depending on which just completed.

You'd want to observe if the interrupt is indeed occurring.

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