SPI Help - moving from Teensy 3.2 to 4.1

Here's something interesting - and delightful for me!
My new board has arrived, with the schematic as in post #20 above.
It works!
The code in the app is this at IMU start-up... very similar the test code I used on the STM test board.

Code:
bool dbIMU_STMicro::setup(void) {
    pinMode(AccelCS_Pin, OUTPUT);
    digitalWrite(AccelCS_Pin, HIGH);
    SPI.begin();

    // Check for corerect WHOAMI
    int attemptCount = 1;
    while (whoamI != EXPECTED_WHOAMI && attemptCount < 5) {
        Serial.printf("Get whoamI attempt: %d\tSending command: %d to pin: %d\n", attemptCount++, WHOAMI_COMMAND, AccelCS_Pin);
        receiveSPI(AccelCS_Pin, WHOAMI_COMMAND , &whoamI, 1);
        if (whoamI == EXPECTED_WHOAMI) {
            Serial.printf("\tGOOD whoamI: %02X\t at %lu ms\n\n", whoamI, millis());
            _IMU_isInitialized = true;
        } else {
            Serial.printf("\tbad whoamI: 0x%02X\t and should be 0x%02X\n\n", whoamI, EXPECTED_WHOAMI);
            // Serial.printf("AccelCS_Pin = %d\n", AccelCS_Pin);
        }
        while (attemptCount == 5 ) ;

    }

I'm going to puzzle around with what else might be different in hardware or software.

But for now, this is a happy surprise!

Thanks Paul and @sicco for your help so far!
 
Here's something interesting - and delightful for me!
My new board has arrived, with the schematic as in post #20 above.
It works!
The code in the app is this at IMU start-up... very similar the test code I used on the STM test board.

Code:
bool dbIMU_STMicro::setup(void) {
    pinMode(AccelCS_Pin, OUTPUT);
    digitalWrite(AccelCS_Pin, HIGH);
    SPI.begin();

    // Check for corerect WHOAMI
    int attemptCount = 1;
    while (whoamI != EXPECTED_WHOAMI && attemptCount < 5) {
        Serial.printf("Get whoamI attempt: %d\tSending command: %d to pin: %d\n", attemptCount++, WHOAMI_COMMAND, AccelCS_Pin);
        receiveSPI(AccelCS_Pin, WHOAMI_COMMAND , &whoamI, 1);
        if (whoamI == EXPECTED_WHOAMI) {
            Serial.printf("\tGOOD whoamI: %02X\t at %lu ms\n\n", whoamI, millis());
            _IMU_isInitialized = true;
        } else {
            Serial.printf("\tbad whoamI: 0x%02X\t and should be 0x%02X\n\n", whoamI, EXPECTED_WHOAMI);
            // Serial.printf("AccelCS_Pin = %d\n", AccelCS_Pin);
        }
        while (attemptCount == 5 ) ;

    }

I'm going to puzzle around with what else might be different in hardware or software.

But for now, this is a happy surprise!

Thanks Paul and @sicco for your help so far!

Just a prewarning: while you use the standard T4 SPI library, at the start of a transaction, expect the MOSI line to go from 'undefined' to either hard 0 or hard 1. That happens with /SS high and SCK going 'undefined' to hard 1 (with SPI_MODE3). If MOSI (=I2C SDA) goes 1 to 0 while SCK (=I2C SCL) is 1, and SS is also 1, then, as long as I2C is still enabled (bit I2C_disable==0 in CTRL4_C) in the ST MEMS as optional communication interface, then it is interpreted as I2C START and unless you show the MEMS an I2C STOP it will be deaf for whatever SPI you'd initiate.
In your example code, because the last bit of the byte 'WHOAMI_COMMAND' happens to be a one, you might be lucky second time around after POR. But likely the very first time after a true power on reset, that MOSI level will be going to zero right after you do an SPI_transaction.begin(). With no pullups enabled, it remains a gamble what then does and does not materialize. I would not bet on it...

There's just no way of setting the CTRL3 and CTRL4 registers in these ST MEMS to guaranteed 'will always work with T4 SPI library' settings over this T4 SPI driver to prevent the deadlock once I2C START is seen. To set these after a power on reset using SPI, the SPI interface must first work. Catch22...
 

The board is designed by me and produced at JLCPCB.
IMG_0083.jpg

and the IMU MEMS chip has this local schematic around the IMU

IMU on db18 Board.jpg
 
Just a prewarning:
Thanks @sicco.
While the original Teensy SPI-transaction-based coded just worked on my custom board, I'll be trying to break it. And bolster it.
It is a strange catch-22.

And I think I'll submit a ticket to ST Micro, though I'm only recently feeling conversant enough to write a clear request.
Perhaps they have a best practice for their MEMs chips reliably entering SPI mode without risk of I2S mode entry.
Thanks for poking at this with me!
 
I submitted a support request to ST Micro documenting the saga, and asking for best practices when using this chip for SPI comms.
I'll report back.
Thanks, all, for your help!
 
Advice from ST Micro seems to be:
- enter I2C commands sufficient to disable I2C. Then use SPI.

So, since I have a pull-up resistor on CS, and this can be the I2C active mode (on start-up), and since the shared pins on the LSM6DSM are not on the standard I2C pins on the Teensy, I'll try the following:
Code:
setup() {
   pinMode(MISO, OUTPUT);
   digitalWrite(MISO, HIGH); // LSM6DSM pin SAO/SD0 causes the I2C address to be 6 ( address = 4 if pulled LOW)
   Wire.setSDA(MOSI); // pin 11 the Teensy
   Wire.setSCL(SCK); // pin 13 the Teensy
   Wire.begin();
   Wire.beginTransmission(6);
   Wire.write(0x13); // CTRL4_C register
   Wire.write(0x02) // 00000010b - all default config (zeros) except disabling I2C
   Wire.endTransmission();
   Wire.end(); // is this supported?  is it needed to allow subsequent SPI use?

   SPI.begin();
}

I've not intentionally used I2C before.
Does this make sense as written?
 
Maybe. But I'm not sure that I2C with Wire library from the Teensy4.1 can be done from any Teensy pin just like that.
Plus you'll need to set (or pullup) the /SS input to make sure the interface is in I2C and not SPI interface after power on reset...
Will you have SDA and SCL pullups. Externally or internally in the Teensy? How many ohms? What data rate will I2C be here?

It should be possible to stick with only transfers via the MEMS SPI interface, provided you do a mimicked I2C stop condition upfront on the SCK and MOSI.
Writing an SPI bit banging or an I2C bit banging algorithm, output only, no input yet, to ensure register 0x13 really gets set properly is probably your safest bet.
Using the T4_DMA_SPI library that I share before is another way to skin this cat.
Or do a modification to the Teensy SPI library so that for Teensy4 the level on the SOUT ('MOSI') is tri-stated instead of set to some unpredictable hard 1 or 0 value when a transaction gets opened. Plus enable pullup as well on the MOSI pin then...
 
Maybe the SoftWire library might be helpful?

https://github.com/stevemarple/SoftWire

You would want to use this for I2C on the SPI pins and call its end() function before calling SPI.begin().

There is also a similar SoftwareWire library which probably will not work on Teensy 4.x, as it has AVR register conventions hard-coded. But SoftWire looks promising, as it uses only the Arduino API functions.
 
Back
Top