Non-blocking analogRead()

249 views
Skip to first unread message

Jacob Christ

unread,
Mar 23, 2017, 1:35:22 AM3/23/17
to Arduino Developers
We've recently implemented non-blocking analogRead()'s for chipKIT-core.  We saw 5x speed improvement in some programs.  Should Arduino want to implement something like this it would be nice if we could have parity with our API's.  Attached is a quick power point on how its working and some API examples.

Jacob


Jacob Christ
ProLinear/PONTECH, Inc.
+1 (909) 652-0670 Phone
http://www.pontech.com
chipKIT-core 1.4.0 Non-Blocking Analog Reads.pdf

Matthew Ford

unread,
Mar 23, 2017, 1:47:06 AM3/23/17
to devel...@arduino.cc
Here is a link to a similar library I did some time ago.  Method names are slightly different.

http://www.forward.com.au/pfod/ArduinoProgramming/pollingAnalogReadLibrary/index.html

My library also handles ignoring the first read in AVR 8bit chips, after changing the reference. 
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.


Ricardo JL Rufino

unread,
Mar 23, 2017, 11:17:52 AM3/23/17
to devel...@arduino.cc
Reading several pins using this method is possible?




To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.


--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

Matthew Ford

unread,
Mar 23, 2017, 12:23:46 PM3/23/17
to devel...@arduino.cc
Yes, this code only handles the AtoD conversion.  The input pin multiplexer setting is done separately.
Of course with this hardware you can only sample one pin at a time :-(
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.


Jacob Christ

unread,
Mar 23, 2017, 4:09:23 PM3/23/17
to Arduino Developers
Here is an untested example of reading more than one ADC pin...

/* This example shows how to read multiple analog inputs
 * using non-blocking analogRead()'s
 * The sizeof the adc_pins_to_read[] and adc_read_results[]
 * should match, if they do not you may have problems
 * by: Jacob Christ
 * License: BSD 3-Clause
 */
 
uint8_t  adc_pins_to_read[] = { A0, A1, A3 };
uint16_t adc_read_results[] = { 0x0, 0x0, 0x0 };
uint8_t  adc_index = 0;


void setup() {
    analogReadConversionStart(adc_pins_to_read[adc_index]);
}

void loop() {
    uint32_t value;
    if ( analogReadConversionComplete() ) {
      adc_read_results[adc_index] = analogReadConversion();
      adc_index = (adc_index + 1) % sizeof(adc_pins_to_read);
      analogReadConversionStart(adc_pins_to_read[adc_index]);
    }
}


Jacob Christ
ProLinear/PONTECH, Inc.
+1 (909) 652-0670 Phone
http://www.pontech.com

Paul Stoffregen

unread,
Mar 23, 2017, 4:27:12 PM3/23/17
to devel...@arduino.cc

> Of course with this hardware you can only sample one pin at a time :-(

Actually, some modern chips do allow sampling more than one signal at a
time, because they have 2 or even 4 physical ADCs.

A forward-looking API might be designed to allow for this sort of
hardware, which already exists today in some chips and is likely to
become more common as microcontrollers become more advanced.



William Westfield

unread,
Mar 24, 2017, 4:46:14 AM3/24/17
to devel...@arduino.cc
>> Of course with this hardware you can only sample one pin at a time :-(
>
> Actually, some modern chips do allow sampling more than one signal at a time

Don’t some of the modern chips also have “smart” A2Ds that you can set up to sequentially do conversions on multiple channels, placing the results in convenient registers or doing DMA?

(so: Yes. Sam3X (Due) lets you put any or all of the A2D channels into a “sequence”, and each channel has a separate register where it the last conversion result is stored. So, at the expense of having the response time “lengthened” by a factor of N, you can have N results available “instantly.”) (The Sam3x also lets you put channels into the sequence more than once, so you potentially can read particular channels faster than other channels.) TI Tiva (TM4c123…) has something similar, but they add FIFOs as well…)

BillW/WestfW

Rob Tillaart

unread,
Mar 24, 2017, 7:07:46 AM3/24/17
to Arduino Developers
HI Paul, 
good argument, here some thoughts to consider.

There are two strategies to have a robust and simple API

1) hide the number of ADC's under an analogPin() class. 
- The enduser can instantiate an object for every pin she uses. 
- The class internals (+helper classes) solves the distribution over the available ADC's by means of a request queue.
- Both blocking and async calls are added to the queue.
- Option to make it a priority queue (deque) so some pin will be served faster than others (additional param)
- the analogRead interrupt helps to implement the queue handling work in the background.

2) make the number of ADC's explicit and create an ADC() class
- for every ADC on the device you can have an instance (like HW serial on MEGA)
- the ADC has a method ADC.analogRead(pin) = synchronous call
- the ADC has methods  ADC.start(pin), ADC.completed(), ADC.value() = async call
- the ADC has methods ADC.maxValue() --> returns 1023 for an UNO and 4095 for a 12 bit ADC

