Closed ChrisBeeves closed 1 month ago
It works perfectly on RP2040 chip as well, so you are doing something wrong. It is not a library issue...
Which SPI pins do you use? GP2-3-4?
That was my initial though as well, and of course I could be doing something wrong.
I use the SPI0 pins on 16,17,18,19. I see they are available on many pins. Does the library point at 2-4?
(edit): Tried 0-4 pins too without further success. Tried on a pico2 and a pico1
My library does not point anywhere. You have to check where the SPI library points for your specific microcontroller. I worked with the code in the past several months using an RP2040 chip, I even developed a board for it and it works.
I did check, that’s why I used the pins I used.
I’m sorry if I put this in the wrong section, it was more a question I need help with rather than reporting an error, I see that now.
The problem remains though, if I write the example code to a Raspberry Pi Pico using the defined rp2040 pins in the sketch, it does not work. I printed the SPI pins to make 100% sure. For the Arduino using the same method, it just works.
It is hard to know without knowing more details...
How does the constructor look like? Did you modify my example code? If yes, to what extent?
First I tried to use the pins defined in the example for RP2040 and only removed an excess paranthesis at row 178. That did not work.
Then I used this code to get the current SPI pins without doubt:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.print("MOSI: ");
Serial.println(MOSI);
Serial.print("MISO: ");
Serial.println(MISO);
Serial.print("SCK: ");
Serial.println(SCK);
Serial.print("SS: ");
Serial.println(SS);
}
Returns this;
MOSI: 19 MISO: 16 SCK: 18 SS: 17
So, I modified your example like this:
`
//This code belongs to the ADS1256 library developed by Curious Scientist
//A very detailed documentation can be found at: https://curiousscientist.tech/ads1256-custom-library
#include <ADS1256.h>
//Below a few examples of pin descriptions for different microcontrollers I used:
//ADS1256 A(2, 0, 8, 10, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //Arduino Nano
//ADS1256 A(7, 10, 5, 9, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //ATmega32U4
//ADS1256 A(PA2, 0, 0, PA4, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //STM32 blue pill
//ADS1256 A(16, 17, 0, 5, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //ESP32 WROOM 32
//ADS1256 A(7, 0, 8, 10, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //Teensy 4.0
ADS1256 A(7, 0, 6, 17, 2.500); //DRDY, RESET, SYNC(PDWN), CS, VREF(float). //RP2040 Waveshare Mini
long rawConversion = 0; //24-bit raw value
float voltageValue = 0; //human-readable floating point value
int singleEndedChannels[8] = {SING_0, SING_1, SING_2, SING_3, SING_4, SING_5, SING_6, SING_7}; //Array to store the single-ended channels
int differentialChannels[4] = {DIFF_0_1, DIFF_2_3, DIFF_4_5, DIFF_6_7}; //Array to store the differential channels
int inputChannel = 0; //Number used to pick the channel from the above two arrays
char inputMode = ' '; //can be 's' and 'd': single-ended and differential
int pgaValues[7] = {PGA_1, PGA_2, PGA_4, PGA_8, PGA_16, PGA_32, PGA_64}; //Array to store the PGA settings
int pgaSelection = 0; //Number used to pick the PGA value from the above array
int drateValues[16] =
{
DRATE_30000SPS,
DRATE_15000SPS,
DRATE_7500SPS,
DRATE_3750SPS,
DRATE_2000SPS,
DRATE_1000SPS,
DRATE_500SPS,
DRATE_100SPS,
DRATE_60SPS,
DRATE_50SPS,
DRATE_30SPS,
DRATE_25SPS,
DRATE_15SPS,
DRATE_10SPS,
DRATE_5SPS,
DRATE_2SPS
}; //Array to store the sampling rates
int drateSelection = 0; //Number used to pick the sampling rate from the above array
String registers[11] =
{
"STATUS",
"MUX",
"ADCON",
"DRATE",
"IO",
"OFC0",
"OFC1",
"OFC2",
"FSC0",
"FSC1",
"FSC2"
};//Array to store the registers
int registerToRead = 0; //Register number to be read
int registerToWrite = 0; //Register number to be written
int registerValueToWrite = 0; //Value to be written in the selected register
void setup()
{
Serial.begin(115200); //The value does not matter if you use an MCU with native USB
while (!Serial)
{
; //Wait until the serial becomes available
}
Serial.println("ADS1256 - Custom Library Demo File by Curious Scientist - 2023-11-10");
A.InitializeADC(); //See the documentation for every details
//Setting up CS, RESET, SYNC and SPI
//Assigning default values to: STATUS, MUX, ADCON, DRATE
//Performing a SYSCAL
//Below is a demonstration to change the values through the built-on functions of the library
//Set a PGA value
A.setPGA(PGA_1); //0b00000000 - DEC: 0
//--------------------------------------------
//Set input channels
A.setMUX(DIFF_6_7); //0b01100111 - DEC: 103
//--------------------------------------------
//Set DRATE
A.setDRATE(DRATE_5SPS); //0b00010011 - DEC: 19
//--------------------------------------------
//Read back the above 3 values to check if the writing was succesful
Serial.print("PGA: ");
Serial.println(A.readRegister(IO_REG));
delay(100);
//--
Serial.print("MUX: ");
Serial.println(A.readRegister(MUX_REG));
delay(100);
//--
Serial.print("DRATE: ");
Serial.println(A.readRegister(DRATE_REG));
delay(100);
//Freeze the display for 3 sec
delay(3000);
}
void loop()
{
/* Here I implemented some typical functions that can be useful for using the ADS1256
Changing the registers by the built-in functions or by directly writing the registers
Reading the registers to check the value of it
Read a single conversion
Read a single channel continuously
Read multiple channels continuously
Stop the conversion
All the above things are done through the serial port, the use only has to send certain commands
*/
if (Serial.available() > 0)
{
char commandCharacter = Serial.read(); //we use characters (letters) for controlling the switch-case
switch (commandCharacter) //based on the command character, we decide what to do
{
case 's': //SDATAC - Stop Reading Data Continously
A.stopConversion();
break;
//--------------------------------------------------------------------------------------------------------
case 'L': //Perform a self calibratin
A.sendDirectCommand(SELFCAL);
break;
//--------------------------------------------------------------------------------------------------------
case 'G': //Read a single input continuously
while (Serial.read() != 's') //The conversion is stopped by a character received from the serial port
{
Serial.println(A.convertToVoltage(A.readSingleContinuous()), 6);
//The conversion is printed in Volts with 6 decimal digits
//Note: Certain serial terminals cannot keep up with high speed datastream!
}
A.stopConversion();
break;
//--------------------------------------------------------------------------------------------------------
case 'C': //Cycle single ended inputs (A0+GND, A1+GND ... A7+GND)
while (Serial.read() != 's')//The conversion is stopped by a character received from the serial port
{
float channels[8]; //Buffer that holds 8 conversions (8 single-ended channels)
for (int j = 0; j < 8; j++)
{
channels[j] = A.convertToVoltage(A.cycleSingle()); //store the converted single-ended results in the buffer
}
for (int i = 0; i < 8; i++)
{
Serial.print(channels[i], 4); //print the converted single-ended results with 4 digits
if(i < 7) //Only printing tab between the first 7 conversions
{
Serial.print("\t"); //tab separator to separate the 8 conversions shown in the same line
}
}
Serial.println();//Printing a linebreak - this will put the next 8 conversions in a new line
}
A.stopConversion();
break;
//--------------------------------------------------------------------------------------------------------
case 'D': //Cycle differential inputs (A0+A1, A2+A3, A4+A5, A6+A7)
while (Serial.read() != 's') //The conversion is stopped by a character received from the serial port
{
float channels[4]; //Buffer that holds 4 conversions (4 differential channels)
for (int j = 0; j < 4; j++)
{
channels[j] = A.convertToVoltage(A.cycleDifferential()); //store the converted differential results in the buffer
}
//After the 4 conversions are in the buffer, the contents are printed on the serial terminal
for (int i = 0; i < 4; i++)
{
Serial.print(channels[i], 4);//print the converted differential results from the buffer
if(i < 3) //Only printing tab between the first 3 conversions
{
Serial.print("\t"); //tab separator to separate the 4 conversions shown in the same line
}
}
Serial.println();//Printing a linebreak - this will put the next 4 conversions in a new line
}
A.stopConversion();
break;
//--------------------------------------------------------------------------------------------------------
case 'B': //Speed test
{
//Variables to store and measure elapsed time and define the number of conversions
long numberOfSamples = 150000; //Number of conversions
long finishTime = 0;
long startTime = micros();
for (long i = 0; i < numberOfSamples; i++)
{
A.readSingleContinuous();
//Note: here we just perform the readings and we don't print the results
}
finishTime = micros() - startTime; //Calculate the elapsed time
A.stopConversion();
//Printing the results
Serial.print("Total conversion time for 150k samples: ");
Serial.print(finishTime);
Serial.println(" us");
Serial.print("Sampling rate: ");
Serial.print(numberOfSamples * (1000000.0 / finishTime), 3);
Serial.println(" SPS");
}
break;
//--------------------------------------------------------------------------------------------------------
case 'T': //Testing the serial connection
Serial.println("The serial connection is OK!");
break;
//--------------------------------------------------------------------------------------------------------
case 'a': //Testing a single conversion - Only one single result is returned
rawConversion = A.readSingle(); //Reading the raw value from a previously selected input, passing it to a variable
voltageValue = A.convertToVoltage(rawConversion); //Converting the above conversion into a floating point number
//Printing the results
Serial.print("Single-ended conversion result: ");
Serial.println(voltageValue, 8); //Print the floating point number with 8 digits.
break;
//--------------------------------------------------------------------------------------------------------
case 'M': //set MUX
{
while (!Serial.available());
inputMode = Serial.read(); //Read the input mode
if (inputMode == 's') //single-ended
{
while (!Serial.available());
inputChannel = Serial.parseInt();
A.setMUX(singleEndedChannels[inputChannel]);
//Example: "Ms1" selects the SING_1 as input channel
}
if (inputMode == 'd') //differential
{
while (!Serial.available());
inputChannel = Serial.parseInt();
A.setMUX(differentialChannels[inputChannel]);
//Example: "Md0" selects the DIFF_0_1 as input channel
}
}
break;
//--------------------------------------------------------------------------------------------------------
case 'P': //Set PGA
{
pgaSelection = Serial.parseInt();
while (!Serial.available());
A.setPGA(pgaValues[pgaSelection]);
//Example: P4 will select the PGA = 16
}
break;
//--------------------------------------------------------------------------------------------------------
case 'F': //Set sampling frequency
{
while (!Serial.available());
drateSelection = Serial.parseInt(); //Parse the number (item number in the array)
delay(100);
Serial.print("DRATE is selected as: ");
Serial.println(drateValues[drateSelection]); //Print the value from the array
delay(100);
A.setDRATE(drateValues[drateSelection]); //Pass the value to the register on the ADS1256
delay(100);
Serial.print("DRATE is set to ");
Serial.println(A.readRegister(DRATE_REG)); //Read the register to see if the value was updated correctly
//Example: F3 will make the DRATE = 3750 SPS
}
break;
//--------------------------------------------------------------------------------------------------------
case 'R': //read register
{
while (!Serial.available());
registerToRead = Serial.parseInt(); //This part reads the number of the register from the serial port
Serial.print("Value of ");
Serial.print(registers[registerToRead]);
Serial.print(" register is: ");
Serial.println(A.readRegister(registerToRead));
//Example: "R2" will read the register at address 2 which is the ADCON register
//Note: The value is printed as a decimal number
}
break;
//--------------------------------------------------------------------------------------------------------
case 'W': //Write register
{
while (!Serial.available());
registerToWrite = Serial.parseInt(); //This part reads the number of the register from the serial port
while (!Serial.available());
registerValueToWrite = Serial.parseInt(); //This part reads the value of the register from the serial port
A.writeRegister(registerToWrite, registerValueToWrite);
//Example: "W1 35" will write 35 ("00100011") on register 1 which is the MUX register.
//This will make the input as DIFF_2_3 (A2(+) & A1(-))
}
break;
//--------------------------------------------------------------------------------------------------------
}
}
}
`
Can you see something obviously wrong?
It seems OK. Do you, by any chance, mix up the pin numbers and the GPIO numbers?
No, don't think so. That would put the SCK on pin 18 GND.
I just tried putting an SPI screen on those pins and it works. Doesn't use the MOSI though..
I am out of ideas, to be honest. Maybe you can try a different DRDY pin. For my custom board, where SCK is GPIO2, MOSI is GPIO3 and MISO is GPIO4, the constructor looks like this:
ADS1256 A(18, 20, 21, 19, 2.500);
Had to edit that a little since my board has SCK on 18 and MOSI on 19. Changing DRDY pin had no effect.
This is very strange. Reminds me of the strangeness with the Nano-esp32 with arduino pin numbering. Chaos.
Bought a new ADS board, still the same issue.
But if the code works with Pro Micro and it does not work with Pi Pico, why did you replace the ADS1256? The issue is most probably not with the ADS1256 board. The code 10000% works with the RP2040 chip (which is in a Pi Pico).
The code 10000% does not work with any of my picos. Now I can’t get anything working. I had it up and running with a Leonardo and a Pro micro but they won’t even work on the new module now. I understand that it is close to impossible for you to help troubleshoot since everything looks without fault. I have quadruple checked everything (as far as I can tell) and tried different cables. I have no idea what to do next. Would be nice to know if anyone else had it working on exactly the same hardware and in that case what the constructor looks like.
I got it working on a Pico W just now as well... Constructor: ADS1256 A(15, 0, 14, 17, 2.5); SPI: MISO-16, MOSI-19, SCK-18, SS-17. Notice: these are the GPIO numbers and NOT the physical pin numbers. They would be 21, 25, 24 and 22. Proof because you don't seem to trust me:
It’s not that I don’t trust you, not at all! I’m sorry if I have made it sound like that.
Thank you for testing, I’ll try that constructor and wiring. I appreciate you taking the time!
@ChrisBeeves I saw your results in my mail, but I can't see them here. Do you by any chance accidentally mix the MOSI and MISO pins?
If you mean by accidentally "systematically and on purpose",
yes...
I feel.. sorry..
I owe you a beer or two..
How mind boggingly stupid of me!
I just knew it was something simple like this!
Nah, this is easy to miss because most of the ADS1256 board use "DIN" and "DOUT". And it is a bit misleading (for me, at least) to know whose data in (DIN) and data out (DOUT) should be considered.
But anyway, I am glad that we made it work. Lessons learned, experience gained. Now you can focus on the fun part!
Yeah, that's what got me.
I am glad too. Now I have high hopes on improving the application again!
Again, thank you for your time and the nice library.
Running the example file with a Pi Pico or Pi Pico 2 i only seem to get zeros in the Serial Monitor;
After that it goes silent. It's like the spi is not communicating. I tried changing the CS pin to Rpi standard (17) but that does nothing.
It works perfectly on the arduino pro micro, but I just can't get the Raspberries talking.