Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to perform SPI write before starting DMA transfer? #472

Open
nullobject opened this issue Nov 29, 2023 · 3 comments
Open

How to perform SPI write before starting DMA transfer? #472

nullobject opened this issue Nov 29, 2023 · 3 comments

Comments

@nullobject
Copy link

nullobject commented Nov 29, 2023

Is it possible to do a normal SPI write before starting a DMA transfer?

I am trying to use DMA to write the frame buffer to an OLED display (SSD1322), but I need to write a couple of commands to the display before sending the pixel data.

For example, building on the SPI DMA example it would be nice to be able to do something like this:

transfer.start(|spi| {
    // Write a command before beginning the transfer
    dc.set_low();
    cs.set_low();
    spi.write(&[0x11u8, 0x22, 0x33]).unwrap(); // <-- can't call write here because SPI is disabled
    cs.set_high();

    // Write frame buffer using DMA transfer
    dc.set_high();
    cs.set_low();
    spi.enable_dma_tx();
    spi.inner_mut().cr1.modify(|_, w| w.spe().enabled());
    spi.inner_mut().cr1.modify(|_, w| w.cstart().started());
});

Unfortunately the types make this impossible, as the SPI reference passed to the closure is disabled.

Any suggestions?

It would be nice to just use a similar API to the I2C DMA example:

transfer.start(|i2c| {
    // This closure runs right after enabling the stream

    // Issue the first part of an I2C transaction to read data from a
    // touchscreen

    // Write register index
    i2c.write(0xBA >> 1, &[0x41, 0xE4]).unwrap();

    // Start a read of 10 bytes
    i2c.master_read(0xBA >> 1, 10, i2c::Stop::Automatic);
});
@mlamoore
Copy link
Contributor

mlamoore commented Nov 29, 2023 via email

@nullobject
Copy link
Author

I'm this situation, why wouldn't you just use DMA to send the command as

well as the data? It seems simpler to me (in C as well as Rust) to set up

the SPI and DMA peripherals to work together, then send one short DMA

transfer with the command, followed by a longer DMA transfer with the data.

@mlamoore Thanks for the reply.

I need to send 3 commands to the display (row address, column address, write enable) before sending the frame buffer data.

Sending the commands and frame buffer with DMA would require extra state so the interrupt handler knows what to do next. e.g. The DC signal needs to be asserted for data, and deasserted for commands. The CS signal needs to be asserted/deasserted for each transaction.

In C, this is three blocking HAL_SPI_Transmit calls followed by a HAL_SPI_Transmit_DMA call, which is quite simple to implement.

@nullobject
Copy link
Author

@mlamoore Hi again. I am still looking for a solution.

Do you know of any examples of how to do multiple DMA transfers, like you suggested?

Does this require freeing each DMA transfer when it is complete to gain access to the resources (i.e. SPI instance) and start another transfer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants