Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions cpp-rpi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ADS1220

### C++ example (for Raspberry Pi)

##### Prerequisites
- Install [WiringPi](http://wiringpi.com);
- Install [spidev-lib++](https://github.com/milekium/spidev-lib).

##### Wiring

All pins numbers are referring to the physical number.

| Raspberry Pi | ADS1220 breakout | Note
|----------------|------------------|-
| Pin 13 | DRDY | Or other GPIO pin
| Pin 21 (MISO) | MISO |
| Pin 19 (MOSI) | MOSI |
| Pin 23 (SCLK) | SCLK |
| Pin 18 | CS | Or other GPIO pin
| GND | CLK |
| 3.3V | DVDD |
| GND | DGND |
| 3.3V | AVDD |
| GND | AGND |
| N/A | REFN0 / REFP0 | Floating
| N/A | AIN0-3 | Connect your inputs (e.g. pot)

##### Compile & run

```
g++ -std=c++20 -o ads example.cpp ads1220.cpp -lspidev-lib++ -lwiringPi
./ads
```
178 changes: 178 additions & 0 deletions cpp-rpi/ads1220.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#include "ads1220.h"

#include <unistd.h>
#include <iostream>

#include <spidev_lib++.h>
#include <wiringPi.h>

using namespace std;

Ads1220::Ads1220(int csPin, int drdyPin) : _csPin(csPin), _drdyPin(drdyPin) {
pinMode(csPin, OUTPUT);
pinMode(drdyPin, INPUT);

string spidevPath = "/dev/spidev0.1";
spi = new SPI(spidevPath.c_str());
if (!spi->begin()) {
cerr << "Could't init SPI on path " << spidevPath << endl;
exit(1);
}
spi->setMode(1);
spi->setSpeed(50000);
spi->setBitPerWord(8);

sendSpiCommand(SpiCommand::RESET, 0);
usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(csPin, LOW);

writeRegister(REG0_ADDR, _configReg0);
writeRegister(REG1_ADDR, _configReg1);
writeRegister(REG2_ADDR, _configReg2);
writeRegister(REG3_ADDR, _configReg3);

setPgaBypass(true);
setDataRate(DataRate::SPS_1000);
setOperatingMode(OperatingMode::TURBO);
setConversionMode(ConversionMode::CONTINUOUS);
setVoltageReferenceSource(VoltageReferenceSource::ANALOG_SUPPLY_AVDD_AVSS);

usleep(_sleepBetweenCommandsInMicroSeconds);
cout << "Initialised SPI on " << spidevPath << " with config: "
<< int(readRegister(REG0_ADDR)) << ", " << int(readRegister(REG1_ADDR)) << ", "
<< int(readRegister(REG2_ADDR)) << ", " << int(readRegister(REG3_ADDR)) << endl;

digitalWrite(csPin, HIGH);

usleep(300000);
}

Ads1220::Ads1220() : Ads1220(DEFAULT_CS_PIN, DEFAULT_DRDY_PIN) {}

Ads1220::~Ads1220() {
delete spi;
}

uint32_t Ads1220::readValue(MultiplexerConfiguration configuration) {
selectMultiplexerConfiguration(configuration);
usleep(_sleepBetweenCommandsInMicroSeconds);

if (_singleShotMode) {
sendSpiCommand(SpiCommand::START, 0);
usleep(_sleepBetweenCommandsInMicroSeconds);
}

while (digitalRead(_drdyPin) != LOW) {
usleep(_sleepBetweenCommandsInMicroSeconds);
}

digitalWrite(_csPin, LOW);
usleep(_sleepBetweenCommandsInMicroSeconds);

spi->read(_rxBuffer + 0, 1);
spi->read(_rxBuffer + 1, 1);
spi->read(_rxBuffer + 2, 1);

uint32_t value = (_rxBuffer[0] << 16) | (_rxBuffer[1] << 8) | _rxBuffer[2];

digitalWrite(_csPin, HIGH);
usleep(_sleepBetweenCommandsInMicroSeconds);

return value;
}

uint32_t Ads1220::readUntilNewValue(MultiplexerConfiguration configuration, int32_t previousValue) {
while (true) {
uint32_t value = readValue(configuration) >> _shiftResultBy;
int32_t diff = value - previousValue;
if (value <= _maxResult && abs(diff) > _detectionThreshold) {
return value;
}
}
}

void Ads1220::setPgaGain(PgaGain gain) {
_configReg0 &= ~MASK_CONFIG_0_PGA_GAIN;
_configReg0 |= int(gain) << 1;
writeRegister(REG0_ADDR, _configReg0);
}

void Ads1220::setPgaBypass(bool bypass) {
_configReg0 &= ~MASK_CONFIG_0_PGA_BYPASS;
_configReg0 |= bypass;
writeRegister(REG0_ADDR, _configReg0);
}

void Ads1220::setDataRate(DataRate rate) {
_configReg1 &= ~MASK_CONFIG_1_DATA_RATE;
_configReg1 |= int(rate) << 5;
writeRegister(REG1_ADDR, _configReg1);
}

void Ads1220::setOperatingMode(OperatingMode mode) {
_configReg1 &= ~MASK_CONFIG_1_OPERATING_MODE;
_configReg1 |= int(mode) << 3;
writeRegister(REG1_ADDR, _configReg1);
}

void Ads1220::setConversionMode(ConversionMode mode) {
_configReg1 &= ~MASK_CONFIG_1_CONVERSION_MODE;
_configReg1 |= int(mode) << 2;
writeRegister(REG1_ADDR, _configReg1);
_singleShotMode = mode == ConversionMode::SINGLE_SHOT;
}

void Ads1220::setVoltageReferenceSource(VoltageReferenceSource source) {
_configReg2 &= ~MASK_CONFIG_2_VOLTAGE_REFERENCE;
_configReg2 |= int(source) << 6;
writeRegister(REG2_ADDR, _configReg2);
}

void Ads1220::sendSpiCommand(SpiCommand command, uint8_t payload) {
digitalWrite(_csPin, LOW);
usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(_csPin, HIGH);
usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(_csPin, LOW);
usleep(_sleepBetweenCommandsInMicroSeconds);

_txBuffer[0] = int(command) | payload;
spi->write(_txBuffer, 1);

usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(_csPin, HIGH);
}

void Ads1220::writeRegister(uint8_t addr, uint8_t data) {
digitalWrite(_csPin, LOW);
usleep(_sleepBetweenCommandsInMicroSeconds);

// 0100rrnn - rr=register address; nn=number bytes to write
_txBuffer[0] = int(SpiCommand::WREG) | (addr << 2);
_txBuffer[1] = data;
spi->write(_txBuffer, 2);

usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(_csPin, HIGH);
}

uint8_t Ads1220::readRegister(uint8_t addr) {
digitalWrite(_csPin, LOW);
usleep(_sleepBetweenCommandsInMicroSeconds);

// 0010rrnn - rr=register address; nn=number bytes to read
_txBuffer[0] = int(SpiCommand::RREG) | (addr << 2);
spi->write(_txBuffer, 1);
spi->read(_rxBuffer, 1);

usleep(_sleepBetweenCommandsInMicroSeconds);
digitalWrite(_csPin, HIGH);

return _rxBuffer[0];
}

void Ads1220::selectMultiplexerConfiguration(MultiplexerConfiguration configuration) {
_configReg0 &= ~MASK_CONFIG_0_MUX;
_configReg0 |= int(configuration) << 4;
writeRegister(REG0_ADDR, _configReg0);
}
139 changes: 139 additions & 0 deletions cpp-rpi/ads1220.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#pragma once

#include <cstdint>

class SPI;

class Ads1220 {
public:
Ads1220(int csPin, int drdyPin);
Ads1220();
~Ads1220();

enum MultiplexerConfiguration {
AIN0_SINGLE_ENDED = 0b1000,
AIN1_SINGLE_ENDED = 0b1001,
AIN2_SINGLE_ENDED = 0b1010,
AIN3_SINGLE_ENDED = 0b1011,
// Check the datasheet (section 8.6.1.1) for more configurations
};

enum PgaGain {
GAIN_1 = 0b000, // default
GAIN_2 = 0b001,
GAIN_4 = 0b010,
GAIN_8 = 0b011,
GAIN_16 = 0b100,
GAIN_32 = 0b101,
GAIN_64 = 0b110,
GAIN_128 = 0b111,
};

enum DataRate {
// SPS values are for the normal operating mode
SPS_20 = 0b000, // default
SPS_45 = 0b001,
SPS_90 = 0b010,
SPS_175 = 0b011,
SPS_330 = 0b100,
SPS_600 = 0b101,
SPS_1000 = 0b110,
};

enum OperatingMode {
NORMAL = 0b00, // default
DUTY_CYCLE = 0b01,
TURBO = 0b10,
};

enum ConversionMode {
SINGLE_SHOT = 0b0, // default
CONTINUOUS = 0b1,
};

enum VoltageReferenceSource {
INTERNAL_2048_mV = 0b00, // default
EXTERNAL_REFP0_REFN0 = 0b01,
EXTERNAL_AIN0_REFP1_AIN3_REFN1 = 0b10,
ANALOG_SUPPLY_AVDD_AVSS = 0b11,
};

uint32_t readValue(MultiplexerConfiguration configuration);
uint32_t readUntilNewValue(MultiplexerConfiguration configuration, int32_t previousValue);

void setPgaGain(PgaGain gain);
void setPgaBypass(bool bypass); // default: false (enabled)
void setDataRate(DataRate rate);
void setOperatingMode(OperatingMode mode);
void setConversionMode(ConversionMode mode);
void setVoltageReferenceSource(VoltageReferenceSource source);

void setShiftResultBy(int value) { _shiftResultBy = value; }
void setMaxResult(int value) { _maxResult = value; }
void setDetectionThreshold(int value) { _detectionThreshold = value; }
void setSleepBetweenCommandsInMicroSeconds(int value) { _sleepBetweenCommandsInMicroSeconds = value; }

private:
SPI* spi = nullptr;

int _csPin;
int _drdyPin;

bool _singleShotMode = true;

uint8_t _configReg0 = 0;
uint8_t _configReg1 = 0;
uint8_t _configReg2 = 0;
uint8_t _configReg3 = 0;

uint8_t _txBuffer[2];
uint8_t _rxBuffer[3];

int _shiftResultBy = 10;
int _maxResult = 8192;
int _detectionThreshold = 3;

int _sleepBetweenCommandsInMicroSeconds = 500;

enum SpiCommand {
RESET = 0b00000110,
START = 0b00001000,
POWERDOWN = 0b00000010,
RDATA = 0b00010000,
RREG = 0b00100000,
WREG = 0b01000000,
};

void sendSpiCommand(SpiCommand command, uint8_t payload);
void writeRegister(uint8_t addr, uint8_t data);
uint8_t readRegister(uint8_t addr);

void selectMultiplexerConfiguration(MultiplexerConfiguration configuration);

static constexpr const int DEFAULT_CS_PIN = 18;
static constexpr const int DEFAULT_DRDY_PIN = 13;

static constexpr const uint8_t REG0_ADDR = 0x00;
static constexpr const uint8_t REG1_ADDR = 0x01;
static constexpr const uint8_t REG2_ADDR = 0x02;
static constexpr const uint8_t REG3_ADDR = 0x03;

static constexpr const uint8_t MASK_CONFIG_0_MUX = 0b11110000;
static constexpr const uint8_t MASK_CONFIG_0_PGA_GAIN = 0b00001110;
static constexpr const uint8_t MASK_CONFIG_0_PGA_BYPASS = 0b00000001;

static constexpr const uint8_t MASK_CONFIG_1_DATA_RATE = 0b11100000;
static constexpr const uint8_t MASK_CONFIG_1_OPERATING_MODE = 0b00011000;
static constexpr const uint8_t MASK_CONFIG_1_CONVERSION_MODE = 0b00000100;
static constexpr const uint8_t MASK_CONFIG_1_TEMPERATURE_SENSOR_MODE = 0b00000010;
static constexpr const uint8_t MASK_CONFIG_1_BURNOUT_CURRENT_SOURCES = 0b00000001;

static constexpr const uint8_t MASK_CONFIG_2_VOLTAGE_REFERENCE = 0b11000000;
static constexpr const uint8_t MASK_CONFIG_2_FIR_FILTER = 0b00110000;
static constexpr const uint8_t MASK_CONFIG_2_LOW_SIDE_SWITCH = 0b00001000;
static constexpr const uint8_t MASK_CONFIG_2_IDAC_CURRENT = 0b00000111;

static constexpr const uint8_t MASK_CONFIG_3_IDAC1_ROUTING = 0b11100000;
static constexpr const uint8_t MASK_CONFIG_3_IDAC2_ROUTING = 0b00011100;
static constexpr const uint8_t MASK_CONFIG_3_DRDY_MODE = 0b00000010;
};
27 changes: 27 additions & 0 deletions cpp-rpi/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <iostream>

#include <wiringPi.h>

#include "ads1220.h"

#define CS_PIN 18
#define DRDY_PIN 13

using namespace std;

int main(void) {
int err = wiringPiSetupPhys();
if (err != 0) {
cerr << "Couldn't setup wiringPi: " << err << endl;
exit(err);
}

Ads1220 ads(CS_PIN, DRDY_PIN);

uint32_t previousValue = 0;
while (true) {
uint32_t value = ads.readUntilNewValue(Ads1220::MultiplexerConfiguration::AIN0_SINGLE_ENDED, previousValue);
cout << "AIN0: " << value << endl;
previousValue = value;
}
}
Binary file added cpp.tar
Binary file not shown.