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!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.