stm32-rs / stm32f4xx-hal

A Rust embedded-hal HAL for all MCUs in the STM32 F4 family
BSD Zero Clause License
550 stars 208 forks source link

Allow to change SPI mode #708

Open sre opened 10 months ago

sre commented 10 months ago

Hi,

Right now SPI mode is configured when initializing the SPI bus controller. But in a shared SPI bus each device might require a different SPI mode. Please provide an API to change the SPI mode before doing a transaction.

Thanks,

-- Sebastian

burrbull commented 2 months ago

Please add usage example.

How this API should look like?

sre commented 2 months ago

I ran into this by having MAX31913 (mode 0) and TMC5072 (mode 3) being used on the same SPI bus.

I suppose ideally it would be similar to how Linux handles it with the mode being part of the SPI device instead of the SPI bus. Linux automatically configures the bus into the correct mode based on the device doing a transaction.

The alternative would be providing a bus function, which can be used to change the bus mode. Then this function needs to be called before doing a transaction.

Edit: My local workaround is using MODE 3 for both devices. This results in the first bit missing for the MAX31913 communication. This quick hack works for me, since I have nothing important connected to the matching input channel. But it is obviously is not a good general solution.

burrbull commented 2 months ago

I suppose ideally it would be similar to how Linux handles it with the mode being part of the SPI device instead of the SPI bus. Linux automatically configures the bus into the correct mode based on the device doing a transaction.

I'm not familiar with Linux SPI. From your description looks like linux saves config for each device and dynamically changes it on each transaction. But:

  1. embedded-hal traits does not know anything about connected device. So it will be incompatible with e-h.
  2. Changing context on each transaction can slow down connection + firmware growing.

The alternative would be providing a bus function, which can be used to change the bus mode. Then this function needs to be called before doing a transaction.

Manual switch looks more reasonable. Some spi.set_mode()? Should it wait for previous transaction to complete? Stop peripheral?

sre commented 2 months ago

embedded-hal traits does not know anything about connected device. So it will be incompatible with e-h.

It got changed a little bit in 1.0, so that there is a SpiDevice, but it only knows about the chip select and not any other SPI information. But I agree that this solution would requires further extensions to the embedded-hal trait.

Changing context on each transaction can slow down connection + firmware growing.

IIRC Linux only changes the context if its needed by caching the information about the currently set mode. But obviously that needs some extra code and increases the firmware size.

Manual switch looks more reasonable. Some spi.set_mode()? Should it wait for previous transaction to complete? Stop peripheral?

Right. That obviously needs to wait for the previous transaction to complete, otherwise thins will break apart :) I quickly skipped over the TRM and it does not seem like the peripheral needs to be stopped to change CPOL/CPHA.

I just discussed this quickly at my Hackerspace and got one more suggestion, which should not require changing embedded-hal and does not require as many manual calls to spi.set_mode(): Allow creating two SpiBus instances for the same hardware like this:

burrbull commented 2 months ago

Looks like most legal is to just make custom SpiDevice implementation which set mode on each transaction. Not the fastest way, but simple and flexible.

burrbull commented 2 months ago

@sre Could you test #523 if you have something which uses SpiBus::write ?