2

I am using the AD/DA Hat from WaveShare https://www.waveshare.com/wiki/High-Precision_AD/DA_Board I want to realize a continuous readout of the data. It worked very well so far, but I am not so experienced with SPI (or serial communcation in gerneral) My two questions are:

1) Is it possible that any data will be lost, if for example the AD/DA Hat writes faster than the refresh rate of my program. Or will all data be saved in a buffer and I can read them afterwards?

2) If I set the sample rate to very low (e.g. 5 Hz).. I will get data from SPI like [12, 125, 85, 0, 0, 0, 0, 0, 0, 0, 0, 15, 114, 43, 0, 0, ...] My readout of the ADC consits of 3 Bytes, so the rest is low. Because SPI has no start-, stop-bits I dont know how to extract the 3 bytes from the contiuous readout... For the given example I could program a logic which extract the bytes afterwards But it is not very safe because the first or last bit of my actual readout could be zero as well.

Thanks for your help my friends

tlfong01
  • 4,665
  • 3
  • 10
  • 24
markus321
  • 23
  • 1
  • 3

3 Answers3

7

Any answer might only be of limited help to you as long as you have not understood how SPI actually works, so you should take a detailed look at this interface.

Concerning question 1: SPI is a master-slave-system where any interaction has to be initiated by the master. The sensor itself is not able to write to the master, instead it is read by the master (raspberry pi). Therefore the sensor will not "write" more often than your loop "makes it write" by calling the corresponding SPI-read-function. The sensor might (or probably will) have done several measurements between two read-outs, but that's usually the case. It wouldn't be better if the sensor was slower than your program. If it turns out that this is actually the case you better make use of the data-ready-pin mentioned in RogerJones' answer.

Question 2: Instead of using start-/stop-bits a transmission is triggered by selecting the slave (pulling its select pin low). You usually have to write the register address you want to read first, after that you can read a specific amount of bytes. As you know the address and length of the measurement data, you don't need to parse or "extract" any bytes. You simply select the bytes you desire and will get those back right away.

Sim Son
  • 671
  • 3
  • 12
5

In addition to the other answer about the SPI protocol I notice that the product page you linked to shows that, as well as the SPI CS pin on GPIO 15 (BCM22), the ADS1256 ADC has a "Data Ready" pin connected to GPIO 11 (BCM17). You could monitor this and only fetch a new sample when the data is available rather than just reading the data back constantly --- you might be getting the same data repeated if there's no new conversion between your read attempts. By using the "Data Ready" pin in this way you'd get the fastest data rate from the board (assuming you can read the data out fast enough) without missing or replicating data points. How you'd do this would depend on the programming language you've used but using an interrupt on pin 11 would appear to be a good start.

Looking at the provided code and datasheet it looks like you can also change the ADC sample rate so if you are having problems keeping up you can slow the chip down, the slowest sample frequency is about 50Hz giving your code 20ms to read the data.

Roger Jones
  • 1,494
  • 7
  • 14
-2

Question

How to read ADC results from ADS1256?

Short Answer

Getting to know SPI

As pointed out by @Sim Son, you need to know basic SPI and have some practical hardware/software experience, before you can understand how SPI ADS1256 programming.

Getting to know ADC

Then you need to know basics of ADC, like what is the meaning of single end and differential end channels, gain factors etc,

Getting to know ADS1256

Then you need to read the data sheet, to get a rough idea of the functions of the pinout, eg, AN-~AN7, Reset, DataReady (Note 1), Beside the SPI pins (CLK, MOSI, MISO, CS), and the functions of the 11 registers.

Getting to know the WaveShare ADS1256 Demo Program

Then you can now study the program and get a rough idea of what the program is doing its job by 3 big steps:

  1. Define Gain Channels, Data Rates, Register Addresses, ADC Commands

  2. Define ADS1256 Class with methods init, reset, writeCommand, writeReg, ReadData

  3. Define ADC1256 methods readChipId, config, setSingleEndChannel, setDiffChannel, setScanMode, init, waitReady, readData, getOneChannelValue, getAllChannelValues, ...

Note 1 - As pointed out by @Roger Jones, the DataReay pin is important if you wish to get the highest sample rate. The following picture show how to roughly calculate the maximum data rate for a particular SPI frequency.

