Feather M0 and ProtoCentral ADS1262

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Feather M0 and ProtoCentral ADS1262

Post by law1 »

Colleagues:

Struggling desperately with M0 Adalogger interface to ProtoCentral ADS1262 in conflict with internal SD card. Have attempted modified libraries, pin assignments, etc., but finding this SPI interface more than challenging.

Code example uses some ADC setups for "internal" ADC, but will be "tuned" to the ADS1262 if I can handle the basic interface.

Very hopeful for your kind guidance and suggestions.
Attachments
Analog_data_logger_ADS1262_schematic.pdf
(304.01 KiB) Downloaded 54 times

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by mikeysklar »

@law1,

There is a lot going on here with the additional FeatherWings in your schematic.

Are you able to make the M0 Adalogger work correctly with only the SD card? Is it able to work with only the SD Card and ProtoCentral? If you want to post some example code of using the two devices we can take a look. Use CODE bracket and do not post the entire project code. Usually it is just pulling the CS pin HIGH when not in use.

User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by law1 »

Kind Colleague:

Sincere appreciation for your interest!

I have tested the various elements of this proposed system individually, using mostly Arduino IDE "examples" for the SD, SPI, GPS, RTC, WiFINNA, etc. All of these brief examples performed as expected Testing the AirLift - ESP32 WiFi the SPI interface I follow MOSI>MOSO "convention" Using the IDE example code and default "chip select" (13 default) it functions as described.

