analogRead() inside an ISR, bad idea? I need some help!

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

analogRead() inside an ISR, bad idea? I need some help!

Post by AndrewBCN »

Hello,

Using Arduino IDE 1.8.x and STM32 Core 2.1 with an STM32F411CEU6 Black Pill.

I need to read an analog value from inside an Interrupt Service Routine that runs just once per second (the constraint is that the analog value must be read 2µs +/- 500ns after the interrupt itself). But I am using analogRead() already inside loop() at various points.

So my questions:

1. If I call analogRead() inside the ISR and the interrupt occurs while another analogRead() call was executing in loop(), will this completely mangle either or both analogRead() calls? Or does analogRead() disable interrupts while executing?

2. I have read that analogRead() as implemented is somewhat inefficient, because the ADC has to be completely reconfigured for each call. Does anybody know how long analogRead() takes to run on a 80 ~ 100MHz STM32F4? I am asking because I simultaneously use two serial interfaces, one at 115200 baud and the other at 38400 baud, and I was wondering if an excessively long analogRead() would cause the loss of some character(s)?

3. Is there a simple example of reading an ADC channel using HAL code, which is supposedly faster, and how long does that take? What special requirement would that impose on my code? Is it worth the extra programming/debugging effort?

I apologize if these sound like basic questions. I haven't really had much experience with analogRead() until now. :oops:

Thanks for any help!
by fpiSTM » Mon Oct 25, 2021 12:35 pm
It is a bad idea to use analogRead in an ISR.
As it configures, calibrate, process, wait for result and deinit. Too long for an isr and no interrupt is not disabled.
In that case you need to implement manually using ll for example.
You can refers to F4 example:
https://github.com/STMicroelectronics/S ... Conversion
Go to full post
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by fpiSTM »

It is a bad idea to use analogRead in an ISR.
As it configures, calibrate, process, wait for result and deinit. Too long for an isr and no interrupt is not disabled.
In that case you need to implement manually using ll for example.
You can refers to F4 example:
https://github.com/STMicroelectronics/S ... Conversion
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by mrburnette »

AndrewBCN wrote: Mon Oct 25, 2021 12:15 pm ...
I need to read an analog value from inside an Interrupt Service Routine ...
NO YOU DO NOT ...

Simply set a bool flag (global) and read the analog value in your main (loop{} ) or any called function.

If you absolutely need a time-dependent analog value, do some personal research, starting here.

More: https://www.google.com/search?q=stm32+r ... g+directly
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by AndrewBCN »

mrburnette wrote: Mon Oct 25, 2021 12:35 pm
AndrewBCN wrote: Mon Oct 25, 2021 12:15 pm ...
I need to read an analog value from inside an Interrupt Service Routine ...
NO YOU DO NOT ...

Simply set a bool flag (global) and read the analog value in your main (loop{} ) or any called function.

...
As I wrote, I have the constraint that I must read the ADC within a narrow time window (2µs +/-500ns after the interrupt), so simply setting a flag inside the ISR and later reading the analog value in loop() if the flag is set, is not an option.
Last edited by AndrewBCN on Mon Oct 25, 2021 1:12 pm, edited 1 time in total.
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by ag123 »

I did tried codes that use analogRead() (but libmaple (roger's) core) from within an interrupt, and it is mainly a timer interrupt.
I do not have any constraint of the analogRead() delay from timer interrupt to aquisition, other than that it need to keep the sample rates rather constant.
I'd think this is ok so long as
1) sample rates need to be pretty low
2) not too much other dependencies other than simply reading a value

I did try implementations like writing into a buffer during the timer interrupt where each time it does analogRead() and updates the buffer.
It works quite ok literally.

for STM core, there are some overheads i'd guess as of current, I'm also kind of hoping that part can be further optimized, e.g. so that the overheads needed for each analogRead() is reduced. I think this is rather important and a lot of applications literally uses it that way.
I can think of 3d printers all doing analogRead() (in Marlin) to get hot end and bed temperatures from thermistors, and that is a lot of boards using it that way going by how the 'industry' is evolving.
Last edited by ag123 on Mon Oct 25, 2021 1:11 pm, edited 2 times in total.
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by AndrewBCN »

