B4J Question ADS1256 Waveshare High-precision ADC Module

gmachacek

Member
Licensed User
Longtime User
Hi,
does anybody have expirience with Raspberry SPI Bus and ADS1256?
I have communication but can't get data from the ADS1256.

B4X:
#Region Project Attributes 
    #MainFormWidth: 800
    #MainFormHeight: 600 
    #MergeLibraries: true
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private btnClearList As B4XView
    Private tarProtocol As B4XView
    
    Private Spi As Int
    Private rwSpi As Int
    
    Private timLoop As Timer
    
    Dim tempBytes As ByteConverter
    
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("frmMain") 'Load the layout file.
    MainForm.Show
    addText("Programm started")
    
    timLoop.Initialize("timLoop",1000)
    timLoop.Enabled = True
    
    Spi = WiringPiSPISetup(0,32000000)
    addText("WiringPiSPISetup:" & Spi)
    
End Sub

Sub timLoop_Tick
    Dim strData As String = "0"
    Dim Data() As Byte = tempBytes.StringToBytes(strData,"UTF8")
    rwSpi = WiringPiSPIDataRW(0,Data,strData.Length)
    addText("WiringPiSPIDataRW:" & rwSpi)
End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub btnClearList_Click
    tarProtocol.Text = ""
End Sub

Sub addText(Text As String)
    tarProtocol.Text = tarProtocol.Text & Text & CRLF
End Sub

Sub WiringPiSPISetup(Channel As Int, Speed As Int) As Int
    Dim jo As JavaObject
    Return jo.InitializeStatic("com.pi4j.wiringpi.Spi").RunMethod("wiringPiSPISetup", Array As Object(Channel, Speed))
End Sub

Sub WiringPiSPIDataRW(Channel As Int, Data() As Byte, Len As Int) As Int
    Dim jo As JavaObject
    Return jo.InitializeStatic("com.pi4j.wiringpi.Spi").RunMethod("wiringPiSPIDataRW", Array As Object(Channel, Data, Len))
End Sub

20200725_122216.jpg


The function WiringSPIDataRW returns always the length of the data string.

thx in advance
Georg
 

emexes

Expert
Licensed User
does anybody have expirience with Raspberry SPI Bus and ADS1256?
I have experience with neither, but I'm not going to let that minor detail slow me down. 🍻

Have you used SPI before? Have you used SPI and Pi before?

My first step would be to read registers that have specific power-up values containing both 0s and 1s, to make sure the SPI communication is indeed happening.

The datasheet indicates that registers 1, 2, 3 and 4 power-up to 0x01, 0x20, 0xF0 and 0xE0 respectively, so try reading those and see what you get.

My second step would be to write the calibration registers and read them back, make sure that both directions of SPI communication are working.

Then, if you have anything hooked up to the GPIO pins, try reading/writing those, make sure we are indeed in control of the ADS1256.

Then I'd try reading the ADC, initially with default close-enough calibration numbers, see if the number varies in accordance with the input test signal.
 
Upvote 0

gmachacek

Member
Licensed User
Longtime User
Hello Emexes
I didn't use SPI before. I used I2C for example with the Piface2 board and that worked fine for me.
If I do not get to a result with SPI I will switch to AD board with I2C for Raspberry.
I need analog Inputs for my Raspberry for my project.
Thx for your input I will let the community know the result.
Regards Georg
 
Upvote 0

emexes

Expert
Licensed User
I didn't use SPI before.
No worries. Your initial problem is that SPI works simulataneously in both directions, both sending and receiving one bit with each SPI clock pulse. Well, it's not so much a problem, more of an initiation surprise for newcomers.

So, typically to read a register you would send the register number, and ignore the data sent back to you by the SPI device whilst clocking out that register number, and then send n dummy bytes to generate clock pulses on which the SPI device will send you the register contents.

The WiringPiSPIDataRW(0,Data,strData.Length) function will send the contents of Data(), and and replace those contents of Data() with the data returned by the SPI device.
 
Upvote 0

emexes

Expert
Licensed User
Another little SPI hurdle is that there are four clock modes - from memory, active high/low x rising/falling edge - and even when I've had access to the schematics and datasheet, I still get it wrong half the time. So basically just try a simple register read in each of the four modes, see which mode reliably returns the register value.

The datasheet I have gives the following clues to reading a register:

1595758792654.png


1595758860829.png


1595758951124.png
 
Upvote 0

emexes

