Skip to content
This repository has been archived by the owner on Feb 8, 2023. It is now read-only.

Commit

Permalink
Merge pull request #120 from arntsonl/i2canalog_addon
Browse files Browse the repository at this point in the history
I2C Analog ADS1219 Addon Support
  • Loading branch information
TheTrainGoes authored Oct 8, 2022
2 parents 3dde6ec + 22ab131 commit 0ca5186
Show file tree
Hide file tree
Showing 13 changed files with 32,518 additions and 31,776 deletions.
15 changes: 10 additions & 5 deletions configs/Pico/BoardConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#define PIN_BUTTON_A1 20 // A1 / Guide / Home / ~ / 13 / ~
#define PIN_BUTTON_A2 21 // A2 / ~ / Capture / ~ / 14 / ~
#define PIN_BUTTON_TURBO 14 // Turbo
#define PIN_BUTTON_REVERSE 22 // UDLR Reverse
#define PIN_BUTTON_REVERSE -1 // UDLR Reverse
#define PIN_SLIDER_LS -1 // Left Stick Slider
#define PIN_SLIDER_RS -1 // Right Stick Slider

Expand Down Expand Up @@ -122,10 +122,6 @@
#define ANALOG_ADC_VRY -1


// Reverse Button section
#define REVERSE_LED_PIN 12


// This is the I2C Display section (commonly known as the OLED display section).
// In this section you can specify if a display as been enabled, which pins are assined to it, the block address and speed.
// The default for `HAS_I2C_DISPLAY` is `1` which enables it.
Expand Down Expand Up @@ -179,6 +175,15 @@
#define DISPLAY_FLIP 0
#define DISPLAY_INVERT 0

// I2C Analog ADS1219 Add-on Options
#define I2C_ANALOG1219_SDA_PIN -1
#define I2C_ANALOG1219_SCL_PIN -1
#define I2C_ANALOG1219_BLOCK i2c0
#define I2C_ANALOG1219_SPEED 400000
#define I2C_ANALOG1219_ADDRESS 0x40

// Reverse Button section
#define REVERSE_LED_PIN -1
#define REVERSE_UP_DEFAULT 1
#define REVERSE_DOWN_DEFAULT 1
#define REVERSE_LEFT_DEFAULT 1
Expand Down
51 changes: 51 additions & 0 deletions include/inputs/i2canalog1219.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef _I2CAnalog_H
#define _I2CAnalog_H

#include <ADS1219.h>

#include "gpaddon.h"

#include "GamepadEnums.h"

#ifndef I2C_ANALOG1219_SDA_PIN
#define I2C_ANALOG1219_SDA_PIN -1
#endif

#ifndef I2C_ANALOG1219_SCL_PIN
#define I2C_ANALOG1219_SCL_PIN -1
#endif

#ifndef I2C_ANALOG1219_BLOCK
#define I2C_ANALOG1219_BLOCK i2c0
#endif

#ifndef I2C_ANALOG1219_SPEED
#define I2C_ANALOG1219_SPEED 400000
#endif

#ifndef I2C_ANALOG1219_ADDRESS
#define I2C_ANALOG1219_ADDRESS 0x40
#endif

// Analog Module Name
#define I2CAnalog1219Name "I2CAnalog"

typedef struct {
float A[4];
} ADS_PINS;

class I2CAnalog1219Input : public GPAddon {
public:
virtual bool available(); // GPAddon available
virtual void setup(); // Analog Setup
virtual void process(); // Analog Process
virtual std::string name() { return I2CAnalog1219Name; }
private:
ADS1219 * ads;
ADS_PINS pins;
int channelHop;
uint32_t uIntervalMS; // ADS1219 Interval
uint32_t nextTimer; // Turbo Timer
};

#endif // _I2CAnalog_H_
5 changes: 5 additions & 0 deletions include/storagemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ struct BoardOptions
uint8_t reverseActionDown;
uint8_t reverseActionLeft;
uint8_t reverseActionRight;
int i2cAnalog1219SDAPin;
int i2cAnalog1219SCLPin;
int i2cAnalog1219Block;
uint32_t i2cAnalog1219Speed;
uint8_t i2cAnalog1219Address;
char boardVersion[32]; // 32-char limit to board name
uint32_t checksum;
};
Expand Down
213 changes: 213 additions & 0 deletions lib/ADS1219/ADS1219.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include "ADS1219.h"

#include <cstring>

ADS1219::ADS1219(int bWire, int sda, int scl, i2c_inst_t *picoI2C, int32_t speed, uint8_t addr) {
bbi2c.iSDA = sda;
bbi2c.iSCL = scl;
bbi2c.picoI2C = picoI2C;
bbi2c.bWire = bWire;
iSpeed = speed;
address = addr;
config = 0x00;
singleShot = true;
}

void ADS1219::begin() {
I2CInit(&bbi2c, iSpeed); // on Linux, SDA = bus number, SCL = device address
reset();
}

// 8.5.3.3 START/SYNC (0000 100x)
// In single-shot conversion mode, the START/SYNC command is used to start a single conversion, or (when sent
// during an ongoing conversion) to reset the digital filter and then restart a single new conversion. When the
// device is set to continuous conversion mode, the START/SYNC command must be issued one time to start
// converting continuously. Sending the START/SYNC command when converting in continuous conversion mode
// resets the digital filter and restarts continuous conversions.
void ADS1219::start(){
uc[0] = 0x08;
I2CWrite(&bbi2c, address, uc, 1);
}

