ArduinoCore-mbed icon indicating copy to clipboard operation
ArduinoCore-mbed copied to clipboard

SPI.beginTransaction() doesn't set the new mode.

Open zapta opened this issue 1 year ago • 1 comments

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);
}

SCR01

zapta avatar Jan 14 '24 22:01 zapta

One workaround that works, is to issue a begin/transfer/end transaction with zero bytes, each time the SPI mode (or just CPOL?) change.

zapta avatar Jan 17 '24 19:01 zapta