Both classes can have additional methods like
- get/set prescaler
- get/set noiseThreshold
- whatEverOneCanComeUpWith()

At the moment of writing this I prefer option 2 as this class shows exactly what is in the chip.
Furthermore it could be the base class e.g. for a fast  SPI based ADC component giving 
both internal and external ADC's the same base interface.
Think implementation would also be simpler and less errorprone.

my 2 cents, 
Rob

Thomas Roell

unread,
Mar 24, 2017, 7:57:17 AM3/24/17
to devel...@arduino.cc
Rob,

I second option 2. There are MCU classes where one MCU has 1 ADC, and the other has 3 ADC, both otherwise they are identical. 

ADC.maxValue(). Don't really like that one at all. It implies that there is a place where you can configure the reported resolution. And that could be a problem if an application does not respect what a given ADC really can do. It seems better to expose the native resolution and support only that, either throu a macro or throu a function.

- Thomas

Rob Tillaart

unread,
Mar 24, 2017, 9:11:05 AM3/24/17
to Arduino Developers
fair enough, maxValue() should return the upper range (so 1023 for UNO) but apparently not clear from the name.
uint32_t ADC.range() ? 
or
uint8_t ADC.bits() which returns 10 or 12 etc instead?

Technically it is possible that a chip has e.g. 2 fast lowres ADC and 1 slow highres ADC

If we want to be bits independant we should have float ADC.relativeValue() which returns a scaled 
value between 0.0000 and 1.0000. Drawback is that it automatically include float libs.

Rob


Thomas Roell

unread,
Mar 24, 2017, 10:00:30 AM3/24/17
to devel...@arduino.cc
ADC.resolution() seems to be a better name. Or ADC_RESOLUTION as macro ?

I'd recommend against reintroducing the convoluted range remapped that got added to analogRead(). A simple unsigned integer value should be returned. In reality a lot of the more advanced use cases will forward the analog values into some DSP type library. It's wiser to let the downstream code decide how to map the incoming data for efficiency reasons. For that reason alone a ADC_RESOLUTION macro is preferable, as some conversion logic can then be compile time generated. I see the argument for multiple ADCs and the macro conflict though.

There is no real value in exposing different ADC resolutions, just from the code complexity aspect.

- Thomas



Andrew Kroll

unread,
Mar 24, 2017, 1:23:12 PM3/24/17
to devel...@arduino.cc
What I usually do to "hide" details and get a common API is emulate what is lacking.
This sometimes comes at a cost though, sometimes speed, sometimes code size.

Another thing that should be done if emulation is out of the question, is to define a macro that can tell the code what is possible/available, so that if there is an alternate workaround, it can be implemented, or at least your code can work around certain penalties.

Nothing is free, there are always tradeoffs. What needs to happen is that whatever route is chosen, it has to make sense, and if there are some limitations because not one size fits all, that needs to be documented and alternate demos for those cases.


Visit my github for awesome Arduino code @ https://github.com/xxxajk

Reply all
Reply to author
Forward
0 new messages