Using the Feather M0 Adalogger (with built-in) SD (on CS 4), I had hacked together a script to record internal ADC data to the SD card, along with GPS sentences as header followed by "appending" "buffered" ADC data from external signal on analog input (A0). I managed to create START/STOP subroutines (currently activated by "push-buttons" to avoid crashing any more SD cards (3) by other testing with improperly "closed" SD files or other misunderstood mischief.

With all of the above under some control and consistency, and finally receiving my ProtoCentral ADS1262 and "bi-directional level-converters" it seems I have descended into chaos. In the meanwhile I seem to have stumbled upon at least repeatable conditions of the ADS1262, albeit the data values seem to be all zero's.

In hope of minimizing my impositions, if your might have any general examples of this ProCentral ADS1262 interface to Feather M0 they would be greatly appreciated for my study. I KNOW I will be facing challenges of managing the highest sample rates and buffering the "streaming" capture of 4 channels of ADC data to SD card.

[img]
Capture.JPG
Capture.JPG (98.85 KiB) Viewed 531 times
[/img], [img]
Capture.JPG
Capture.JPG (98.85 KiB) Viewed 531 times
[/img]
Attachments
AirLift - ESP32 WiFi removed, on SD & ADS1262 on SPI
AirLift - ESP32 WiFi removed, on SD & ADS1262 on SPI
20211022_120918.jpg (314.63 KiB) Viewed 531 times

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by mikeysklar »

The ADS1262 is not a piece of hardware we utilize and I was unable to find any example using it with the M0. I suspect the ADS1262 library is behaving badly with CS release timing and will need to be tested in isolation then add another SPI device such as your SD card. Best of luck to you on troubleshooting this.

User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by law1 »

mikeysklar;

Most sincere thanks for your considerations of the ADS12652. Complex and supposedly capable device to challenge us all.

Regards

User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by law1 »

In continued pursuit of a high-speed data logger I have upgraded to a Feather M4 Express (much faster) to interface with the ProtoCentral ADS1262 and other devices. I am working on adapting my Feather M0 Adalogger sketch to the M4 which also requires an external SD card on the SPI bus. My breadboard fur-ball includes the level-converters to the ADS1262 and other devices in the plan. (each have been checked independently and are disconnected currently) . Crude schematic follows:
featherM4_with_ADS1262_et_al_schematic.JPG
featherM4_with_ADS1262_et_al_schematic.JPG (184.52 KiB) Viewed 464 times
The ProtoCentral ADS1262 example comes from link following:

https://github.com/Protocentral/ProtoCe ... ential.ino

I am working on adapting an example from Arruda and a load-cell using the ADS1262 to avoid messing with "interrupts" as the M4 doesn't support the TC4 clock example used for the M0. The Arruda sketch embeds the "defines & registers" to avoid modifying the rather crude library examples from GitHub thru the testing.

https://e2e.ti.com/support/data-convert ... 71#2344271

Additionally, I have connected the Saleae Logic Analyzer to assure the control signals for the ADS1262 where I could send the *.sr file for detailed zoom of captured SPI results:

[img]
logic_analyzer_view.png
logic_analyzer_view.png (412.31 KiB) Viewed 464 times
[/img]

With this background, the challenge is/remains the data values stored (and displayed for troubleshooting) are all "zeros" from the ADS1262. Serial monitor display of "triggered" data stream with "gps" header values:

[img]
Capture.JPG
Capture.JPG (52.28 KiB) Viewed 464 times
[/img]

My adapting code follows for your humor/pity/ or kind advice. It seems like the "clocks" may be derived from both the M4 master AND the ADS1262 slave, however the ADS1262 support information is limited or absent regarding SPI control. I am trying to embed some "digitalWrite" command states to the controls but not much seems to change. ???

The musings of wizards would be greatly appreciated.

Code: Select all

#include <SPI.h>
#include <SdFat.h>
#include <stdint.h>
#include <Adafruit_GPS.h>
#include <ads1262.h>
//#include <WiFiNINA.h>

SdFat SD;
File myFile;
char filename[15];

// name of the GPS hardware serial port?
#define GPSSerial Serial1

// Connect to the GPS on the hardware port
Adafruit_GPS GPS(&GPSSerial);

String NMEA1;
String NMEA2;
char c;

const int btnStart = A3;
const int btnStop = A4;
const int ledStart = A1;
const int ledStop = A2;
const int sd_cs_pin = 10;  //Feather M4 SD card chip-select pin

int recPressed = 0;
int stopPressed = 0;
int flag = 0;

ads1262 ads1262;  //ADS class

//ADS1262 global
#define PGA 1                     // Programmable Gain = 1
#define VREF 2.50                 // Internal reference of 2.048V
#define VFSR VREF/PGA             
#define FSR (((long int)1<<23)-1)  



#define CONFIG_SPI_MASTER_DUMMY 0xFF
// Register Read Commands
//#define RREG 0x20
//#define WREG 0x40
#define START 0x08
#define STOP 0x0A
#define RDATA1 0x12

//Pins used for the connection with the sensor, the other you need are controlled by the SPI library):  (Feather pins assigned in ads1262.h)
//const int ADS1262_DRDY_PIN = 6;
//const int ADS1262_CS_PIN = 9;
//const int ADS1262_START_PIN = 5;
//const int ADS1262_PWDN_PIN = A0;

//Register address
#define POWER 0x01 //11h (default)
#define INTERFACE 0x02 //05h (default)
#define MODE0 0x03 //00h (default)
#define MODE1 0x04 //80h (default)
#define MODE2 0x05 //04h (default) 
#define INPMUX 0x06 //01h (default)
#define OFCAL0 0x07 //00h (default)
#define OFCAL1 0x08 //00h (default)
#define OFCAL2 0x09 //00h (default)
#define FSCAL0 0x0A //00h (default)
#define FSCAL1 0x0B //00h (default)
#define FSCAL2 0x0C //40h (default)
#define IDACMUX 0x0D //BBh (default)
#define IDACMAG 0x0E //00h (default)
#define REFMUX 0x0F //00h (default)
#define TDACP 0x10 //00h (default)
#define TDACN 0x11 //00h (default)
#define GPIOCON 0x12 //00h (default)
#define GPIODIR 0x13 //00h (default)
#define GPIODAT 0x14 //00h (default)
#define ADC2CFG 0x15 //00h (default)
#define ADC2MUX 0x16 //01h (default)
#define ADC2OFC0 0x17 //00h (default)
#define ADC2OFC1 0x18 //00h (default)
#define ADC2FSC0 0x19 //00h (default)
#define ADC2FSC1 0x1A //40h (default)

float volt_V=0;
float volt_mV=0;
volatile int i;
volatile char SPI_RX_Buff[10];
volatile long ads1262_rx_Data[10];
volatile static int SPI_RX_Buff_Count = 0;
volatile char *SPI_RX_Buff_Ptr;
volatile int Responsebyte = false;
volatile signed long sads1262Count = 0;
volatile signed long uads1262Count=0;
double resolution;

unsigned long start=0;
int counter1, counter2=0;
int cell = 1;

void setup() 
{
  // 9600 baud is the default rate for the Ultimate GPS/Featherwing
  GPSSerial.begin(9600);

  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  // Default is 1 Hz update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  delay(1000); //Pause 

  pinMode(13,OUTPUT);
  pinMode(12,OUTPUT); 
  pinMode(11,OUTPUT);
  pinMode(10, OUTPUT);        // DON'T change this(10) - Hardware sd_cs_pin pin must be left as output for SD library functions to work correctly
  pinMode(ledStart, OUTPUT);
  pinMode(ledStop, OUTPUT);
  pinMode(btnStop, INPUT_PULLUP);
  pinMode(btnStart, INPUT_PULLUP);

  // initalize the  data ready and chip select pins:
  pinMode(ADS1262_DRDY_PIN, INPUT);          //data ready input line
  pinMode(ADS1262_CS_PIN, OUTPUT);           //chip enable output line
  pinMode(ADS1262_START_PIN, OUTPUT);        // start 
  pinMode(ADS1262_PWDN_PIN, OUTPUT);         // Power down output     

  digitalWrite(ADS1262_START_PIN, HIGH);     // for testing trying to get ADS1262 running actual data values
  digitalWrite(ADS1262_CS_PIN, HIGH);        // for testing trying to get ADS1262 running actual data values
  
  Serial.begin(115200);      // Max Baud Rate
  SPI.begin();               // start SPI library
  SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE1));
  Serial.println("ads1262 Initialised successfully....");
  delay(2000);
  ads1262_Init();            // initialise ads1262 slave

