SPI Communication Issue: MISO Line Stays High on Particle.io B524

I'm experiencing an issue with SPI communication between a Particle.io B524 and a slave module connected to my Dev Board.

When using an Arduino, the MISO line behaves correctly: it goes low when the CS line is low and stays low throughout the transaction. However, with the Particle.io B524, the MISO line stays high when the CS line is low.

Any suggestions on how to fix this?

My B524 is connected to a M2 Som Eval Board v.1.2
CS = Pin 34
MISO = Pin 36
MOSI = Pin 38
CLK = Pin 40
GND = Pin 42

Here is my code:

/*
 * Project myProject
 * Author: Your Name
 * Date:
 * For comprehensive documentation and examples, please visit:
 * https://docs.particle.io/firmware/best-practices/firmware-template/
 */

// Include Particle Device OS APIs
#include "Particle.h"

// Let Device OS manage the connection to the Particle Cloud
// SYSTEM_MODE(AUTOMATIC);
SYSTEM_MODE(MANUAL);

// Run the application and system concurrently in separate threads
SYSTEM_THREAD(ENABLED);

// Show system, cloud connectivity, and application logs over USB
// View logs with CLI using 'particle serial monitor --follow'
SerialLogHandler logHandler(LOG_LEVEL_INFO);

const int SPI_CS_PIN = D8; // Chip Select pin
const int DELAY_TIMER = 1; //

// Define command to be sent
const uint8_t COMMAND[] = {0x32, 0x00};

void setup()
{
    // Set up SPI
    SPI.begin(SPI_MODE_MASTER, SPI_CS_PIN);
    SPI.setClockSpeed(1000000);
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);

    // Set up the chip select pin
    pinMode(SPI_CS_PIN, OUTPUT);
    digitalWrite(SPI_CS_PIN, HIGH); // Keep CS high initially

    Serial.begin(9600);
    delay(1000);
}

void loop()
{
    // Send the initial command to the DW1001
    digitalWrite(SPI_CS_PIN, LOW);
    delay(DELAY_TIMER);
    for (int i = 0; i < sizeof(COMMAND); ++i)
    {
        SPI.transfer(COMMAND[i]);
    }
    digitalWrite(SPI_CS_PIN, HIGH);
    Serial.println("Sent initial command: 0x0C 0x00");

    // Receive the response
    uint8_t response[2]; // Adjust size if needed
    digitalWrite(SPI_CS_PIN, LOW);
    delay(DELAY_TIMER);
    for (int i = 0; i < sizeof(response); ++i)
    {
        response[i] = SPI.transfer(0x00); // Send dummy byte to read response
    }
    digitalWrite(SPI_CS_PIN, HIGH);

    // Process the received response
    Serial.print("Received response: ");
    for (int i = 0; i < sizeof(response); ++i)
    {
        Serial.printf("0x%02X ", response[i]);
    }
    Serial.println();

    uint8_t values[20];
    digitalWrite(SPI_CS_PIN, LOW);

    delay(DELAY_TIMER);
    for (int i = 0; i < 20; ++i)
    {
        values[i] = SPI.transfer(0x00); // Send dummy byte to read values
    }
    digitalWrite(SPI_CS_PIN, HIGH);

    Serial.print("Received values: ");
    for (int i = 0; i < sizeof(values); ++i)
    {
        Serial.printf("0x%02X ", values[i]);
    }
    Serial.println();

    delay(2000);
}

In idle state the MISO pin should go Hi-Z so neither HIGH nor LOW unless there is some other influence pulling the pin.

1 Like

When communicating from Arduino to the same device, the communication looks like this, and nothing else is different:

Can you also share a trace of the Boron's behaviour during the read cycle? (like in your Arduino plot)
Also what device are you communicating with?

Is there a defined behaviour of the target device during "command transfer" that would suggest it would pull the line LOW?
IIRC the master is not obliged to pull the line low when it expects the slave to set the level on the line.

BTW, instead of performing multiple single byte transfers I'd go with the buffer transfer as shown here

Even when the impact is minimal with a 2-byte payload, I find the code more readable. With larger payloads the DMA access realy becomes handy.

I'd also like to note that SPI derives from the Stream class and hence also supports all its methods.

1 Like

Thank you for all the feedback, it is still not working. I tried the buffer transfer method, but seems not to work on Arduino, so will give it a go later.

I am trying to connect to the DWM1001 from Qorvo. Qorvo DWM1001

I realize now I might have worked with different code sets on Arduino and Particle, but aligned them to be exactly the same. But what I find now is that MOSI is high in idle on particle, but low on Arduino.

Working on Arduino:

Not working on Particle:

Below is my code:

#include <SPI.h>

#ifdef PLATFORM_ID
// Include Particle Device OS APIs
//#include "Particle.h"

// Let Device OS manage the connection to the Particle Cloud
SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

// Show system, cloud connectivity, and application logs over USB
SerialLogHandler logHandler(LOG_LEVEL_INFO);

const int SPI_CS_PIN = D8;    // Chip Select pin  
#else
#ifdef ARDUINO
const int SPI_CS_PIN = 10;    // Chip Select pin  

