2017-03-09 02:01 AM
Hello!
I would like to use the ADC with DMA in order to do the following:
- manually start the ADC in (discontinuous) scan mode
- sample 3 channels
- put the adc result with DMA to some array.
- no further (automatic/continuous sampling) till the next manual ADC start.
So the ADC should start, scan the 3 regular channels. The DMA should fill the array and afterwards I expect that the ADC_FLAG_EOC should be set?
Since I never saw it set I read the DMA1_FLAG_TC1 instead.
The problems are:
1. The DMA1_FLAG_TC1 is always set. (because ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE), but otherwise I should re-initialize the DMA?)
2. I cannot clear the ADC_FLAG_EOC or DMA1_FLAG_TC1.
3. There are always some values changing in the DMA_CNDTR1 register and I'm not sure why since everything should have been done quickly after the ADC_SoftwareStartConv(ADC).
The ADC uses the HSI (no prescaler) and the CPU is clocked @ 2MHz
I guess I misunderstand how DMA works in this case. Please review my code and give me directions.
Thanks!
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
uint8_t i = 0;
uint32_t volatile adcResult[3]= { 0, 0, 0 };
uint32_t volatile voltage[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t volatile current[10];// = 0;
#define ADC1_DR_ADDRESS ((uint32_t)0x40012458)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA clock enable
DMA_DeInit(DMA1_Channel1); //DMA1 channel1 configuration
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcResult;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 3;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //peripheral address register...??
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //increment pointer
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Byte, HalfWord or Word
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //Byte, HalfWord or Word
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Circular; //????
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //???
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable DMA1 channel1
ADC_TempSensorVrefintCmd(ENABLE);
delay_ms(5); //Internal reference needs 3ms startup time! ; there is a flag like vrefrdy - check the datasheet
RCC_HSICmd(ENABLE); //16MHz, ADC requirement
/* Enable the GPIOF or GPIOA Clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //IDD_MEASUREMENT_GPIO_CLK = RCC_AHBPeriph_GPIOA
/* GPIOA0 as ADC_Channel_0 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3; //PA0,3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //analog
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
/* Check that HSI oscillator is ready */
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_Cmd(ADC1, DISABLE);
/* For medium+ and high density devs -> two banks (A,B) 3.3 from RefManual
ADC_BankSelection(ADC1, ADC_Bank_B);
*/
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
//ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 3;//1;
ADC_Init(ADC1, &ADC_InitStructure);
/* Define delay between ADC1 conversions */
// Delay is introduced when the ADC clock is higher than the CPU clock...
//ADC_DelayLength_Freeze: Delay until the converted data has been read.
ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_Freeze);
/* Enable ADC1 Power Down during Delay */
ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
/*
If the channel is configured in noncircular mode, no DMA request is served after the last
transfer (that is once the number of data items to be transferred has reached zero). In order
to reload a new number of data items to be transferred into the DMA_CNDTRx register, the
DMA channel must be disabled.
*/
ADC_RegularChannelConfig(ADC1, 0x11, 1, ADC_SampleTime_16Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_16Cycles); //ref.manual-> 8, for 12 bit-> 12+4 cycles (16 cycles) min. -> 384+12?
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_16Cycles);
/* Enable the request after last transfer for DMA Circular mode */
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
while ( ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET ) {} /* Wait until ADC1 ON status */
uint16_t vref;
for( i=0; i<10; i++ ) {
ADC_SoftwareStartConv(ADC1);
while( ! DMA_GetFlagStatus( DMA1_FLAG_TC1 ) );
//while( ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) == RESET );// DO NOT USE WITH DMA, CHECK DMA TRANSFER COMPLETE THOUGH!
vref = adcResult[0];
current[i] = adcResult[1];
voltage[i] = adcResult[2];
ADC_GetConversionValue(ADC1);
DMA_ClearFlag( DMA1_FLAG_GL1 );
DMA_ClearITPendingBit( DMA1_IT_GL1 );
delay_ms(1);
}
ADC_Cmd(ADC1, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);
ADC_TempSensorVrefintCmd(DISABLE);
RCC_HSICmd(DISABLE);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Solved! Go to Solution.
2017-03-13 04:28 AM
So many days of wasted time, unfortunately. Maybe it isn't wasted if there is a 'solution'?
Let me introduce my findings.
It is all because of the debugger. I built the ADC_IDDMeas example to exclude any my code errors.
The example didn't run as expected - got stuck in the while( ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) )...
Shocked.
But by mistake or not I tried also to run the program instead of stepping it and I found that then the code executes correctly.
Got back to my test program, modified the clocks (since I assumed that it is the CPU clock's frequency) and retried.
Again - no luck.
And then I found that if I'm watching the ADC_SR register directly in the debugger the code sticks in the loop, but if I'm watching the CPU registers for example, the code executes as I expected.
Not only.
Since I still had some doubts on the EOC flag I used the following code:
uint16_t var0 = 1;
uint8_t startFlag = 3;
uint8_t clearedFlag = 3;
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = ADC_GetConversionValue(ADC1);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
}�?�?�?�?�?�?�?�?�?�?�?
And it confirms that the flag is set correctly.
Let me post all the code of my test program since I believe it will be helpful for learning purposes.
Please keep in mind that it needs to be changed according to your needs (Scan mode enabled/disabled, continuous mode enabled/disabled), you have to set your variables for the DMA (if you use it) and the loops too.
Have fun and don't be egoistic, share your knowledge!
CAUTION: In SCAN mode (No DMA) I used ADC_EOCOnEachRegularChannelCmd( ADC1, ENABLE ); since I was unable to ensure correct sequence of ADC_GetConversionValue(). This way the program waits each channel Even if I can't see the flag with the debugger, I guess that the EOC flag is reset on each ADC_GetConversionValue().
//#define USEDMA
#define ADCCHANNELSNBR 3 //can be 1 or 3.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include 'stm32l1xx_adc.h'
#include 'stm32l1xx.h' //for TypeDefs
#include 'system_stm32l1xx.h'
#include 'core_cm3.h'
#include 'core_cmFunc.h'
#include 'core_cmInstr.h'
#include 'stm32l1xx_rcc.h'
#ifdef USEDMA
#include 'stm32l1xx_dma.h'
#endif
void main(){
RCC_HCLKConfig( RCC_SYSCLK_Div1 ); // AHB clock = SYSCLK
RCC_PCLK1Config( RCC_HCLK_Div1 );
RCC_PCLK2Config( RCC_HCLK_Div1 ); //RCC_HCLK_Div1: APB2 clock = HCLK (from AHB clock)
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //MISC in the help file...
ADC_TempSensorVrefintCmd(ENABLE);
/******************/
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
#ifdef USEADCINTERRUPT
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init( &NVIC_InitStructure );
#endif
#ifdef USEDMA
uint16_t adcResult[3] = { 0, 0, 0 };
DMA_InitTypeDef DMA_InitStructure;
#define ADC1_DR_ADDRESS ((uint32_t)0x40012458)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA clock enable
DMA_DeInit(DMA1_Channel1); //DMA1 channel1 configuration
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcResult;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADCCHANNELSNBR;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //peripheral address register...??
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //increment pointer
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Byte, HalfWord or Word
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //Byte, HalfWord or Word
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Circular DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //???
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable DMA1 channel1
#endif
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //IDD_MEASUREMENT_GPIO_CLK = RCC_AHBPeriph_GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3; //PA0,3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //analog
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
RCC_HSICmd(ENABLE); //16MHz, ADC requirement
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_Cmd(ADC1, DISABLE);
ADC_DeInit(ADC1);
ADC_StructInit( &ADC_InitStructure );
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
#if ADCCHANNELSNBR > 1
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
#else
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
#endif
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = ADCCHANNELSNBR;
ADC_Init(ADC1, &ADC_InitStructure);
#ifdef USEADCINTERRUPT
ADC_ITConfig( ADC1, ADC_IT_EOC, ENABLE );
#endif
//ADC_ContinuousModeCmd( ADC1, DISABLE );
#ifdef USEDMA
ADC_DMACmd( ADC1, DISABLE );
#endif
ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_Freeze);
ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_16Cycles);
#if ADCCHANNELSNBR > 1
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_16Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 3, ADC_SampleTime_16Cycles);
#endif
#ifdef ADCCHANNELSNBR > 1
ADC_EOCOnEachRegularChannelCmd( ADC1, ENABLE );
#endif
#ifdef USEDMA
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
#endif
ADC_Cmd(ADC1, ENABLE);
while ( ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET ) {}
uint16_t volatile var0 = 1;
uint16_t volatile var1 = 1;
uint16_t volatile var2 = 1;
uint8_t startFlag = 3;
uint8_t clearedFlag = 3;
#ifndef USEDMA
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = ADC_GetConversionValue(ADC1);
#if ADCCHANNELSNBR == 1
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
#endif
#if ADCCHANNELSNBR > 1
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var1 = ADC_GetConversionValue(ADC1);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var2 = ADC_GetConversionValue(ADC1);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
#endif
}
#endif
#ifdef USEDMA
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = adcResult[0];
var1 = adcResult[1];
var2 = adcResult[2];
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
}
#endif
/*
ADC_Cmd(ADC1, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);
ADC_TempSensorVrefintCmd(DISABLE);
RCC_HSICmd(DISABLE);
return;
*/
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Yes, the code has some garbage in it, but you can see what were my intentions / testing points.
2017-03-09 08:52 AM
//ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
Always better to set something than leave random stack junk in the structure that might get misinterpreted.
2017-03-10 01:26 PM
Thank you for your remark. Unfortunately it didn't help.
I did some experiments and actually I prepared an empty (EWARM IAR) project dedicated to ADC and ADC+DMA testing.
http://www.filedropper.com/logger2-adctest
http://www.filedropper.com/logger2-adctest-dma
In my tests combinations with SCAN mode enabled/disabled work (as expected, when enabled, the correct number of conversions is taken after each ADC_SoftwareStartConv(), if it is 1 (actually no SCAN mode) it samples the channel once; if there are more channels - it makes the required number of conversions (which I can see in the ADC_DR register with the debugger).
Same with the DMA.
The only drawback is that I couldn't identify the correct way for checking EOC / DMA_TC (i had troubles clearing DMA_TC or global flags).
What is left to me is to calculate the minimum waiting time for the ADC samples (ADC samples per channel * number of channels * 1/adc_freq) for a software delay (which isn't a problem in my case - 2MHz CPU vs 16MHz ADC clocks...)
Anyway, if you have any suggestions please feel free to share.
Best regards!
2017-03-13 04:28 AM
So many days of wasted time, unfortunately. Maybe it isn't wasted if there is a 'solution'?
Let me introduce my findings.
It is all because of the debugger. I built the ADC_IDDMeas example to exclude any my code errors.
The example didn't run as expected - got stuck in the while( ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC ) )...
Shocked.
But by mistake or not I tried also to run the program instead of stepping it and I found that then the code executes correctly.
Got back to my test program, modified the clocks (since I assumed that it is the CPU clock's frequency) and retried.
Again - no luck.
And then I found that if I'm watching the ADC_SR register directly in the debugger the code sticks in the loop, but if I'm watching the CPU registers for example, the code executes as I expected.
Not only.
Since I still had some doubts on the EOC flag I used the following code:
uint16_t var0 = 1;
uint8_t startFlag = 3;
uint8_t clearedFlag = 3;
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = ADC_GetConversionValue(ADC1);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
}�?�?�?�?�?�?�?�?�?�?�?
And it confirms that the flag is set correctly.
Let me post all the code of my test program since I believe it will be helpful for learning purposes.
Please keep in mind that it needs to be changed according to your needs (Scan mode enabled/disabled, continuous mode enabled/disabled), you have to set your variables for the DMA (if you use it) and the loops too.
Have fun and don't be egoistic, share your knowledge!
CAUTION: In SCAN mode (No DMA) I used ADC_EOCOnEachRegularChannelCmd( ADC1, ENABLE ); since I was unable to ensure correct sequence of ADC_GetConversionValue(). This way the program waits each channel Even if I can't see the flag with the debugger, I guess that the EOC flag is reset on each ADC_GetConversionValue().
//#define USEDMA
#define ADCCHANNELSNBR 3 //can be 1 or 3.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include 'stm32l1xx_adc.h'
#include 'stm32l1xx.h' //for TypeDefs
#include 'system_stm32l1xx.h'
#include 'core_cm3.h'
#include 'core_cmFunc.h'
#include 'core_cmInstr.h'
#include 'stm32l1xx_rcc.h'
#ifdef USEDMA
#include 'stm32l1xx_dma.h'
#endif
void main(){
RCC_HCLKConfig( RCC_SYSCLK_Div1 ); // AHB clock = SYSCLK
RCC_PCLK1Config( RCC_HCLK_Div1 );
RCC_PCLK2Config( RCC_HCLK_Div1 ); //RCC_HCLK_Div1: APB2 clock = HCLK (from AHB clock)
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //MISC in the help file...
ADC_TempSensorVrefintCmd(ENABLE);
/******************/
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
#ifdef USEADCINTERRUPT
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ADC1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init( &NVIC_InitStructure );
#endif
#ifdef USEDMA
uint16_t adcResult[3] = { 0, 0, 0 };
DMA_InitTypeDef DMA_InitStructure;
#define ADC1_DR_ADDRESS ((uint32_t)0x40012458)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA clock enable
DMA_DeInit(DMA1_Channel1); //DMA1 channel1 configuration
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcResult;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = ADCCHANNELSNBR;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //peripheral address register...??
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //increment pointer
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //Byte, HalfWord or Word
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //Byte, HalfWord or Word
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Circular DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //???
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable DMA1 channel1
#endif
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //IDD_MEASUREMENT_GPIO_CLK = RCC_AHBPeriph_GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3; //PA0,3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //analog
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
RCC_HSICmd(ENABLE); //16MHz, ADC requirement
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_Cmd(ADC1, DISABLE);
ADC_DeInit(ADC1);
ADC_StructInit( &ADC_InitStructure );
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
#if ADCCHANNELSNBR > 1
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
#else
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
#endif
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = ADCCHANNELSNBR;
ADC_Init(ADC1, &ADC_InitStructure);
#ifdef USEADCINTERRUPT
ADC_ITConfig( ADC1, ADC_IT_EOC, ENABLE );
#endif
//ADC_ContinuousModeCmd( ADC1, DISABLE );
#ifdef USEDMA
ADC_DMACmd( ADC1, DISABLE );
#endif
ADC_DelaySelectionConfig(ADC1, ADC_DelayLength_Freeze);
ADC_PowerDownCmd(ADC1, ADC_PowerDown_Idle_Delay, ENABLE);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_16Cycles);
#if ADCCHANNELSNBR > 1
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_16Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 3, ADC_SampleTime_16Cycles);
#endif
#ifdef ADCCHANNELSNBR > 1
ADC_EOCOnEachRegularChannelCmd( ADC1, ENABLE );
#endif
#ifdef USEDMA
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
#endif
ADC_Cmd(ADC1, ENABLE);
while ( ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET ) {}
uint16_t volatile var0 = 1;
uint16_t volatile var1 = 1;
uint16_t volatile var2 = 1;
uint8_t startFlag = 3;
uint8_t clearedFlag = 3;
#ifndef USEDMA
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = ADC_GetConversionValue(ADC1);
#if ADCCHANNELSNBR == 1
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
#endif
#if ADCCHANNELSNBR > 1
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var1 = ADC_GetConversionValue(ADC1);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var2 = ADC_GetConversionValue(ADC1);
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
#endif
}
#endif
#ifdef USEDMA
while(1) {
ADC_SoftwareStartConv(ADC1);
startFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET) {}
var0 = adcResult[0];
var1 = adcResult[1];
var2 = adcResult[2];
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
clearedFlag = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
}
#endif
/*
ADC_Cmd(ADC1, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE);
ADC_TempSensorVrefintCmd(DISABLE);
RCC_HSICmd(DISABLE);
return;
*/
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Yes, the code has some garbage in it, but you can see what were my intentions / testing points.