start = millis(); 

   digitalWrite(sd_cs_pin, LOW);    // for testing "if" statement for Start loop

  if (SD.begin(sd_cs_pin, SPI_HALF_SPEED)) {        //testing changes to SPI speed
        delay(10);
  for (int dloop = 0; dloop < 4; dloop++) {  
        digitalWrite(ledStart,!digitalRead(ledStart));
        delay(100);
      }
    }
    else { // if error, flash LED twice per second, until reset
      while(1) {
        digitalWrite(ledStart,!digitalRead(ledStart));
        delay(500);
      }
    } 
  strcpy(filename, "ANALOG00.BIN");   // Template for file name, characters 6 & 7 get set automatically later

   digitalWrite(sd_cs_pin, HIGH);     // for testing "if" statement for Start loop
 } 

void loop() 
{
  if (digitalRead(btnStart) == LOW && recPressed == 0) {
    StartRec(); // launch StartRec method
  }
  if (digitalRead(btnStop) == LOW) {
    StopRec(); // launch StopRec method
  }

//  while (digitalRead(ADS1262_DRDY_PIN) == HIGH){ //while data is not ready - do nothing
//    Serial.println(","); 
//  }   

    volatile int i ;
 
    if((digitalRead(ADS1262_DRDY_PIN)) == LOW)  //monitor DRDY pin
    {                  
    SPI_RX_Buff_Ptr = ads1262_Read_Data();  //6Bytes <STATUS|DATA1|DATA2|DATA3|DATA4|CHECKSUM>
    Responsebyte = true;
   }
    
    if(Responsebyte == true)
    {
      for(i = 0; i <5; i++) //Remove STATUS byte?
    {   
    SPI_RX_Buff[SPI_RX_Buff_Count++] = *(SPI_RX_Buff_Ptr + i);              
    }
    Responsebyte = false;
    }
  
  if(SPI_RX_Buff_Count >= 5)
  {     
    ads1262_rx_Data[0]= (unsigned char)SPI_RX_Buff[1];  // read 4 bytes adc count
    ads1262_rx_Data[1]= (unsigned char)SPI_RX_Buff[2];
    ads1262_rx_Data[2]= (unsigned char)SPI_RX_Buff[3];
    ads1262_rx_Data[3]= (unsigned char)SPI_RX_Buff[4];
 
    uads1262Count = (signed long) (((unsigned long)ads1262_rx_Data[0]<<24)|((unsigned long)ads1262_rx_Data[1]<<16)|(ads1262_rx_Data[2]<<8)|ads1262_rx_Data[3]);//get the raw 32-bit adc count out by shifting
    sads1262Count = (signed long) (uads1262Count);      // get signed value
    resolution = (double)((double)VREF/pow(2,31));      //resolution= Vref/(2^n-1) , Vref=2.5, n=no of bits
    volt_V      = (resolution)*(float)sads1262Count;    // voltage = resolution * adc count
    volt_mV   =   volt_V*1000;                          // voltage in mV
    Serial.println(volt_mV);                            // uncomment to test sample values, comment for better data rates
//    Serial.print(":");
//    Serial.println(sads1262Count);

    SPI_RX_Buff_Count = 0;
  }

    myFile = SD.open(filename, O_RDWR | O_APPEND);  //re-open file to append buffer data in "loop"
    myFile.println(volt_mV);
    myFile.close(); 
     
//VERIFYING THE NUMBER OF SAMPLE RATE OUTPUT
    counter1++;
    if (millis() - start > 1000) {
//Serial.println(counter1);
      start = millis();
      counter1=0;
    }  
 }

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void StartRec()   // start recording method
{ 
  digitalWrite(ledStart,HIGH);
  digitalWrite(ledStop,LOW);

  digitalWrite(ADS1262_CS_PIN, LOW);  
  
  recPressed = 1;
  stopPressed = 0;

    for (uint8_t i = 0; i < 100; i++) {
    filename[6] = '0' + i/10;
    filename[7] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (! SD.exists(filename)) {
      break;
    }
  }  
  readGPS();  //This is a function below which reads two NMEA sentences from GPS to create record "header"

  myFile = SD.open(filename, FILE_WRITE);

  Serial.print(NMEA1);  //Uncomment these lines to display GPGGA on serial monitor,       !!! Start loop will not execute if serial monitor is not displayed
  delay(10);  
  Serial.print(NMEA2);  //Uncomment these lines to display GPRMC on serial monitor,       !!! Start loop will not execute if serial monitor is not displayed
  delay(10);    

  myFile.println(NMEA1); //try to write NMEA1 GGA as file header
  myFile.close();
  delay(100);
  myFile = SD.open(filename, O_RDWR | O_APPEND);  //re-open file to append NMEA2
  myFile.println(NMEA2); //try to write NMEA2 RMC as file header
  myFile.close();
  delay(100);  

}

void StopRec() { // stop recording method
  
  digitalWrite(ledStart,LOW);
  digitalWrite(ledStop,HIGH);

  digitalWrite(ADS1262_CS_PIN, HIGH);  
  
  myFile.close();
  recPressed = 0;
}

void readGPS(){  //This function will read and remember two NMEA sentences from GPS
  clearGPS();    //Serial port probably has old or corrupt data, so begin by clearing it all out
  while(!GPS.newNMEAreceived()) { //Keep reading characters in this loop until a good NMEA sentence is received
  c=GPS.read(); //read a character from the GPS
  }
GPS.parse(GPS.lastNMEA());  //Once you get a good NMEA, parse it
NMEA1=GPS.lastNMEA();      //Once parsed, save NMEA sentence into NMEA1
while(!GPS.newNMEAreceived()) {  //Go out and get the second NMEA sentence, should be different type than the first one read above.
  c=GPS.read();
  }
GPS.parse(GPS.lastNMEA());
NMEA2=GPS.lastNMEA();
}  

void clearGPS() {  //Since between GPS reads, we still have data streaming in, we need to clear the old data by reading a few sentences, and discarding these
while(!GPS.newNMEAreceived()) {
  c=GPS.read();
  }
GPS.parse(GPS.lastNMEA());
while(!GPS.newNMEAreceived()) {
  c=GPS.read();
  }
GPS.parse(GPS.lastNMEA());
}

//ADS1262 configuration

