Skip to content

alif/machine_spi: Improve transfer function. #17513

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

iabdalkader
Copy link
Contributor

Summary

Improve SPI transfer function to poll MP events and time out if blocking transfer fails.

Testing

Tested with OLED display, works fine. This follows the driver's SPI transfer function.

Trade-offs and Alternatives

It is possible to optimize the FIFO transfer further, but I chose to keep it simple.

@kwagyeman
Copy link
Contributor

@iabdalkader - All good. Works for read/write.

@dpgeorge
Copy link
Member

Thanks, the implementation looks fine, and the existing test tests/extmod/machine_spi_rate.py still passes.

But I'm not sure about having a timeout argument in the SPI construction. No other ports have this, and it's not documented (so documentation should be added here).

The problem is, the timeout depends on the transfer size. You can see in stm32 that the SPI timeout is calculated depending on the length (and it's not user configurable). Maybe for API simplicity the alif port can do the same thing, just have a fixed timeout that depends on the input transfer length?

(Note that I2C and UART do have timeouts that can be set by the user, but they are not related to the transfer size, rather to the character size. Also note that stm32 spi send/recv has a timeout so it can be specified per transaction.)

@iabdalkader
Copy link
Contributor Author

iabdalkader commented Jun 26, 2025

Yes, no problem we can remove it. It's just so SPI doesn't get stuck forever. How do I calculate the timeout based on transfer size? Example? Like 100uS * len for example?

@dpgeorge
Copy link
Member

Like 100uS * len for example?

Yes, something simple like that would be OK, that's how stm32 does it. Could also take into account the frequency, then it would be something like:

predicted_time_us = (1000000 * len * 8 +freq - 1) / freq;
timeout_us = 2 * predicted_time_us + 100;

Just need to think about integer overflow in the above for large len and small freq. Maybe better to calculate it in milliseconds.

@iabdalkader
Copy link
Contributor Author

Just need to think about integer overflow in the above for large len and small freq. Maybe better to calculate it in milliseconds.

We could use:

    // Estimate timeout in milliseconds
    uint32_t timeout = 2 * (((len * 8 * 1000) + freq - 1) / freq) + 1;

But actually the timeout here is intended to just make sure the polling times out eventually, if for any reason SPI gets stuck, that's why it starts over every time poll_flag is called. So I replaced this with a fixed 100ms.

@dpgeorge
Copy link
Member

But actually the timeout here is intended to just make sure the polling times out eventually, if for any reason SPI gets stuck, that's why it starts over every time poll_flag is called. So I replaced this with a fixed 100ms.

OK, that's a good solution. Nice and simple.

- Poll MP events (USB fails during long transfers otherwise).
- Add timeout for blocking transfer.

Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants