SPI in slave mode using Particle Boron is not working

I'm having a lot of trouble getting my boron (development board) to receive SPI data in slave mode from an OpenMV camera. The camera module (RT1062) is just sending numbers for now, but I'd like for it to eventually send images. Here's the set up;

Boron's SCK => D2 is connected to the OpenMV's SCK (Pin P2)
Boron's MOSI => D3 is connected to the OpenMV's MOSI (Pin P0)
Boron's MISO => D4 is connected to the OpenMV's MISO (Pin P1)
Boron's D5 (SS) is connected to the OpenMV's SS (Pin P3)

The link to the OpenMV's pinout is also here OpenMV's pinout and guide

The OpenMV is just sending the number 4 to the Particle, but for some reason, the Particle is not able to read the data coming through. I followed all the instructions here Particle SPI reference, but nothing is working. I'm linking both sets of code below. Please help!

Particle Boron Code - SPI Slave Mode

#include <SPI.h>

SYSTEM_THREAD(ENABLED);

// Define the SPI object and pins
#define SPI1_SS_PIN D5
char receivedData[4];

void setup() {
    // Initialize serial for debugging
    Serial.begin(9600);
    while (!Serial) { ; }  // Wait for serial to be ready

    // Initialize SPI1
    SPI1.begin(SPI_MODE_SLAVE, SPI1_SS_PIN);
    pinMode(SPI1_SS_PIN, INPUT_PULLUP);
   
}

void loop() {
    if (digitalRead(SPI1_SS_PIN) == LOW) {
        // SPI slave read
        SPI1.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
        for (int i = 0; i < 4; i++) {
            receivedData[i] = SPI1.transfer(0xFF);
        }
        SPI1.endTransaction();

        // Debugging: Print received data as raw bytes
        Serial.print("Received data: ");
        for (int i = 0; i < 4; i++) {
            Serial.print(receivedData[i], HEX);
        Serial.print(" ");
        }
        Serial.println();

        // Format the data for publishing
        String dataStr = String::format("%02X %02X %02X %02X", receivedData[0], receivedData[1], receivedData[2], receivedData[3]);
        Serial.println("Formatted data: " + dataStr);

        // Publish the formatted data to the Particle Cloud
        bool success = Particle.publish("ReceivedData", dataStr);
        Serial.println("Publish success: " + String(success));
    }
}

OpenMV Code - Micropython

import time
from machine import SPI, Pin
import urandom  # For generating random numbers

# Setup SPI
spi = SPI(1, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
cs = Pin("P3", Pin.OUT)
cs.value(1)

def send_numbers():
    #numbers = [urandom.getrandbits(8) for i in range(4)]  # Generate 4 random bytes
    number = 4
    time.sleep(4)
    cs.value(0)
    spi.write(bytearray(number))
    cs.value(1)
    print("Sent numbers:", number)  # Debugging line

while True:
    send_numbers()
    time.sleep(1)

I don't see you employing the SPI1.onSelect() function as outlined in the SPI-Slave example

// SPI1 slave example
static uint8_t rx_buffer[64];
static uint8_t tx_buffer[64];
static uint32_t select_state = 0x00;
static uint32_t transfer_state = 0x00;

SerialLogHandler logHandler(LOG_LEVEL_TRACE);

void onTransferFinished() {
    transfer_state = 1;
}

void onSelect(uint8_t state) {
    if (state)
        select_state = state;
}

/* executes once at startup */
void setup() {
    for (int i = 0; i < sizeof(tx_buffer); i++)
      tx_buffer[i] = (uint8_t)i;
    SPI1.onSelect(onSelect);
    SPI1.begin(SPI_MODE_SLAVE, A5);
}

/* executes continuously after setup() runs */
void loop() {
    while (1) {
        while(select_state == 0);
        select_state = 0;

        transfer_state = 0;
        SPI1.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), onTransferFinished);
        while(transfer_state == 0);
        if (SPI1.available() > 0) {
            Log.dump(LOG_LEVEL_TRACE, rx_buffer, SPI1.available());
            Log.info("Received %d bytes", SPI1.available());
        }
    }
}

Can you give this a try?

Thanks! I’m now seeing data being published. However, it’s the wrong data lol. I deleted the hashtag that commented out the line of code for the OpenMV that generated random numbers, and it’s generating random numbers in the serial monitor. However, the exact numbers that the OpenMV is generating are not translating correctly to particle cloud when I Particle.publish(); e.g., [24, 72, 727, 82] is showing up as different numbers. I doubt that this would be an SPI issue, but I just want to be sure I’m not missing anything.

It could have to do with different endianness of the two platforms.

Maybe you try to send characters rather than binary numbers to check whether the transfer itself is the problem or merely the encoding/decoding of the data.

BTW, 727 is definitely not a single byte value :wink:

Also, how does your current code look?

1 Like

Make sure your SPI data mode (MODE0 - MODE3) and bit order match on both sides. If they don't, you'll get the right number of bytes, but different data. On the Particle side, make sure you set it for SPI1, as in SPI1.setDataMode(SPI_MODE3);

1 Like

Current code, for both, looks like this

OpenMV Code

import time
from machine import SPI, Pin
import urandom  # For generating random numbers

# Setup SPI
spi = SPI(1, baudrate=1000000, polarity=0, phase=0)
cs = Pin("P3", Pin.OUT)
cs.value(1)

def send_numbers():
    numbers = [urandom.getrandbits(4) for _ in range(1)]  # Generate 1 random bytes
    print("Generated numbers:", numbers)  # Debugging line
    cs.value(0)
    spi.write(bytearray(numbers))
    cs.value(1)
    print("Sent numbers:", numbers)  # Debugging line

while True:
    send_numbers()
    time.sleep(2)

Particle Boron Codestrong text

#include "Particle.h"

SYSTEM_THREAD(ENABLED);

// Define the SPI object and pins
#define SPI1_SS_PIN D5
char receivedData[1];
volatile bool dataReady = false;

void onSelect(uint8_t state) {
    if (state == 1) {  // Selected
        dataReady = true;
    } else {  // Deselected
        dataReady = false;
    }
}

void setup() {
    // Initialize serial for debugging
    Serial.begin(9600);
    while (!Serial) { ; }  // Wait for serial to be ready

    // Initialize SPI1 as slave
    SPI1.setDataMode(SPI_MODE0);
    SPI1.setBitOrder(MSBFIRST);
    SPI1.onSelect(onSelect);
    SPI1.begin(SPI_MODE_SLAVE, SPI1_SS_PIN);

    Serial.println("SPI1 initialized");
}

void loop() {
    if (dataReady) {
        // SPI slave read
        memset(receivedData, 0, sizeof(receivedData));
        SPI1.transfer(NULL, receivedData, sizeof(receivedData), NULL);

        // Debugging: Print received data as integers
        Serial.print("Received data: ");
        for (int i = 0; i < 1; i++) {
            Serial.print(receivedData[i]);
            Serial.print(" ");
       
        }
        }
        Serial.println();

        // Format the data for publishing
        String dataStr = String::format("%d", receivedData[0]);
        Serial.println("Formatted data: " + dataStr);
        
        // Publish the formatted data to the Particle Cloud
        bool success = Particle.publish("ReceivedData", dataStr, PRIVATE);
        
        Serial.println("Publish success: " + String(success));

        dataReady = false;  // Reset the flag
  

That's a good point. I configured the code to reflect these settings. Seems to be resulting in the same mismatching data.

Thanks for the help on this! It turns out the baud rate should be at 115200...they are printing out matching numbers now.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.