I'm planning to use a ADS1220 4-channel 24 bit adc but I really have no experience with SPI. I have found this library but I can't really understand the code that much and also this is measuring the differential voltage. I want to use this for my accelerometer (x, y and z data) but I can't seem to find how to do read from 3 channels, and I can't understand the code in the library :( I've also found a video for this adc in youtube but he didn't used it for multiple channels. I'm sorry for asking this, I'm just pressured since the deadline is really soon.



#include "Protocentral_ADS1220.h"
#include <SPI.h>

#define PGA 1                 // Programmable Gain = 1
#define VREF 3.3           
#define VFSR VREF/PGA             
#define FSR (((long int)1<<23)-1)  

volatile byte MSB;
volatile byte data;
volatile byte LSB;
//volatile char SPI_RX_Buff[3];
volatile byte *SPI_RX_Buff_Ptr;

long int bit32, data1, data2, data3;
long int bit24;

Protocentral_ADS1220 ADS1220;

void setup() {
  pinMode(ADS1220_CS_PIN, OUTPUT);
  pinMode(ADS1220_DRDY_PIN, INPUT);


void loop() {

  byte *config_reg;

  data1 = aRead(0x81);
  data2 = aRead(0x91);
  data3 = aRead(0xA1);

  Serial.print("    ");
  Serial.print("    ");


long int aRead(uint8_t config_byte) {
  ADS1220.writeRegister(CONFIG_REG0_ADDRESS , config_byte);
  uint8_t r = ADS1220.readRegister(CONFIG_REG0_ADDRESS);


  while (ADS1220.NewDataAvailable == false) {
    SPI_RX_Buff_Ptr = ADS1220.Read_Data();

  if(ADS1220.NewDataAvailable = true) {
    ADS1220.NewDataAvailable = false;

    MSB = SPI_RX_Buff_Ptr[0];    
    data = SPI_RX_Buff_Ptr[1];
    LSB = SPI_RX_Buff_Ptr[2];

    bit24 = MSB;
    bit24 = (bit24 << 8) | data;
    bit24 = (bit24 << 8) | LSB;        

    bit24= ( bit24 << 8 );
    bit32 = ( bit24 >> 8 );

  return bit32;

I tried to use the above sketch and I successfully read from 3 different channels but I noticed that the readings vary too much, compared to the example code. In the example code when I turn my potentiometer full CW, it outputs 8388607 which is correct right? since it is signed int.

But when running this sketch, the image below shows the output when the potentiometer is fully CW. Also turning the potentiometer fully CCW leads to negative values (shown in the 2nd picture) but in the example code, it gives 100-300 decimal values. Also these are the configuration registers I sent in registers 1-3 (I edited it in the part of the library) and for register 0, it is on the sketch.

Config_Reg1 = 0x00; Config_Reg2 = 0x40; Config_Reg3 = 0x00;

serial monitor output enter image description here

using accelerometer

format is (x,y,z) enter image description here

  • What kind of deadline? School project or assignment? Dec 10, 2016 at 20:05
  • Writing ADC driver code from scratch is NOT easy. What is wrong with the ADC built into most Arduino's processors? The ADC driver for most Arduino's is already part of the Arduino SDK.
    – st2000
    Dec 10, 2016 at 20:15
  • What's the model number of the accelerometer? Many of them digitize their results already. Dec 10, 2016 at 21:47
  • @MikaelPatel it's for my thesis in college
    – Ralph
    Dec 11, 2016 at 12:00
  • @jwpat7 adxl335, this has analog outputs, my adviser wants to have a 24 bit output accelerometer, I know there are lots of accelerometer that has 16 bit output which is already enough for precise measurements but I wanna give a try implementing an external adc before suggesting to my adviser to use accelerometers with digitized outputs
    – Ralph
    Dec 11, 2016 at 12:03

1 Answer 1


To get an understanding of how to read from the various ADS1220 channels, first review Figure 38, Analog Input Multiplexer, in the Datasheet as obtained from a link on TI.com's ADS1220 technicaldocuments webpage.

Figure 38 As can be seen, you'll need to close a switch from an AINx input line to the AINₚ bus, and also close the switch between AINₙ and AVSS. The IDACx switches and the BCS switches should remain open.

To operate those switches, first look at §8.6.1, Configuration Registers, in the Register Map section of the Datasheet. You'll see that MUX bits are in register 0, BCS is in register 1, IDAC is in register 2, and IxMUX are in register 3. To see what to put into those fields, look at Tables 16, 17, 19, and 20. For the MUX field, you will want a binary value like 1000, 1001, 1010, or 1011 to select one of AIN0-AIN3 as the AINₚ input and AVSS as the AINₙ input. BCS, IDAC, I1MUX, and I2MUX all should be zero.

For example, to read channels 0, 1, 2 in sequence, set MUX to 1000, set up other register fields, and trigger a conversion. After reading the result, change MUX to 1001, trigger a conversion, read result, change MUX to 1010, trigger a conversion, read result, etc.

Edit 1: In slightly more detail, one could do as follows.

• Use a WREG command [as in §; or some library equivalent] to send three bytes to set up Configuration Registers 1, 2, 3.
• For i=0, 1, and 2 in turn, construct a configuration byte, send that byte to Configuration Register 0, start a conversion, await result, read result; as follows:

Set the MUX field of a byte to i
Set PGA as desired (ie, to 1, 2, or 4, via codes 000, 001, or 010)
Set the PGA_BYPASS bit (as required when AINₙ = AVSS)
Use a WREG to send the constructed byte to Configuration Register 0
Use a START/SYNC command to start a conversion (see §
Wait for DRDY to go low
Use an RDATA command to read iᵗʰ ADC result (see §

Edit 2: In Protocentral's ADS1220.ino sketch, one finds the code sequence

  MSB = SPI_RX_Buff_Ptr[0];    
  data = SPI_RX_Buff_Ptr[1];
  LSB = SPI_RX_Buff_Ptr[2];
  bit24 = MSB;
  bit24 = (bit24 << 8) | data;
  bit24 = (bit24 << 8) | LSB; // Converting 3 bytes to a 24 bit int
  bit24= ( bit24 << 8 );
  bit32 = ( bit24 >> 8 );     // Converting 24 bit two's complement to 32 bit two's complement

More competently and concisely, and with SPI_RX_Buff_Ptr renamed to SPI_RX_Buff, this could be written as:

  bit32 = (((long)(SPI_RX_Buff[0]<<8 | SPI_RX_Buff[1])<<8 | SPI_RX_Buff[2])<<8)>>8;

which acts as follows: Assemble three bytes from SPI_RX_Buff into a 24-bit twos-complement-signed number. Shift that number left 8 bits so that its sign bit now sits in the sign bit position of a 32-bit signed integer. Shift that result 8 bits right with sign extension so that the final result is a signed 32-bit integer with possible values from -2²³ up to (2²³-1).

Sign extension occurs – usually – because in many implementations of C, the >> operator does an arithmetic shift instead of a logical shift when its operand is signed.

  • I just read this and it made me understand the datasheet, thank you so much!! I'll just update you if I was able to make it work
    – Ralph
    Dec 13, 2016 at 18:17
  • hello I'm wondering what would I send first when I want to read the data. I found this youtube video and he started with setting CS to low (which I think I should also do in my case) then sends a byte which is equal primary byte with a start bit and single/diff mode and to a register mask that isolates 3 LSB. I'm sorry if I'm noob but it would mean a lot to me if you help
    – Ralph
    Dec 13, 2016 at 18:42
  • I'm guessing I should send all those 4 configuration registers? I just don't know the flow I'm sorry
    – Ralph
    Dec 13, 2016 at 19:06
  • oh I get it why he and it with a mask, just to be sure that the config register will not be changed during the process, now my main concern is how to send these configuration registers
    – Ralph
    Dec 13, 2016 at 19:09
  • Edit 1 reflects my understanding (from datasheet) of the process - I haven't tried it out, and haven't looked at what library calls might apply Dec 13, 2016 at 19:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.