Expert
Licensed User
and thus the following approximate code should do that sample read of the MUX and ADCON registers:
B4X:
Dim Data(4) As Byte    '2 command bytes out followed by 2 register content bytes in = 4 bytes total

Data(0) = 0x11    'command = read, starting from register 1
Data(1) = 0x01    'read 2 registers (n + 1)

Log("Function return result = " & WiringPiSPIDataRW(0, Data, Data.Length))

Dim LogLine As String = "SPI data received ="
For I = 0 to Data.Length - 1
    LogLine = LogLine & " " & Data(I)
Next
Log(LogLine)
Remember to try all four clock modes - typically, the last one you try will be the one that works - and also note that this device has a SPI clock upper limit of 2.5 MHz (200 ns + 200 ns) and so for the purpose of getting stuff going, I'd be using eg 1 MHz to be sure, to be sure. 🍻

1595760013360.png
 
Upvote 0

emexes

Expert
Licensed User
Uh, there is the small issue of t6 which is a 50-master-clock-cycle delay to allow the ADS1256 to get return data ready. Assuming the master clock is 32 MHz, then setting the SPI clock speed to 0.25 MHz is a kludgy way of doing it, until I read the WiringPiSPI documentation to find the proper way of doing it. Or maybe WiringPiSPI already inserts a delay between each byte... but how would it know how long is long enough? 🤔
 
Upvote 0

emexes

Expert
Licensed User
Ok, I thought WiringPiSPI was doing the chip select too, but apparently not. So the above code amended would look like (get ready for some hand-wavy vagueness):
B4X:
Dim CommandData(2) As Byte

CommandData(0) = 0x11    'command = read, starting from register 1
CommandData(1) = 0x01    'read 2 registers (n + 1)

'might need a small delay here to ensure this transfer isn't too soon after the previous transfer
ADS1256ChipSelectGPIO = Low    'or however that's done
'might need a small delay here to give ADS156 time to wake up

Log("Command function return result = " & WiringPiSPIDataRW(0, CommandData, CommandData.Length))

Dim ActualData(2)    'one byte per register being read ie 2 registers = 2 bytes

'probably need a small delay here when logging delays are removed ie t6 = eg 50/32 microseconds
Log("Actual function return result = " &  WiringPiSPIDataRW(0, ActualData, ActualData.Length))

ADS1256ChipSelectGPIO = High    'or however that's done

Dim LogLine As String = "Actual data received ="    'expecting to get power-on reset values of 1 and 32 (ie 01H and 20H) (per datasheet table 23)
For I = 0 to ActualData.Length - 1
    LogLine = LogLine & " " & ActualData(I)
Next
Log(LogLine)
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Obviously you'd be encapsulating the SPI stuff into say:

ADS1256_Command(C As Byte)
ADS1256_ReadRegister(R As Byte) As Byte
ADS1256_WriteRegister(R As Byte, V as Byte)
ADS1256_ReadADC( ) As Int

and then you'd use those to configure the ADC, initiate a conversion, wait for conversion complete, and read the result.
 
Upvote 0

KiloBravo

Active Member
Licensed User
No worries. Your initial problem is that SPI works simulataneously in both directions, both sending and receiving one bit with each SPI clock pulse. Well, it's not so much a problem, more of an initiation surprise for newcomers.

So, typically to read a register you would send the register number, and ignore the data sent back to you by the SPI device whilst clocking out that register number, and then send n dummy bytes to generate clock pulses on which the SPI device will send you the register contents.
What emexes said !!! This really confused me when I was looking at SPI.
I saw code with a Dummy Byte and was not sure why they had that. Maybe I knew at one point, but reading that statement last night I felt like a light bulb came on.
I have not played with a "PI" in a while, but I recently needed to xfer data from an ESP8266 to a PIC16F18426.
I looked at I2C, SPI, and RS232 protocols. Everything has pros and cons. PICs have their own issues as well.
I ended up choosing I2C.
If you go with SPI maybe looking at the Arduino Library will help.

Good Luck !
 
Upvote 0

emexes

Expert
Licensed User
but reading that statement last night I felt like a light bulb came on
I had the same experience understanding binary. It was light bulb off, off, off, off... and then one day on holidays I thought: heck, if I had to count with just two thumbs, how would I do it? And I mucked around for a bit, and then the light bulb came on. More than 40 years later, I can still remember sitting at that kitchen table when it happened.

Similarly with CRC's. Polynomial division, phooey!
 
Upvote 0
Top