ADS1256 data rate calculation

Now I am connecting Rpi to the ADS1256 Module

ads1256_connect

ads1256 wiring

ADS1256 Test Rig

ads1256 test rig 1


Long Answer


References

(1) ADS1256 Datasheet - TI

(2) [ADS1256] Measuring Single-Ended 0- to 5-V Signals with Differential Delta-Sigma ADCs Application Report - TI 2015may

(3) [ADS1256] How delta-sigma ADCs work, Part 1 - TI

(4) How can ADS1256 Read Negative Values?

(5) How can ADS1256 Read Full Scale Values?

(6) ADS1256 Python Libraries

(7) C library for Broadcom BCM 2835 [GPIO] as used in Raspberry Pi [v1.59 2012 26 pin Rpi 2]

(8) WaveShare ADS1250 ADC Module Tutorial

(9) WaveShare ADS1250 ADC Module Schematic

(10) Waveshare/High-Precision-AD-DA-Board Python 3 Demo Program

(11) AliExpress ADS1256 24 Bit ADC Modules

(12) AliExpress ADS1256IDB ADC Module - US$30


Appendices

Appendix A - WaveShare ADS1256 ADC Module Picture

waveshare adc


Appendix B - WaveShare ADS1256 ADC Module Schematic

Waveshare adc schematic


Appendix C - ADS1256 Characteristics

ads1256 char


Appendix D - ADS1256 Overview

ads1256 overview


Appendix E - ADS1256 Connection Diagram

ads1256 connection diagram


Appendix F - Rpi3B+ ADS1256 Wiring V0.2

Rpi3B+ ADS1256 Wiring V0.2

Circuit URL

rpi ads1526 wiring


Appendix G - ADS1256 Register Map

reg map

Appendix H - Commands

commands


Appendix I - One shot mode ADC

For one short mode of standby-wakeUp-readData, the wake up delay is only 33.3 uS.

one short mode ADC


Appendix J - Write Register and Read Register

wreg

rreg


Appendix K - Status Register 0x00

status reg


Appendix L - SPI Loopback test (before testing ADS1256)

Now I am doing a SPI loopback test as a preparation to read and write ADS1256 ADC registers.

# spi_loopback_50_2019jun0901 tlfong01 2019jun09hkt2153 ***
# Rpi3B+ stretch 2019apr08, python 3.5.3 

# Test     - loopBackTest - SPI port send and receive one byte/two bytes/three bytes.
# Function - Send 1/2/3 bytes MOSI and read back from MISO. 
# Setup    - Connet MOSI pin to MISO pin to form a loop.

# Setting up for 2 SPI channels
# /boot/config.txt dtoverlay setting 
# dtparam=i2c_arm=on
# dtparam=spi=on
# dtoverlay=spi1-3cs
# $ ls -l /dev/spi* should show the following 5 SPI ports:
# /dev/spidev0.0, /dev/spidev0.1, /dev/spidev1.0, /dev/spidev1.1, /dev/spidev1.2

from   time import sleep
import spidev

# *** SPI Channel 0 Config ***

spiPort00 = spidev.SpiDev()
spiPort00.open(0,0)
spiPort00.max_speed_hz = 100000

spiPort01 = spidev.SpiDev()
spiPort01.open(0,1)
spiPort01.max_speed_hz = 100000

# *** SPI Channel 1 Config ***

spiPort10 = spidev.SpiDev()
spiPort10.open(1,0)
spiPort10.max_speed_hz = 100000

spiPort11 = spidev.SpiDev()
spiPort11.open(1,1)
spiPort11.max_speed_hz = 100000

spiPort12 = spidev.SpiDev()
spiPort12.open(1,2)
spiPort12.max_speed_hz = 100000

# *** SPI Send/Receive 1/2/3 Bytes ***

def spiSendRecvOneByte(spiPort, sendByte):
    sendByteArray = [sendByte]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

# *** Loopback 1/2/3 Bytes ***

def loopbackOneByte(spiPort, sendByte):
    recvByteArray     = spiSendRecvOneByte(spiPort, sendByte)
    recvByte          = recvByteArray[0]
    print('\n  Begin loopbackOneByte(),....')
    #print('')
    print('      sendByte  = ', hex(sendByte))
    print('      recvByte  = ', hex(recvByte))
    #print('')
    print('  End   loopbackOneByte(),....', end = '')
    return

