-
Notifications
You must be signed in to change notification settings - Fork 214
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
UsartSpi
Support
#562
base: main
Are you sure you want to change the base?
UsartSpi
Support
#562
Conversation
Needs to be tested. Will test via Arudino UNO when I move them ig
…ny SPI modules to test on...
mcu/atmega-hal/src/spi.rs
Outdated
@@ -31,6 +31,66 @@ avr_hal_generic::impl_spi! { | |||
cs: port::PB0, | |||
} | |||
|
|||
#[cfg(any( |
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.
// Devices where UART port can be a SPI port
Idea, maybe a wild idea: The new code in one Anyway: Success with testing. |
Wait. It actually worked on hardware? Part of me is surprised lol I'll probably move it into its own module, but can't use one config, because they align to different ports between devices. |
Currently added in (I think) at minimum all the USART0 implimentations. But there's still a large portion to go, and finding the XCK pin requires getting the datasheet for each. |
…cludes rejig of pin layouts between boards.
Implements USART, correctly, on all devices. Should past CI successfully. An example could be in order, however, I am lacking any SPI slaves, so I cannot test this myself. |
SPI can be tested very easily by looping back MOSI to MISO (so TX to RX in this case). We also have this in our real SPI example, maybe it makes sense to add an example that does the same for |
… doesn't have the right pins. Will fix that soon. If someone else can test would be great.
Hey, there seem to be some compiler errors, as seen in CI. Can you take a look? |
I went on and tested the My diff to get it to compile: diff --git a/examples/atmega2560/src/bin/atmega2560-usart_spi-feedback.rs b/examples/atmega2560/src/bin/atmega2560-usart_spi-feedback.rs
index 3a2d145..bce2ad4 100644
--- a/examples/atmega2560/src/bin/atmega2560-usart_spi-feedback.rs
+++ b/examples/atmega2560/src/bin/atmega2560-usart_spi-feedback.rs
@@ -36,12 +36,12 @@ fn main() -> ! {
// Create SPI interface.
let (mut spi, _) = usart_spi::Usart1Spi::new(
- dp.SPI,
+ dp.USART1,
pins.pd5.into_output(),
pins.pd3.into_output(),
pins.pd2.into_pull_up_input(),
pins.pd4.into_output().downgrade(),
- spi::Settings::default(),
+ atmega_hal::spi::Settings::default(),
);
loop { Other configs, for reference: USART2: let (mut spi, _) = usart_spi::Usart2Spi::new(
dp.USART2,
pins.ph2.into_output(),
pins.ph1.into_output(),
pins.ph0.into_pull_up_input(),
pins.pd4.into_output().downgrade(),
atmega_hal::spi::Settings::default(),
); USART3: let (mut spi, _) = usart_spi::Usart3Spi::new(
dp.USART3,
pins.pj2.into_output(),
pins.pj1.into_output(),
pins.pj0.into_pull_up_input(),
pins.pd4.into_output().downgrade(),
atmega_hal::spi::Settings::default(),
); |
(Tested)[Rahix#562 (comment)]. Introduces points for other examples commented in.
// Set the baudrate of the UBRRn, idk what it should be set to, so for now, it'll be set to 0 | ||
self.[<ubrr $n>].write(|w| unsafe{w.bits(0)}); |
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.
UBRR sets the SPI clock frequency, so it should look something like this? I tested and it works, but I'm not sure if this is the best way to write the register in Rust.
// Set the baudrate of the UBRRn, idk what it should be set to, so for now, it'll be set to 0 | |
self.[<ubrr $n>].write(|w| unsafe{w.bits(0)}); | |
// Set the clock divider for SPI clock. | |
self.[<ubrr $n>].write(|w| { | |
match settings.clock { | |
crate::spi::SerialClockRate::OscfOver2 => w.bits(0), | |
crate::spi::SerialClockRate::OscfOver4 => w.bits(1), | |
crate::spi::SerialClockRate::OscfOver8 => w.bits(3), | |
crate::spi::SerialClockRate::OscfOver16 => w.bits(7), | |
crate::spi::SerialClockRate::OscfOver32 => w.bits(15), | |
crate::spi::SerialClockRate::OscfOver64 => w.bits(31), | |
crate::spi::SerialClockRate::OscfOver128 => w.bits(63), | |
} | |
}); |
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.
If you are certain on the numbers, you can make use of the commit 65b304e ("generic: spi: Assign discriminant values to clock rate enum") that I just pushed:
self.[<ubrr $n].write(|w| {
2u8.pow(settings.clock as u32) - 1
});
@Rahix I was wondering if it would make sense to re-export configuration structs and enums defined in |
To be honest, I would prefer not to add such re-exports. The more paths there are to reach an item the more convoluted user code will get. |
use $crate::hal::spi; | ||
|
||
// Setup control registers | ||
// We start by setting the UBBRn to 0 |
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.
Don't comment what code is doing, that should be obvious from reading the line below. Please comment why it is doing this — what's the purpose of setting UBBRn to 0 here?
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.
Unsure of the purpose.
But code examples in the data sheet all do so, explicitly setting it to 0, before setting the baudrate (which I will update the calculation for)
// Enable receiver and transmitter, and also the rec interrupt. | ||
self.[<ucsr $n b>].write(|w| w | ||
.[<txen $n>]().set_bit() | ||
.[<rxen $n>]().set_bit() | ||
.[<rxcie $n>]().set_bit() | ||
); |
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.
Don't enable the interrupt by default - it should always be explicitly enabled by the user through a method call, see e.g.
avr-hal/avr-hal-generic/src/usart.rs
Lines 300 to 308 in 65b304e
/// Enable the interrupt for [`Event`]. | |
pub fn listen(&mut self, event: Event) { | |
self.p.raw_interrupt(event, true); | |
} | |
/// Disable the interrupt for [`Event`]. | |
pub fn unlisten(&mut self, event: Event) { | |
self.p.raw_interrupt(event, false); | |
} |
You don't need to implement this here, though — it should be part of the spi
module.
fn raw_release(&mut self) { | ||
// Probably a better way to "release" the SPI interface, but from the datasheet, this is what they suggest, so ig it works | ||
self.[<ucsr $n c>].write(|w| w.[<umsel $n>]().usart_async()); | ||
} |
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.
Similar to the USART code, you also need to disable the USART peripheral here:
avr-hal/avr-hal-generic/src/usart.rs
Lines 506 to 510 in 65b304e
fn raw_deinit(&mut self) { | |
// Wait for any ongoing transfer to finish. | |
$crate::nb::block!(self.raw_flush()).ok(); | |
self.[<ucsr $n b>].reset(); | |
} |
(The UCSRnB reset is the important part).
With that included, you can drop your comment.
sclk: port::PE2, | ||
mosi: port::PE1, | ||
miso: port::PE0, | ||
cs: port::Dynamic, |
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.
Hm, this is quite a hack. We really don't need the cs
dance for MSPIM so it would be nice to somehow wrangle the SPI module to not require a CS pin for MSPIM...
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.
This was done because I impliment SpiOps to cheap out on work, and not rewrite everything.
I can either reimplement a new spiops, or, force the use of a DummyPin internally (so users don’t have to worry about it) via the DummyPin crate (I believe that’s its name)
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 would be fine with defining a UsartSpiDummyCs
pin type that needs to be passed to Spi::new()
to sidestep this. Pulling in an external crate for this is not a good idea, I think.
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.
An alternative to the Dummy CS Pin (and what I believe my original thought process was), is how it is, where it's dynamic, meaning the CS can be handled by the driver in some which way, by manual toggle instead of SPI handling it.
PR regarding issue #561.
This is just so I have the PR made for now, work still needs to be made on it.
So far,
USART0
is implemented for most of theatmega
mc's. However, they are not tested, as I am lacking something to test it with.