├── extras └── ADS1256_ArduinoLibrary_Documentation_20251023.pdf ├── README.md ├── library.properties ├── keywords.txt ├── LICENSE ├── src ├── ADS1256.h └── ADS1256.cpp └── examples └── ADS1256-Example └── ADS1256-Example.ino /extras/ADS1256_ArduinoLibrary_Documentation_20251023.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CuriousScientist0/ADS1256/HEAD/extras/ADS1256_ArduinoLibrary_Documentation_20251023.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ADS1256 2 | An Arduino-compatible library for the ADS1256 24-bit analog-to-digital converter. 3 | 4 | For usage, see the documentation: https://github.com/CuriousScientist0/ADS1256/blob/main/extras/ADS1256_ArduinoLibrary_Documentation_20251023.pdf 5 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ADS1256 2 | version=1.6.0 3 | author=Curious Scientist 4 | maintainer=Curious Scientist 5 | sentence=An Arduino-compatible library for the 24-bit ADS1256 analog-to-digital converter. 6 | paragraph=It can also work with STM32 (STM32duino), ESP32 and RP2040-based microcontrollers. 7 | category=Sensors 8 | url=https://github.com/CuriousScientist0/ADS1256 9 | architectures=avr, stm32, esp32, renesas_uno, rp2040 10 | includes=ADS1256.h 11 | depends= 12 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Syntax Colouring Map For ADS1256 2 | 3 | # Datatypes (KEYWORD1) 4 | ADS1256 KEYWORD1 5 | 6 | # Methods and Functions (KEYWORD2) 7 | InitializeADC KEYWORD2 8 | 9 | readRegister KEYWORD2 10 | writeRegister KEYWORD2 11 | setDRATE KEYWORD2 12 | setPGA KEYWORD2 13 | getPGA KEYWORD2 14 | setMUX KEYWORD2 15 | setByteOrder KEYWORD2 16 | getByteOrder KEYWORD2 17 | setBuffer KEYWORD2 18 | getBuffer KEYWORD2 19 | setAutoCal KEYWORD2 20 | getAutoCal KEYWORD2 21 | setGPIO KEYWORD2 22 | writeGPIO KEYWORD2 23 | readGPIO KEYWORD2 24 | setCLKOUT KEYWORD2 25 | setSDCS KEYWORD2 26 | sendDirectCommand KEYWORD2 27 | 28 | readSingle KEYWORD2 29 | readSingleContinuous KEYWORD2 30 | cycleDifferential KEYWORD2 31 | convertToVoltage KEYWORD2 32 | stopConversion KEYWORD2 33 | 34 | # Instances (KEYWORD2) 35 | 36 | # Constants (LITERAL1) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 CuriousScientist0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/ADS1256.h: -------------------------------------------------------------------------------- 1 | //ADS1256 header file 2 | /* 3 | Name: ADS1256.h 4 | Created: 2022/07/14 5 | Author: Curious Scientist 6 | Editor: Notepad++ 7 | Comment: Visit https://curiousscientist.tech/blog/ADS1256-custom-library 8 | Special thanks to 9 | Abraão Queiroz for spending time on the code and suggesting corrections for ESP32 microcontrollers 10 | Benjamin Pelletier for pointing out and fixing an issue around the handling of the DRDY signal 11 | */ 12 | 13 | #ifndef _ADS1256_h 14 | #define _ADS1256_h 15 | 16 | #include 17 | 18 | //Differential inputs 19 | #define DIFF_0_1 0b00000001 //A0 + A1 as differential input 20 | #define DIFF_2_3 0b00100011 //A2 + A3 as differential input 21 | #define DIFF_4_5 0b01000101 //A4 + A5 as differential input 22 | #define DIFF_6_7 0b01100111 //A6 + A7 as differential input 23 | 24 | //Single-ended inputs 25 | #define SING_0 0b00001111 //A0 + GND (common) as single-ended input 26 | #define SING_1 0b00011111 //A1 + GND (common) as single-ended input 27 | #define SING_2 0b00101111 //A2 + GND (common) as single-ended input 28 | #define SING_3 0b00111111 //A3 + GND (common) as single-ended input 29 | #define SING_4 0b01001111 //A4 + GND (common) as single-ended input 30 | #define SING_5 0b01011111 //A5 + GND (common) as single-ended input 31 | #define SING_6 0b01101111 //A6 + GND (common) as single-ended input 32 | #define SING_7 0b01111111 //A7 + GND (common) as single-ended input 33 | 34 | //PGA settings //Input voltage range 35 | #define PGA_1 0b00000000 //± 5 V 36 | #define PGA_2 0b00000001 //± 2.5 V 37 | #define PGA_4 0b00000010 //± 1.25 V 38 | #define PGA_8 0b00000011 //± 625 mV 39 | #define PGA_16 0b00000100 //± 312.5 mV 40 | #define PGA_32 0b00000101 //+ 156.25 mV 41 | #define PGA_64 0b00000110 //± 78.125 mV 42 | 43 | //Datarate //DEC 44 | #define DRATE_30000SPS 0b11110000 //240 45 | #define DRATE_15000SPS 0b11100000 //224 46 | #define DRATE_7500SPS 0b11010000 //208 47 | #define DRATE_3750SPS 0b11000000 //192 48 | #define DRATE_2000SPS 0b10110000 //176 49 | #define DRATE_1000SPS 0b10100001 //161 50 | #define DRATE_500SPS 0b10010010 //146 51 | #define DRATE_100SPS 0b10000010 //130 52 | #define DRATE_60SPS 0b01110010 //114 53 | #define DRATE_50SPS 0b01100011 //99 54 | #define DRATE_30SPS 0b01010011 //83 55 | #define DRATE_25SPS 0b01000011 //67 56 | #define DRATE_15SPS 0b00110011 //51 57 | #define DRATE_10SPS 0b00100011 //35 58 | #define DRATE_5SPS 0b00010011 //19 59 | #define DRATE_2SPS 0b00000011 //3 60 | 61 | //Status register 62 | #define BITORDER_MSB 0 63 | #define BITORDER_LSB 1 64 | #define ACAL_DISABLED 0 65 | #define ACAL_ENABLED 1 66 | #define BUFFER_DISABLED 0 67 | #define BUFFER_ENABLED 1 68 | 69 | //Register addresses 70 | #define STATUS_REG 0x00 71 | #define MUX_REG 0x01 72 | #define ADCON_REG 0x02 73 | #define DRATE_REG 0x03 74 | #define IO_REG 0x04 75 | #define OFC0_REG 0x05 76 | #define OFC1_REG 0x06 77 | #define OFC2_REG 0x07 78 | #define FSC0_REG 0x08 79 | #define FSC1_REG 0x09 80 | #define FSC2_REG 0x0A 81 | 82 | //Command definitions 83 | #define WAKEUP 0b00000000 84 | #define RDATA 0b00000001 85 | #define RDATAC 0b00000011 86 | #define SDATAC 0b00001111 87 | #define RREG 0b00010000 88 | #define WREG 0b01010000 89 | #define SELFCAL 0b11110000 90 | #define SELFOCAL 0b11110001 91 | #define SELFGCAL 0b11110010 92 | #define SYSOCAL 0b11110011 93 | #define SYSGCAL 0b11110100 94 | #define SYNC 0b11111100 95 | #define STANDBY 0b11111101 96 | #define RESET 0b11111110 97 | //---------------------------------------------------------------- 98 | 99 | 100 | class ADS1256 101 | { 102 | public: 103 | static constexpr int8_t PIN_UNUSED = -1; 104 | 105 | //Constructor 106 | ADS1256(const int8_t DRDY_pin, const int8_t RESET_pin, const int8_t SYNC_pin, const int8_t CS_pin, float VREF, SPIClass* spi = &SPI); 107 | 108 | //Initializing function 109 | void InitializeADC(); 110 | //ADS1256(int drate, int pga, int byteOrder, bool bufen); 111 | 112 | //Read a register 113 | long readRegister(uint8_t registerAddress); 114 | 115 | //Write a register 116 | void writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite); 117 | 118 | //Individual methods 119 | void setDRATE(uint8_t drate); 120 | void setPGA(uint8_t pga); 121 | uint8_t getPGA(); 122 | void setMUX(uint8_t mux); 123 | void setByteOrder(uint8_t byteOrder); 124 | uint8_t getByteOrder(); 125 | void setBuffer(uint8_t bufen); 126 | uint8_t getBuffer(); 127 | void setAutoCal(uint8_t acal); 128 | uint8_t getAutoCal(); 129 | void setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3); 130 | void writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value); 131 | uint8_t readGPIO(uint8_t gpioPin); 132 | void setCLKOUT(uint8_t clkout); 133 | void setSDCS(uint8_t sdcs); 134 | void sendDirectCommand(uint8_t directCommand); 135 | 136 | //Get a single conversion 137 | long readSingle(); 138 | 139 | //Single input continuous reading 140 | long readSingleContinuous(); 141 | 142 | //Cycling through the single-ended inputs 143 | long cycleSingle(); //Ax + COM 144 | 145 | //Cycling through the differential inputs 146 | long cycleDifferential(); //Ax + Ay 147 | 148 | //Converts the reading into a voltage value 149 | float convertToVoltage(int32_t rawData); 150 | 151 | //Stop AD 152 | void stopConversion(); 153 | 154 | private: 155 | 156 | SPIClass* _spi; //Pointer to an SPIClass object 157 | 158 | void waitForLowDRDY(); // Block until DRDY is low 159 | void waitForHighDRDY(); // Block until DRDY is high 160 | void updateMUX(uint8_t muxValue); 161 | inline void CS_LOW(); 162 | inline void CS_HIGH(); 163 | 164 | void updateConversionParameter(); //Refresh the conversion parameter based on the PGA 165 | 166 | float _VREF = 0; //Value of the reference voltage 167 | float conversionParameter = 0; //PGA-dependent multiplier 168 | //Pins 169 | int8_t _DRDY_pin; //Pin assigned for DRDY 170 | int8_t _RESET_pin; //Pin assigned for RESET 171 | int8_t _SYNC_pin; //Pin assigned for SYNC 172 | int8_t _CS_pin; //Pin assigned for CS 173 | 174 | //Register values 175 | byte _DRATE; //Value of the DRATE register 176 | byte _ADCON; //Value of the ADCON register 177 | byte _MUX; //Value of the MUX register 178 | byte _PGA; //Value of the PGA (within ADCON) 179 | byte _GPIO; //Value of the GPIO register 180 | byte _STATUS; //Value of the status register 181 | byte _GPIOvalue; //GPIO value 182 | byte _ByteOrder; //Byte order 183 | 184 | byte _outputBuffer[3]; //3-byte (24-bit) buffer for the fast acquisition - Single-channel, continuous 185 | long _outputValue; //Combined value of the _outputBuffer[3] 186 | bool _isAcquisitionRunning; //bool that keeps track of the acquisition (running or not) 187 | uint8_t _cycle; //Tracks the cycles as the MUX is cycling through the input channels 188 | }; 189 | #endif -------------------------------------------------------------------------------- /examples/ADS1256-Example/ADS1256-Example.ino: -------------------------------------------------------------------------------- 1 | //This code belongs to the ADS1256 library developed by Curious Scientist 2 | //A very detailed documentation can be found at: https://curiousscientist.tech/ads1256-custom-library 3 | 4 | #include 5 | 6 | //#define ADS1256_SPI_ALREADY_STARTED //prevent internal _spi->begin() to allow custom SPI initialization 7 | 8 | //Platform-specific pin definitions 9 | #if defined(ARDUINO_ARCH_RP2040) 10 | #pragma message "Using RP2040" 11 | //#define USE_SPI1 //Alternative USE_SPI for RP2040 - Uncomment to use SPI1 12 | #if defined(USE_SPI1) 13 | #pragma message "Using SPI1 (SPI1)" 14 | #define SPI_MOSI 11 15 | #define SPI_MISO 12 16 | #define SPI_SCK 10 17 | #define USE_SPI SPI1 18 | #else 19 | #pragma message "Using SPI (SPI0)" 20 | #define SPI_MOSI 3 //19 21 | #define SPI_MISO 4 //16 22 | #define SPI_SCK 2 //18 23 | #define USE_SPI SPI 24 | #endif 25 | //----------------------------------------- 26 | 27 | #elif defined(ARDUINO_ARCH_STM32) 28 | #pragma message "Using STM32" 29 | //#define USE_SPI2 //Uncomment to use SPI2 30 | #if defined(USE_SPI2) 31 | #pragma message "Using SPI2" 32 | #define USE_SPI spi2 33 | SPIClass spi2(PB15, PB14, PB13); //MOSI, MISO, SCK 34 | #else 35 | #pragma message "Using SPI (SPI1)" 36 | #define USE_SPI SPI //Default SPI1, pre-instantiated as 'SPI' on PA7, PA6, PA5 37 | #endif 38 | //----------------------------------------- 39 | #elif defined(TEENSYDUINO) 40 | #pragma message "Using Teensy" 41 | //#define USE_SPI1 //Uncomment to use SPI1 on Teensy 4.0 or 4.1 42 | //#define USE_SPI2 //Uncomment to use SPI2 on Teensy 4.0 or 4.1 43 | #if defined(USE_SPI2) 44 | #pragma message "Using SPI2 (SPI3)" 45 | #define USE_SPI SPI2 46 | #elif defined(USE_SPI1) 47 | #pragma message "Using SPI1 (SPI2)" 48 | #define USE_SPI SPI1 49 | #else 50 | #pragma message "Using SPI (SPI1)" 51 | #define USE_SPI SPI 52 | #endif 53 | //----------------------------------------- 54 | 55 | #elif defined(ARDUINO_ARCH_ESP32) 56 | #pragma message "Using ESP32" 57 | SPIClass hspi(HSPI); 58 | //#define USE_HSPI // Uncomment to use HSPI instead of VSPI 59 | #if defined(USE_HSPI) 60 | #pragma message "Using HSPI" 61 | #define USE_SPI hspi 62 | #else 63 | #pragma message "Using VSPI" 64 | #define USE_SPI SPI 65 | #endif 66 | //----------------------------------------- 67 | #else //Default fallback (Arduino AVR) 68 | #define SPI_MOSI MOSI 69 | #define SPI_MISO MISO 70 | #define SPI_SCK SCK 71 | #define USE_SPI SPI 72 | //----------------------------------------- 73 | #endif 74 | 75 | 76 | //Below a few examples of pin descriptions for different microcontrollers I used: 77 | //ADS1256 A(2, ADS1256::PIN_UNUSED, 8, 10, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //Arduino Nano/Uno - OK 78 | //ADS1256 A(7, ADS1256::PIN_UNUSED, 10, 9, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //ATmega32U4 -OK 79 | //ADS1256 A(16, 17, ADS1256::PIN_UNUSED, 15, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //ESP32 WROOM 32 - OK (HSPI+VSPI) 80 | //ADS1256 A(7, ADS1256::PIN_UNUSED, 8, 10, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //Teensy 4.0 - OK 81 | //ADS1256 A(7, ADS1256::PIN_UNUSED, 6, 5, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //RP2040 Waveshare Mini - OK 82 | //ADS1256 A(18, 20, 21, 19, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float), SPI bus. //RP2040 Zero - OK 83 | ADS1256 A(15, ADS1256::PIN_UNUSED, 14, 17, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float), SPI bus. //RP2040 Pico W - OK 84 | //ADS1256 A(PA2, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, PA4, 2.500, &USE_SPI); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //STM32 "blue pill" - SPI1 - OK 85 | //ADS1256 A(PB10, PB11, ADS1256::PIN_UNUSED, PB12, 2.500, &USE_SPI); // DRDY, RESET, SYNC, CS, VREF, SPI //STM32 "blue pill" - SPI2 - OK 86 | 87 | long rawConversion = 0; //24-bit raw value 88 | float voltageValue = 0; //human-readable floating point value 89 | 90 | int singleEndedChannels[8] = { SING_0, SING_1, SING_2, SING_3, SING_4, SING_5, SING_6, SING_7 }; //Array to store the single-ended channels 91 | int differentialChannels[4] = { DIFF_0_1, DIFF_2_3, DIFF_4_5, DIFF_6_7 }; //Array to store the differential channels 92 | int inputChannel = 0; //Number used to pick the channel from the above two arrays 93 | char inputMode = ' '; //can be 's' and 'd': single-ended and differential 94 | 95 | int pgaValues[7] = { PGA_1, PGA_2, PGA_4, PGA_8, PGA_16, PGA_32, PGA_64 }; //Array to store the PGA settings 96 | int pgaSelection = 0; //Number used to pick the PGA value from the above array 97 | 98 | int drateValues[16] = { 99 | DRATE_30000SPS, 100 | DRATE_15000SPS, 101 | DRATE_7500SPS, 102 | DRATE_3750SPS, 103 | DRATE_2000SPS, 104 | DRATE_1000SPS, 105 | DRATE_500SPS, 106 | DRATE_100SPS, 107 | DRATE_60SPS, 108 | DRATE_50SPS, 109 | DRATE_30SPS, 110 | DRATE_25SPS, 111 | DRATE_15SPS, 112 | DRATE_10SPS, 113 | DRATE_5SPS, 114 | DRATE_2SPS 115 | }; //Array to store the sampling rates 116 | 117 | int drateSelection = 0; //Number used to pick the sampling rate from the above array 118 | 119 | String registers[11] = { 120 | "STATUS", 121 | "MUX", 122 | "ADCON", 123 | "DRATE", 124 | "IO", 125 | "OFC0", 126 | "OFC1", 127 | "OFC2", 128 | "FSC0", 129 | "FSC1", 130 | "FSC2" 131 | }; //Array to store the registers 132 | 133 | int registerToRead = 0; //Register number to be read 134 | int registerToWrite = 0; //Register number to be written 135 | int registerValueToWrite = 0; //Value to be written in the selected register 136 | 137 | void setup() { 138 | Serial.begin(115200); //The value does not matter if you use an MCU with native USB 139 | 140 | while (!Serial) { 141 | ; //Wait until the serial becomes available 142 | } 143 | 144 | Serial.println("ADS1256 - Custom Library Demo File by Curious Scientist - 2025-05-28"); 145 | 146 | #if defined(ARDUINO_ARCH_RP2040) //If RP2040 is used, we need to pass the SPI pins 147 | SPI.setSCK(SPI_SCK); 148 | SPI.setTX(SPI_MOSI); 149 | SPI.setRX(SPI_MISO); 150 | #endif 151 | 152 | #if defined(USE_HSPI) //If ESP32 is used, we need to start SPI with a non-strapping MISO pin 153 | hspi.begin(14, 25, 13); //SCK, MISO (safe), MOSI 154 | #endif 155 | 156 | A.InitializeADC(); //See the documentation for every details 157 | //Setting up CS, RESET, SYNC and SPI 158 | //Assigning default values to: STATUS, MUX, ADCON, DRATE 159 | //Performing a SYSCAL 160 | 161 | //Below is a demonstration to change the values through the built-on functions of the library 162 | //Set a PGA value 163 | A.setPGA(PGA_1); //0b00000000 - DEC: 0 164 | //-------------------------------------------- 165 | 166 | //Set input channels 167 | A.setMUX(DIFF_6_7); //0b01100111 - DEC: 103 168 | //-------------------------------------------- 169 | 170 | //Set DRATE 171 | A.setDRATE(DRATE_5SPS); //0b00010011 - DEC: 19 172 | //-------------------------------------------- 173 | 174 | //Read back the above 3 values to check if the writing was succesful 175 | Serial.print("PGA: "); 176 | Serial.println(A.getPGA()); 177 | delay(100); 178 | //-- 179 | Serial.print("MUX: "); 180 | Serial.println(A.readRegister(MUX_REG)); 181 | delay(100); 182 | //-- 183 | Serial.print("DRATE: "); 184 | Serial.println(A.readRegister(DRATE_REG)); 185 | delay(100); 186 | 187 | //Freeze the display for 3 sec 188 | delay(3000); 189 | } 190 | 191 | void loop() { 192 | /* Here I implemented some typical functions that can be useful for using the ADS1256 193 | Changing the registers by the built-in functions or by directly writing the registers 194 | Reading the registers to check the value of it 195 | Read a single conversion 196 | Read a single channel continuously 197 | Read multiple channels continuously 198 | Stop the conversion 199 | ...etc. 200 | All the above things are done through the serial port, the use only has to send certain commands 201 | */ 202 | 203 | 204 | if (Serial.available() > 0) { 205 | char commandCharacter = Serial.read(); //we use characters (letters) for controlling the switch-case 206 | 207 | switch (commandCharacter) //based on the command character, we decide what to do 208 | { 209 | case 's': //SDATAC - Stop Reading Data Continously 210 | A.stopConversion(); 211 | break; 212 | //-------------------------------------------------------------------------------------------------------- 213 | case 'L': //Perform a self calibration 214 | A.sendDirectCommand(SELFCAL); 215 | break; 216 | //-------------------------------------------------------------------------------------------------------- 217 | case 'G': //Read a single input continuously 218 | while (Serial.read() != 's') //The conversion is stopped by a character received from the serial port 219 | { 220 | Serial.println(A.convertToVoltage(A.readSingleContinuous()), 6); 221 | //The conversion is printed in Volts with 6 decimal digits 222 | //Note: Certain serial terminals cannot keep up with high speed datastream! 223 | } 224 | A.stopConversion(); 225 | break; 226 | //-------------------------------------------------------------------------------------------------------- 227 | case 'C': //Cycle single ended inputs (A0+GND, A1+GND ... A7+GND) 228 | while (Serial.read() != 's') //The conversion is stopped by a character received from the serial port 229 | { 230 | float channels[8]; //Buffer that holds 8 conversions (8 single-ended channels) 231 | for (int j = 0; j < 8; j++) { 232 | channels[j] = A.convertToVoltage(A.cycleSingle()); //store the converted single-ended results in the buffer 233 | } 234 | for (int i = 0; i < 8; i++) { 235 | Serial.print(channels[i], 4); //print the converted single-ended results with 4 digits 236 | 237 | if (i < 7) //Only printing tab between the first 7 conversions 238 | { 239 | Serial.print("\t"); //tab separator to separate the 8 conversions shown in the same line 240 | } 241 | } 242 | Serial.println(); //Printing a linebreak - this will put the next 8 conversions in a new line 243 | } 244 | A.stopConversion(); 245 | break; 246 | //-------------------------------------------------------------------------------------------------------- 247 | case 'D': //Cycle differential inputs (A0+A1, A2+A3, A4+A5, A6+A7) 248 | while (Serial.read() != 's') //The conversion is stopped by a character received from the serial port 249 | { 250 | float channels[4]; //Buffer that holds 4 conversions (4 differential channels) 251 | for (int j = 0; j < 4; j++) { 252 | channels[j] = A.convertToVoltage(A.cycleDifferential()); //store the converted differential results in the buffer 253 | } 254 | 255 | //After the 4 conversions are in the buffer, the contents are printed on the serial terminal 256 | for (int i = 0; i < 4; i++) { 257 | Serial.print(channels[i], 4); //print the converted differential results from the buffer 258 | 259 | if (i < 3) //Only printing tab between the first 3 conversions 260 | { 261 | Serial.print("\t"); //tab separator to separate the 4 conversions shown in the same line 262 | } 263 | } 264 | Serial.println(); //Printing a linebreak - this will put the next 4 conversions in a new line 265 | } 266 | A.stopConversion(); 267 | break; 268 | //-------------------------------------------------------------------------------------------------------- 269 | case 'B': //Speed test 270 | { 271 | //Variables to store and measure elapsed time and define the number of conversions 272 | long numberOfSamples = 30000; //Number of conversions 273 | long finishTime = 0; 274 | long startTime = micros(); 275 | 276 | for (long i = 0; i < numberOfSamples; i++) { 277 | A.readSingleContinuous(); 278 | //Note: here we just perform the readings and we don't print the results 279 | } 280 | 281 | finishTime = micros() - startTime; //Calculate the elapsed time 282 | 283 | A.stopConversion(); 284 | 285 | //Printing the results 286 | Serial.print("Total conversion time for 150k samples: "); 287 | Serial.print(finishTime); 288 | Serial.println(" us"); 289 | 290 | Serial.print("Sampling rate: "); 291 | Serial.print(numberOfSamples * (1000000.0 / finishTime), 3); 292 | Serial.println(" SPS"); 293 | } 294 | break; 295 | //-------------------------------------------------------------------------------------------------------- 296 | case 'T': //Testing the serial connection 297 | Serial.println("The serial connection is OK!"); 298 | break; 299 | //-------------------------------------------------------------------------------------------------------- 300 | case 'a': //Testing a single conversion - Only one single result is returned 301 | 302 | rawConversion = A.readSingle(); //Reading the raw value from a previously selected input, passing it to a variable 303 | voltageValue = A.convertToVoltage(rawConversion); //Converting the above conversion into a floating point number 304 | 305 | //Printing the results 306 | Serial.print("Single-ended conversion result: "); 307 | Serial.println(voltageValue, 8); //Print the floating point number with 8 digits. 308 | break; 309 | //-------------------------------------------------------------------------------------------------------- 310 | case 'M': //set MUX 311 | { 312 | while (!Serial.available()); 313 | inputMode = Serial.read(); //Read the input mode 314 | 315 | if (inputMode == 's') //single-ended 316 | { 317 | while (!Serial.available()); 318 | inputChannel = Serial.parseInt(); 319 | A.setMUX(singleEndedChannels[inputChannel]); 320 | //Example: "Ms1" selects the SING_1 as input channel 321 | } 322 | 323 | if (inputMode == 'd') //differential 324 | { 325 | while (!Serial.available()); 326 | inputChannel = Serial.parseInt(); 327 | A.setMUX(differentialChannels[inputChannel]); 328 | //Example: "Md0" selects the DIFF_0_1 as input channel 329 | } 330 | } 331 | break; 332 | //-------------------------------------------------------------------------------------------------------- 333 | case 'P': //Set PGA 334 | { 335 | while (!Serial.available()); 336 | pgaSelection = Serial.parseInt(); 337 | A.setPGA(pgaValues[pgaSelection]); 338 | //Example: P4 will select the PGA = 16 339 | Serial.print("PGA value: "); 340 | Serial.println(A.getPGA()); //Read the PGA from the register and print it 341 | } 342 | break; 343 | //-------------------------------------------------------------------------------------------------------- 344 | case 'F': //Set sampling frequency 345 | { 346 | while (!Serial.available()); 347 | drateSelection = Serial.parseInt(); //Parse the number (item number in the array) 348 | delay(100); 349 | Serial.print("DRATE is selected as: "); 350 | Serial.println(drateValues[drateSelection]); //Print the value from the array 351 | delay(100); 352 | A.setDRATE(drateValues[drateSelection]); //Pass the value to the register on the ADS1256 353 | delay(100); 354 | Serial.print("DRATE is set to "); 355 | Serial.println(A.readRegister(DRATE_REG)); //Read the register to see if the value was updated correctly 356 | //Example: F3 will make the DRATE = 3750 SPS 357 | } 358 | break; 359 | //-------------------------------------------------------------------------------------------------------- 360 | case 'R': //read register 361 | { 362 | while (!Serial.available()); 363 | registerToRead = Serial.parseInt(); //This part reads the number of the register from the serial port 364 | Serial.print("Value of "); 365 | Serial.print(registers[registerToRead]); 366 | Serial.print(" register is: "); 367 | Serial.println(A.readRegister(registerToRead)); 368 | //Example: "R2" will read the register at address 2 which is the ADCON register 369 | //Note: The value is printed as a decimal number 370 | } 371 | break; 372 | //-------------------------------------------------------------------------------------------------------- 373 | case 'W': //Write register 374 | { 375 | while (!Serial.available()); 376 | registerToWrite = Serial.parseInt(); //This part reads the number of the register from the serial port 377 | while (!Serial.available()); 378 | registerValueToWrite = Serial.parseInt(); //This part reads the value of the register from the serial port 379 | 380 | A.writeRegister(registerToWrite, registerValueToWrite); 381 | //Example: "W1 35" will write 35 ("00100011") on register 1 which is the MUX register. 382 | //This will make the input as DIFF_2_3 (A2(+) & A1(-)) 383 | } 384 | break; 385 | //-------------------------------------------------------------------------------------------------------- 386 | } 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /src/ADS1256.cpp: -------------------------------------------------------------------------------- 1 | //ADS1256 cpp file 2 | /* 3 | Name: ADS1256.cpp 4 | Created: 2022/07/14 5 | Author: Curious Scientist 6 | Editor: Notepad++ 7 | Comment: Visit https://curiousscientist.tech/blog/ADS1256-custom-library 8 | Special thanks to: 9 | Abraão Queiroz for spending time on the code and suggesting corrections for ESP32 microcontrollers 10 | Benjamin Pelletier for pointing out and fixing an issue around the handling of the DRDY signal 11 | RadoMmm for suggesting an improvement on the ADC-to-Volts conversion 12 | */ 13 | 14 | #include "Arduino.h" 15 | #include "ADS1256.h" 16 | #include "SPI.h" 17 | 18 | #define convertSigned24BitToLong(value) ((value) & (1l << 23) ? (value) - 0x1000000 : value) 19 | 20 | //Constructor 21 | ADS1256::ADS1256(const int8_t DRDY_pin, const int8_t RESET_pin, const int8_t SYNC_pin, const int8_t CS_pin,float VREF, SPIClass* spi): _spi(spi), 22 | _DRDY_pin(DRDY_pin), _RESET_pin(RESET_pin), _SYNC_pin(SYNC_pin), _CS_pin(CS_pin), _VREF(VREF), _PGA(0) 23 | { 24 | pinMode(_DRDY_pin, INPUT); 25 | 26 | if(RESET_pin != PIN_UNUSED) 27 | { 28 | pinMode(_RESET_pin, OUTPUT); 29 | } 30 | 31 | if(SYNC_pin != PIN_UNUSED) 32 | { 33 | pinMode(_SYNC_pin, OUTPUT); 34 | } 35 | 36 | if(CS_pin != PIN_UNUSED) 37 | { 38 | pinMode(_CS_pin, OUTPUT); 39 | } 40 | 41 | updateConversionParameter(); 42 | } 43 | 44 | //Initialization 45 | void ADS1256::InitializeADC() 46 | { 47 | //Chip select LOW 48 | CS_LOW(); 49 | 50 | //We do a manual chip reset on the ADS1256 - Datasheet Page 27/ RESET 51 | if(_RESET_pin != PIN_UNUSED) 52 | { 53 | digitalWrite(_RESET_pin, LOW); 54 | delay(200); 55 | digitalWrite(_RESET_pin, HIGH); //RESET is set to high 56 | delay(1000); 57 | } 58 | 59 | //Sync pin is also treated if it is defined 60 | if(_SYNC_pin != PIN_UNUSED) 61 | { 62 | digitalWrite(_SYNC_pin, HIGH); //RESET is set to high 63 | } 64 | 65 | #ifndef ADS1256_SPI_ALREADY_STARTED //Guard macro to allow external initialization of the SPI 66 | _spi->begin(); 67 | #endif 68 | 69 | //Applying arbitrary default values to speed up the starting procedure if the user just want to get quick readouts 70 | //We both pass values to the variables and then send those values to the corresponding registers 71 | delay(200); 72 | 73 | _STATUS = 0b00110110; //BUFEN and ACAL enabled, Order is MSB, rest is read only 74 | writeRegister(STATUS_REG, _STATUS); 75 | delay(200); 76 | 77 | _MUX = 0b00000001; //MUX AIN0+AIN1 78 | writeRegister(MUX_REG, _MUX); 79 | delay(200); 80 | 81 | _ADCON = 0b00000000; //ADCON - CLK: OFF, SDCS: OFF, PGA = 0 (+/- 5 V) 82 | writeRegister(ADCON_REG, _ADCON); 83 | delay(200); 84 | 85 | updateConversionParameter(); 86 | 87 | _DRATE = 0b10000010; //100SPS 88 | writeRegister(DRATE_REG, _DRATE); 89 | delay(200); 90 | 91 | sendDirectCommand(0b11110000); //Offset and self-gain calibration 92 | delay(200); 93 | 94 | _isAcquisitionRunning = false; //MCU will be waiting to start a continuous acquisition 95 | } 96 | 97 | void ADS1256::waitForLowDRDY() 98 | { 99 | while (digitalRead(_DRDY_pin) == HIGH) {} 100 | } 101 | 102 | void ADS1256::waitForHighDRDY() 103 | { 104 | #if F_CPU >= 48000000 //Fast MCUs need this protection to wait until DRDY goes high after a conversion 105 | while (digitalRead(_DRDY_pin) == LOW) {} 106 | #endif 107 | } 108 | 109 | void ADS1256::stopConversion() //Sending SDATAC to stop the continuous conversion 110 | { 111 | waitForLowDRDY(); //SDATAC should be called after DRDY goes LOW (p35. Figure 33) 112 | _spi->transfer(0b00001111); //Send SDATAC to the ADC 113 | CS_HIGH(); //We finished the command sequence, so we switch it back to HIGH 114 | _spi->endTransaction(); 115 | 116 | _isAcquisitionRunning = false; //Reset to false, so the MCU will be able to start a new conversion 117 | } 118 | 119 | void ADS1256::setDRATE(uint8_t drate) //Setting DRATE (sampling frequency) 120 | { 121 | writeRegister(DRATE_REG, drate); 122 | _DRATE = drate; 123 | delay(200); 124 | } 125 | 126 | void ADS1256::setMUX(uint8_t mux) //Setting MUX (input channel) 127 | { 128 | writeRegister(MUX_REG, mux); 129 | _MUX = mux; 130 | delay(200); 131 | } 132 | 133 | void ADS1256::setPGA(uint8_t pga) //Setting PGA (input voltage range) 134 | { 135 | _PGA = pga; 136 | _ADCON = readRegister(ADCON_REG); //Read the most recent value of the register 137 | 138 | _ADCON = (_ADCON & 0b11111000) | (_PGA & 0b00000111); // Clearing and then setting bits 2-0 based on pga 139 | 140 | writeRegister(ADCON_REG, _ADCON); 141 | delay(200); 142 | 143 | updateConversionParameter(); //Update the multiplier according top the new PGA value 144 | } 145 | 146 | uint8_t ADS1256::getPGA() //Reading PGA from the ADCON register 147 | { 148 | uint8_t pgaValue = readRegister(ADCON_REG) & 0b00000111; 149 | //Reading the ADCON_REG and keeping the first three bits. 150 | 151 | return(pgaValue); 152 | } 153 | 154 | void ADS1256::setCLKOUT(uint8_t clkout) //Setting CLKOUT 155 | { 156 | _ADCON = readRegister(ADCON_REG); //Read the most recent value of the register 157 | 158 | //Values: 0, 1, 2, 3 159 | 160 | if(clkout == 0) 161 | { 162 | //00 163 | bitWrite(_ADCON, 6, 0); 164 | bitWrite(_ADCON, 5, 0); 165 | } 166 | else if(clkout == 1) 167 | { 168 | //01 (default) 169 | bitWrite(_ADCON, 6, 0); 170 | bitWrite(_ADCON, 5, 1); 171 | } 172 | else if(clkout == 2) 173 | { 174 | //10 175 | bitWrite(_ADCON, 6, 1); 176 | bitWrite(_ADCON, 5, 0); 177 | } 178 | else if(clkout == 3) 179 | { 180 | //11 181 | bitWrite(_ADCON, 6, 1); 182 | bitWrite(_ADCON, 5, 1); 183 | } 184 | else{} 185 | 186 | writeRegister(ADCON_REG, _ADCON); 187 | delay(100); 188 | } 189 | 190 | void ADS1256::setSDCS(uint8_t sdcs) //Setting SDCS 191 | { 192 | _ADCON = readRegister(ADCON_REG); //Read the most recent value of the register 193 | 194 | //Values: 0, 1, 2, 3 195 | 196 | if(sdcs == 0) 197 | { 198 | //00 (default) 199 | bitWrite(_ADCON, 4, 0); 200 | bitWrite(_ADCON, 3, 0); 201 | } 202 | else if(sdcs == 1) 203 | { 204 | //01 205 | bitWrite(_ADCON, 4, 0); 206 | bitWrite(_ADCON, 3, 1); 207 | } 208 | else if(sdcs == 2) 209 | { 210 | //10 211 | bitWrite(_ADCON, 4, 1); 212 | bitWrite(_ADCON, 3, 0); 213 | } 214 | else if(sdcs == 3) 215 | { 216 | //11 217 | bitWrite(_ADCON, 4, 1); 218 | bitWrite(_ADCON, 3, 1); 219 | } 220 | else{} 221 | 222 | writeRegister(ADCON_REG, _ADCON); 223 | delay(100); 224 | } 225 | 226 | void ADS1256::setByteOrder(uint8_t byteOrder) //Setting byte order (MSB/LSB) 227 | { 228 | _STATUS = readRegister(STATUS_REG); //Read the most recent value of the register 229 | 230 | if(byteOrder == 0) 231 | { 232 | //Byte order is MSB (default) 233 | bitWrite(_STATUS, 3, 0); 234 | //Set value of _STATUS at the third bit to 0 235 | } 236 | else if(byteOrder == 1) 237 | { 238 | //Byte order is LSB 239 | bitWrite(_STATUS, 3, 1); 240 | //Set value of _STATUS at the third bit to 1 241 | } 242 | else{} 243 | 244 | writeRegister(STATUS_REG, _STATUS); 245 | delay(100); 246 | } 247 | 248 | uint8_t ADS1256::getByteOrder() //Getting byte order (MSB/LSB) 249 | { 250 | uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register 251 | 252 | return bitRead(statusValue, 3); 253 | } 254 | 255 | void ADS1256::setAutoCal(uint8_t acal) //Setting ACAL (Automatic SYSCAL) 256 | { 257 | _STATUS = readRegister(STATUS_REG); //Read the most recent value of the register 258 | 259 | if(acal == 0) 260 | { 261 | //Auto-calibration is disabled (default) 262 | bitWrite(_STATUS, 2, 0); 263 | //_STATUS |= B00000000; 264 | } 265 | else if(acal == 1) 266 | { 267 | //Auto-calibration is enabled 268 | bitWrite(_STATUS, 2, 1); 269 | //_STATUS |= B00000100; 270 | } 271 | else{} 272 | 273 | writeRegister(STATUS_REG, _STATUS); 274 | delay(100); 275 | } 276 | 277 | uint8_t ADS1256::getAutoCal() //Getting ACAL (Automatic SYSCAL) 278 | { 279 | uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register 280 | 281 | return bitRead(statusValue, 2); 282 | } 283 | 284 | void ADS1256::setBuffer(uint8_t bufen) //Setting input buffer (Input impedance) 285 | { 286 | _STATUS = readRegister(STATUS_REG); //Read the most recent value of the register 287 | 288 | if(bufen == 0) 289 | { 290 | //Analog input buffer is disabled (default) 291 | //_STATUS |= B00000000; 292 | bitWrite(_STATUS, 1, 0); 293 | } 294 | else if(bufen == 1) 295 | { 296 | //Analog input buffer is enabled (recommended) 297 | //_STATUS |= B00000010; 298 | bitWrite(_STATUS, 1, 1); 299 | } 300 | else{} 301 | 302 | writeRegister(STATUS_REG, _STATUS); 303 | delay(100); 304 | } 305 | 306 | uint8_t ADS1256::getBuffer() //Getting input buffer (Input impedance) 307 | { 308 | uint8_t statusValue = readRegister(STATUS_REG); //Read the whole STATUS register 309 | 310 | return bitRead(statusValue, 1); 311 | } 312 | 313 | void ADS1256::setGPIO(uint8_t dir0, uint8_t dir1, uint8_t dir2, uint8_t dir3) //Setting GPIO 314 | { 315 | _GPIO = readRegister(IO_REG); //Read the most recent value of the register 316 | 317 | //Default: 11100000 - DEC: 224 - Ref: p32 I/O section 318 | //Sets D3-D0 as input or output 319 | uint8_t GPIO_bit7, GPIO_bit6, GPIO_bit5, GPIO_bit4; 320 | 321 | //Bit7: DIR3 322 | if(dir3 == 1) 323 | { 324 | GPIO_bit7 = 1; //D3 is input (default) 325 | } 326 | else 327 | { 328 | GPIO_bit7 = 0; //D3 is output 329 | } 330 | bitWrite(_GPIO, 7, GPIO_bit7); 331 | //----------------------------------------------------- 332 | //Bit6: DIR2 333 | if(dir2 == 1) 334 | { 335 | GPIO_bit6 = 1; //D2 is input (default) 336 | } 337 | else 338 | { 339 | GPIO_bit6 = 0; //D2 is output 340 | } 341 | bitWrite(_GPIO, 6, GPIO_bit6); 342 | //----------------------------------------------------- 343 | //Bit5: DIR1 344 | if(dir1 == 1) 345 | { 346 | GPIO_bit5 = 1; //D1 is input (default) 347 | } 348 | else 349 | { 350 | GPIO_bit5 = 0; //D1 is output 351 | } 352 | bitWrite(_GPIO, 5, GPIO_bit5); 353 | //----------------------------------------------------- 354 | //Bit4: DIR0 355 | if(dir0 == 1) 356 | { 357 | GPIO_bit4 = 1; //D0 is input 358 | } 359 | else 360 | { 361 | GPIO_bit4 = 0; //D0 is output (default) 362 | } 363 | bitWrite(_GPIO, 4, GPIO_bit4); 364 | //----------------------------------------------------- 365 | 366 | writeRegister(IO_REG, _GPIO); 367 | delay(100); 368 | } 369 | 370 | void ADS1256::writeGPIO(uint8_t dir0value, uint8_t dir1value, uint8_t dir2value, uint8_t dir3value) //Writing GPIO 371 | { 372 | _GPIO = readRegister(IO_REG); 373 | 374 | //Sets D3-D0 output values 375 | //It is important that first one must use setGPIO, then writeGPIO 376 | 377 | uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0; 378 | 379 | //Bit3: DIR3 380 | if(dir3value == 1) 381 | { 382 | GPIO_bit3 = 1; 383 | } 384 | else 385 | { 386 | GPIO_bit3 = 0; 387 | } 388 | bitWrite(_GPIO, 3, GPIO_bit3); 389 | //----------------------------------------------------- 390 | //Bit2: DIR2 391 | if(dir2value == 1) 392 | { 393 | GPIO_bit2 = 1; 394 | } 395 | else 396 | { 397 | GPIO_bit2 = 0; 398 | } 399 | bitWrite(_GPIO, 2, GPIO_bit2); 400 | //----------------------------------------------------- 401 | //Bit1: DIR1 402 | if(dir1value == 1) 403 | { 404 | GPIO_bit1 = 1; 405 | } 406 | else 407 | { 408 | GPIO_bit1 = 0; 409 | } 410 | bitWrite(_GPIO, 1, GPIO_bit1); 411 | //----------------------------------------------------- 412 | //Bit0: DIR0 413 | if(dir0value == 1) 414 | { 415 | GPIO_bit0 = 1; 416 | } 417 | else 418 | { 419 | GPIO_bit0 = 0; 420 | } 421 | bitWrite(_GPIO, 0, GPIO_bit0); 422 | //----------------------------------------------------- 423 | 424 | writeRegister(IO_REG, _GPIO); 425 | delay(100); 426 | } 427 | 428 | uint8_t ADS1256::readGPIO(uint8_t gpioPin) //Reading GPIO 429 | { 430 | uint8_t GPIO_bit3, GPIO_bit2, GPIO_bit1, GPIO_bit0, GPIO_return; 431 | 432 | _GPIO = readRegister(IO_REG); //Read the GPIO register 433 | 434 | //Save each bit values in a variable 435 | GPIO_bit3 = bitRead(_GPIO, 3); 436 | GPIO_bit2 = bitRead(_GPIO, 2); 437 | GPIO_bit1 = bitRead(_GPIO, 1); 438 | GPIO_bit0 = bitRead(_GPIO, 0); 439 | 440 | delay(100); 441 | 442 | switch(gpioPin) //Selecting which value should be returned 443 | { 444 | case 0: 445 | GPIO_return = GPIO_bit0; 446 | break; 447 | 448 | case 1: 449 | GPIO_return = GPIO_bit1; 450 | break; 451 | 452 | case 2: 453 | GPIO_return = GPIO_bit2; 454 | break; 455 | 456 | case 3: 457 | GPIO_return = GPIO_bit3; 458 | break; 459 | } 460 | 461 | return GPIO_return; 462 | 463 | } 464 | 465 | void ADS1256::sendDirectCommand(uint8_t directCommand) 466 | { 467 | //Direct commands can be found in the datasheet Page 34, Table 24. 468 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 469 | 470 | CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence" 471 | delayMicroseconds(5); 472 | _spi->transfer(directCommand); //Send Command 473 | delayMicroseconds(5); 474 | CS_HIGH(); //REF: P34: "CS must stay low during the entire command sequence" 475 | 476 | _spi->endTransaction(); 477 | } 478 | 479 | 480 | float ADS1256::convertToVoltage(int32_t rawData) //Converting the 24-bit data into a voltage value 481 | { 482 | return(conversionParameter * rawData); 483 | } 484 | 485 | void ADS1256::writeRegister(uint8_t registerAddress, uint8_t registerValueToWrite) 486 | { 487 | waitForLowDRDY(); 488 | 489 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 490 | //SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1. 491 | 492 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 493 | 494 | delayMicroseconds(5); //see t6 in the datasheet 495 | 496 | _spi->transfer(0x50 | registerAddress); // 0x50 = 01010000 = WREG 497 | 498 | _spi->transfer(0x00); //2nd (empty) command byte 499 | 500 | _spi->transfer(registerValueToWrite); //pass the value to the register 501 | 502 | CS_HIGH(); 503 | _spi->endTransaction(); 504 | delay(100); 505 | 506 | } 507 | 508 | long ADS1256::readRegister(uint8_t registerAddress) //Reading a register 509 | { 510 | waitForLowDRDY(); 511 | 512 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 513 | //SPI_MODE1 = output edge: rising, data capture: falling; clock polarity: 0, clock phase: 1. 514 | 515 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 516 | 517 | _spi->transfer(0x10 | registerAddress); //0x10 = 0001000 = RREG - OR together the two numbers (command + address) 518 | 519 | _spi->transfer(0x00); //2nd (empty) command byte 520 | 521 | delayMicroseconds(5); //see t6 in the datasheet 522 | 523 | uint8_t regValue = _spi->transfer(0xFF); //read out the register value 524 | 525 | CS_HIGH(); 526 | _spi->endTransaction(); 527 | delay(100); 528 | return regValue; 529 | } 530 | 531 | 532 | long ADS1256::readSingle() //Reading a single value ONCE using the RDATA command 533 | { 534 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 535 | CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence" 536 | waitForLowDRDY(); 537 | _spi->transfer(0b00000001); //Issue RDATA (0000 0001) command 538 | delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30. 539 | 540 | _outputBuffer[0] = _spi->transfer(0); // MSB 541 | _outputBuffer[1] = _spi->transfer(0); // Mid-byte 542 | _outputBuffer[2] = _spi->transfer(0); // LSB 543 | 544 | //Shifting and combining the above three items into a single, 24-bit number 545 | _outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]); 546 | _outputValue = convertSigned24BitToLong(_outputValue); 547 | 548 | CS_HIGH(); //We finished the command sequence, so we set CS to HIGH 549 | _spi->endTransaction(); 550 | 551 | return(_outputValue); 552 | } 553 | 554 | long ADS1256::readSingleContinuous() //Reads the recently selected input channel using RDATAC 555 | { 556 | if(_isAcquisitionRunning == false) 557 | { 558 | _isAcquisitionRunning = true; 559 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 560 | CS_LOW(); //REF: P34: "CS must stay low during the entire command sequence" 561 | waitForLowDRDY(); 562 | _spi->transfer(0b00000011); //Issue RDATAC (0000 0011) 563 | delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30. 564 | } 565 | else 566 | { 567 | waitForLowDRDY(); 568 | } 569 | 570 | _outputBuffer[0] = _spi->transfer(0); // MSB 571 | _outputBuffer[1] = _spi->transfer(0); // Mid-byte 572 | _outputBuffer[2] = _spi->transfer(0); // LSB 573 | 574 | _outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]); 575 | _outputValue = convertSigned24BitToLong(_outputValue); 576 | 577 | waitForHighDRDY(); 578 | 579 | return _outputValue; 580 | } 581 | 582 | long ADS1256::cycleSingle() 583 | { 584 | if(_isAcquisitionRunning == false) 585 | { 586 | _isAcquisitionRunning = true; 587 | _cycle = 0; 588 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 589 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 590 | _spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX 591 | _spi->transfer(0x00); 592 | _spi->transfer(SING_0); //AIN0+AINCOM 593 | CS_HIGH(); 594 | delay(50); 595 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 596 | } 597 | else 598 | {} 599 | 600 | if(_cycle < 8) 601 | { 602 | _outputValue = 0; 603 | waitForLowDRDY(); 604 | //Step 1. - Updating MUX 605 | switch (_cycle) 606 | { 607 | //Channels are written manually 608 | case 0: //Channel 2 609 | updateMUX(SING_1); //AIN1+AINCOM 610 | break; 611 | 612 | case 1: //Channel 3 613 | updateMUX(SING_2); //AIN2+AINCOM 614 | break; 615 | 616 | case 2: //Channel 4 617 | updateMUX(SING_3); //AIN3+AINCOM 618 | break; 619 | 620 | case 3: //Channel 5 621 | updateMUX(SING_4); //AIN4+AINCOM 622 | break; 623 | 624 | case 4: //Channel 6 625 | updateMUX(SING_5); //AIN5+AINCOM 626 | break; 627 | 628 | case 5: //Channel 7 629 | updateMUX(SING_6); //AIN6+AINCOM 630 | break; 631 | 632 | case 6: //Channel 8 633 | updateMUX(SING_7); //AIN7+AINCOM 634 | break; 635 | 636 | case 7: //Channel 1 637 | updateMUX(SING_0); //AIN0+AINCOM 638 | break; 639 | } 640 | //Step 2. 641 | _spi->transfer(0b11111100); //SYNC 642 | delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us 643 | _spi->transfer(0b11111111); //WAKEUP 644 | 645 | //Step 3. 646 | //Issue RDATA (0000 0001) command 647 | _spi->transfer(0b00000001); 648 | delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30. 649 | 650 | _outputBuffer[0] = _spi->transfer(0x0F); // MSB 651 | _outputBuffer[1] = _spi->transfer(0x0F); // Mid-byte 652 | _outputBuffer[2] = _spi->transfer(0x0F); // LSB 653 | 654 | _outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]); 655 | _outputValue = convertSigned24BitToLong(_outputValue); 656 | 657 | _cycle++; //Increase cycle - This will move to the next MUX input channel 658 | if(_cycle == 8) 659 | { 660 | _cycle = 0; //Reset to 0 - Restart conversion from the 1st input channel 661 | } 662 | } 663 | 664 | return _outputValue; 665 | } 666 | 667 | long ADS1256::cycleDifferential() 668 | { 669 | if(_isAcquisitionRunning == false) 670 | { 671 | _cycle = 0; 672 | _isAcquisitionRunning = true; 673 | _spi->beginTransaction(SPISettings(1920000, MSBFIRST, SPI_MODE1)); 674 | 675 | //Set the AIN0+AIN1 as inputs manually 676 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 677 | _spi->transfer(0x50 | 1); // 0x50 = WREG //1 = MUX 678 | _spi->transfer(0x00); 679 | _spi->transfer(DIFF_0_1); //AIN0+AIN1 680 | CS_HIGH(); 681 | delay(50); 682 | CS_LOW(); //CS must stay LOW during the entire sequence [Ref: P34, T24] 683 | } 684 | else 685 | {} 686 | 687 | if(_cycle < 4) 688 | { 689 | _outputValue = 0; 690 | //DRDY has to go low 691 | waitForLowDRDY(); 692 | 693 | //Step 1. - Updating MUX 694 | switch (_cycle) 695 | { 696 | case 0: //Channel 2 697 | updateMUX(DIFF_2_3); //AIN2+AIN3 698 | break; 699 | 700 | case 1: //Channel 3 701 | updateMUX(DIFF_4_5); //AIN4+AIN5 702 | break; 703 | 704 | case 2: //Channel 4 705 | updateMUX(DIFF_6_7); //AIN6+AIN7 706 | break; 707 | 708 | case 3: //Channel 1 709 | updateMUX(DIFF_0_1); //AIN0+AIN1 710 | break; 711 | } 712 | 713 | _spi->transfer(0b11111100); //SYNC 714 | delayMicroseconds(4); //t11 delay 24*tau = 3.125 us //delay should be larger, so we delay by 4 us 715 | _spi->transfer(0b11111111); //WAKEUP 716 | 717 | //Step 3. 718 | _spi->transfer(0b00000001); //Issue RDATA (0000 0001) command 719 | delayMicroseconds(7); //Wait t6 time (~6.51 us) REF: P34, FIG:30. 720 | 721 | _outputBuffer[0] = _spi->transfer(0); // MSB 722 | _outputBuffer[1] = _spi->transfer(0); // Mid-byte 723 | _outputBuffer[2] = _spi->transfer(0); // LSB 724 | 725 | _outputValue = ((long)_outputBuffer[0]<<16) | ((long)_outputBuffer[1]<<8) | (_outputBuffer[2]); 726 | _outputValue = convertSigned24BitToLong(_outputValue); 727 | 728 | _cycle++; 729 | if(_cycle == 4) 730 | { 731 | _cycle = 0; 732 | //After the 4th cycle, we reset to zero so the next iteration reads the 1st MUX again 733 | } 734 | } 735 | 736 | return _outputValue; 737 | } 738 | 739 | void ADS1256::updateConversionParameter() 740 | { 741 | conversionParameter = ((2.0 * _VREF) / 8388608.0) / (pow(2, _PGA)); //Calculate the "bit to Volts" multiplier 742 | //8388608 = 2^{23} - 1, REF: p23, Table 16. 743 | } 744 | 745 | void ADS1256::updateMUX(uint8_t muxValue) 746 | { 747 | _spi->transfer(0x50 | MUX_REG); //Write to the MUX register (0x50 is the WREG command) 748 | _spi->transfer(0x00); 749 | _spi->transfer(muxValue); //Write the new MUX value 750 | } 751 | 752 | inline void ADS1256::CS_LOW() 753 | { 754 | if (_CS_pin != PIN_UNUSED) //Sets CS LOW if it is not an unused pin 755 | { 756 | digitalWrite(_CS_pin, LOW); 757 | } 758 | } 759 | 760 | inline void ADS1256::CS_HIGH() 761 | { 762 | if (_CS_pin != PIN_UNUSED) //Sets CS HIGH if it is not an unused pin 763 | { 764 | digitalWrite(_CS_pin, HIGH); 765 | } 766 | } --------------------------------------------------------------------------------