ArduinoCore-mbed
ArduinoCore-mbed copied to clipboard
SPI.beginTransaction() doesn't set the new mode.
TL:DR, SPI clock level is not adjusted to SPI mode before CS is asserted low.
Consider the example program below on Raspberry Pi Pico. It performs alternative SPI transactions using two SPI settings and two respective CS outputs. The first setting uses SPI MODE0 and the second SPI MODE2. The expectation is that the clk idle level should be adjusted to the mode by SPI.beginTransaction() but it is adjusted only when the actual transfer starts, after the CS was asserted low.
The oscilloscope screenshot below shows a transaction using MODE0 and CS1. Notice how the idle level when CS is asserted low is incorrect for MODE0.
Expected behavior: SPI.beginTransaction() should adjust immediately the clk idle level to the mode passed to it. Or, provide an alternative method to adjust the mode and clock idle level before asserting the CS low.
#include <SPI.h>
#define CS1 20
#define CS2 21
SPISettings settings1(1000000, MSBFIRST, SPI_MODE0);
SPISettings settings2(1000000, MSBFIRST, SPI_MODE2);
void setup() {
Serial.begin(115200);
pinMode(CS1, OUTPUT);
pinMode(CS2, OUTPUT);
digitalWrite(CS1, HIGH);
digitalWrite(CS2, HIGH);
SPI.begin();
}
void loop() {
// MODE1 transaction on CS1.
SPI.beginTransaction(settings1);
digitalWrite(CS1, LOW); // CS1 on
SPI.transfer(0x11);
SPI.endTransaction();
digitalWrite(CS1, HIGH); // CS1 off
// MODE2 transaction on CS2.
SPI.beginTransaction(settings2);
digitalWrite(CS2, LOW); // CS2 on
SPI.transfer(0x22);
SPI.endTransaction();
digitalWrite(CS2, HIGH); // CS2 off
Serial.println("loop");
delay(1000);
}
One workaround that works, is to issue a begin/transfer/end transaction with zero bytes, each time the SPI mode (or just CPOL?) change.