embedded-hal icon indicating copy to clipboard operation
embedded-hal copied to clipboard

Add SPI traits that are not bound to `Word`?

Open jmjoy opened this issue 1 year ago • 3 comments
trafficstars

Some external devices use SPI transfers with flexible data sizes, such as certain small OLED screens.

When using Embassy, this works very well because the transfer method of its SPI struct uses the word size as a generic parameter of the method: https://docs.embassy.dev/embassy-stm32/git/stm32f103c8/spi/struct.Spi.html#method.transfer

However, in embedded-hal, the SPI generics are bound to Word, such as SpiBus<Word>. For SPI structs that own the implementation of this trait, it's not possible to flexibly change the data size: https://docs.rs/embedded-hal/1.0.0/embedded_hal/spi/trait.SpiBus.html

Therefore, is it possible to add an SPI trait that is not bound to Word?

jmjoy avatar Oct 24 '24 02:10 jmjoy

What the problem to implement SpiBus<AnyWord> for Spi?

Where:

enum AnyWord {
    U8(u8),
    U16(u16),
    AnyOther,
}
``` or just `struct AnyWord`.

burrbull avatar Oct 24 '24 05:10 burrbull

What the problem to implement SpiBus<AnyWord> for Spi?

Where:

enum AnyWord {
    U8(u8),
    U16(u16),
    AnyOther,
}
``` or just `struct AnyWord`.

Using enum will increase the size of elements. For example, the element in the example will ultimately be equal to the size of a u16 + 1, which is not favorable for embedded systems.

jmjoy avatar Oct 24 '24 06:10 jmjoy

However, in embedded-hal, the SPI generics are bound to Word, such as SpiBus<Word>. For SPI structs that own the implementation of this trait, it's not possible to flexibly change the data size

You can do multiple where bounds for different word sizes at the same time, which makes it behave similarly to a generic method.

struct MyDriver<T> {
    spi: T,
}

impl<T> MyDriver<T>
where
    T: SpiBus<u8> + SpiBus<u16>, // two bounds!
{
    fn do_something(&mut self) {
        self.spi.write(&[0u8, 1, 2, 3]).unwrap(); // will use SpiBus<u8>>::write
        self.spi.write(&[0u16, 1, 2, 3]).unwrap(); // will use SpiBus<u16>>::write
    }
}

What the problem to implement SpiBus<AnyWord> for Spi?

this wouldn't work with DMA. To be able to DMA you need an array of "bare" u8 or u16 etc.

Dirbaio avatar Oct 24 '24 10:10 Dirbaio

However, in embedded-hal, the SPI generics are bound to Word, such as SpiBus. For SPI structs that own the implementation of this trait, it's not possible to flexibly change the data size

You can do multiple where bounds for different word sizes at the same time, which makes it behave similarly to a generic method.

struct MyDriver<T> {
    spi: T,
}

impl<T> MyDriver<T>
where
    T: SpiBus<u8> + SpiBus<u16>, // two bounds!
{
    fn do_something(&mut self) {
        self.spi.write(&[0u8, 1, 2, 3]).unwrap(); // will use SpiBus<u8>>::write
        self.spi.write(&[0u16, 1, 2, 3]).unwrap(); // will use SpiBus<u16>>::write
    }
}

What the problem to implement SpiBus<AnyWord> for Spi?

this wouldn't work with DMA. To be able to DMA you need an array of "bare" u8 or u16 etc.

Thank you for your great use of generics!

jmjoy avatar Oct 25 '24 01:10 jmjoy