# *** Tests to loopback SPI Channel 0  ***

def testLoopbackOneByteSpiPort0():
    print('\nBegin loopbackOneByteSpiPort0(),....', end = '')
    loopbackOneByte(spiPort00, 0x5b)
    print('\nEnd   loopbackOneByteSpiPort0(),....', end = '')
    return

# *** Tests to loopback SPI Channel 1 ***

def testLoopbackOneByteSpiPort1():
    print('\nBegin   loopbackOneByteSpiPort1(),....', end = '')
    loopbackOneByte(spiPort10, 0x5b)
    print('\nEnd   loopbackOneByteSpiPort1(),....', end = '')
    return

# *** Main Tests ***

# *** Loopback Tests ***

testLoopbackOneByteSpiPort0()
#testLoopbackOneByteSpiPort1()

# *** Sample Output ***

''' Smple output 
Begin loopbackOneByteSpiPort0(),....
  Begin loopbackOneByte(),....
      sendByte  =  0x5b
      recvByte  =  0x5b
  End   loopbackOneByte(),....
End   loopbackOneByteSpiPort0(),....
'''
''' Smple output 
Begin   loopbackOneByteSpiPort1(),....
  Begin loopbackOneByte(),....
      sendByte  =  0x5b
      recvByte  =  0x5b
  End   loopbackOneByte(),....
End   loopbackOneByteSpiPort1(),....
'''

# *** End ***

Appendix M - SPI Loopback test (1/2/3 bytes)

ADS1256 needs send/receive two and three bytes. So I have also tested the 1/2/3 bytes loopback version.

# spi_loopback_123_v70_2019jun0901 tlfong01 2019jun09hkt2302 ***
# Rpi3B+ stretch 2019apr08, python 3.5.3 

from   time import sleep
import spidev

# *** SPI Channel 0 Config ***

spiPort00 = spidev.SpiDev()
spiPort00.open(0,0)
spiPort00.max_speed_hz = 100000

# *** Spi port functions ***

def setSpiPortSpeed(spiPortNum, speedName):
    spiPortList[spiPortNum].max_speed_hz = speedDict[speedName]
    return

def closeSpiPortAll():
    for i in spiPortList:
        i.close()
    return

# *** SPI Send/Receive 1/2/3 Bytes ***

def spiSendRecvOneByte(spiPort, sendByte):
    sendByteArray = [sendByte]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvTwoBytes(spiPort, sendByte1, sendByte2):
    sendByteArray = [sendByte1, sendByte2]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    sendByteArray = [sendByte1, sendByte2, sendByte3]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

# *** Loopback 1/2/3 Bytes ***

def loopbackOneByte(spiPort, sendByte):
    recvByteArray     = spiSendRecvOneByte(spiPort, sendByte)
    recvByte          = recvByteArray[0]
    print('\n  Begin loopbackOneByte(),...')
    #print('')
    print('      sendByte  = ', hex(sendByte))
    print('      recvByte  = ', hex(recvByte))
    #print('')
    print('  End   loopbackOneByte().', end = '')
    return

def loopbackTwoBytes(spiPort, sendByte1, sendByte2):
    recvByteArray     = spiSendRecvTwoBytes(spiPort, sendByte1, sendByte1)
    recvByte0          = recvByteArray[0]
    recvByte1          = recvByteArray[1]
    print('\n  Begin loopbackThreeBytes(),...')
    #print('')
    print('      sendBytes  = ', hex(sendByte1), hex(sendByte2))
    print('      recvBytes  = ', hex(recvByte1), hex(sendByte2))
    #print('')
    print('  End   loopbackTwoBytes().', end = '')
    return

def loopbackThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    recvByteArray      = spiSendRecvThreeBytes(spiPort, sendByte1, sendByte1, sendByte3)
    recvByte0          = recvByteArray[0]
    recvByte1          = recvByteArray[1]
    recvByte2          = recvByteArray[2]
    print('\n  Begin loopbackThreeBytes(),...')
    #print('')
    print('      sendBytes  = ', hex(sendByte1), hex(sendByte2), hex(sendByte3))
    print('      recvBytes  = ', hex(recvByte1), hex(sendByte2), hex(sendByte3))
    #print('')
    print('  End   loopbackThreeBytes().', end = '')
    return

