-
Notifications
You must be signed in to change notification settings - Fork 33
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
LPSPI Rework Open Discussion Points #147
Comments
@mciantyre In case you have some time, I'd appreciate your though on this, or if you have additional open questions I missed. I'm sure I missed plenty that will pop up later. |
I have some ideas for naming the async components here. These names depends on the design, so if that design doesn't work, we'll think of something different. Other ways to re-use the
Regarding 2: it would be OK with me to consider an
After removing the CS pin from the interface, I believe today's LPSPI driver can be a foundation for an async driver. It needs tweaks and extensions, but its lower-level API tries to support this use case. If the existing driver doesn't work, then reach for the RAL. We'll need to remove the chip select pin from the driver, turning it into something supporting
DMA + interrupts should work. Only supporting
Some status flags, like RDF and TDR, are read-only and cannot be cleared. Disabling the interrupt enable bits should work for these bits, and should also work for all other events. This allows a custom future to check and maintain the status register in its
I'm not a fan of "use cassette to go from async to blocking" for two reasons:
Raw pointers are OK. We can build our own / seek out existing safe abstractions. Any considerations for introducing an intermediary (ring) buffer within an async LPSPI driver? Let the user decide the buffer size when they create their async LPSPI driver. We use it as another FIFO for the interrupt case, and as the source / destination of DMA transfers. We incur extra copying and buffering in the driver, and the user pays in extra program memory. The extra buffer might change where / how we interact with the hardware FIFO, interrupt flags, status registers; not sure if that change is helpful. And if we require that the user supply us with a |
What would be the advantage of this, opposed to streaming into the hardware fifos directly? |
For DMA use-case: If we require that the user supply us with a For interrupts, we can reduce the number of executor wake-ups (different than the number of activating interrupts). We achieve this by moving hardware FIFO management into the interrupt handler. The user yields at Reducing the number of executor wake-ups might avoid cooperative multitasking issues. If we're managing the hardware FIFOs through code paths in the executor, we could over- or under-run a FIFO while another task isn't yielding. This might be less of a concern; I think executors like RTIC and embassy have ways to express task priorities. It's also not a perfect solution, since avoiding the problem still depends on the ring buffer's size (but at least the user controls that size). And for both cases, we have a consistent way to realize interrupt and DMA I/O. In the transmit path, we're filling a ring buffer, then triggering some state machine to empty that buffer. In the receive path, we're triggering some state machine to fill a ring buffer, then emptying that buffer. The distinction of interrupt and DMA is the answer to "what's that state machine on the other side of this buffer?" Once we establish the design, it naturally translates into an async LPUART driver implementation, supporting a peripheral that only has a four byte hardware FIFO. |
Uff, that's a lot to think about :D |
Architectural questions
u32
works always,u16
works never, andu8
works sometimes, depending on alignment (even if we align with slice::align_to. The read and write buffer could be misaligned to each other, making it impossible to DMA.)How should
embedded-hal
andembedded-hal-async
be implemented? Shouldembedded-hal
simply be acassette
poll
wrapper around theasync
version or be its own thing? (problem: implementation complexity, which reduces confidence in correctness)cassette
. Reason: Even in the blocking version,async
makes it trivially easy to listen to the write & read side simultaneously, because it will simply poll both sides of the operation alternatingly. Withoutasync
, the read and write operations whould have to be interleaved somehow. That is, if we manage to get rid of the critical section in the poll function; this one is kind of a problem for the sync version.Should critical sections be allowed inside of the interrupt handler? Should critical sections be held as short as possible?
How to combine
u8
/u16
/u32
without having to provide a separate implementation for each?* u8
and store alignment information separately. Then split them into 6 parts:u32
basedu8
/u16
transfer.Should the implementation be reference or raw pointer based?
unsafe
required, and hence increased confidence in correctnessThe text was updated successfully, but these errors were encountered: