Porting SPI code from Rasberry Pi to Particle

I’m trying to get the the AD7172, an ADC interfaced over SPI, to work with the Photon. As described here the main part is to correctly implement the Communication driver. The driver consists of three functions (https://github.com/analogdevicesinc/no-OS/blob/master/common_drivers/communication/generic/Communication.c):

  • SPI_Init() – initializes the communication peripheral.
  • SPI_Write() – writes data to the device.
  • SPI_Read() – reads data from the device.

I’ve previously implemented this on a Rasberry Pi using the bcm2835 library:

/******************************************************************************/
/* Include Files                                                              */
/******************************************************************************/
#include "Communication.h"
#include <bcm2835.h>

/***************************************************************************//**
 * @brief Initializes the SPI communication peripheral.
 *
 * @param lsbFirst - Transfer format (0 or 1).
 *                   Example: 0x0 - MSB first.
 *                            0x1 - LSB first.
 * @param clockFreq - SPI clock frequency (Hz).
 *                    Example: 1000 - SPI clock frequency is 1 kHz.
 * @param clockPol - SPI clock polarity (0 or 1).
 *                   Example: 0x0 - Idle state for clock is a low level; active
 *                                  state is a high level;
 *	                      0x1 - Idle state for clock is a high level; active
 *                                  state is a low level.
 * @param clockEdg - SPI clock edge (0 or 1).
 *                   Example: 0x0 - Serial output data changes on transition
 *                                  from idle clock state to active clock state;
 *                            0x1 - Serial output data changes on transition
 *                                  from active clock state to idle clock state.
 *
 * @return status - Result of the initialization procedure.
 *                  Example: 1 - if initialization was successful;
 *                           0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char SPI_Init(unsigned char lsbFirst,
                       unsigned long clockFreq,
                       unsigned char clockPol,
                       unsigned char clockEdg)
{
    printf("Start SPI_init\n");


    if (!bcm2835_init())
    {
        printf("bcm2835_init failed. Are you running as root??\n");
        return 0;
    }
    if (!bcm2835_spi_begin())
    {
        printf("bcm2835_spi_begin failedg. Are you running as root??\n");
        return 0;
    }
    
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE3);                   // The not default
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);                      // The default
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
    

    printf("SPI_Init done\n");


    return 1;
}

/***************************************************************************//**
 * @brief Reads data from SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer as an input parameter and the
 *               read buffer as an output parameter.
 * @param bytesNumber - Number of bytes to read.
 *
 * @return Number of read bytes.
*******************************************************************************/
unsigned char SPI_Read(unsigned char slaveDeviceId,
                       unsigned char* data,
                       unsigned char bytesNumber)
{


    bcm2835_spi_transfern(data, bytesNumber);
    return sizeof(data);


}

/***************************************************************************//**
 * @brief Writes data to SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer.
 * @param bytesNumber - Number of bytes to write.
 *
 * @return Number of written bytes.
*******************************************************************************/
unsigned char SPI_Write(unsigned char slaveDeviceId,
                        unsigned char* data,
                        unsigned char bytesNumber)
{
    
    printf("Called SPIWrite with:%x\n",data);
    bcm2835_spi_writenb(data, bytesNumber);



    printf("SPI_Write() is done\n");
    return sizeof(data);

}

I now tried to port this to the Particle using the native SPI library, but this does not seem to be to succesful.
This is the code I cooked up so far:

/******************************************************************************/
/* Include Files                                                              */
/******************************************************************************/

#include "Particle.h"
#include "Communication.h"


/***************************************************************************//**
 * @brief Initializes the SPI communication peripheral.
 *
 * @param lsbFirst - Transfer format (0 or 1).
 *                   Example: 0x0 - MSB first.
 *                            0x1 - LSB first.
 * @param clockFreq - SPI clock frequency (Hz).
 *                    Example: 1000 - SPI clock frequency is 1 kHz.
 * @param clockPol - SPI clock polarity (0 or 1).
 *                   Example: 0x0 - Idle state for clock is a low level; active
 *                                  state is a high level;
 *	                      0x1 - Idle state for clock is a high level; active
 *                                  state is a low level.
 * @param clockEdg - SPI clock edge (0 or 1).
 *                   Example: 0x0 - Serial output data changes on transition
 *                                  from idle clock state to active clock state;
 *                            0x1 - Serial output data changes on transition
 *                                  from active clock state to idle clock state.
 *
 * @return status - Result of the initialization procedure.
 *                  Example: 1 - if initialization was successful;
 *                           0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char SPI_Init(unsigned char lsbFirst,
                       unsigned long clockFreq,
                       unsigned char clockPol,
                       unsigned char clockEdg)
{
    Serial.printf("Start SPI_init\n");

    SPI.begin();  // defaults to set A2 as an OUTPU
    SPI.setBitOrder(MSBFIRST); // Data is read and written MSB first.
    SPI.setDataMode(SPI_MODE3);
    SPI.setClockDivider(SPI_CLOCK_DIV256); 
    
    Serial.printf("SPI_Init done\n");


    return 1;
}

/***************************************************************************//**
 * @brief Reads data from SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer as an input parameter and the
 *               read buffer as an output parameter.
 * @param bytesNumber - Number of bytes to read.
 *
 * @return Number of read bytes.
*******************************************************************************/
unsigned char SPI_Read(unsigned char slaveDeviceId,
                       unsigned char* data,
                       unsigned char bytesNumber)
{

    static uint8_t rx_buffer[64];
    static uint8_t tx_buffer[64];

    for (int i = 0; i < bytesNumber; i++)
        tx_buffer[i] = 0x00; //Create dummy to send


    //SPI.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), NULL);
    digitalWrite(A2, LOW);
    SPI.transfer(tx_buffer, data, bytesNumber, NULL); //Transfer dummy bytes and read output, do not use callback (NULL)
    digitalWrite(A2, HIGH);

    Serial.printf("SPI_Read() size: %d\t",bytesNumber);
    Serial.printf("SPI_Read() result: %.2X\n",data);


    return sizeof(data);

 
}

/***************************************************************************//**
 * @brief Writes data to SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer.
 * @param bytesNumber - Number of bytes to write.
 *
 * @return Number of written bytes.
*******************************************************************************/
unsigned char SPI_Write(unsigned char slaveDeviceId,
                        unsigned char* data,
                        unsigned char bytesNumber)
{
    
    
    static uint8_t rx_buffer[64];
    static uint8_t tx_buffer[64];

    
    digitalWrite(A2, LOW);
    SPI.transfer(data, rx_buffer, bytesNumber, NULL);
    digitalWrite(A2, HIGH);


    Serial.printf("SPI_Write() data: %.2X\t",data);
    Serial.printf("SPI_Write() result: %.2X\t",rx_buffer);
    Serial.printf("Size %d\n",bytesNumber);


}

When I try to set the setup register in the AD7172, I do read values back from the AD7172, but they all seemed ‘random numbers’. I’m wondering wether the SPI_Read() and SPI_Write() functions are actually correctly implemented (ie. with sending the ‘dummy bytes’)?