Incorrect SPI communication when compiled with Platform IO for teensey 4.1. But not w

asdwaf

New member
Dear PJRC 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

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);
}
 
Please open an issue with PlatformIO.

Officially, PJRC only maintains and tests Teensyduino with Arduino. If the same code works in Arduino and fails in PlatformIO, that sort of issue needs to be raised on PlatformIO's issue tracker.
 
That looks like 1 bit shifted.
Are you sure SPI MODE 1 is correct?

Very unlikely, that Platformio produces other code than Arduino for SPI re: the Bit shift.
Esp with knowing that they just use Teensyduino.
I can't believe that and doubt the Platformio crew can help you here.
But i'm courious. Let us know ...
 
If it were me, I would probably hook up the SPI pins to a Logic Analyzer and compare the two versions to see if anything obvious.

Other things I might check include things like:

Are the compiler options the same? For example CPU speed... Optimization types... Is it using the same SPI library in both cases?

Again if me, I would maybe try changing your delayMicroseconds... from 10 to 15 or 50 or ... And see if that makes a difference.
Try lowering the SPI speed to see if that helps

As maybe you are right on the fringe of timings that work with that device.

Can we assume you are using the same setup in both cases, that is the same device, with same wiring on same teensy...
 
Dear Paul, Frank, and Kurt, 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 the troubles. The issue has been solved.

To FrankB - Thanks to you, I remembered to re-check the SPI values.
To KurtE - Yes all the setup is same. Hence the huge confusion.

Regards,
 
Back
Top