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

spi::SpiInterface::send_command hangs since SSD1322 SPI doesn't support reading #1

Open
kalj opened this issue May 8, 2020 · 6 comments

Comments

@kalj
Copy link

kalj commented May 8, 2020

When trying out the basic example code (adapted for a raspberry pi), the program hangs at the call to init. Looking further, it seems every call to send_command hangs in the while loop preceded by this comment:

        // The SPI device has FIFOs that we must ensure are drained before the bus will
        // quiesce. This must happen before asserting DC for a command.

The explanation can be found in the data sheet (e.g. http://www.newhavendisplay.com/specs/NHD-3.12-25664UCY2.pdf page 11): "Note: Read is not available in serial mode."

By commenting out the while loop, everything seems to work fine. I don't really know what the solution is, since that seems to non-standard SPI behavior. Perhaps it needs to implement another, more restricted SPI interface with no send function?

@edarc
Copy link
Owner

edarc commented May 8, 2020

Sorry it's not working! There's been some discussion over on the embedded_hal repo about how the spi::FullDuplex trait is not very well defined with respect to hardware FIFOs, and so sometimes there are interoperability problems. I haven't checked if there's been any progress on that. I may need to just make a blocking interface (and possibly remove the async support) so it works more reliably with other HAL crates.

Were you able to tell if it's just spinning in that loop, or if the .read() call is blocked? The latter should not happen because it's supposed to be async, but anything is possible :)

Which crate are you using to get an implementation of embedded_hal::spi::FullDuplex on your RPi? I mostly tested this on STM32, so it would be nice to get it working elsewhere.

@kalj
Copy link
Author

kalj commented Mar 1, 2021

Sorry for the bad response back.

It is spinning in the loop; the read() call is not blocked.

I am using rppal and I am using a Raspberry Pi Zero W.

Can I give you any other information?

@edarc
Copy link
Owner

edarc commented Mar 3, 2021

I think this might be caused by mismatched assumptions between what ssd1322 expects from a FullDuplex, and what the rppal implementation provides. In the absence of guidance from the embedded_hal definition/documentation, I am unfortunately not sure which libraries need fixing.

The rrpal impl unconditionally returns Ok(v) where v is the last byte shifted in on MISO, even if v has already been returned before, a.k.a. even if no new transfer has occurred. It will never return nb::Error::WouldBlock when there is no more data to read, which is what that while-let in send_command is expecting.

Despite the fact that the SSD1322 does not have a MISO line to return data back to the master, the FullDuplex trait is documented as requiring one read call for every send call, or the hardware may overflow the receive buffer (in this case, with garbage from a floating or tied MISO line). As the comment alludes, the loop on read is intended to prevent this and also to detect that all FIFOs on the SPI master are empty before changing the state of the D/C line. Without some way to synchronize this, the driver can toggle the D/C line while the hardware is still shifting one or more bytes out on MOSI, which violates the timing requirements for the SSD1322.

As I mentioned previously, there has been some debate about whether FullDuplex trait is well-specified enough to be interoperable, and I think this is another example of that: the documentation for FullDuplex::read actually doesn't say that rppal's implementation is incorrect, because it doesn't require implementors to provide the behavior I'm relying on -- namely that it should only return each incoming word once, and that it should return nb::Error::WouldBlock if the receive FIFO is empty.

There is a tracking issue for FullDuplex trait's problems already; let me try to catch up on any developments there and figure out what to do.

@edarc
Copy link
Owner

edarc commented Mar 3, 2021

Tracking bugs on FullDuplex that I know of:

@kalj
Copy link
Author

kalj commented Mar 4, 2021

Thanks for your answers. Unfortunately, the complex interplay between the rust type system and the full duplex SPI protocol makes this a bit too complicated for me to fully grasp. If I understand you correctly, there is no simple workaround for this issue when using rppal / embedded_hal? I found the alternative SPI crate https://github.com/rust-embedded/rust-spidev -- can I use that somehow or do I need something which implements the embedded_hal traits?

@kalj
Copy link
Author

kalj commented Mar 4, 2021

Another problem I am experiencing is that each spi.send inside send_data_async takes way too long time and cpu resources. Checking with an oscilloscope, data is in fact sent out at the configured 10MHz, but it takes 40µs between each byte sent to the display, time which is spent busy inside spi.send. Perhaps this is completely unrelated, or due to other problems in rppal, but do you have any feeling for what might be going on there?

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