This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

ADC input selection change time

I am using internal ADC to sample 2 (sometimes 3) channels on about 333Hz frequency. What I do is:

  • set channel 1 as input (always two-thirds prescaling, VBG reference)

  • start 3ms repeated timer

  • when timer triggers, sampling at chan1 starts and app goes to sleep

  • wakeup when adc finishes - check one more time if it really is not busy - store result

  • change ADC input to channel 2 and start sampling - then go to sleep

  • wait for wakeup again, check if not busy, store result - change input to chan 1 - go to sleep

  • wait for another 3ms timer trigger...

My problem is that sometimes (very rarely, but regularly!) my readings seems to be connected, ex. Chan1 should read value about 0, Chan2 should read value about 1000. In most cases it is ok, but sometimes chan1 reads value about 1000 (just like CONFIG.INPSEL mux react too slowly). It is possible that my code is buggy, but I am wondering if it is possible that ADC reacts REALLY slowly for its input changes when sampling really fast.

  • Hi Wojtek

    Your sequence of events seems to be reasonable, i.e. that you store the ADC result before reconfiguring to the second AIN pin. This problem is not familiar to me, I'm not sure if I tested consecutive sampling from two different pins.

    To see if it is a MUX problem, can you try to add delay between configuring and start sampling.

    Update 24.6.2015 Reviewing your case again I am thinking there might be a different reason for your observation. What I am suspecting is that occasionally your sampling sequence is not finished when the TIMER triggers again a new sampling sequence. This could happen if the CPU is doing other stuff for 2-3ms, then the TIMER interrupt may be pending for 2-3ms and you will have two timer interrupts executing very close to each other. Possible scenario:

    • when timer triggers, interrupt is pending but not executed because the CPU is busy

    • in ~3ms the CPU is no longer busy and the timer interrupt is executed, sampling at chan1 starts and app goes to sleep

    • wakeup when adc finishes - check one more time if it really is not busy - store result

    • another timer interrupt is triggered, and execution of timer handler is pending

    • change ADC input to channel 2 and start sampling - then attempting to sleep

    • CPU does not sleep because the second timer interrupt is pending, configuring the ADC again to the first channel while the ADC is supposed to sample for the second channel.

    From this scenario, you might get a false result.

    Could this possibly be happening in your case? What happens if you decrease the sampling frequency to say 10ms, does the problem go away? Are you using the CPU for something else than just the ADC sampling? Do you have softdevice enabled perhaps?

    If this is the problem, possible solution would be to just wait for the ADC to finish sampling instead of going to sleep (that is going to cost you increased current consumption) or you could maintain a state variable in order to prevent the above scenario.

  • I tried that. After LAST measurement in cycle I immediately change input to channel1. Channel 1 sampling is started by 3ms timer, so there is quite long delay after configuring, before starting. Still, sometimes channel1 gets samples similar to readings from last channel.

    I solved my problem by adding one additional dummy sampling before each channel. It doubles ADC usage, but it works. This solution is a bit dirty, it would be nice to understand what causes this problem to solve it properly...

  • Thank You Stefan,

    While testing I noticed that my timer handler function is scheduled, and even after stopping that timer, function executes few more times. That means You could be right, and my application is so overloaded with other operations (softdevice enabled, 2 or 3 services are in use... My scheduler queue is quite big) that sometimes it just have to take some time to execute all operations pending in scheduler.

    BUT on the other hand, my workaround with adding additional dummy readings (channel selection -> dummy reading -> proper reading) works fine, I see no more bad readings while using it. This is a bit confusing.

    I am not able to test it with longer interval right now - I'll try to do it some day and I will post results then.

  • Ok, good that you have a workaround, even though I quickly do not understand why it works.

    By the way, a timer interrupt should preempt all tasks executed in the scheduler since scheduler tasks have lowest priority. Therefore any scheduler tasks should not interfere with the ADC operation. If you are however sending a lot of BLE data over the air or executing extended tasks in other interrupt handlers, that might be interrupting/delaying execution of the timer handler.

    This thread describes more on the ADC sampling frequency limitations when using the softdevice.

  • I checked my app right now and it seems You were right - timer has been triggered (and started new sampling burst) sometimes BEFORE burst has been finished. I think that was the reason of my strange readings. I just set my app to not start new burst (just ignore timer trigger) if there is still old sampling in progress and I see no bad readings. I have to do some more testing, but it seems that problem is solved. Thank You for linking that thread also!

Related