Hal_spi_transfer function hangs when using SC16IS740SPI

The above function that never exits and hangs the DeviceOS causing a watchdog timer reset. The file in question is spi_hal.cpp line 459. This using the B-SOM B402 particle module and DeviceOS 6.2.0. The chip being used is the SC16IS760. We are using SPI1 not shared.
The call stack: begin() -> writeRegister() -> spi.transfer(reg << 3); -> transfer() -> static_cast(hal_spi_transfer(_spi, _data));

Repo link:

So why would it hang there forever?

There is a problem in the SC16IS8740RK library in that the DMA version never worked properly on Gen 3 devices. I fixed this by disabling that DMA when HAL_PLATFORM_MESH was defined. The problem is that that define was deprecated and no longer exists, so the code that was disabled in version 0.0.3 became enabled again on newer versions of Device OS.

I fixed this and released a new version 0.0.9.

2 Likes

We are not running into any issue with the DMA portion of the driver, since we hang in SC16IS740SPI.begin(). The firmware gets stuck in SC16IS740SPI.writeRegister() on spi.transfer(reg << 3);
We modified the device os 4.2.0 to output logs before and after the following in hal_spi_transfer

// add log 1 here
    // Wait for SPI transfer finished
    while(spiMap[spi].transmitting) {
        ;
    }
// add log 2 here

We see our log 1, but not log 2. We know that this part was not assembled with the board correctly, but instead of failing the call to begin, the firmware hangs, so we cannot detect this failure in firmware. Its strange, since we have not seen this behavior from other spi devices. For instance, if I remove an sd card, my driver fails to init, it does not hang. For the SC16IS740SPI, it doesn't even seem like a driver issue, but a device os issue. I am wondering why spiMap[spi].transmitting is stuck true. The only other spi calls prior to this are spi.begin() in the driver's preBegin function. Could it be initialization of the spi bus is never completing because the chip was not assembled properly, leading to spiMap[spi].transmitting stuck in true?

It's not clear to me how that would happen. In SPI, the master side controls the length of transmission, and the transmission should terminate even if there was no device connected. This is different than I2C, which can hang when the I2C device behaves strangely.

I suppose it might be possible if something is affecting interrupts. On nRF52, the transmissing flag is cleared from spiMasterEventHandler which I think is affected by the interrupt mask.

I measured my spi1 clock signal and found that it went from 0 to 600mV after calling SC16IS740SPI.begin(). This gave me the idea to see if I could replicate this issue without the IC or the SC16IS740SPI library, which I was able to do.

I can replicate this issue on a m.2 eval board v1.2 and a b402 running the firmware below with device os 4.2.0. I disconnected the sd card by removing the jumpers and set SD_CK (spi1 clock) to GND.

My interpretation of this is that the SPI1 driver depends on proper functionality of the SPI1 clock signal, otherwise it is liable to hang the firmware.

#include "Particle.h"

SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler(LOG_LEVEL_INFO);

uint32_t loopTime;

void setup() {
    Serial.begin();
    while(!Serial.isConnected()) {
        Particle.process();
    }
    delay(1000);
    Log.info("Start");

    SPI1.begin(D6);
    digitalWrite(D6, HIGH);
    SPI1.setBitOrder(MSBFIRST);
    SPI1.setClockSpeed(4, MHZ); // Default: 4
    SPI1.setDataMode(SPI_MODE0);
    pinResetFast(D6);
    SPI1.transfer(0xAA);
    pinSetFast(D6);

    loopTime = millis();
}

void loop() {
    if(millis() - loopTime > 2000) {
        loopTime = millis();
        Log.info("loop");
    }
}



SPI SCK is an output from the MCU. It would not surprise me if grounding the output causes odd behavior.

1 Like

I also tried this firmware with an MSOM on 6.2.0 on a muon board, jumping SPI1 SCK (pin 11) to ground (pin 6) and did not experience hanging when calling SPI1.transfer.