# *** Test Loopback 1/2/3 bytes ***

def testLoopbackOneByteSpiPort0():
    print('\nBegin loopbackOneByteSpiPort0(),...', end = '')
    loopbackOneByte(spiPort00, 0x5b)
    print('\nEnd   loopbackOneByteSpiPort0().', end = '')
    return

def testLoopbackTwoBytesSpiPort0():
    print('\nBegin loopbackTwoBytesSpiPort0(),...', end = '')
    loopbackTwoBytes(spiPort00, 0x5b, 0x6b)
    print('\nEnd   loopbackTwoByte0SpiPort0().', end = '')
    return

def testLoopbackThreeBytesSpiPort0():
    print('\nBegin loopbackThreeBytesSpiPort0(),...', end = '')
    loopbackThreeBytes(spiPort00, 0x5b, 0x5c, 0x5d)
    print('\nEnd   loopbackThreeByteSpisPort0().', end = '')
    return

# *** Main Tests ***

# *** Loopback Tests ***

testLoopbackOneByteSpiPort0()
testLoopbackTwoBytesSpiPort0()
testLoopbackThreeBytesSpiPort0()

# *** Sample Output ***

''' Smple output 
>>> 
 RESTART: /home/pi/Python Programs/test1203/spi_loopback_test60_2019may3001.py 

Begin loopbackOneByteSpiPort0(),...
  Begin loopbackOneByte(),...
      sendByte  =  0x5b
      recvByte  =  0x5b
  End   loopbackOneByte().
End   loopbackOneByteSpiPort0().
Begin loopbackTwoBytesSpiPort0(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x6b
      recvBytes  =  0x5b 0x6b
  End   loopbackTwoBytes().
End   loopbackTwoByte0SpiPort0().
Begin loopbackThreeBytesSpiPort0(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x5c 0x5d
      recvBytes  =  0x5b 0x5c 0x5d
  End   loopbackThreeBytes().
End   loopbackThreeByteSpisPort0().
>>> 
'''

# *** End ***

tlfong01
  • 4,665
  • 3
  • 10
  • 24
  • 1
    Thanks a lot for the detailed information. I read the datasheet and tried to set up the timing correctly. But waitiing for the "data rdy poin" led to a delay of roughly 0.5 seconds. However, I realized that the delay corresponds with the sample rate which I set up. Now it seems to work fine. – markus321 Jun 08 '19 at 11:26
  • Just a quick reply. I am just starting to learn this ADC, so I have not yet read the datasheet thoroughly. My first feeling is that if your data rate is low, you DO NOT NEED to read the data ready signal which is useful for very high data rate. But I am only 60% sure. – tlfong01 Jun 08 '19 at 12:14
  • Another quick note. ADS1256 has two conversion modes: (1) one shot, (2) continuous. A wild guess is that for both modes, the conversion time should be much much less than 1mS (if SPI frequency is 100kHz, say). Again I am only 60% sure. I need to read the datasheet carefully, and of course verify by engineering experimentation. Perhaps I can try tomorrow. – tlfong01 Jun 08 '19 at 12:39
  • One reason you have the ridiculously long 0.5 second delay is perhaps you UNNECESSARILY set data rate to a very low value. See Appendix I of my answer. Again I am only 60% sure. I need to do engineering experimentation to verify my guess. – tlfong01 Jun 09 '19 at 07:34
  • Thanks guys, as I wrote the delay correspondes with the set up data rate (more in detail: the mux speed of the different channels corresponds with the data rate). So i realized 125 Hz for all 8 channels. 30 kS/s is just for single channel use. I am sure that it is possible to realize a higher rate than 125 Hz (but maybe not with a pi) but it is fine for my application. – markus321 Jun 10 '19 at 19:04
  • Thank you for your explanation on the delay and data rate. I am still studying the datasheet and found it more complex than I thought. So I need to go very slowly and it might take me perhaps one or two hobbyist weeks to get more knowledge to understand you explanation. So see you later. BTW, I am still a ADS1256 newbie, so my earlier comments might be incorrect and misleading. I will use erratas later. Good luck to your ADS1256 project. – tlfong01 Jun 11 '19 at 02:45