2022-10-13 09:29 AM
I have tried multiple different configurations, software trigger, hardware trigger, the only way to read ADC channels in sequence is to use DISCONT=1 and trigger each reading individually. I have minimized my project to a testcase where a software trigger should initiate a sequence reading channel 0 through 2 and the EOC and EOS events are counted in the ISR then printed over usart. Am I missing something? Both EOS and EOC increment by 1 after each ADSTART...
// Main loop:
DelayCycles(1000000);
ADC1->CR |= ADC_CR_ADSTART;
DelayCycles(1000000);
if(EOS_COUNT != old_EOS_COUNT){
old_EOS_COUNT = EOS_COUNT;
etl::string<32> text;
etl::string_stream stream(text);
stream << "EOS_COUNT:" << EOS_COUNT << "\tISR:\t" << etl::bin << ADC1->ISR << "\n";
dbg << stream.str();
}
if(EOC_COUNT != old_EOC_COUNT){
old_EOC_COUNT = EOC_COUNT;
etl::string<32> text;
etl::string_stream stream(text);
stream << "EOC_COUNT:" << EOC_COUNT << "\tDR:\t" << etl::dec << ADC1->DR << "\n";
dbg << stream.str();
}
}
// ADC and Timer configuration (Timer is unused in my test case)
/* --------------------------------------------------------------- */
// SET UP ADC
/* --------------------------------------------------------------- */
// select TIM3 trgo;
// ADC1->CFGR1 |= ADC_CFGR1_EXTEN_0 | ADC_CFGR1_EXTSEL_1 | ADC_CFGR1_EXTSEL_0;
// Set sample time
// WRITE_REG(ADC1->SMPR,ADC_SMPR_SMP1_2);
CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_DISCEN);
CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_CONT);
// Enable adc voltage regulator
ADC1->CR |= ADC_CR_ADVREGEN;
DelayCycles(16000);
// Start adc cal sequence
SET_BIT(ADC1->CR,ADC_CR_ADCAL);
while(READ_BIT(ADC1->CR,ADC_CR_ADCAL)){}
DelayCycles(16000);
// Clear the ADRDY bit by writing '1'
SET_BIT(ADC1->ISR,ADC_ISR_ADRDY);
// Set conversion channels
ADC1->CHSELR |= 0b111;
while(!READ_BIT(ADC1->ISR, ADC_ISR_CCRDY)){}
SET_BIT(ADC1->ISR,ADC_ISR_CCRDY);
// Enable ADC and wait till ready
SET_BIT(ADC1->CR, ADC_CR_ADEN);
while(!READ_BIT(ADC1->ISR, ADC_ISR_ADRDY)){}
SET_BIT(ADC1->ISR, (ADC_ISR_ADRDY));
// Enable end of conversion interrupt and start
SET_BIT(ADC1->IER, ADC_IER_EOCIE);
SET_BIT(ADC1->IER, ADC_IER_EOSIE);
NVIC_SetPriority(ADC1_IRQn, 0x3);
NVIC_EnableIRQ(ADC1_IRQn);
SET_BIT(ADC1->CR, ADC_CR_ADSTART);
/* --------------------------------------------------------------- */
// SET UP TIM3
/* --------------------------------------------------------------- */
TIM3->PSC = 1999;
TIM3->ARR = 3999;
TIM3->CR2 |= TIM_CR2_MMS_1;
NVIC_SetPriority(TIM3_IRQn, 0x1);
NVIC_EnableIRQ(TIM3_IRQn);
SET_BIT(TIM3->DIER, TIM_DIER_UIE);
SET_BIT(TIM3->CR1, TIM_CR1_CEN);
// ISR
uint32_t EOS_COUNT;
uint32_t EOC_COUNT;
#ifdef __cplusplus
extern "C"{
#endif
void ADC1_IRQHandler(void){
if(READ_BIT(ADC1->ISR, ADC_ISR_EOC){
EOC_COUNT++;
// (*adc_eoc_handler)(ADC1->DR);
}
if(READ_BIT(ADC1->ISR,ADC_ISR_EOS)){
//(*adc_eos_handler)();
EOS_COUNT++;
}
if(READ_BIT(ADC1->ISR,ADC_ISR_EOS))
SET_BIT(ADC1->ISR,ADC_ISR_EOC);
if(READ_BIT(ADC1->ISR,ADC_ISR_EOS))
SET_BIT(ADC1->ISR,ADC_ISR_EOS);
}
#ifdef __cplusplus
}
The usart output is as follows:
EOC_COUNT:189 DR: 2
EOS_COUNT:190 ISR: 0
EOC_COUNT:190 DR: 3
EOS_COUNT:191 ISR: 0
EOC_COUNT:191 DR: 1
EOS_COUNT:192 ISR: 0
EOC_COUNT:192 DR: 4
EOS_COUNT:193 ISR: 0
EOC_COUNT:193 DR: 2
EOS_COUNT:194 ISR: 0
EOC_COUNT:194 DR: 1
Solved! Go to Solution.
2022-10-13 10:23 AM
Right, you are missing something. What you are missing is the value of ADC conversion time compared to interrupt entry + service + return time. No chance to handle multiple channel conversion without DMA other than using WAIT mechanism - the next conversion starts after reading the previous result.
2022-10-13 10:23 AM
Right, you are missing something. What you are missing is the value of ADC conversion time compared to interrupt entry + service + return time. No chance to handle multiple channel conversion without DMA other than using WAIT mechanism - the next conversion starts after reading the previous result.
2022-10-13 11:26 AM
I think you are partially correct. If I increase the sample time to 19.5 ADC Clock cycles 2 EOC events happen for each EOS event. I think there should be 3 EOC events, see the diagram, but it's an improvement. Also the data register now holds the data corresponding to the last channel in the sequence which is nice.
Actually, when the WAIT bit is set, 3 EOC events happen for each EOS, so that definitely solved the issue.
However if there previously was not enough time in the interrupt routine to reset the EOC flag the OVERRUN flag should have been set by hardware. It wasn't since I checked that by also printing out the ISR register... Strange business
I guess I can solve the issue reliably by using WAIT, or implementing DMA for this. Cheers!
2022-10-13 01:35 PM
In any case 3 EOC events are generated but since the total interrupt handling time is now approx. > 2 x conversion time, you miss one event and the ISR is fired 2 times after the chage (was fired only once before).