fpiSTM wrote: Mon Oct 25, 2021 12:35 pm It is a bad idea to use analogRead in an ISR.
As it configures, calibrate, process, wait for result and deinit. Too long for an isr and no interrupt is not disabled.
In that case you need to implement manually using ll for example.
You can refers to F4 example:
https://github.com/STMicroelectronics/S ... Conversion
Merci, fpiSTM.
Yes, I was afraid of that. I guess I have to go the hard way and implement reading all the analog values manually and from inside the ISR, since the problem remains that if I read the ADC during the ISR even once, this will still randomly botch the rest of the analogRead() calls in loop().
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by AndrewBCN »

ag123 wrote: Mon Oct 25, 2021 1:07 pm ...
I do not have any constraint of the analogRead() delay from timer interrupt to aquisition,
...
Unfortunately I have that exact constraint: I must read the ADC within a narrow time window of 2µS +/-500ns after the interrupt. So that really determines three things:
1. Reading the ADC channel with that special constraint must take place inside the ISR.

2. All other ADC channel reads must also take place inside the same ISR.

3. Because analogRead() is rather inefficient, I have to program the sequence of ADC channel readings manually. :shock:
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by mrburnette »

AndrewBCN wrote: Mon Oct 25, 2021 1:20 pm ...
Unfortunately I have that exact constraint: I must read the ADC within a narrow time window of 2µS +/-500ns after the interrupt.
https://community.st.com/s/question/0D5 ... onversions


For large data acquisition projects, hardware is usually thrown at the problem and storage/analysis moved to a PC (or rPi'ish board).

https://www.mccdaq.com/PDFs/specs/DS-US ... S-Plus.pdf
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: analogRead() inside an ISR, bad idea? I need some help!

Post by ag123 »

AndrewBCN wrote: Mon Oct 25, 2021 1:20 pm Unfortunately I have that exact constraint: I must read the ADC within a narrow time window of 2µS +/-500ns after the interrupt. So that really determines three things:
1. Reading the ADC channel with that special constraint must take place inside the ISR.

2. All other ADC channel reads must also take place inside the same ISR.

3. Because analogRead() is rather inefficient, I have to program the sequence of ADC channel readings manually. :shock:
There are some things i may try in this situation.
instead of an interrupt, i may do a *spinlock* ! https://en.wikipedia.org/wiki/Spinlock
e.g.

Code: Select all

// active low !
while(digitalRead(pin)); //wait for a zero on pin
uint16_t value = analogRead();
and to improve the speeds of analogRead() a little more extreme
NB - i've never tried these codes, I do not know if they'd work

Code: Select all

  // "analogRead"
  // start conversion
  LL_ADC_REG_StartConversionSWStart(ADC1);
  // another spinlock to check end of conversion;
  while(!LL_ADC_IsActiveFlag_EOCS(ADC1));
  // ok we've got an end-of-conversion
  LL_ADC_ClearFlag_EOCS(ADC1);
  // now read the register, the notion is you have setup everything else prior
  // like which pin you want to read
  uint16_t value = LL_ADC_REG_ReadConversionData12(ADC1);
barely 'higher level' than reading registers directly
Well I don't know if it'd work
:P

edit:
i just remembered something, there is something call 'injected' mode
https://www.st.com/resource/en/applicat ... ronics.pdf
you may want to check that out, it seem it may suit your application
apparently stm32 ADCs can be externally triggered as well, you may want to check that out in the ref manual
that sounds interesting as it would seemed then all it takes is to hook the end-of-conversion interrupt, so that the adc does all the work in h/w,
and later simply interrupt when the data is ready to be read.
as for that 'interleaving' delay, you may want to explore using the sample times
Post Reply

Return to “General discussion”