In an effort to increase the number of times per second the loop function is called when using analogRead functions non-blocking equivalent functions have been implemented into the chipKIT-core.
The existing analogRead function does three things: <ol> <li>Select ADC channel and start conversion.</li> <li>Do nothing while waiting for conversion to complete.</li> <li>Read converted value and return it to user.</li> </ol>
The “do nothing” part is what we aim to eliminate this non-blocking implementation and is indeed what we have done. Three newly exposed functions [analogReadConversionStart(pin), analogReadConversionComplete(), analogReadConversion()] implement and the analogRead() in wiring_analog.c simply becomes this:
int analogRead(uint8_t pin)
{
analogReadConversionStart(pin);
while( ! analogReadConversionComplete() );
return analogReadConversion();
}
The result of using the non-blocking analogRead functions result in a simple loop speed up of nearly 2x. On a MZ EFG chip this speed up is about 4.9x as fast as the blocking functions and allows for a loop frequency greater than 1MHz!
chipKIT Board (Rev) | PIC32 | Clock Freq | loop() Frequency Blocking Analog Read | loop() Frequency Non-Blocking Analog Read | Improvement | Notes |
---|---|---|---|---|---|---|
Lenny | MX | 40 Mhz | 49.14 kHz (20.35uS) | 127.39 kHz (7.84uS) | 2.59 | |
Fubarino SD (1.5) | MX | 80 Mhz | 90.91 kHz (10.99uS) | 217.39 kHz (4.60uS) | 2.39 | |
Wi-Fire (C) | MZEFG | 200 Mhz | 233.10 kHz (4.29uS) | 1162.79 kHz (0.86us) | 4.98 | |
Wi-Fire (B) | MZECG | 200 Mhz | 405.63 Hz (2465.3uS) | N/A | N/A | Non-Blocking Not Supported |
The following code example shows how to use the non-blocking analogRead functions. In the current implementation it is important that you do not mix blocking and non-blocking analogRead functions due to an internal state machine that keeps track of which ADC channel is currently selected.
This example is used to benchmark the performance of the non-blocking and blocking analog read functions and will print the results to the serial monitor. The default mode is Non-Blocking. To switch to Blocking ADC for comparison simply comment out #define FAST_ADC.
// This is in wiring.c, we shouldn't have to redefine it here (issue #288)
#define CORETIMER_TICKS_PER_MICROSECOND (F_CPU / 2 / 1000000UL)
//#define ADC_TEST_PIN A12
#define ADC_TEST_PIN 16
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // start serial for output
delay(3000);
Serial.println("chipKIT-core ADC speed test");
#define FAST_ADC
#ifdef FAST_ADC
analogReadConversionStart(ADC_TEST_PIN);
#endif
}
void loop() {
// put your main code here, to run repeatedly:
static uint32_t start_us = readCoreTimer();
static uint32_t stop_us = readCoreTimer();
uint32_t value;
#ifdef FAST_ADC
if ( analogReadConversionComplete() ) {
value = analogReadConversion();
analogReadConversionStart(ADC_TEST_PIN);
}
#else
value = analogRead(ADC_TEST_PIN);
#endif
stop_us = readCoreTimer(); //micros();
// Display Loop Time
Serial.print("ADC_TEST_PIN: ");
Serial.print(value, DEC);
Serial.println("");
Serial.print("F_CPU: ");
Serial.print(F_CPU, DEC);
Serial.print(" ");
float us = (float)(stop_us - start_us) / (float)CORETIMER_TICKS_PER_MICROSECOND;
Serial.print(us, 3);
Serial.print(" us, ");
Serial.print(1.0 / us * 1000000.0, 3);
Serial.print(" Hz");
Serial.println("");
delay(1000);
start_us = readCoreTimer(); //micros();
}