Setting up channels for the Analog-to-digital converter (ADC)

A project log for ATtiny 1-series with Arduino support

Creating a break-out board for the ATtiny1616 where sketches can be uploaded from Arduino with the Arduino UNO or a modified AVR JTAG ICE

Sander van de BorSander van de Bor 07/04/2019 at 04:280 Comments

In one of the earlier logs PORT was explained, but that can only be used for digital I/O, meaning, it can turn outputs on or off, or detect if an input is on or off. The actual pin number for digital I/O consists of a PORT letter followed by a pin (or bit #) in that PORT. Every non-power related leg (like VDD and GND) on the ATtiny is linked to one of those PORTS, but that is usually not the only function of that leg.

The Analog to Digital Converter (ADC) is a great feature on the MCU to measure input voltage. Instead of using PORT to link a the digital I/O to the leg, it uses channels. The ATtiny1616 has 12 input channels (AIN0 to AIN11) on two ADC’s (ADC0 and ADC1). The location of these input channels (we are going to use ADC0 only) are as follows:

//                          _____
//                  VDD   1|*    |20  GND
// (nSS)  (AIN4) PA4  0~  2|     |19  16~ PA3 (AIN3)(SCK)(EXTCLK)
//        (AIN5) PA5  1~  3|     |18  15  PA2 (AIN2)(MISO)
// (DAC)  (AIN6) PA6  2   4|     |17  14  PA1 (AIN1)(MOSI)
//        (AIN7) PA7  3   5|     |16  17  PA0 (AIN0/nRESET/UPDI)
//        (AIN8) PB5  4   6|     |15  13  PC3
//        (AIN9) PB4  5   7|     |14  12  PC2
// (RXD) (TOSC1) PB3  6   8|     |13  11~ PC1 (PWM only on 1-series)
// (TXD) (TOSC2) PB2  7~  9|     |12  10~ PC0 (PWM only on 1-series)
// (SDA) (AIN10) PB1  8~ 10|_____|11   9~ PB0 (AIN11)(SCL)

So as you can see a leg could have be a digital pin (for example PA4) and an analog input (AIN4). Like the digital I/O we are going to tell Arduino which pin# is linked to each analog channel as follows in pins_arduino.h:

#define digitalPinToAnalogInput(p)      ((p<6)?(p+4):(p==17?0:((p>13)?(p-13):((p==8)?10:(p==9?11:NOT_A_PIN))))) 

Big thanks to Spence Konde! He helped enormous in creating all the pre-processor macros. But newbies, like me, are probably wondering what this line above is doing. 

We are all familiar with an if statement, for example:

if(p < 6) {
    p = p + 4;
} else {
    P = NOT_A_PIN;

There is actually a shorter method writing the same if statement above, for example  as follows:

p = (p<6)?(p+4):NOT_A_PIN; 

Using this same method for the macro above will result in the following if statement:

if(p < 6) {
    digitalPinToAnalogInput(p) = p + 4;
} elseif (p == 17 {
    digitalPinToAnalogInput(p) = 0;
} elseif (p > 13 {
    digitalPinToAnalogInput(p) = p-13;
} elseif (p == 8 {
    digitalPinToAnalogInput(p) = 10;
} elseif (p == 9 {
    digitalPinToAnalogInput(p) = 11;
else {

With “p” being the Arduino pin number, we can now determine which channel belongs to that pin with the macro above. For example when p=5 (leg #7), digitalPinToAnalogInput(p) will be 5 + 4, resulting in channel 9.

You can just read the voltage on the input pin by entering the following in Arduino:

analogRead(5) // reading the analog input on channel 9. 

But most Arduino’s have a dedicated section for analog inputs, for example on the Arduino UNO A0 up to A5 are used as analog inputs. In order to use these A0, A1 etc numbers we have to add these with macros to the pins_arduino.h as well as follows:  

#define PIN_A0   (17)
#define PIN_A1   (14)
#define PIN_A2   (15)
#define PIN_A3   (16)
#define PIN_A4    (0)
#define PIN_A5    (1)
#define PIN_A6    (2)
#define PIN_A7    (3)
#define PIN_A8    (4)
#define PIN_A9    (5)
#define PIN_A10  (10)
#define PIN_A11  (11)

static const uint8_t  A0 = PIN_A0;
static const uint8_t  A1 = PIN_A1;
static const uint8_t  A2 = PIN_A2;
static const uint8_t  A3 = PIN_A3;
static const uint8_t  A4 = PIN_A4;
static const uint8_t  A5 = PIN_A5;
static const uint8_t  A6 = PIN_A6;
static const uint8_t  A7 = PIN_A7;
static const uint8_t  A8 = PIN_A8;
static const uint8_t  A9 = PIN_A9;
static const uint8_t A10 = PIN_A10;
static const uint8_t A11 = PIN_A11; 

Instead of only using the pin#, now analogRead(A9) can be used as well, resulting with the same readings.

In the next log I will explain the internal voltages which can be used to get a reliable analog input reading.