#endif
#endif

const int DELAY_TIMER = 0;

void setup() {
    // Set up SPI
    SPI.begin();
    SPI.setDataMode(SPI_MODE1);
    SPI.setClockSpeed(1000000);

    // Set up the chip select pin
    pinMode(SPI_CS_PIN, OUTPUT);
    digitalWrite(SPI_CS_PIN, HIGH);  // Keep CS high initially

    // Set MOSI pin as OUTPUT and set it LOW initially
    
    
    Serial.begin(9600);
    delay(1000);
}

void loop() {
    
    // Send the initial command to the DW1001
    digitalWrite(SPI_CS_PIN, LOW);
    
    SPI.transfer(0x0C);
    SPI.transfer(0x00);
    digitalWrite(SPI_CS_PIN, HIGH);

    
    Serial.println("Sent initial command: 0x0C 0x00");
    delay(DELAY_TIMER);

    
    // Read the frame size and number of frames to receive
    digitalWrite(SPI_CS_PIN, LOW);
    uint8_t size = SPI.transfer(0xFF);
    uint8_t num = SPI.transfer(0xFF);
    digitalWrite(SPI_CS_PIN, HIGH);

    
    Serial.print("Size: ");
    Serial.println(size);
    Serial.print("num: ");
    Serial.println(num);
    delay(DELAY_TIMER);

    uint8_t values[size];

    
    digitalWrite(SPI_CS_PIN, LOW);
    for (int i = 0; i < size; ++i) {
        values[i] = SPI.transfer(0xFF);  // Send dummy byte to read values
    }
    digitalWrite(SPI_CS_PIN, HIGH);



    Serial.print("Received values: ");
    for (int i = 0; i < size; ++i) {
        if (values[i] < 0x10) {
            Serial.print("0x0");
        } else {
            Serial.print("0x");
        }
        Serial.print(values[i], HEX);
        Serial.print(" ");
    }
    Serial.println();

    delay(2000);
}

Sorry, but I cannot see any difference between the two traces.

The working and non-working traces in post 5 look identical to me. And in the original post, you said that MISO was high, and the post 5 that MOSI was staying high.

The B524 does not, and should not, drive the MISO pin when in master mode. It's in input mode and the slave device is what drives the pin when its CS pin is selected. If it's not going low, it's because the slave devices isn't driving it low as ScruffR mentioned.

2 Likes

Thank you for pointing that out. I realized I uploaded the same picture twice; I’ll correct it later today.

The main difference is that in the working example, MOSI is low in idle mode. My earlier comment about MISO being high was an observation, and I now understand it is controlled by the slave, so it isn’t crucial.

However, what puzzles me is that MOSI is high in idle mode, as seen in the images. Is this correct?

Could there be a difference in how the SPI library of Particle and Arduino work?

The state of MOSI does not matter when no CS pin is selected, because none of the slave devices are reading the bus (marked as xxxx in the diagram).

In mode 1, it's supposed to be low in idle state (after CS is low but before a clock cycle). The side that drives the data line does so on rising CLK and it's sampled by the other side on falling CLK.

2 Likes

Thank you @rickkas7 , @ScruffR for you help so far. I have updated my previous post with the correct images. Hope this helps clarify, and apologise for the confusion.

I think I found the difference. This is how Arduino does it: SPI.begin() - Arduino Reference

It initializes the SPI bus by setting SCK, MOSI, and SS to outputs, pulling SCK and MOSI low, and SS high.

How can I do the same on Particle ?

I managed to set the clock low, by applying following, but MOSI stays HIGH ?

const int SPI_CS_PIN = D8; // Chip Select pin
const int SPI_MOSI_PIN = MOSI; // Chip Select pin
const int SPI_CLOCK_PIN = SCK; // Chip Select pin

// Set up the chip select pin
pinMode(SPI_CS_PIN, OUTPUT);
pinMode(SPI_MOSI_PIN, OUTPUT); 
pinMode(SPI_CLOCK_PIN, OUTPUT); 
digitalWrite(SPI_CS_PIN, HIGH);  // Keep CS high initially
digitalWrite(SPI_MOSI_PIN, LOW);  // Keep MOSI Low initially
digitalWrite(SPI_CLOCK_PIN, LOW);  // Keep CLOCK Low initially

I am not able to set MOSI LOW in idle mode, any help ?

You cannot set the state of the MISO line. It's by definition only set by the SPI slave device when one is selected. It's indeterminate (floating) when not being driven by a slave device because SPI doesn't have pull resistors (unlike I2C).

Agree, @rickkas7 and sorry for the mess up in the thread. Initially I was chasing MISO, but later identified MOSI was causing me trouble.

I need to MOSI to LOW in idle mode. Can you advise ?

I am not sure where to update the title to correct it from MISO to MOSI ?

You can't manually set the MOSI line using digitalWrite. It's controlled only by the SPI controller.

The state of MOSI when no devices are selected is also indeterminate, because SPI slave devices don't read it when not selected. What state it's in after beginning a transaction but before the SCK clocks in the first data bit is determined by the SPI mode. It's low in SPI mode 1.

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