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: CS must be configured before SPI peripheral #27
Comments
It seems like something is happening before the |
Some more reading through section 17.1.2 made me realize I might be causing a conflict on the SS pin. I tried disconnecting everything, and now it's actually returning. However it doesn't seem to be reading any data back. Still debugging. |
Did the SPI feedback example work for you? |
@lights0123 That's what I'm going to try next. |
Hmmm, yup, the example worked perfectly. Must be something else. |
Figured it out. The CS pin must be set to output mode before SPI is initialized. The example does that and it works fine, but my code was setting it to output mode after. All good! |
Also for future reference, I had written code like this: block!(spi.send(0).and_then(|_| { spi.read() }))? This is incorrect because it will retry the entire expression if the read blocks at all, which causes it to re-send, creating an infinite loop of writing and retrying. The correct syntax is block!(spi.send(0)).and_then(|_| { block!(spi.read()) })? |
This is an ugly detail that one can easily step over :/ Maybe we can handle this in |
We could accept a borrow of the CS pin as an argument and set its mode. Then the user would still have ownership. |
@jonahbron setting the mode is done by transferring ownership— |
Ah okay, so it would need to pass back out an OutputPin. The only way I know of to do that is for the constructor to return a tuple. |
I think we can't avoid moving the CS pin into the SPI device (and keeping it there). Any other way would leave open the possibility that a user later changes the pin's mode again. And this would immediately break the SPI device ... Though of course the pin needs to be accessible to the user, for setting its state. We can either provide methods on the SPI device for that, or add a method that returns a reference to the pin: // Either
pub fn cs_set_high(&mut self) { self.cs.set_high() }
pub fn cs_set_low(&mut self) { self.cs.set_low() }
// Or
pub fn cs(&mut self) -> &mut $CsType { &mut self.cs } I think both approaches would be sound. |
Ah, but users probably want to move the CS pin into a driver ... So we'll need to somehow allow the user to own the pin but in a way where they can't modify its mode. I think the only feasible way to archieve this is with a wrapper type: pub struct CsPin($CsType);
impl OutputPin for CsPin {
// ...
}
impl Spi {
pub fn new(peripheral: ..., cs: $CsType) -> (Spi, CsPin) {
// ...
(Spi { ...}, CsPin(cs))
}
} |
I think that's a great idea. If we take that approach, we still need a way to unwrap it if the user decides they don't want SPI active anymore. Maybe...
Although, it's possible that if a chip had two SPI peripherals, the user could use one to falsely unwrap the CS pin from another. So it's not 100% safe. |
We can prevent that by creating separate wrapper types for each SPI peripheral. So I think this approach looks like the way to go! |
Excellent point. I'll get to work on it. |
@jonahbron, are you still interested in working on this or should someone else take up this issue? |
I am but I forgot about it 😁 . Github doesn't do a great job of floating assigned issues up to your attention. |
No problem! Just need to know whether I should keep you assigned or not ;) |
The AVR SPI peripheral's internal state machine depends on proper setup of the CS pin. If it is not configured as output, it will immediately reset itself to SPI slave mode. Prevent this from happening by making the SPI HAL-driver take ownership of the CS pin and enforcing it to be configured as output. Ref: #27
I'm trying to use the SPI library but it's not working as expected. The
send
method works fine and returns without incident, but theread
method blocks forever.It never makes it past the
block
macro, it seems that it's returning WouldBlock forever. Allread
does is try to flush, code here:https://github.com/Rahix/avr-hal/blob/master/avr-hal-generic/src/spi.rs#L125
The is_write_in_progress is obviously true as expected, since a send was just executed. But it seems that the write complete status register is not being set.
https://github.com/Rahix/avr-hal/blob/master/avr-hal-generic/src/spi.rs#L127
Documentation for the SPI interrupt flag is in section 18.5.2 of this document:
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
I'm trying to debug this but any suggestions are welcome.
The text was updated successfully, but these errors were encountered: