Incorrect SPI communication when compiled with Platform IO for teensey 4.1. But not when using arduino IDE

Dear Platform IO team, when I compile my code with PlatformIO (vsCode), reading register via SPI communication gives different value than desired.

required register value 1
achieved register value 0
Write to Register 0x1 failed! on SetRegisterValue

required register value 240
achieved register value 120
Write to Register 0x1 failed! on SetRegisterValue

But when I put the same code to the arduino IDE, I get correct register write and reads.

Micro Controller - Teensey 4.1
SPI Communication - ADS1256
Softwares - WIN10 - ATOM 1.58 + Core 5.2.3 Home 3.4.0
Softwares - WIN10 - VS CODE 1.62.3 + Core 5.2.3 Home 3.4.0
Arduino - Arduino 1.9.16 Teenseyduino 1.55

Minimal reproducible code

// Library by - https://github.com/mbilsky/TeensyADS1256

// built up on the work of:
// https://github.com/Flydroid/ADS12xx-Library
// https://gist.github.com/dariosalvi78/f2e990b4317199d235bbf5963c3486ae
// https://github.com/adienakhmad/ADS1256
// Interrupt function

#include <Arduino.h>
#include <SPI.h> //SPI communication

#define SPI_SPEED 1900000

// /* For information to the register and settings see manual page (p..) */

// /* ADS1248 Register (see p42 for Register Map) */

#define STATUS 0x00 // Status Control Register 0
#define MUX 0x01    // Multiplexer Control Register 0
#define ADCON 0x02  // A/D Control Register 0
#define DRATE 0x03  // A/D Data Rate Control Register 0
#define OFC0 0x05   // Offset Calibration Coefficient Register 1
#define OFC1 0x06   // Offset Calibration Coefficient Register 2
#define OFC2 0x07   // Offset Calibration Coefficient Register 2
#define FSC0 0x08   // Full scale Callibration Coefficient Register 0
#define FSC1 0x09   // Full scale Callibration Coefficient Register 1
#define FSC2 0x0A   // Full scale Callibration Coefficient REgister 2

#define STATUS_RESET 0x01 // Reset STATUS Register
#define MUX_RESET 0x01 // Reset MUX0 Register
#define PGA_1 B00000000 //(default)

#define DR_30000 B11110000 // 30.000 SPS (default)
#define DR_1000  B10100001 //1.000 SPS


#define RESET 0xFE   // Reset To Power UP values
#define NOP 0xFF     // No operation
#define RDATA 0x01  // Read data once
#define SDATAC 0x0F // Stop reading data continously
#define RREG 0x10 // Read From Register
#define WREG 0x50 // Write To Register
#define SELFCAL 0xF0 // Self Offset Calibration


#define ADS_RST_PIN 3 // ADS1256 reset pin
#define ADS_RDY_PIN 2 // ADS1256 data ready
#define ADS_CS_PIN 10 // ADS1256 chip select





volatile int DRDY_state = HIGH;

void DRDY_Interuppt() { DRDY_state = LOW; }

void Reset() {
  SPI.beginTransaction(SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE1)); // initialize SPI with  clock, MSB first, SPI Mode1
  digitalWriteFast(10, LOW);
  delayMicroseconds(10);
  SPI.transfer(RESET);  // Reset
  delay(2);             // Minimum 0.6ms required for Reset to finish.
  SPI.transfer(SDATAC); // Issue SDATAC
  delayMicroseconds(100);
  digitalWriteFast(10, HIGH);
  SPI.endTransaction();
}

long GetRegisterValue(uint8_t regAdress) {
  uint8_t bufr;
  digitalWriteFast(10, LOW);
  delayMicroseconds(10);
  SPI.transfer(RREG | regAdress); // send 1st command byte, address of the register
  SPI.transfer(0x00);             // send 2nd command byte, read only one register
  delayMicroseconds(10);
  bufr = SPI.transfer(NOP); // read data of the register
  delayMicroseconds(10);
  digitalWriteFast(10, HIGH);
  // digitalWrite(_START, LOW);
  SPI.endTransaction();
  return bufr;
}

void waitforDRDY() {
  while (DRDY_state) {
    continue;
  }
  noInterrupts();
  DRDY_state = HIGH;
  interrupts();
}

void SetRegisterValue(uint8_t regAdress, uint8_t regValue) {

  //  uint8_t regValuePre = GetRegisterValue(regAdress);
  //  if (regValue != regValuePre) {
  // digitalWrite(_START, HIGH);
  delayMicroseconds(10);
  waitforDRDY();
  SPI.beginTransaction(
      SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE1)); // initialize SPI with SPI_SPEED, MSB first, SPI Mode1
  digitalWriteFast(10, LOW);
  delayMicroseconds(10);
  SPI.transfer(WREG | regAdress); // send 1st command byte, address of the register
  SPI.transfer(0x00);             // send 2nd command byte, write only one register
  SPI.transfer(regValue);         // write data (1 Byte) for the register
  delayMicroseconds(10);
  digitalWriteFast(10, HIGH);
  // digitalWrite(_START, LOW);

  long regRecvValue = GetRegisterValue(regAdress);
  //
  Serial.print("required register value ");
  Serial.println(regValue);
  Serial.print("achieved register value ");
  Serial.println(regRecvValue);

  //

  if (regValue != regRecvValue) { // Check if write was succesfull
    Serial.print("Write to Register 0x");
    Serial.print(regAdress, HEX);
    Serial.println(" failed! on SetRegisterValue");
  } else {
    Serial.println("success on SetRegisterValue");
  }
  SPI.endTransaction();

  //  }
}

void SendCMD(uint8_t cmd) {
  waitforDRDY();
  SPI.beginTransaction(
      SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE1)); // initialize SPI with 4Mhz clock, MSB first, SPI Mode0
  digitalWriteFast(10, LOW);
  delayMicroseconds(10);
  SPI.transfer(cmd);
  delayMicroseconds(10);
  digitalWriteFast(10, HIGH);
  SPI.endTransaction();
}

void initADS() {
  attachInterrupt(ADS_RDY_PIN, DRDY_Interuppt, FALLING);

  digitalWrite(ADS_RST_PIN, LOW);
  delay(10);                       // LOW at least 4 clock cycles of onboard clock. 100 microsecons is enough
  digitalWrite(ADS_RST_PIN, HIGH); // now reset to deafult values

  delay(1000);

  // now reset the ADS
  Reset();

  // let the system power up and stabilize (datasheet pg 24)
  delay(2000);
  // this enables the buffer which gets us more accurate voltage readings
  // SetRegisterValue(STATUS,B00110010);

  Serial.println(GetRegisterValue(STATUS));

  // next set the mux register
  // we are only trying to read differential values from pins 0 and 1. your needs may vary.
  // this is the default setting so we can just reset it
  SetRegisterValue(MUX, MUX_RESET); // set the mux register
  // B00001000 for single ended measurement

  // now set the ADCON register
  // set the PGA to 64x
  // you need to adjust the constants for the other ones according to datasheet pg 31 if you need other values
  SetRegisterValue(ADCON, PGA_1); // set the adcon register

  // next set the data rate
  SetRegisterValue(DRATE, DR_30000); // set the drate register

  // we're going to ignore the GPIO for now...

  // lastly, we need to calibrate the system

  // let it settle
  delay(2000);

  // then do calibration
  SendCMD(SELFCAL); // send the calibration command

  // then print out the values
  delay(5);

  Serial.print("OFC0: ");
  Serial.println(GetRegisterValue(OFC0));
  Serial.print("OFC1: ");
  Serial.println(GetRegisterValue(OFC1));
  Serial.print("OFC2: ");
  Serial.println(GetRegisterValue(OFC2));
  Serial.print("FSC0: ");
  Serial.println(GetRegisterValue(FSC0));
  Serial.print("FSC1: ");
  Serial.println(GetRegisterValue(FSC1));
  Serial.print("FSC2: ");
  Serial.println(GetRegisterValue(FSC2));
}



// library files

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("booting");

  // initialize the ADS
  pinMode(ADS_CS_PIN, OUTPUT);
  //   digitalWrite (ADS_CS_PIN, HIGH);
  // https://forum.arduino.cc/t/solved-spi-communication-failure-anything-obvious-with-the-code/172109

  pinMode(ADS_RDY_PIN, INPUT);
  pinMode(ADS_RST_PIN, OUTPUT);
  digitalWrite(ADS_CS_PIN, HIGH);
  // https://forum.arduino.cc/t/solved-spi-communication-failure-anything-obvious-with-the-code/172109

  SPI.begin();

  initADS();
  Serial.println("done init");


}

int32_t val1;
int32_t val2;
int32_t val3;

void loop() {
  Serial.println("here");

  SetRegisterValue(0x00,B00000000);
  SetRegisterValue(0x01, B00001000);
  SetRegisterValue(0x02, B00000010);
  SetRegisterValue(0x03, B00010011);
  delay(1000);
}

Are you sure platform-teensy is also up-to-date so that it uses the same core version? Open a CLI and execute pio platform update teensy, then re-upload the program. Does it still fail?

The Platform Io is installed as extension on vs code so calling pio on CLI gives 'pio' is not recognized as an internal or external command, operable program or batch file.

You must explicitly use the CLI I linked in the post above, not the general CLI.

Dear maxgerhardt, yes I had made the mistake of using wrong CLI. I did the update as you mentioned but still I am facing the same problems.

Wrong output from VSCode + teensey

required register value 8
achieved register value 4
Write to Register 0x1 failed! on SetRegisterValue
required register value 2
achieved register value 1
Write to Register 0x2 failed! on SetRegisterValue
required register value 19
achieved register value 9
Write to Register 0x3 failed! on SetRegisterValue

Correct output from Arduino

required register value 8
achieved register value 8
success on SetRegisterValue
required register value 2
achieved register value 2
success on SetRegisterValue
required register value 19
achieved register value 19
success on SetRegisterValue

Can it be because I might be missing something on SPI communication and Arduino might be filling it up for me during compilation? Like I don’t need to add includes when I use multiple files in Arduino IDE as it creates the link for me automatically?

Regards,

Dear maxgerhardt, I would like to acknowledge my mistake. In distance past, I had mistakenly modified SPI.h of platformIO packages and set SPI_MODE1 value to SPI_MODE0.

I do acknowledge my mistake and am deeply sorry for your troubles.

Regards,

1 Like