This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS1256 and Python compatibility. Problems with SPI.

Other Parts Discussed in Thread: ADS1256, ADS1262, ADS1255, DAC8552

Hello,

I've recently purchased this board for my Raspberry:

It has an ADS1256 and I'm trying to communicate with it via SPI. I had problems though, and even the library creator doesn't know how to help me. So he told me that maybe it can communicate just through C language. Can you give me an answer?

Thanks in advance!

  • Alberto,


    What sort of problems are you having?

    In general, if you are having problems with the SPI communications, I would highly recommend using an oscilloscope or logic analyzer to make sure that the SPI communications are correct. If you can plot them up and post them back and we'll see what the problem could be. Generally, you want to confirm the type of SPI, and all the timing diagram information. After that, we can verify the actual data coming out of the ADC or read back the registers.

    In general, we don't have and development collateral with the raspberry pi. We generally will support the ADC with operation, but it's hard to combine that with different microcontroller platforms.


    Joseph Wu
  • Hi Joseph,
    the problems are with communication. I havent checked with the oscilloscope yet, but Im probably not catching what registers are for and overall how to write them in the script. In the script I transfered at first 0x00 (I think its the WAKEUP byte, isnt it?), then I transfered 0x01 that should be the RDAT byte, with a delay of 7 microsec given that the clock is 7.68 MHz. By the way it returns me "0" as a value. Then Im not sure about the script, but it does the same even for single commands in the interpreter.
  • Hi Alberto,

    One common mistake with communication is with not holding CS low throughout the entire communication transaction.  What I mean here is CS must stay low not only when SCLK is active, but between each byte transferred until the entire command sequence is complete.  If CS goes high between byte transfers, the SPI will reset and any issued command will be canceled.

    Best regards,

    Bob B

  • Hi Bob,

    I'll check that and send you the results. By the way I still have doubts on what commands I should use. Can you give me some hint for reading data?

    Thanks, Alberto

  • Hi Alberto,

    First you must make sure that the SYNC/PDWN pin is high (pin 14 on the ADS1256) to make sure the device is active.  To read the data by command, you would issue the RDATA command (0x01) followed by a short delay to decode the command and then three bytes of SCLK to read the data.  Most microcontrollers issue the SCLK by writing to TX buffer.  In this case you would send the WAKEUP command (0x00 or 0xFF).  The sequence would look like CS low followed by 0x01, short delay for command decode, 0xFF, 0xFF, 0xFF then CS set high. You capture the data received following each TX byte of the WAKEUP sent, and assemble the data received from the RX buffer to an integer value.

    Best regards,

    Bob B

  • Thanks for the reply. I still have a doubt though: do you mean MISO and MOSI when you write TX and RX? I'm asking you that because in the Raspberry header, RX and TX refer to UART. I'm sorry for silly questions but I'm new to serial commumication.

    Alberto

  • Hi Alberto,

    I'm referring to the low level buffer within the SPI peripheral used on the RaspberryPi for MISO and MOSI.  Have you looked at this example code from the PCB reference information you originally posted:

    http://www.waveshare.com/wiki/File:High-Precision-AD-DA-Board-Code.7z

    This code has a file called 'ads1256_test.c' that contains the structure for reading data, and reading and writing registers.  The function for reading data, ADS1256_ReadData(), is a good example for showing exactly what to do.  The low level RX and TX buffers that I was referring to are contained and hidden in the SPI function call:

    read = bcm2835_spi_transfer(data);

    bcm2835_spi_transfer() returns the data read from the receive buffer and sending 'data' writes to the transmit buffer.

    Best regards,

    Bob B

  • Hi Bob,

    I tried to get some hints from the C script, but I can't get much since I've always used Python. Do you think I should go ahead with C?

    I wrote a script following your advices, but it returns me (0, 0, 0). The CS pin and PDWN pin are wired to the header, so through if clauses I got to know if CS keeps low during process and if PDWN is high. They are both fine, this is the script:

           

    import spidev
    import time
    import pigpio
    pi = pigpio.pi()
    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.writebytes([0x01])
    time.sleep(0.0007)
    while True:

    if pi.read(22) == 0 and pi.read(27) == 1:

              print(spi.xfer2([0x00]))
              print(spi.xfer2([0x00]))
              print(spi.xfer2([0x00]))
              pi.write(22, 1)

    # GPIO 22 = CS

    #GPIO 27 = PDWN

    It looks very bad, and all it returns me is [0, 0, 0]. the xfer2 method should send and receive bytes without changing CS pin state, then pi.write changes the CS pin state.

    I've probably not caught what you told me in your last messages. 

    I'll wait for your reply

    Alberto

  • Hi Alberto,

    I believe we have come full circle and are back to where Joseph suggested that you get oscilloscope or logic analyzer shots of the communication.  We do not know if the peripheral is setup correctly, or is even transmitting any data to the ADS1256.

    Best regards,

    Bob B

  • Hi Alberto,

    have you been successful communicating to the ADS1256 ?

    I had my first successful attempt using Python a few minutes ago...but I tried to use PyBCM2835 instead of spidev as wrapper.

    The advantage of PyBCM2835 is that you can "translate" the c-code from ads1256_test.c "directly" to Python-code.
    My understanding of ads1256_test.c is that the chip select line is set "manually" (2 red marked lines in following python code).

    import PyBCM2835
    import time

    rCmd = 0x10
    rState = 0x00

    PyBCM2835.init();

    PyBCM2835.spi_begin();

    PyBCM2835.spi_setBitOrder(PyBCM2835.SPI_BIT_ORDER_LSBFIRST)
    PyBCM2835.spi_setDataMode(PyBCM2835.SPI_MODE1)
    PyBCM2835.spi_setClockDivider(PyBCM2835.SPI_CLOCK_DIVIDER_1024)
    #PyBCM2835.spi_setClockDivider(PyBCM2835.SPI_CLOCK_DIVIDER_65536)
    PyBCM2835.spi_chipSelect(PyBCM2835.SPI_CS0)
    PyBCM2835.spi_setChipSelectPolarity(PyBCM2835.SPI_CS0, PyBCM2835.LOW)
    PyBCM2835.gpio_fsel(PyBCM2835.RPI_GPIO_P1_15, PyBCM2835.GPIO_FSEL_OUTP)
    PyBCM2835.gpio_write(PyBCM2835.RPI_GPIO_P1_15, PyBCM2835.HIGH)

    n = 0

    for n in range(0, 100):
        
        PyBCM2835.gpio_write(PyBCM2835.RPI_GPIO_P1_15, PyBCM2835.LOW)
        PyBCM2835.spi_transfer(rCmd)
        PyBCM2835.spi_transfer(rState)
        #time.sleep(0.0001)
        print bin (PyBCM2835.spi_transfer(0xff))
        PyBCM2835.gpio_write(PyBCM2835.RPI_GPIO_P1_15, PyBCM2835.HIGH)
        time.sleep(0.1)
        n += 1


    PyBCM2835.spi_end();
    PyBCM2835.close();

    The "interesting" thing is what the logic analyser shows concerning cs-line (brown line / green frame) :
    The line is going HIGH between each byte no matter if the "red" lines are used or commented out.
    The only difference is the answer (blue line / red frame) ?

  • Hello everyone,

    I've made some progress, I can read bytes now, but seems like I can read only the last 2 bytes.

    What I do is set CS low, send WAKEUP (0x00), 10 ųs delay, send three READDATA(0x01) and then print.

  • Hi Alberto,

    After sending the RDATA command, you'll want to send 0x00, 0x00, 0x00 to retrieve the data. "0x00" acts like a "NOP" during this process...

    Otherwise, by sending three RDATA commands (0x01, 0x01, 0x01), you're restarting the read data process after each byte and the device will output the MSByte again.

    Another thing to keep in mind...

    Since SPI is full-duplex, often times the SPI receive buffer will hold onto previously read values, including "junk" bytes. For example, when you send the WAKEUP command to the ADS1256, you don't care about the incoming data (to your MCU) during that byte; however, the SPI receive buffer doesn't know that and will store the incoming "junk" byte. You may need to read or clear out the SPI receive buffer after each SPI byte transmission so that "junk" bytes don't accumulate. You can read the byte after each transmission but only store the value when you know the incoming data is meaningful.


    Best Regards,
    Chris

  • Thank you very much, this helped me a lot. By the way, to clear the receive buffer, should I reset the chip?
  • Hi Alberto,

    No, I don't think you would want to reset the MCU...then you would need to reconfigure all the clocks and SPI settings.

    Usually, just fetching the value is enough to clear it. For example on the MSP430, here is one way of implementing it (in C):

     

    unsigned char transferByte(unsigned char dataByte)
    {
    	while(USCI_B_SPI_isBusy(USCI_B0_BASE));           // Wait while SPI bus is busy
    	USCI_B_SPI_transmitData(USCI_B0_BASE, dataByte);  // Send "dataByte"
    	while(USCI_B_SPI_isBusy(USCI_B0_BASE));           // Wait for send to complete
    	return USCI_B_SPI_receiveData(USCI_B0_BASE);      // Return received data byte
    }
    

     

    Best Regards,
    Chris

  • Hi Chris,

    So I should assure that the sending buffer is empty before I receive something in the receive buffer?
  • Hi Alberto,

    I'm not sure how it works on the Raspberry Pi. If your working with an SPI library though, chances are the library code handles this low-level operation. If you're reading data and you see a byte out of place here and there (corresponding to the same place an SPI command is being sent) then you'll have to figure a way to ignore it.

    How is your data looking?

    Best Regards,
    Chris

  • Hi Chris,

    Data looks fine, even though it doesn't seem really precise when I convert it in voltage, I don't know if this issue comes from dummy bytes, what do you think?

    Best Regards,
    Alberto
  • Hi Alberto,

    Sorry for the delayed response.

    The dummy byte would likely take the place of the most significant data byte; therefore, you would probably see very random-looking data if that was the cause.

    When you say the data doesn't look precise, what in particular are you seeing? Are the results noisier than expected or the average value drifting? Does calibration improve the results?

     

    Also, what do you have connected to the ADC input and reference pins? In many cases, the input signal or reference source can be the reason for poor performance.

     
    Best Regards,
    Chris

  • Frank,
    I had the same application problem as the OP. Raspberry pi 2 ver b, waveshare AD/DA board. goal: read ADC from python.

    Following your example, I used libbcm2835 as the wrapper. I don't know why PyBCM2835 did not work for me. This is working with Python3.

    I have gotten some code working in which I think I can set the data rate and analog channel (0-3), then read the 24-bit response. M y strategy was to mimic the example c-code provided by waveshare "ads1256_test.c". Some of the variables are not available as library object attributes so I had to look into the header file "bcm238.h" for the info and hard code them in.

    I am not a computer scientist, so there are probably some mistakes and hilarious stylistic problems here. One issue I can't figure out is why the three 8-bit chunks seem to be out of order. I used a command to set lowest significant bits first, but it had no effect. I still have to verify that the analog signals are correct with real inputs. Perhaps I am still sending wrong commands to the chip and getting the wrong 8-bit chunks together.

    Try the code below.

    -Felix



    #Python code
    import libbcm2835._bcm2835 as soc
    import time
    import os
    import numpy
    CMD_RDATA = 0x01
    rState = 0x00
    RPI_GPIO_P1_15=22
    RPI_GPIO_P1_11=17
    BCM2835_GPIO_FSEL_OUTP=0x01
    BCM2835_GPIO_FSEL_INPT=0x00
    BCM2835_GPIO_PUD_UP=0x02
    REG_MUX=1
    CMD_WREG=0x50
    ADS1256_GAIN_1=(0)
    # This means pin HIGH, true, 3.3volts on a pin. */
    HIGH=0x1
    # This means pin LOW, false, 0volts on a pin. */
    LOW=0x0

    #Channel values
    #(_ch == 0)
    #ADS1256_WriteReg(REG_MUX, (0 << 4) | 1); /* DiffChannal AIN0£¬ AIN1 */
    RegValue=(0 << 4) | 1
    #(_ch == 1)
    #ADS1256_WriteReg(REG_MUX, (2 << 4) | 3); /*DiffChannal AIN2£¬ AIN3 */
    #RegValue=(2 << 4) | 3
    #(_ch == 2)
    #ADS1256_WriteReg(REG_MUX, (4 << 4) | 5); /*DiffChannal AIN4£¬ AIN5 */
    #RegValue=(4 << 4) | 5
    #(_ch == 3)
    #ADS1256_WriteReg(REG_MUX, (6 << 4) | 7); /*DiffChannal AIN6£¬ AIN7 */
    #RegValue=(6 << 4) | 7


    #Some initialization
    soc.bcm2835_init()
    soc.bcm2835_spi_begin()
    soc.bcm2835_spi_setBitOrder(soc.BCM2835_SPI_BIT_ORDER_LSBFIRST )
    soc.bcm2835_spi_setDataMode(soc.BCM2835_SPI_MODE1)
    soc.bcm2835_spi_setClockDivider(soc.BCM2835_SPI_CLOCK_DIVIDER_1024)
    soc.bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_OUTP)
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)
    soc.bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_INPT)
    soc.bcm2835_gpio_set_pud(RPI_GPIO_P1_11, BCM2835_GPIO_PUD_UP)
    buf0=[0,0,0,0]
    #Select the rate
    buf0[0] = (0 << 3) | (1 << 2) | (0 << 1)
    buf0[1] = 0x08;
    buf0[2] = (0 << 5) | (0 << 3) | (ADS1256_GAIN_1 << 0)
    buf0[3] = 0xF0
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, LOW)
    soc.bcm2835_spi_transfer(CMD_WREG | 0)
    soc.bcm2835_spi_transfer(0x03)
    soc.bcm2835_spi_transfer(buf0[0])
    soc.bcm2835_spi_transfer(buf0[1])
    soc.bcm2835_spi_transfer(buf0[2])
    soc.bcm2835_spi_transfer(buf0[3])

    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)

    ###Select Channel
    ###CS_0
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, LOW)
    soc.bcm2835_spi_transfer(CMD_WREG | REG_MUX)
    soc.bcm2835_spi_transfer(RegValue)
    soc.bcm2835_spi_transfer(rState)
    ###CS_1
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)


    print('Begin')
    n = 0
    buf=[0, 0, 0]
    savedata=numpy.zeros(100)
    savetime=numpy.zeros(100)


    for n in range(0, 100):
    #print(time.clock())
    #CS_0
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, LOW)
    soc.bcm2835_spi_transfer(CMD_RDATA)
    soc.bcm2835_spi_transfer(rState)
    time.sleep(0.0005)
    buf[0]=soc.bcm2835_spi_transfer(0xff)
    buf[1]=soc.bcm2835_spi_transfer(0xff)
    buf[2]=soc.bcm2835_spi_transfer(0xff)

    read1=(buf[2] << 16) & 0x00FF0000
    read2=(buf[1] << 8)
    read3=(buf[0] << 0)
    read123=read1+read2+read3
    #CS_1
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)

    if (read123 & 0x800000):
    read123 |= 0xFF000000

    savedata[n]=read123
    savetime[n]=time.clock()

    print(read123 /pow(2,24) )
    #print(buf )
    #print(time.clock())
    #print(time.clock())

    time.sleep(0.001)
    n += 1


    soc.bcm2835_spi_end();
    soc.bcm2835_close();

    print(savedata)
    print(savetime)
  • Hi,

    i'm Jonathan and work with a ads1262, i'm read the spidev is a bug with no comunicate to the convert. I have a raspberry pi model b+. When i installing libbcm2835 ()  fatal error, no load library, no to recognize "_bcm2835". 

    How i can install the right library?.

    Thanks you very much

  • Hi Felix, 

    I was trying your code on my Raspberry Pi3 using either python 2.7.9 and 3.5.2. Either program crashes the kernel and restarts the shell on the "soc.bcm2835_spi_setDataMode(soc.BCM2835_SPI_MODE1)" line.  Have you see this before?  Any hints on what I'm doing wrong?

    Cheers, 

    gr8

  • I think I used the library from here www.airspayce.com/.../
    Did you follow all the make and install procedures?
  • Sorry gr8, your error sounds pretty general so many things might cause that. Something seems wrong at a pretty high level. You probably will get a crash even if your code only just first mentions the bcm2835 library. Maybe, I had that kind of problem when I my python environment did not have the bcm2835 libraries installed in the right version of python. You might have to check if the library files are installed in the right place. Do you see libbcm2835 in your usr/local/lib/python2.7 folder?

    By the way. I have found some big errors in my original code. I believe I was was reading the three buffer entries in the reverse order. I also was reading the single rather than differential signals. I have also updated the code to broadcast UDP messages, in case you want a remote computer or mobile device to monitor the data.

    See code below:





    # -*- coding: utf-8 -*-
    import libbcm2835._bcm2835 as soc
    import time
    import os
    import numpy
    import struct
    from socket import *


    ##Communication settings
    #Put your own ip number here otherwise the code will not work
    host = "192.168.1.5" # set to IP address of target computer

    port = 13000
    addr = (host, port)
    UDPSock = socket(AF_INET, SOCK_DGRAM)
    msg=bytes()


    ## The following code mirrors the structure of ADS1256_test.c as provided
    ## by WAVESHARE for the High Precision AD/DA Board add-on for Raspberry Pi

    #Constants used for ADC. These come from the header files for BCM2835
    CMD_RDATA = 0x01
    CMD_RDATAC = 0x03 #Read Data Continuously
    CMD_SYNC = 0xFC
    CMD_WAKEUP = 0x00
    CMD_RESET = 0xFE #Reset to Power-Up Values 1111 1110 (FEh)
    rState = 0x00
    RPI_GPIO_P1_15=22
    RPI_GPIO_P1_11=17
    BCM2835_GPIO_FSEL_OUTP=0x01
    BCM2835_GPIO_FSEL_INPT=0x00
    BCM2835_GPIO_PUD_UP=0x02
    REG_MUX=1
    CMD_WREG=0x50
    ADS1256_GAIN_1=(0)
    HIGH=0x1
    LOW=0x0
    buf=[0, 0, 0]



    ##Some basic commands to open GPIO
    def CS_0():
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, LOW)

    def CS_1():
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)




    def SelectRate():
    buf0=[0,0,0,0]

    #Select the rate
    buf0[0] = (0 << 3) | (1 << 2) | (0 << 1)
    buf0[1] = 0x08
    buf0[2] = (0 << 5) | (0 << 3) | (ADS1256_GAIN_1 << 0)
    buf0[3] = 0xF0 #max rate
    buf0[3] = 0xA1 #1000 sps

    CS_0()
    soc.bcm2835_spi_transfer(CMD_WREG | 0)
    soc.bcm2835_spi_transfer(0x03)
    soc.bcm2835_spi_transfer(buf0[0])
    soc.bcm2835_spi_transfer(buf0[1])
    soc.bcm2835_spi_transfer(buf0[2])
    soc.bcm2835_spi_transfer(buf0[3])
    CS_1()
    soc.bcm2835_delayMicroseconds(20)

    def InitializeADC():
    soc.bcm2835_init()
    soc.bcm2835_spi_begin()
    soc.bcm2835_spi_setBitOrder(soc.BCM2835_SPI_BIT_ORDER_LSBFIRST )
    soc.bcm2835_spi_setDataMode(soc.BCM2835_SPI_MODE1)
    soc.bcm2835_spi_setClockDivider(soc.BCM2835_SPI_CLOCK_DIVIDER_1024)

    soc.bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_OUTP)
    soc.bcm2835_gpio_write(RPI_GPIO_P1_15, HIGH)
    soc.bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_INPT)
    soc.bcm2835_gpio_set_pud(RPI_GPIO_P1_11, BCM2835_GPIO_PUD_UP)
    CS_0()
    soc.bcm2835_spi_transfer(0xFE) #Reset AD/AD card to factory
    CS_1()

    def SelectDiffChannel(ch):
    RegValue=(ch << 4) | (1 << 3)
    CS_0()
    soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(CMD_WREG | REG_MUX)
    soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(0x00)
    soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(RegValue)
    CS_1()

    soc.bcm2835_delayMicroseconds(5)
    ##ADS1256_WriteCmd(CMD_SYNC);
    CS_0()
    soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(CMD_SYNC)
    CS_1()
    soc.bcm2835_delayMicroseconds(5)

    CS_0()
    soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(CMD_WAKEUP)
    CS_1()
    soc.bcm2835_delayMicroseconds(25)

    def GetOneSampleADC():
    #buf=[0, 0, 0]
    CS_0()
    #soc.bcm2835_delayMicroseconds(2)
    soc.bcm2835_spi_transfer(CMD_RDATA)
    #soc.bcm2835_delayMicroseconds(10)
    buf[0]=soc.bcm2835_spi_transfer(0xff)
    buf[1]=soc.bcm2835_spi_transfer(0xff)
    buf[2]=soc.bcm2835_spi_transfer(0xff)
    read123=(buf[0] << 16) & 0x00FF0000
    read123+=(buf[1] << 8)
    read123+=(buf[2] << 0)
    if (read123 & 0x800000):
    read123 |= 0xFF000000
    return read123

    #just some empty vectors
    savedata0=numpy.zeros((100))
    savedata1=numpy.zeros((100))
    savedata2=numpy.zeros((100))
    savedata3=numpy.zeros((100))
    savetime=numpy.zeros((100))



    n = 0
    timeold=time.clock()

    ##Main Script
    InitializeADC()
    SelectRate()

    for n in range(0, 100): #How many time samples total
    for cc in range(0, 4): #Go through each cc differential channel
    #t1= time.clock()

    SelectDiffChannel(cc)
    t0= time.clock()
    #print("t2", time.clock()-t0)
    #soc.bcm2835_delayMicroseconds(100)
    read123=GetOneSampleADC()

    if cc==0:
    savedata0[n]=read123
    if cc==1:
    savedata1[n]=read123
    if cc==2:
    savedata2[n]=read123
    if cc==3:
    savedata3[n]=read123

    #Ask Python how time has passed
    tnew=time.clock()
    savetime[n]=tnew-timeold
    timeold=tnew

    #Set a delay between samples
    #soc.bcm2835_delayMicroseconds(1000)
    time.sleep(.001)
    ##End of Waveshare Code

    ##UDP Communication
    ##Convert a double into a byte, pick "endian"
    msg0=struct.pack("<d", savedata0[n])
    msg1=struct.pack("<d", savedata1[n])
    msg2=struct.pack("<d", savedata2[n])
    msg=msg0+msg1+msg2 ## Concatenate messages

    #Uncomment this to actually try to send a UDP message
    #UDPSock.sendto(msg, addr)

    n += 1


    soc.bcm2835_spi_end();
    soc.bcm2835_close();



    #Display the saved data
    print(savedata0 / (2**24))
    print(savedata1/ (2**24))
    print(savedata2/ (2**24))
    print(savedata3/ (2**24))

    print(savetime)

    UDPSock.close()
    os._exit(0)
  • As a final note, I would like to mention that I gave up on the approach I have posted above altogether because of performance issues. The whole endeavor was motivated by the idea that python would be a nice user friendly environment to access data from the waveshare board. But there is just too much overhead for python to be constantly talking to BCM2835. I suppose there might be some strange application where you need flexible access the the objects in BCM2835. However, for me, I just wanted fairly efficient access to the 4 analog differential signals. So what I did was turn the entire C code supplied by waveshare into a header file and a callable function that I can access form Python. If anyone is interested I can send them both pieces of code, but I am hesitant to post it because the C code is too lengthy.

  • Felix, much appreciated for all the help. I haven't had a chance to run it yet as I figure I'll need a solid chunk of time to troubleshoot.  Since it sounds like you did exactly what I want to do, would you mind sending me the header file/callable function directly(sidebar)?  

    Again,many thanks for the assistance,

  • Hi Felix, 

    I tried to run your new code and I get the same error where the kernel crashes and restarts the shell on the "soc.bcm2835_spi_setDataMode(soc.BCM2835_SPI_MODE1)" line.  I fear I am making a basic error.

    To answer your previous questions:

    > "You probably will get a crash even if your code only just first mentions the bcm2835 library. "

    The "import libbcm2835._bcm2835 as soc" seems to be fine and returns no error.  Also it will process through "soc.bcm2835_spi_setBitOrder(soc.BCM2835_SPI_BIT_ORDER_LSBFIRST )" before it trips up on the following line.

    I believe I am running v1.50 from www.airspayce.com/.../

    One thing I had issues with from the instructions was finding if my device tree was enabled.  It seems that rpi3/jessie no longer has advanced options?  And I could not find a thread anywhere that addressed how to enable the device tree through jessie.

    "sudo raspi-config
    under Advanced Options - enable Device Tree
    Reboot.

    > Do you see libbcm2835 in your usr/local/lib/python2.7 folder?

    I have libbcm2835 in my usr/local/lib/python2.7/dist-packages folder.

    > "You might have to check if the library files are installed in the right place. "

    If I had my library files installed in the wrong place, wouldn't I get an error when I imported libbcm2835?

    Anyways, if you'll let me try your c code, perhaps I'll have better luck?

    Cheers, 

    gr8

  • hello gr8,

    I am sorry this isn't working for you so far.

    So you are saying the code crashes on the setDataMode line? This does sound like a problem with communicating with the board. Have you been able to run the example c-code from waveshare?
    www.waveshare.com/.../DA_Board
    From this I was able to at least verify that the hardware was okay. Also, I can't remember if I had to change the jumper settings from what it was when it was shipped to me. Here is what the manual says for using the digital to analog conversion:

    >>Jumper settings:
    >>Set the Power Supply to 5V: connect the pin 5V and VCC.
    >>Set the Reference Input Voltage to 5V: connect the pin 5V and VREF.
    >>Connect the pin DA0 to LEDA, the pin DA1 to LEDB. Then the brightness of LEDA indicator will be changed according to the voltage output of
    >>DA0 and the brightness of LEDB indicator will be changed according to the voltage output of DA1.

    If the example code works, then I would skip over to my c code with python calling function. See below.

    If not, then maybe there's still something wrong with pi settings. I am also running Jessie, but on a raspberry pi 2. My raspi-config still shows the Device Tree Option. I found some documentation that told me that /boot/config.txt should have a line that says "device_tree= ". Otherwise it's on by default. I found another forum that recommends adding an explicit line for the waveshare. www.raspberrypi.org/.../viewtopic.php. I don't have this but maybe its needed for pi 3?

    If you can't get any of this to work on pi 3, maybe you should borrow someone's pi 2. I can send you a copy of my disk image if you like.

    I couldn't find a way to attach my python and c-code, so let me try pasting them here:


    #python_c_test.py

    from myModule import *
    import time
    print("Intialize AD/DA Board", myInitFunction())
    to=time.time()
    delT=0.001;
    ii=0;
    init=0
    while (ii<20):
    t1=time.time()
    delT=t1-to
    if delT>=0.001:
    if ii>0:
    init=1
    sensors=myMainFunction(init, 5.0)
    to=t1
    print("Result:", sensors, "time:",delT)
    ii=ii+1

    print("Closing Communication", myClosingFunction())
    #End of Python File


    //myModule.c
    //To compile this file:
    //gcc -shared -lbcm2835 -I/usr/include/python2.7/ -lpython2.7 -o myModule.so myModule.c

    //This c-code can be compiled to provided a library file usable by python 2.x
    //It is designed to return 1 sample of 8 channels.
    //The following is nearly verbatim from ADS1256_test.c supplied from WAVESHARE company.
    //This code was a demo that allows 8-channels from the ADC to be read and output to screen

    //We will moslty have a lot of function definitions before we get to the modifications for Python

    //The main change is to split the Main function into an initialization phase and a running phase.
    //The motivation for this design is so that Python can start intialization, then asks for data
    //only as needed. The c-functionality can then exit without holding up the python script.

    //We will mark New Code and Orginal Code

    //This include line for Python needs to come first according to python documentation
    //New Code

    //Including this file could be tricky. My compile environment did not know where it was
    //so I had to specify its location manually
    #include <Python.h>

    //Original Code
    //Note all the orginal functions were dropped in here unmodified
    //Look for next instance of New Code
    #include <stdio.h>
    #include <bcm2835.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <math.h>
    #include <errno.h>
    #include <time.h>

    //CS ----- SPICS
    //DIN ----- MOSI
    //DOUT ----- MISO
    //SCLK ----- SCLK
    //DRDY ----- ctl_IO data starting
    //RST ----- ctl_IO reset



    #define DRDY RPI_GPIO_P1_11 //P0
    #define RST RPI_GPIO_P1_12 //P1
    #define SPICS RPI_GPIO_P1_15 //P3

    #define CS_1() bcm2835_gpio_write(SPICS,HIGH)
    #define CS_0() bcm2835_gpio_write(SPICS,LOW)

    #define DRDY_IS_LOW() ((bcm2835_gpio_lev(DRDY)==0))

    #define RST_1() bcm2835_gpio_write(RST,HIGH);
    #define RST_0() bcm2835_gpio_write(RST,LOW);



    /* Unsigned integer types */
    #define uint8_t unsigned char
    #define uint16_t unsigned short
    #define uint32_t unsigned long




    typedef enum {FALSE = 0, TRUE = !FALSE} bool;


    /* gain channelî */
    typedef enum
    {
    ADS1256_GAIN_1 = (0), /* GAIN 1 */
    ADS1256_GAIN_2 = (1), /*GAIN 2 */
    ADS1256_GAIN_4 = (2), /*GAIN 4 */
    ADS1256_GAIN_8 = (3), /*GAIN 8 */
    ADS1256_GAIN_16 = (4), /* GAIN 16 */
    ADS1256_GAIN_32 = (5), /*GAIN 32 */
    ADS1256_GAIN_64 = (6), /*GAIN 64 */
    } ADS1256_GAIN_E;

    /* Sampling speed choice*/
    /*
    11110000 = 30,000SPS (default)
    11100000 = 15,000SPS
    11010000 = 7,500SPS
    11000000 = 3,750SPS
    10110000 = 2,000SPS
    10100001 = 1,000SPS
    10010010 = 500SPS
    10000010 = 100SPS
    01110010 = 60SPS
    01100011 = 50SPS
    01010011 = 30SPS
    01000011 = 25SPS
    00110011 = 15SPS
    00100011 = 10SPS
    00010011 = 5SPS
    00000011 = 2.5SPS
    */
    typedef enum
    {
    ADS1256_30000SPS = 0,
    ADS1256_15000SPS,
    ADS1256_7500SPS,
    ADS1256_3750SPS,
    ADS1256_2000SPS,
    ADS1256_1000SPS,
    ADS1256_500SPS,
    ADS1256_100SPS,
    ADS1256_60SPS,
    ADS1256_50SPS,
    ADS1256_30SPS,
    ADS1256_25SPS,
    ADS1256_15SPS,
    ADS1256_10SPS,
    ADS1256_5SPS,
    ADS1256_2d5SPS,

    ADS1256_DRATE_MAX
    } ADS1256_DRATE_E;

    #define ADS1256_DRAE_COUNT = 15;

    typedef struct
    {
    ADS1256_GAIN_E Gain; /* GAIN */
    ADS1256_DRATE_E DataRate; /* DATA output speed*/
    int32_t AdcNow[8]; /* ADC Conversion value */
    uint8_t Channel; /* The current channel*/
    uint8_t ScanMode; /*Scanning mode, 0 Single-ended input 8 channel£¬ 1 Differential input 4 channel*/
    } ADS1256_VAR_T;



    /*Register definition£º Table 23. Register Map --- ADS1256 datasheet Page 30*/
    enum
    {
    /*Register address, followed by reset the default values */
    REG_STATUS = 0, // x1H
    REG_MUX = 1, // 01H
    REG_ADCON = 2, // 20H
    REG_DRATE = 3, // F0H
    REG_IO = 4, // E0H
    REG_OFC0 = 5, // xxH
    REG_OFC1 = 6, // xxH
    REG_OFC2 = 7, // xxH
    REG_FSC0 = 8, // xxH
    REG_FSC1 = 9, // xxH
    REG_FSC2 = 10, // xxH
    };

    /* Command definition£º TTable 24. Command Definitions --- ADS1256 datasheet Page 34 */
    enum
    {
    CMD_WAKEUP = 0x00, // Completes SYNC and Exits Standby Mode 0000 0000 (00h)
    CMD_RDATA = 0x01, // Read Data 0000 0001 (01h)
    CMD_RDATAC = 0x03, // Read Data Continuously 0000 0011 (03h)
    CMD_SDATAC = 0x0F, // Stop Read Data Continuously 0000 1111 (0Fh)
    CMD_RREG = 0x10, // Read from REG rrr 0001 rrrr (1xh)
    CMD_WREG = 0x50, // Write to REG rrr 0101 rrrr (5xh)
    CMD_SELFCAL = 0xF0, // Offset and Gain Self-Calibration 1111 0000 (F0h)
    CMD_SELFOCAL= 0xF1, // Offset Self-Calibration 1111 0001 (F1h)
    CMD_SELFGCAL= 0xF2, // Gain Self-Calibration 1111 0010 (F2h)
    CMD_SYSOCAL = 0xF3, // System Offset Calibration 1111 0011 (F3h)
    CMD_SYSGCAL = 0xF4, // System Gain Calibration 1111 0100 (F4h)
    CMD_SYNC = 0xFC, // Synchronize the A/D Conversion 1111 1100 (FCh)
    CMD_STANDBY = 0xFD, // Begin Standby Mode 1111 1101 (FDh)
    CMD_RESET = 0xFE, // Reset to Power-Up Values 1111 1110 (FEh)
    };


    ADS1256_VAR_T g_tADS1256;
    static const uint8_t s_tabDataRate[ADS1256_DRATE_MAX] =
    {
    0xF0, /*reset the default values */
    0xE0,
    0xD0,
    0xC0,
    0xB0,
    0xA1,
    0x92,
    0x82,
    0x72,
    0x63,
    0x53,
    0x43,
    0x33,
    0x20,
    0x13,
    0x03
    };







    void bsp_DelayUS(uint64_t micros);
    void ADS1256_StartScan(uint8_t _ucScanMode);
    static void ADS1256_Send8Bit(uint8_t _data);
    void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate);
    static void ADS1256_DelayDATA(void);
    static uint8_t ADS1256_Recive8Bit(void);
    static void ADS1256_WriteReg(uint8_t _RegID, uint8_t _RegValue);
    static uint8_t ADS1256_ReadReg(uint8_t _RegID);
    static void ADS1256_WriteCmd(uint8_t _cmd);
    uint8_t ADS1256_ReadChipID(void);
    static void ADS1256_SetChannal(uint8_t _ch);
    static void ADS1256_SetDiffChannal(uint8_t _ch);
    static void ADS1256_WaitDRDY(void);
    static int32_t ADS1256_ReadData(void);

    int32_t ADS1256_GetAdc(uint8_t _ch);
    void ADS1256_ISR(void);
    uint8_t ADS1256_Scan(void);




    void bsp_DelayUS(uint64_t micros)
    {
    bcm2835_delayMicroseconds (micros);
    }


    /*
    *********************************************************************************************************
    * name: bsp_InitADS1256
    * function: Configuration of the STM32 GPIO and SPI interface£¬The connection ADS1256
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */


    void bsp_InitADS1256(void)
    {
    #ifdef SOFT_SPI
    CS_1();
    SCK_0();
    DI_0();
    #endif

    //ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_1000SPS); /* ÅäÖÃADC²ÎÊý£º ÔöÒæ1:1, Êý¾ÝÊä³öËÙÂÊ 1KHz */
    }




    /*
    *********************************************************************************************************
    * name: ADS1256_StartScan
    * function: Configuration DRDY PIN for external interrupt is triggered
    * parameter: _ucDiffMode : 0 Single-ended input 8 channel£¬ 1 Differential input 4 channe
    * The return value: NULL
    *********************************************************************************************************
    */
    void ADS1256_StartScan(uint8_t _ucScanMode)
    {
    g_tADS1256.ScanMode = _ucScanMode;
    /* ¿ªÊ¼É¨ÃèÇ°, ÇåÁã½á¹û»º³åÇø */
    {
    uint8_t i;

    g_tADS1256.Channel = 0;

    for (i = 0; i < 8; i++)
    {
    g_tADS1256.AdcNow[i] = 0;
    }
    }

    }

    /*
    *********************************************************************************************************
    * name: ADS1256_Send8Bit
    * function: SPI bus to send 8 bit data
    * parameter: _data: data
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_Send8Bit(uint8_t _data)
    {

    bsp_DelayUS(2);
    bcm2835_spi_transfer(_data);
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_CfgADC
    * function: The configuration parameters of ADC, gain and data rate
    * parameter: _gain:gain 1-64
    * _drate: data rate
    * The return value: NULL
    *********************************************************************************************************
    */
    void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)
    {
    g_tADS1256.Gain = _gain;
    g_tADS1256.DataRate = _drate;

    ADS1256_WaitDRDY();

    {
    uint8_t buf[4]; /* Storage ads1256 register configuration parameters */

    /*Status register define
    Bits 7-4 ID3, ID2, ID1, ID0 Factory Programmed Identification Bits (Read Only)

    Bit 3 ORDER: Data Output Bit Order
    0 = Most Significant Bit First (default)
    1 = Least Significant Bit First
    Input data is always shifted in most significant byte and bit first. Output data is always shifted out most significant
    byte first. The ORDER bit only controls the bit order of the output data within the byte.

    Bit 2 ACAL : Auto-Calibration
    0 = Auto-Calibration Disabled (default)
    1 = Auto-Calibration Enabled
    When Auto-Calibration is enabled, self-calibration begins at the completion of the WREG command that changes
    the PGA (bits 0-2 of ADCON register), DR (bits 7-0 in the DRATE register) or BUFEN (bit 1 in the STATUS register)
    values.

    Bit 1 BUFEN: Analog Input Buffer Enable
    0 = Buffer Disabled (default)
    1 = Buffer Enabled

    Bit 0 DRDY : Data Ready (Read Only)
    This bit duplicates the state of the DRDY pin.

    ACAL=1 enable calibration
    */
    //buf[0] = (0 << 3) | (1 << 2) | (1 << 1);//enable the internal buffer
    buf[0] = (0 << 3) | (1 << 2) | (0 << 1); // The internal buffer is prohibited

    //ADS1256_WriteReg(REG_STATUS, (0 << 3) | (1 << 2) | (1 << 1));

    buf[1] = 0x08;

    /* ADCON: A/D Control Register (Address 02h)
    Bit 7 Reserved, always 0 (Read Only)
    Bits 6-5 CLK1, CLK0 : D0/CLKOUT Clock Out Rate Setting
    00 = Clock Out OFF
    01 = Clock Out Frequency = fCLKIN (default)
    10 = Clock Out Frequency = fCLKIN/2
    11 = Clock Out Frequency = fCLKIN/4
    When not using CLKOUT, it is recommended that it be turned off. These bits can only be reset using the RESET pin.

    Bits 4-3 SDCS1, SCDS0: Sensor Detect Current Sources
    00 = Sensor Detect OFF (default)
    01 = Sensor Detect Current = 0.5 ¦Ì A
    10 = Sensor Detect Current = 2 ¦Ì A
    11 = Sensor Detect Current = 10¦Ì A
    The Sensor Detect Current Sources can be activated to verify the integrity of an external sensor supplying a signal to the
    ADS1255/6. A shorted sensor produces a very small signal while an open-circuit sensor produces a very large signal.

    Bits 2-0 PGA2, PGA1, PGA0: Programmable Gain Amplifier Setting
    000 = 1 (default)
    001 = 2
    010 = 4
    011 = 8
    100 = 16
    101 = 32
    110 = 64
    111 = 64
    */
    buf[2] = (0 << 5) | (0 << 3) | (_gain << 0);
    //ADS1256_WriteReg(REG_ADCON, (0 << 5) | (0 << 2) | (GAIN_1 << 1)); /*choose 1: gain 1 ;input 5V/
    buf[3] = s_tabDataRate[_drate]; // DRATE_10SPS;

    CS_0(); /* SPIƬѡ = 0 */
    ADS1256_Send8Bit(CMD_WREG | 0); /* Write command register, send the register address */
    ADS1256_Send8Bit(0x03); /* Register number 4,Initialize the number -1*/

    ADS1256_Send8Bit(buf[0]); /* Set the status register */
    ADS1256_Send8Bit(buf[1]); /* Set the input channel parameters */
    ADS1256_Send8Bit(buf[2]); /* Set the ADCON control register,gain */
    ADS1256_Send8Bit(buf[3]); /* Set the output rate */

    CS_1(); /* SPI cs = 1 */
    }

    bsp_DelayUS(5);
    }


    /*
    *********************************************************************************************************
    * name: ADS1256_DelayDATA
    * function: delay
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_DelayDATA(void)
    {
    /*
    Delay from last SCLK edge for DIN to first SCLK rising edge for DOUT: RDATA, RDATAC,RREG Commands
    min 50 CLK = 50 * 0.13uS = 6.5uS
    */
    bsp_DelayUS(10); /* The minimum time delay 6.5us */
    }




    /*
    *********************************************************************************************************
    * name: ADS1256_Recive8Bit
    * function: SPI bus receive function
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */
    static uint8_t ADS1256_Recive8Bit(void)
    {
    uint8_t read = 0;
    read = bcm2835_spi_transfer(0xff);
    return read;
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_WriteReg
    * function: Write the corresponding register
    * parameter: _RegID: register ID
    * _RegValue: register Value
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_WriteReg(uint8_t _RegID, uint8_t _RegValue)
    {
    CS_0(); /* SPI cs = 0 */
    ADS1256_Send8Bit(CMD_WREG | _RegID); /*Write command register */
    ADS1256_Send8Bit(0x00); /*Write the register number */

    ADS1256_Send8Bit(_RegValue); /*send register value */
    CS_1(); /* SPI cs = 1 */
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_ReadReg
    * function: Read the corresponding register
    * parameter: _RegID: register ID
    * The return value: read register value
    *********************************************************************************************************
    */
    static uint8_t ADS1256_ReadReg(uint8_t _RegID)
    {
    uint8_t read;

    CS_0(); /* SPI cs = 0 */
    ADS1256_Send8Bit(CMD_RREG | _RegID); /* Write command register */
    ADS1256_Send8Bit(0x00); /* Write the register number */

    ADS1256_DelayDATA(); /*delay time */

    read = ADS1256_Recive8Bit(); /* Read the register values */
    CS_1(); /* SPI cs = 1 */

    return read;
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_WriteCmd
    * function: Sending a single byte order
    * parameter: _cmd : command
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_WriteCmd(uint8_t _cmd)
    {
    CS_0(); /* SPI cs = 0 */
    ADS1256_Send8Bit(_cmd);
    CS_1(); /* SPI cs = 1 */
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_ReadChipID
    * function: Read the chip ID
    * parameter: _cmd : NULL
    * The return value: four high status register
    *********************************************************************************************************
    */
    uint8_t ADS1256_ReadChipID(void)
    {
    uint8_t id;

    ADS1256_WaitDRDY();
    id = ADS1256_ReadReg(REG_STATUS);
    return (id >> 4);
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_SetChannal
    * function: Configuration channel number
    * parameter: _ch: channel number 0--7
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_SetChannal(uint8_t _ch)
    {
    /*
    Bits 7-4 PSEL3, PSEL2, PSEL1, PSEL0: Positive Input Channel (AINP) Select
    0000 = AIN0 (default)
    0001 = AIN1
    0010 = AIN2 (ADS1256 only)
    0011 = AIN3 (ADS1256 only)
    0100 = AIN4 (ADS1256 only)
    0101 = AIN5 (ADS1256 only)
    0110 = AIN6 (ADS1256 only)
    0111 = AIN7 (ADS1256 only)
    1xxx = AINCOM (when PSEL3 = 1, PSEL2, PSEL1, PSEL0 are ¡°don¡¯t care¡±)

    NOTE: When using an ADS1255 make sure to only select the available inputs.

    Bits 3-0 NSEL3, NSEL2, NSEL1, NSEL0: Negative Input Channel (AINN)Select
    0000 = AIN0
    0001 = AIN1 (default)
    0010 = AIN2 (ADS1256 only)
    0011 = AIN3 (ADS1256 only)
    0100 = AIN4 (ADS1256 only)
    0101 = AIN5 (ADS1256 only)
    0110 = AIN6 (ADS1256 only)
    0111 = AIN7 (ADS1256 only)
    1xxx = AINCOM (when NSEL3 = 1, NSEL2, NSEL1, NSEL0 are ¡°don¡¯t care¡±)
    */
    if (_ch > 7)
    {
    return;
    }
    ADS1256_WriteReg(REG_MUX, (_ch << 4) | (1 << 3)); /* Bit3 = 1, AINN connection AINCOM */
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_SetDiffChannal
    * function: The configuration difference channel
    * parameter: _ch: channel number 0--3
    * The return value: four high status register
    *********************************************************************************************************
    */
    static void ADS1256_SetDiffChannal(uint8_t _ch)
    {
    /*
    Bits 7-4 PSEL3, PSEL2, PSEL1, PSEL0: Positive Input Channel (AINP) Select
    0000 = AIN0 (default)
    0001 = AIN1
    0010 = AIN2 (ADS1256 only)
    0011 = AIN3 (ADS1256 only)
    0100 = AIN4 (ADS1256 only)
    0101 = AIN5 (ADS1256 only)
    0110 = AIN6 (ADS1256 only)
    0111 = AIN7 (ADS1256 only)
    1xxx = AINCOM (when PSEL3 = 1, PSEL2, PSEL1, PSEL0 are ¡°don¡¯t care¡±)

    NOTE: When using an ADS1255 make sure to only select the available inputs.

    Bits 3-0 NSEL3, NSEL2, NSEL1, NSEL0: Negative Input Channel (AINN)Select
    0000 = AIN0
    0001 = AIN1 (default)
    0010 = AIN2 (ADS1256 only)
    0011 = AIN3 (ADS1256 only)
    0100 = AIN4 (ADS1256 only)
    0101 = AIN5 (ADS1256 only)
    0110 = AIN6 (ADS1256 only)
    0111 = AIN7 (ADS1256 only)
    1xxx = AINCOM (when NSEL3 = 1, NSEL2, NSEL1, NSEL0 are ¡°don¡¯t care¡±)
    */
    if (_ch == 0)
    {
    ADS1256_WriteReg(REG_MUX, (0 << 4) | 1); /* DiffChannal AIN0£¬ AIN1 */
    }
    else if (_ch == 1)
    {
    ADS1256_WriteReg(REG_MUX, (2 << 4) | 3); /*DiffChannal AIN2£¬ AIN3 */
    }
    else if (_ch == 2)
    {
    ADS1256_WriteReg(REG_MUX, (4 << 4) | 5); /*DiffChannal AIN4£¬ AIN5 */
    }
    else if (_ch == 3)
    {
    ADS1256_WriteReg(REG_MUX, (6 << 4) | 7); /*DiffChannal AIN6£¬ AIN7 */
    }
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_WaitDRDY
    * function: delay time wait for automatic calibration
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */
    static void ADS1256_WaitDRDY(void)
    {
    uint32_t i;

    for (i = 0; i < 400000; i++)
    {
    if (DRDY_IS_LOW())
    {
    break;
    }
    }
    if (i >= 400000)
    {
    printf("ADS1256_WaitDRDY() Time Out ...\r\n");
    }
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_ReadData
    * function: read ADC value
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */
    static int32_t ADS1256_ReadData(void)
    {
    uint32_t read = 0;
    static uint8_t buf[3];

    CS_0(); /* SPI cs = 0 */

    ADS1256_Send8Bit(CMD_RDATA); /* read ADC command */

    ADS1256_DelayDATA(); /*delay time */

    /*Read the sample results 24bit*/
    buf[0] = ADS1256_Recive8Bit();
    buf[1] = ADS1256_Recive8Bit();
    buf[2] = ADS1256_Recive8Bit();
    read = ((uint32_t)buf[0] << 16) & 0x00FF0000;
    read |= ((uint32_t)buf[1] << 8); /* Pay attention to It is wrong read |= (buf[1] << 8) */
    read |= buf[2];


    CS_1(); /* SPIƬѡ = 1 */

    /* Extend a signed number*/
    if (read & 0x800000)
    {
    read |= 0xFF000000;
    }

    return (int32_t)read;
    }


    /*
    *********************************************************************************************************
    * name: ADS1256_GetAdc
    * function: read ADC value
    * parameter: channel number 0--7
    * The return value: ADC vaule (signed number)
    *********************************************************************************************************
    */
    int32_t ADS1256_GetAdc(uint8_t _ch)
    {
    int32_t iTemp;

    if (_ch > 7)
    {
    return 0;
    }

    iTemp = g_tADS1256.AdcNow[_ch];

    return iTemp;
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_ISR
    * function: Collection procedures
    * parameter: NULL
    * The return value: NULL
    *********************************************************************************************************
    */
    void ADS1256_ISR(void)
    {
    if (g_tADS1256.ScanMode == 0) /* 0 Single-ended input 8 channel£¬ 1 Differential input 4 channe */
    {

    ADS1256_SetChannal(g_tADS1256.Channel); /*Switch channel mode */
    bsp_DelayUS(5);

    ADS1256_WriteCmd(CMD_SYNC);
    bsp_DelayUS(5);

    ADS1256_WriteCmd(CMD_WAKEUP);
    bsp_DelayUS(25);

    if (g_tADS1256.Channel == 0)
    {
    g_tADS1256.AdcNow[7] = ADS1256_ReadData();
    }
    else
    {
    g_tADS1256.AdcNow[g_tADS1256.Channel-1] = ADS1256_ReadData();
    }

    if (++g_tADS1256.Channel >= 8)
    {
    g_tADS1256.Channel = 0;
    }
    }
    else /*DiffChannal*/
    {

    ADS1256_SetDiffChannal(g_tADS1256.Channel); /* change DiffChannal */
    bsp_DelayUS(5);

    ADS1256_WriteCmd(CMD_SYNC);
    bsp_DelayUS(5);

    ADS1256_WriteCmd(CMD_WAKEUP);
    bsp_DelayUS(25);

    if (g_tADS1256.Channel == 0)
    {
    g_tADS1256.AdcNow[3] = ADS1256_ReadData();
    }
    else
    {
    g_tADS1256.AdcNow[g_tADS1256.Channel-1] = ADS1256_ReadData();
    }

    if (++g_tADS1256.Channel >= 4)
    {
    g_tADS1256.Channel = 0;
    }
    }
    }

    /*
    *********************************************************************************************************
    * name: ADS1256_Scan
    * function:
    * parameter:NULL
    * The return value: 1
    *********************************************************************************************************
    */
    uint8_t ADS1256_Scan(void)
    {
    if (DRDY_IS_LOW())
    {
    ADS1256_ISR();
    return 1;
    }

    return 0;
    }





    /*
    *********************************************************************************************************
    * name: Write_DAC8552
    * function: DAC send data
    * parameter: channel : output channel number
    * data : output DAC value
    * The return value: NULL
    *********************************************************************************************************
    */
    void Write_DAC8552(uint8_t channel, uint16_t Data)
    {
    uint8_t i;

    CS_1() ;
    CS_0() ;
    bcm2835_spi_transfer(channel);
    bcm2835_spi_transfer((Data>>8));
    bcm2835_spi_transfer((Data&0xff));
    CS_1() ;
    }
    /*
    *********************************************************************************************************
    * name: Voltage_Convert
    * function: Voltage value conversion function
    * parameter: Vref : The reference voltage 3.3V or 5V
    * voltage : output DAC value
    * The return value: NULL
    *********************************************************************************************************
    */
    uint16_t Voltage_Convert(float Vref, float voltage)
    {
    uint16_t _D_;
    _D_ = (uint16_t)(65536 * voltage / Vref);

    return _D_;
    }



    //New Code
    //Note that this was taken from the beginning of Main before the main while loop
    //Note print commands have been removed
    //Note we are able to declare the PyObject structure since we included Python.h
    //I gave this custom function the name py_myInitFunction, but you can make any
    //function you want with this format. There are no expected inputs to this function.

    /*
    * Init Function to be called from Python
    */
    static PyObject* py_myInitFunction(PyObject* self, PyObject* args)
    {
    char *s = "Now Intializing!";

    uint8_t id;
    bcm2835_init();
    bcm2835_spi_begin();


    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST ); // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE1); // The default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_1024); // The default
    bcm2835_gpio_fsel(SPICS, BCM2835_GPIO_FSEL_OUTP);//
    bcm2835_gpio_write(SPICS, HIGH);
    bcm2835_gpio_fsel(DRDY, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_set_pud(DRDY, BCM2835_GPIO_PUD_UP);

    ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_30000SPS);
    id = ADS1256_ReadChipID();
    //printf("\r\n");
    //printf("ID=\r\n");
    if (id != 3)
    {
    printf("Error, ASD1256 Chip ID = 0x%d\r\n", (int)id);
    }
    else
    {
    printf("Ok, ASD1256 Chip ID = 0x%d\r\n", (int)id);
    }
    //New Code
    //This command changes the basic rate of the device
    //ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_30000SPS);
    ADS1256_StartScan(0);

    return Py_BuildValue("s", s);


    }


    //New Code
    //Note that this function is similar to the initialization
    //but we now have inputs specified by PyArg_ParseTuple()

    /*
    * Main function to be called from Python
    */
    static PyObject* py_myMainFunction(PyObject* self, PyObject* args)
    {
    int32_t adc[8];
    int32_t volt[8];
    uint8_t i;
    uint8_t jj;

    uint8_t ch_num;
    int32_t iTemp;
    uint8_t buf[3];
    long int start_time;
    struct timespec gettime_now;
    double allchann[8];
    double x1, x2, x3, x4, x5, x6, x7, x8;
    //PyArg_ParseTuple is a function from python.h.
    // the "dd" statement asks for two doubles.
    //There are many other data types. See docs.python.org/.../arg.html
    //ADS1256_StartScan(0);

    PyArg_ParseTuple(args, "dd", &x1, &x2);

    ch_num = 4; //max channels

    //while((ADS1256_Scan() == 0)); // this is the default placement of this command
    // for (jj = 0; jj < 30; jj++)
    // {
    for (i = 0; i < ch_num; i++)
    {
    while((ADS1256_Scan() == 0)); //This placement seems to work better from python

    adc[i] = ADS1256_GetAdc(i);
    volt[i] = (adc[i] * 100) / 167;
    //printf("%8ld%8ld",(int)i, (int)adc[i] );
    }
    // }

    for (i = 0; i < ch_num; i++)
    {
    buf[0] = ((uint32_t)adc[i] >> 16) & 0xFF;
    buf[1] = ((uint32_t)adc[i] >> 8) & 0xFF;
    buf[2] = ((uint32_t)adc[i] >> 0) & 0xFF;
    //clock_gettime(CLOCK_REALTIME, &gettime_now);
    //printf("%8ld", (gettime_now.tv_nsec-start_time)/100000);
    //printf("%8ld%8ld%8ld%8ld",(int)i, (int)buf[0] , (int)buf[1] , (int)buf[2] );
    iTemp = volt[i]; /* uV */
    allchann[i]=(double)iTemp/1000000;
    //printf("%8ld", 0.001);
    if (iTemp < 0)
    {
    iTemp = -iTemp;
    //printf(" (-%ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
    }
    else
    {
    //printf(" ( %ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
    }

    }
    //start_time=gettime_now.tv_nsec;
    //bsp_DelayUS(100); //This delay might freeze the entire python for a while.

    //Note: Py_BuildValue allows you to build and return a value
    //return Py_BuildValue("dddddddd", allchann[0], allchann[1], allchann[2], allchann[3], allchann[4], allchann[5], allchann[6], allchann[7]);
    return Py_BuildValue("dddd", allchann[0], allchann[1], allchann[2], allchann[3] );
    //return Py_BuildValue("dd", allchann[0], allchann[1] );
    }






    /*
    * Closing function
    */
    static PyObject* py_myClosingFunction(PyObject* self, PyObject* args)
    {
    double x, y;
    PyArg_ParseTuple(args, "dd", &x, &y);
    bcm2835_spi_end();
    bcm2835_close();
    return Py_BuildValue("d", 1.0);
    }




    /*
    * Bind Python function names to our C functions
    */
    static PyMethodDef myModule_methods[] = {
    {"myInitFunction", py_myInitFunction, METH_VARARGS},
    {"myMainFunction", py_myMainFunction, METH_VARARGS},
    {"myClosingFunction", py_myClosingFunction, METH_VARARGS},
    {NULL, NULL}
    };

    /*
    * Python calls this to let us initialize our module
    */

    void initmyModule()
    {
    (void) Py_InitModule("myModule", myModule_methods);
    }


    //End of C File
  • Hi!

    It might be a little off but I could not find other threads prooving that somebody uses PyBCM2835 for python3.

    I would really appreciate a shot description how you managed to get working PyBCM2835.

    Thanks! 

  • I am sure you have moved past this problem by now, but I just noticed something when I was making a new image for my raspberry pi.

    from they python bindings: 

    GitHub.com/mubeta06/py-libbcm2835 

    Here, there is important note.

    “These bindings require the library be built as a shared library object. To do this manually simply gcc -shared -o libbcm2835.so -fPIC bcm2835.c and copy library to /usr/local/lib.”

    This is referring to the compile from the Broadcom code at 

    Without this step, then the soc.bcm2835_spi_setDataMode object will not be visible from python. 
    Felix