imxrt-rs / imxrt-hal

Rust for NXP i.MX RT
Apache License 2.0
122 stars 29 forks source link

LPSPI: embedded-hal 1.0 rework #145

Open Finomnis opened 7 months ago

Finomnis commented 6 months ago

I briefly looked this over, the delays in the SPI transaction look very strange, is there a particular reason those are there? Won't this imply the need for a timer queue or scheduler of some kind?

That seems like a pretty big ask of what amounts to a hal library?

I'm uncertain what you mean, to be honest. Which delays?

If you are taking about the example, the delay there is not part of our driver code, it comes from embedded-hal 1.0

Finomnis commented 6 months ago

I may be in the minority about the "give users low-level control" design decisions

I personally don't like this, because it introduces ways for the user to break the internal state of the driver. I kind of consider this a functional unsoundness. I found the existing driver very hard to use because it requires me to understand the peripheral, which I as a user don't want to have to understand. I felt I would have to write a driver for the driver to actually use it in a project.

I would personally rather go the other route - closing it off completely and then step by step adding features as required. But that's just my personal opinion.

Finomnis commented 6 months ago

Here's a rough outline of what it might look like:

Let me think about this. You might be onto something.

Be aware that:

teburd commented 6 months ago

I think it’s cool that you are adding support for eh 1.0. I’d note that interrupts are not free of cost and sometimes it really is faster to poll. I saw this in a few spi peripherals in Zephyr that I’ve modified/reviewed. At times interrupts can cause slowdowns. Especially true when doing XIP or on cores with longer pipelines with icache/dcache involved like the M7

Finomnis commented 6 months ago

That might be true!

If we

Then we can go with @mciantyre's architecture proposal.

Finomnis commented 6 months ago

The biggest open question I still have is error handling. But I have to clarify:

mciantyre commented 6 months ago

I found the existing driver very hard to use because it requires me to understand the peripheral, which I as a user don't want to have to understand.

We support embedded-hal for hiding the peripheral's complexity. We still need to give the user APIs for driver configurations, since embedded-hal doesn't help us here. But after you configure your driver and pass ownership into your embedded-hal-using component, it should become difficult to break the driver's internal state.

I'm sure there's use-cases I'm not considering, but that's the thinking for giving users the lower-level control.

there will always be a benefit from using interrupts, even in the dma case. For error handling and for the flush call.

We could require the user to transform InterruptTransmit into DmaTransmit, for example. Once DmaTransmit takes ownership of InterruptTransmit, it could select the I/O behaviors, wait for flush, check errors.

I’d note that interrupts are not free of cost and sometimes it really is faster to poll.

Good point. We're free to spin in async code if we find it profitable. We block the executor and other tasks.

Finomnis commented 6 months ago

But after you configure your driver and pass ownership into your embedded-hal-using component, it should become difficult to break the driver's internal state.

I agree. So we should maybe look into something like a builder pattern?

Finomnis commented 6 months ago

@mciantyre Might have to take a step back over the next couple of days/weeks. If someone has an idea, be free to use my code as a base/reference. There are a couple of things in there that took a while to figure out, like the proper settings of the timing registers and the clock multiplier calculation, which I think are improvements over the original version in a couple of details.

If I do continue (which I will if nobody else wants to take over), I might start incorporating a couple of improvements into the existing driver if you think it would be better to start with the existing one as a low-level backend. We could then add a high-level driver which takes ownership of the low-level one that then can do Embedded Hal Async stuff. Although @mciantyre I would need some guidance on the naming of things, because I feel like both the low level and the high level driver deserve the name Lpspi.

Finomnis commented 6 months ago

Moved discussions over to #147.