Arduino Snippets

A selection of short code snippets for the Arduino that come in handy when the built-in library functions no longer suffice. Need fast timers, short delays, or silly ADC settings? This is the place to look.

For brevity, this is written assuming an Arduino Uno (ATmega328 at 16.00MHz). For different clock speeds and other processors, you may need to slightly modify or completely change things. See AVR Cheat Sheet for snippets for other AVR chips.

Page numbers used throughout this writing reference pages of the ATmega328 datasheet, as the author dislikes incessantly scrolling through the datasheet.

Analog-to-Digital Converter (ADC) Speed

The Arduino's ADC is, by default, run at a somewhat leisurely speed. Some applications may require faster sampling rates. Increasing the ADC clock decreases conversion time at the cost of accuracy. Note that faster is not always better. At high clock speeds, the ADC greatly decreases in resolution and may become completely unresponsive at very high clock speeds. Start with the usual prescaler and gradually increase the speed until the compromise between accuracy and speed is comfortable. For full accuracy, ADC clock speeds should be restricted to less than 200kHz. To change the prescaler, bits ADPS2:0 in ADCSRA should be modified:

// configure ADC (pg. 250)
ADCSRA &= 0xf8; // clear prescaler
ADCSRA |= 0x7 & 4; // set prescaler to /16
ADCSRA |= 1<<ADEN; // make sure ADC is enabled

This sets the ADC prescaler to divide the system clock by 16. This can be changed by selecting a number 0 through 7 for the ADC prescaler bits (in the code above, 4 is the value to change). The prescaler division table is as follows (from Table 23-5, pg. 264):

ADPS2 ADPS1 ADPS0 division factor clock
0 0 0 2 8MHz
0 0 1 2 8MHz
0 1 0 4 4MHz
0 1 1 8 2MHz
1 0 0 16 1MHz
1 0 1 32 500kHz
1 1 0 64 250kHz
1 1 1 128 125kHz

Another way to slightly expedite ADC reads is to streamline the function call. The library function analogRead has a lot of code that doesn't need to run at each call, assuming you aren't mucking with the ADC settings in between. With the ADC configured with whichever prescaler value you choose, you can read from the ADC using the following function, which eliminates some of the overhead from analogRead. Note that this function expects an integer 0-7 as the pin, instead of the A0-A7 you may be used to. This is so that the Arduino does not have to convert these pin numbers to internal pin numbers:

// read from ADC (slimmed down analogRead)
int analogReadFast(uint8_t pin) {
    uint8_t x;
    // select analog reference and pin mux
    // assume analog reference of AVcc
    // allow reading temp, Vbg, and GND (mux > 7)
    ADMUX = (1 << REFS0) | (pin & 0xf);
    // start the conversion
    ADCSRA |= 1 << ADSC;
    // wait for the conversion to finish
    while (ADCSRA & 1 << ADSC) ;
    // read ADCL first, it locks ADCL and ADCH
    x = ADCL;
    // return the ADC value
    return (ADCH << 8) | x;
}

Of course, one should always keep in mind that increasing the ADC clock speed will likely increase clock jitter, which will often dominate as a source of noise. For even faster conversions, the ADC can be put into free-running mode, in which it is always performing a conversion. More on this to come (soon, hopefully).