void ads1262_Init()
{  
  ads1262_Reset(); delay(2000);
  
  ads1262_Reg_Write(POWER, 0x11);delay(10); //11h (default) internal ref enabled
  ads1262_Reg_Write(INTERFACE, 0x0D);delay(10); //05h (default) Status byte enabled, Checksum enablade
  ads1262_Reg_Write(MODE0, 0x00);delay(10); //00h (default) Continuous Conv Mode | 0x40 Pulse conversion mode (one shot conversion)
  ads1262_Reg_Write(MODE1, 0x00);delay(10); //80h (default) FIR Filter | 00h sinc1 | 60h sinc4                              (test changes to FIR filter selection)
  ads1262_Reg_Write(MODE2, 0x5C);delay(10); //04h (default) PGA enabled 1V/V 20sps| 5Ch 32V/V 7200sps | 5Fh 32V/V 38400sps  (test changes to sample rate)
  ads1262_Reg_Write(INPMUX, 0x01);delay(10); //01h (default) Multiplexer, AIN0 e AIN1 | 23h AIN2 e AIN3
  ads1262_Reg_Write(OFCAL0, 0x00);delay(10); //00h (default) Offset Calibration Registers
  ads1262_Reg_Write(OFCAL1, 0x00);delay(10); //00h (default) Offset Calibration Registers
  ads1262_Reg_Write(OFCAL2, 0x00);delay(10); //00h (default) Offset Calibration Registers
  ads1262_Reg_Write(FSCAL0, 0x00);delay(10); //00h (default) Full-Scale Calibration Registers
  ads1262_Reg_Write(FSCAL1, 0x00);delay(10); //00h (default) Full-Scale Calibration Registers
  ads1262_Reg_Write(FSCAL2, 0x40);delay(10); //40h (default) Full-Scale Calibration Registers
  ads1262_Reg_Write(IDACMUX, 0xBB);delay(10); //BBh (default) Output Multiplexer, no connection, no connection
  ads1262_Reg_Write(IDACMAG, 0x00);delay(10); //00h (default) Current magnitude, off
  ads1262_Reg_Write(REFMUX, 0x00);delay(10); //00h (default) Reference Multiplexer, 2.5V, 2.5V
  ads1262_Reg_Write(TDACP, 0x00);delay(10);//00h (default) TDACP, no connection
  ads1262_Reg_Write(TDACN, 0x00);delay(10); //00h (default) TDACN, no connection
  ads1262_Reg_Write(GPIOCON, 0x00);delay(10); //00h (default) GPIO not connected
  ads1262_Reg_Write(GPIODIR, 0x00);delay(10); //00h (default) GPIO output
  ads1262_Reg_Write(GPIODAT, 0x00);delay(10); //00h (default) GPIO low
  ads1262_Reg_Write(ADC2CFG, 0x00);delay(10); //00h (default) ADC2
  ads1262_Reg_Write(ADC2MUX, 0x01);delay(10); //01h (default) 
  ads1262_Reg_Write(ADC2OFC0, 0x00);delay(10); //00h (default) 
  ads1262_Reg_Write(ADC2OFC1, 0x00);delay(10); //00h (default) 
  ads1262_Reg_Write(ADC2FSC0, 0x00);delay(10); //00h (default) 
  ads1262_Reg_Write(ADC2FSC1, 0x40);delay(10); //40h (default)
  SPI.transfer(START); //Start conversion via 08h code
  delay(2000);                                                      //testing delay to allow ADS1262 to get started
}

char* ads1262_Read_Data()
{
  SPI.transfer(RDATA1);
  static char SPI_Dummy_Buff[6];
     for (int i = 0; i < 6; ++i)
  {
    SPI_Dummy_Buff[i] = SPI.transfer(CONFIG_SPI_MASTER_DUMMY); //CONFIG_SPI_MASTER_DUMMY - FFh
  }
  return SPI_Dummy_Buff; // 6Bytes <STATUS|DATA1|DATA2|DATA3|DATA4|CHECKSUM>
}

void ads1262_Reset() //PWDN_PIN MUST BE HIGH FOR OPERATION
{
  digitalWrite(ADS1262_PWDN_PIN, HIGH); delay(100);
  digitalWrite(ADS1262_PWDN_PIN, LOW); delay(100);
  digitalWrite(ADS1262_PWDN_PIN, HIGH); delay(100);
}

void ads1262_Reg_Write (unsigned char READ_WRITE_ADDRESS, unsigned char DATA)
{
  // now combine the register address and the command into one byte:
  byte dataToSend = READ_WRITE_ADDRESS | WREG;
   
  // take the chip select low to select the device:
  SPI.transfer(dataToSend); //Send register location
  SPI.transfer(0x00);   //number of register to wr
  SPI.transfer(DATA);   //Send value to record into register
  delayMicroseconds(2);
}/code]

User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by law1 »

Kind wizards, please find attempt to attach a Saleae logic SR file for zoom and manipulation SPI and ADS1262 "controls".
start_file_w_header.zip
(163.44 KiB) Downloaded 8 times

User avatar
law1
 
Posts: 8
Joined: Tue Aug 17, 2021 12:28 pm

Re: Feather M0 and ProtoCentral ADS1262

Post by law1 »

Kindly disregard PREVIOUS Saleae file (wrong sampling rate to see CLKS)
start_file_w_header.zip
(73.5 KiB) Downloaded 3 times
NEW sample rate for SR file at 8MHz/ 2M samples

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”