How can I use the WriteDma trait

Fellow coders,
I want to create a board crate for our ARM board we have at school. Our display is using a 9 Bit SPI protocol, which currently is not supported. So I'm about to write a double buffered DMA driver that should be generic enough for others to use (I've done that already a while back in C to port uGfx).

My problem is, that while the DMA examples compile, I fail to put the code inside a function. I assume it's a trait bound problem, but all attempts to resolve it failed. The compiler complains about the function wait is missing in transfer: See my function test_write in main.rs.

Thanks for your time

If you see methods not being implemented, always look at the imports. There is either a trait used or some kind of prelude like use some_crate::prelude::*. That'll tell you where to look for the trait.

I think it is the bound on TransferPayload. Like

fn test_write<T:WriteDMA+TransferPayload>(t: T, buffer: &'static [u8])
{
   let transfer = t.write(buffer);
   let x = transfer.wait();
   //               ^^^^^^ My problem: method does not exist in transfer
}

dirty playground

Thank you for studying my issue.

Unfortunately it's not that easy. In the source file dma.rs on line 344 it looks like the method wait is implemented by a macro. (We use SPI3 on connectivity line). I just tried with TransferPayload, but it doesn't solve it.

What error do you get when including the TransferPayload bound on the test_write function? I can see that the spi_dma macro includes (conditionally) SPI3.

It would be easier to see it with a self-contained playground. But I have not been able to load that dependency on it.

I get

error[E0599]: no method named `wait` found for struct `stm32f1xx_hal::dma::Transfer<stm32f1xx_hal::dma::R, &[u8], W>` in the current scope
--> src/main.rs:94:25
 |
94 |        let x = transfer.wait();
 |                         ^^^^ method not found in `stm32f1xx_hal::dma::Transfer<stm32f1xx_hal::dma::R, &[u8], W>`

To reproduce you should be able to clone the repo from here and cargo check it

The actual bound is TxDma<PAYLOAD, C1>: TransferPayload. I see now that fn test_write<W: WriteDma<&'static[u8],u8>+TransferPayload>(t: W, buffer: &'static [u8]) is not enough. We need to have the TxDma written. And this one is a struct, not a trait, which has confused me considerably.

I think this is:

fn test_write<P:PAYLOAD,C:RXCH,>(t: TxDma<P,C>, buffer: &'static [u8])
  where TxDma<P,C>:WriteDma<&'static[u8],u8>+TransferPayload
{
  let transfer = t.write(buffer);
  let x = transfer.wait();
}

One problem is that wait is not a trait method. Instead, there are many separate inherent methods named wait, and the compiler needs to know which one to call. This means you have to be a lot more specific about the the type of t.

A second problem is that you appear to be passing a SpiTxDma<SPI3, REMAP, PINS, C2>, but TransferPayload is not implemented for this type. It is implemented only for these SPI types:

  • SpiTxDma<SPI1, REMAP, PINS, C3>
  • SpiTxDma<SPI2, REMAP, PINS, C5>

Thank you for helping.
I just tried to compile

fn test_write<P, C>(t: TxDma<P,C>, buffer: &'static [u8])
  where TxDma<P,C>:WriteDma<&'static[u8],u8>+TransferPayload
    {
        let transfer = t.write(buffer);
        let x = transfer.wait();
    }

but still get

error[E0599]: no method named `wait` found for struct `stm32f1xx_hal::dma::Transfer<stm32f1xx_hal::dma::R, &[u8], stm32f1xx_hal::dma::TxDma<P, C>>` in the current scope
  --> src/main.rs:96:20
   |
96 |   let x = transfer.wait();
   |                    ^^^^ method not found in `stm32f1xx_hal::dma::Transfer<stm32f1xx_hal::dma::R, &[u8], stm32f1xx_hal::dma::TxDma<P, C>>`

However i feel we are getting closer :slight_smile:
I could write the code to work only in my situation, but I would like to get a generic solution for others.
The relevant crate to interface my display does not support DMA and I think it would be a great addition to get that going.

Yes, SPI3 is only implemented for the connectivity line. However I have enabled the feature="connectivity".
If I write the code without calling the function (everything straight top down, like the example) it compiles.
However to implement the relevant display traits I need to be able to call a function.

Right, the bound is not on any TXCH, but particular for each C1...C5. I guess we need to have 5 test_writes to have the whole scenario. Like

fn test_write<P>(t: TxDma<P,C1>, buffer: &'static [u8])
  where TxDma<P,C1>:WriteDma<&'static[u8],u8>+TransferPayload
    {
        let transfer = t.write(buffer);
        let x = transfer.wait();
    }
1 Like

This compiles:

fn test_write<REMAP, PINS>(t: SpiTxDma<SPI3, REMAP, PINS, C2>, buffer: &'static [u8])
{
    let transfer = t.write(buffer);
    let x = transfer.wait();
}
1 Like

This looks good.
I still have an interference problem, I should be able to sort that out myself.

error[E0282]: type annotations needed
  --> src/main.rs:99:4
   |
99 |    test_write(tx_dma, &buffer1);
   |    ^^^^^^^^^^ cannot infer type for type parameter `REMAP` declared on the function `test_write`

I hoped to get that going with the generic WriteDma trait. However restricting the transfer to SPI devices should be fine too.
Thank you for your effort!