-
Notifications
You must be signed in to change notification settings - Fork 255
UsartSpi Support
#562
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
Changes from 7 commits
4a110c9
8ac3a86
2cd0cbd
82ad09a
ab5fad0
5debde9
a37cbc2
c5b076f
9ddb92b
b88cf04
d9bfd46
597b073
54990d0
46f4183
893f775
8fa453f
3593202
0f0c38c
7b21e5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,91 @@ | ||||||||||||||||||||
| //! MSPIM Implimentation | ||||||||||||||||||||
| use crate::spi; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // This module just impliments a macro for SpiOps, since underlyingly, the Spi type can still be used since it just needs SpiOps | ||||||||||||||||||||
|
|
||||||||||||||||||||
| pub type UsartSpi<H, USART, SCLKPIN, MOSIPIN, MISOPIN, CSPIN> = | ||||||||||||||||||||
| spi::Spi<H, USART, SCLKPIN, MOSIPIN, MISOPIN, CSPIN>; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Impliment SpiOps trait for USART | ||||||||||||||||||||
| #[macro_export] | ||||||||||||||||||||
| macro_rules! impl_usart_spi { | ||||||||||||||||||||
| ( | ||||||||||||||||||||
| hal: $HAL:ty, | ||||||||||||||||||||
| peripheral: $USART_SPI:ty, | ||||||||||||||||||||
| register_suffix: $n:expr, | ||||||||||||||||||||
| sclk: $sclkpin:ty, | ||||||||||||||||||||
| mosi: $mosipin:ty, | ||||||||||||||||||||
| miso: $misopin:ty, | ||||||||||||||||||||
| cs: $cspin:ty, | ||||||||||||||||||||
| ) => { | ||||||||||||||||||||
| $crate::paste::paste! { | ||||||||||||||||||||
| impl $crate::spi::SpiOps<$HAL, $sclkpin, $mosipin, $misopin, $cspin> for $USART_SPI { | ||||||||||||||||||||
|
CoolSlimbo marked this conversation as resolved.
|
||||||||||||||||||||
| fn raw_setup(&mut self, settings: &Settings) { | ||||||||||||||||||||
| use $crate::hal::spi; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Setup control registers | ||||||||||||||||||||
| // We start by setting the UBBRn to 0 | ||||||||||||||||||||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) |
||||||||||||||||||||
| self.[<ubrr $n>].write(|w| w.bits(0)); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // We have to translate the character size register into the 2 bits which are the MSB/LSB and the phase | ||||||||||||||||||||
| // 5 Bit Char = MSB and 1st | ||||||||||||||||||||
| // 6 Bit Char = MSB and 2nd | ||||||||||||||||||||
| // 7 Bit Char = LSB and 1st | ||||||||||||||||||||
| // 8 Bit Char = LSB and 2nd | ||||||||||||||||||||
| self.[<ucsr $n c>].write(|w| { | ||||||||||||||||||||
| w.[<umsel $n>]().spi_master(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| match settings.data_order { | ||||||||||||||||||||
| DataOrder::MostSignificantFirst => match settings.mode.phase { | ||||||||||||||||||||
| spi::Phase::CaptureOnFirstTransition => w.[<ucsz $n>]().chr5(), | ||||||||||||||||||||
| spi::Phase::CaptureOnSecondTransition => w.[<ucsz $n>]().chr6(), | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| DataOrder::LeastSignificantFirst => match settings.mode.phase { | ||||||||||||||||||||
| spi::Phase::CaptureOnFirstTransition => w.[<ucsz $n>]().chr7(), | ||||||||||||||||||||
| spi::Phase::CaptureOnSecondTransition => w.[<ucsz $n>]().chr8(), | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| match settings.mode.polarity { | ||||||||||||||||||||
| spi::Polarity::IdleLow => w.[<ucpol $n>]().clear_bit(), | ||||||||||||||||||||
| spi::Polarity::IdleHigh => w.[<ucpol $n>]().set_bit(), | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // 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() | ||||||||||||||||||||
| ); | ||||||||||||||||||||
|
Comment on lines
+59
to
+91
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
You don't need to implement this here, though — it should be part of the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you elaborate on what you mean by this? I understand why to remove it (idk why it was there to begin with), but do you want me to add methods to change the interrupts? Or something other, because I don't understand "it should be part of the spi module" |
||||||||||||||||||||
|
|
||||||||||||||||||||
| // 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| w.bits(0)); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| 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()); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
Comment on lines
+70
to
+110
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
(The UCSRnB reset is the important part). With that included, you can drop your comment. |
||||||||||||||||||||
|
|
||||||||||||||||||||
| fn raw_check_iflag(&self) -> bool { | ||||||||||||||||||||
| self.[<ucsr $n a>].read().[<rxc $n>]().bit_is_set() | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| fn raw_read(&self) -> u8 { | ||||||||||||||||||||
| self.[<udr $n>].read().bits() | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| fn raw_write(&mut self, byte: u8) { | ||||||||||||||||||||
| self.[<udr $n>].write(|w| unsafe { w.bits(byte) }); | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| fn raw_transaction(&mut self, byte: u8) -> u8 { | ||||||||||||||||||||
| self.raw_write(byte); | ||||||||||||||||||||
| while !self.raw_check_iflag() {} | ||||||||||||||||||||
| self.raw_read() | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }; | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| //! USART MSPIM implimentations | ||
| //! | ||
| //! The following list details how many USARTs and if the USARTs support MSPIM for each board choosable. | ||
| //! | ||
| //! | Board | USARTs | SPI | | ||
| //! |-------|--------|-----| | ||
| //! | `atmega48p` | 1 | Yes | | ||
| //! | `atmega164pa`| 2 | Yes | | ||
| //! | `atmega168` | 1 | Yes | | ||
| //! | `atmega328p` | 1 | Yes | | ||
| //! | `atmega328pb` | 1 | Yes | | ||
| //! | `atmega32a` | 1 | No | | ||
| //! | `atmega32u4` | 1 | Yes | | ||
| //! | `atmega2560` | 4 | Yes | | ||
| //! | `atmega128a` | 2 | No | | ||
| //! | `atmega1280` | 4 | Yes | | ||
| //! | `atmega1284p` | 2 | Yes | | ||
| //! | `atmega8` | 1 | No | | ||
|
|
||
| use crate::port; | ||
| use crate::spi::Settings; | ||
|
|
||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| pub type Usart0Spi = avr_hal_generic::usart_spi::UsartSpi< | ||
| crate::Atmega, | ||
| crate::pac::USART0, | ||
| port::PE2, | ||
| port::PE1, | ||
| port::PE0, | ||
| port::Dynamic, | ||
| >; | ||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| avr_hal_generic::impl_usart_spi! { | ||
| hal: crate::Atmega, | ||
| peripheral: crate::pac::USART0, | ||
| register_suffix: 0, | ||
| sclk: port::PE2, | ||
| mosi: port::PE1, | ||
| miso: port::PE0, | ||
| cs: port::Dynamic, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, this is quite a hack. We really don't need the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would be fine with defining a
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
|
|
||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| pub type Usart1Spi = avr_hal_generic::usart_spi::UsartSpi< | ||
| crate::Atmega, | ||
| crate::pac::USART1, | ||
| port::PD5, | ||
| port::PD3, | ||
| port::PD2, | ||
| port::Dynamic, | ||
| >; | ||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| avr_hal_generic::impl_usart_spi! { | ||
| hal: crate::Atmega, | ||
| peripheral: crate::pac::USART1, | ||
| register_suffix: 1, | ||
| sclk: port::PD5, | ||
| mosi: port::PD3, | ||
| miso: port::PD2, | ||
| cs: port::Dynamic, | ||
| } | ||
|
|
||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| pub type Usart2Spi = avr_hal_generic::usart_spi::UsartSpi< | ||
| crate::Atmega, | ||
| crate::pac::USART2, | ||
| port::PH2, | ||
| port::PH1, | ||
| port::PH0, | ||
| port::Dynamic, | ||
| >; | ||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| avr_hal_generic::impl_usart_spi! { | ||
| hal: crate::Atmega, | ||
| peripheral: crate::pac::USART2, | ||
| register_suffix: 2, | ||
| sclk: port::PH2, | ||
| mosi: port::PH1, | ||
| miso: port::PH0, | ||
| cs: port::Dynamic, | ||
| } | ||
|
|
||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| pub type Usart3Spi = avr_hal_generic::usart_spi::UsartSpi< | ||
| crate::Atmega, | ||
| crate::pac::USART3, | ||
| port::PJ2, | ||
| port::PJ1, | ||
| port::PJ0, | ||
| port::Dynamic, | ||
| >; | ||
| #[cfg(any(feature = "atmega1280", feature = "atmega2560"))] | ||
| avr_hal_generic::impl_usart_spi! { | ||
| hal: crate::Atmega, | ||
| peripheral: crate::pac::USART3, | ||
| register_suffix: 3, | ||
| sclk: port::PJ2, | ||
| mosi: port::PJ1, | ||
| miso: port::PJ0, | ||
| cs: port::Dynamic, | ||
| } | ||
|
|
||
| #[cfg(any( | ||
| feature = "atmega168", | ||
| feature = "atmega328p", | ||
| feature = "atmega328pb", | ||
| feature = "atmega1284p", | ||
| feature = "atmega164pa", | ||
| feature = "atmega48p" | ||
| ))] | ||
| pub type Usart0Spi = avr_hal_generic::usart_spi::UsartSpi< | ||
| crate::Atmega, | ||
| crate::pac::USART0, | ||
| port::PD4, | ||
| port::PD1, | ||
| port::PD0, | ||
| port::Dynamic, | ||
| >; | ||
| #[cfg(any( | ||
| feature = "atmega168", | ||
| feature = "atmega328p", | ||
| feature = "atmega328pb", | ||
| feature = "atmega1284p", | ||
| feature = "atmega164pa", | ||
| feature = "atmega48p" | ||
| ))] | ||
| avr_hal_generic::impl_usart_spi! { | ||
| hal: crate::Atmega, | ||
| peripheral: crate::pac::USART0, | ||
| register_suffix: 0, | ||
| sclk: port::PD4, | ||
| mosi: port::PD1, | ||
| miso: port::PD0, | ||
| 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.