// 8.5.3.4 POWERDOWN (0000 001x)
// The POWERDOWN command places the device into power-down mode. This command shuts down all internal
// analog components, but holds all register values. In case the POWERDOWN command is issued when a
// conversion is ongoing, the conversion completes before the ADS1219 enters power-down mode. As soon as a
// START/SYNC command is issued, all analog components return to their previous states.
void ADS1219::powerDown(){
uc[0] = 0x02;
I2CWrite(&bbi2c, address, uc, 1);
}


// 8.5.3.6 RREG (0010 0rxx)
// The RREG command reads the value of the register at address r. Reading a register must be performed as
// shown in Figure 37 by using two I2C communication frames. The first frame is an I2C write operation where the
// R/W bit at the end of the address byte is 0 to indicate a write. In this frame, the host sends the RREG command
// including the register address to the ADS1219. The second frame is an I2C read operation where the R/W bit at
// the end of the address byte is 1 to indicate a read. The ADS1219 reports the contents of the requested register
// in this second I2C frame.
uint8_t ADS1219::readRegister(adsRegister_t reg){ // reg must be 0 or 1
uc[0] = 0x20 | (reg<<2); // this is a guess
I2CWrite(&bbi2c, address, uc, 1);
I2CRead(&bbi2c, address, uc, 1);
return uc[0];
}

// 8.5.3.7 WREG (0100 00xx dddd dddd)
// The WREG command writes dddd dddd to the configuration register. Figure 38 shows the sequence for writing
// the configuration register. The R/W bit at the end of the address byte is 0 to indicate a write. The WREG
// command forces the digital filter to reset and any ongoing ADC conversion to restart.
void ADS1219::writeRegister(uint8_t data){
uc[0] = CONFIG_REGISTER_ADDRESS;
uc[1] = data;
I2CWrite(&bbi2c, address, uc, 2);
}

// 8.5.3.5 RDATA (0001 xxxx)
// The RDATA command loads the output shift register with the most recent conversion result. Reading conversion
// data must be performed as shown in Figure 36 by using two I2C communication frames. The first frame is an I2C
// write operation where the R/W bit at the end of the address byte is 0 to indicate a write. In this frame, the host
// sends the RDATA command to the ADS1219. The second frame is an I2C read operation where the R/W bit at
// the end of the address byte is 1 to indicate a read. The ADS1219 reports the latest ADC conversion data in this
// second I2C frame. If a conversion finishes in the middle of the RDATA command byte, the state of the DRDY pin
// at the end of the read operation signals whether the old or the new result is loaded. If the old result is loaded,
// DRDY stays low, indicating that the new result is not read out. The new conversion result loads when DRDY is
// high.
uint32_t ADS1219::readConversionResult(){
uc[0] = 0x10; // Read from 24-bit conversion
I2CWrite(&bbi2c, address, uc, 1);
I2CRead(&bbi2c, address, uc, 3);
uint32_t data32 = (uc[0] << 16) | (uc[1] << 8) | (uc[2]);
if (data32 >= 0x800000)
data32 = data32-0x1000000;
return data32; // 24-bit ADC result signage hack
}

// 8.5.3.2 RESET (0000 011x)
// This command resets the device to the default states. No delay time is required after the RESET command is
// latched before starting to communicate with the device as long as the timing requirements (see the I2C Timing
// Requirements table) for the (repeated) START and STOP conditions are met.
void ADS1219::reset(){
uc[0] = 0x6;
I2CWrite(&bbi2c, address, uc, 1);
}

void ADS1219::resetConfig(){
writeRegister(0x00);
}

long ADS1219::readSingleEnded(int channel){
config &= MUX_MASK;
switch (channel){
case (0):
config |= MUX_SINGLE_0;
break;
case (1):
config |= MUX_SINGLE_1;
break;
case (2):
config |= MUX_SINGLE_2;
break;
case (3):
config |= MUX_SINGLE_3;
break;
default:
break;
}
writeRegister(config);
return readConversionResult();
}

long ADS1219::readDifferential_0_1(){
config &= MUX_MASK;
config |= MUX_DIFF_0_1;
writeRegister(config);
return readConversionResult();
}

long ADS1219::readDifferential_2_3(){
config &= MUX_MASK;
config |= MUX_DIFF_2_3;
writeRegister(config);
return readConversionResult();
}

long ADS1219::readDifferential_1_2(){
config &= MUX_MASK;
config |= MUX_DIFF_1_2;
writeRegister(config);
return readConversionResult();
}

long ADS1219::readShorted(){
config &= MUX_MASK;
config |= MUX_SHORTED;
writeRegister(config);
return readConversionResult();
}

void ADS1219::setGain(adsGain_t gain){
config &= GAIN_MASK;
config |= gain;
writeRegister(config);
}

void ADS1219::setDataRate(int rate){
config &= DATA_RATE_MASK;
switch (rate){
case (20):
config |= DATA_RATE_20;
break;
case (90):
config |= DATA_RATE_90;
break;
case (330):
config |= DATA_RATE_330;
break;
case (1000):
config |= DATA_RATE_1000;
break;
default:
break;
}
writeRegister(config);
}

void ADS1219::setConversionMode(adsMode_t mode){
config &= MODE_MASK;
config |= mode;
writeRegister(config);
if (mode == CONTINUOUS){
singleShot = false;
} else {
singleShot = true;
}
}

void ADS1219::setVoltageReference(adsRef_t vref){
config &= VREF_MASK;
config |= vref;
writeRegister(config);
}

void ADS1219::setChannel(int channel){
config &= MUX_MASK;
switch (channel){
case (0):
config |= MUX_SINGLE_0;
break;
case (1):
config |= MUX_SINGLE_1;
break;
case (2):
config |= MUX_SINGLE_2;
break;
case (3):
config |= MUX_SINGLE_3;
break;
default:
break;
}
writeRegister(config);
}
Loading

0 comments on commit 0ca5186

Please sign in to comment.