-
Notifications
You must be signed in to change notification settings - Fork 883
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
Slave spi for stm32 #885
Slave spi for stm32 #885
Conversation
} else { | ||
MasterSlave::Slave | ||
}; | ||
// FIXME: for some reason spi_v3 and spi_v4 set ssi to false on init method, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am refering to this line
https://github.com/embassy-rs/embassy/blob/master/embassy-stm32/src/spi/mod.rs#L276
Is there any reason why ssi = false? for v3/v4 while for other it set to true?
@@ -117,6 +151,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { | |||
) | |||
} | |||
|
|||
// TODO: it receive only on master, on slave in miso is expecting to write something |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think if we will refactor api to make it builder like? It could be second way for initialization.
let builder = SpiBuilder::new(p.SPI3)
.sck( p.PC10)
.mosi(p.PC12)
.build(Config { // runtime config can be kept in build, or moved to other build methods.
frequency: Hz(1_000_000),
..Default::default()
});
vs:
let mut spi = Spi::new(
p.SPI3,
p.PC10,
p.PC12,
p.PC11,
NoDma,
NoDma,
Hertz(1_000_000),
Config::default(),
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're intentionally not using builders, because they become very complicated when they interact with generics. (for example the fact that calling .mosi()
changes the Mosi
generic param). Also, we had a NoPin
exactly like yours in the past, it was removed, see #605.
Multiple constructors is the most straightforward way to do it, and there's little code duplication because they internally all call into new_inner
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, i usually don't like builders too, but for pin configuration (because they usually are static typed) i found it verbose and clear.
The problem with constructors is that they params is annonymous, and it is much easier to make a mess with pin configs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! I think it would be best if the SPI slave driver was a separate struct, instead of a "mode" in the same SPI struct. The reason is they're fundamentally very different, so they require different APIs:
|
Thanks for fast response!
Good point about additional information during slave transfer. But doesn't it look like task for futures composition? exti_ss.wait_for_low();
select(slave_spi.transfer(...), exti_ss.wait_for_high());
//Then if it was exti, check some status, and cancel transfer, or pause transfer by setting ssi=true, and continue transfer on next ss Of course for doing this transfer should support cancellation, as i understand - currently it doesn't.
Agree, but what do you think about supporting TI mode, in that mode frequency is recommended parameter.
I found the comment on FullDuplex trait about "master only" purposes, but why other traits should be avoided. Again, sorry for questions if they looks noobish, i am new in embedded rust, and looks from the view of regular rust developer. |
Yes, in master mode, it doesn't matter if you leave a bit of time between setting SS low and starting the transfer. The slave chip "stays prepared" for longer than it needs to, but it all still works. In slave mode, we are the slave, so we don't control the timing on anything. It's the master that decides the delay between setting SS low and starting sending data. It could do it instantly, with zero delay. If we do "wait for SS low, then start the transfer" in software, if we start the transfer too late we will lose the first bytes of incoming data. So it is broken. The result is not "it works but it's a bit slower", it's "it doesn't work".
in master mode you need more flexibility, for example multiple SS pins for talking to different slaves on a shared bus. Doing it in software makes this flexibility easier. In slave mode you'll never want multiple SS pins.
TI mode is extremely rarely used. I've never seen it used. It's OK if we don't support it for now. And when we do we can make it a config param, having separate structs for master/slave doesn't prevent adding it in the future.
source?
It's true it's not documented, just opened rust-embedded/embedded-hal#396 |
But usually all slave devices can define minimum interface timings that it will accept. Anyway, thanks, for response - i got your point.
I understood, i just cant figure out, how much exti output handling (+ ssi bit setting) is slower than hardware nss. Just wanting to keep more freedom to user of this library, hardware NSS is limit port that user can use. I will try to implement slave module in separate pullrequest - just to check how it would look on code. |
I'd focus on getting it to work in embassy-stm32 first. A trait is not needed to use it, just to write hal-independent drivers. |
I commented to issue #623 about my efforts on implementing SPI slave.
I create two commits:
set_spe
because they brake the whole logic - by making first pseudo clk during (spe=false, spe=true) we also can fix this logic if implement some call back for setting slave select in it, just after spe=true