diff options
| author | Roi Bachynskyi <[email protected]> | 2025-09-01 23:19:24 +0300 |
|---|---|---|
| committer | Roi Bachynskyi <[email protected]> | 2025-09-12 11:07:02 +0300 |
| commit | e74dbe8c5d625f17c0bcee82aa8a2d45deb33a18 (patch) | |
| tree | fdd1b787101398a6bc30a2c07ea4cc258f426752 | |
| parent | f58d2ceda1abcb44cd8e02c24316433ab4777b2c (diff) | |
lpc55: blocking usart rewritten
| -rw-r--r-- | embassy-nxp/src/usart.rs | 1 | ||||
| -rw-r--r-- | embassy-nxp/src/usart/lpc55.rs | 884 |
2 files changed, 332 insertions, 553 deletions
diff --git a/embassy-nxp/src/usart.rs b/embassy-nxp/src/usart.rs index 009c251e2..c426ab96d 100644 --- a/embassy-nxp/src/usart.rs +++ b/embassy-nxp/src/usart.rs | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | //! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. | 1 | //! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. |
| 2 | #![macro_use] | ||
| 3 | 2 | ||
| 4 | #[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")] | 3 | #[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")] |
| 5 | mod inner; | 4 | mod inner; |
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 3f7456a2e..428b80c4b 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs | |||
| @@ -2,9 +2,12 @@ use core::marker::PhantomData; | |||
| 2 | 2 | ||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | 3 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 4 | use embedded_io::{self, ErrorKind}; | 4 | use embedded_io::{self, ErrorKind}; |
| 5 | pub use sealed::SealedInstance; | ||
| 6 | 5 | ||
| 7 | use crate::gpio::AnyPin; | 6 | use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin}; |
| 7 | use crate::pac::flexcomm::Flexcomm as FlexcommReg; | ||
| 8 | use crate::pac::iocon::vals::PioFunc; | ||
| 9 | use crate::pac::usart::Usart as UsartReg; | ||
| 10 | use crate::pac::*; | ||
| 8 | use crate::{Blocking, Mode}; | 11 | use crate::{Blocking, Mode}; |
| 9 | 12 | ||
| 10 | /// Serial error | 13 | /// Serial error |
| @@ -47,16 +50,6 @@ pub enum DataBits { | |||
| 47 | DataBits9, | 50 | DataBits9, |
| 48 | } | 51 | } |
| 49 | 52 | ||
| 50 | impl DataBits { | ||
| 51 | fn bits(&self) -> u8 { | ||
| 52 | match self { | ||
| 53 | Self::DataBits7 => 0b00, | ||
| 54 | Self::DataBits8 => 0b01, | ||
| 55 | Self::DataBits9 => 0b10, | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Parity bit. | 53 | /// Parity bit. |
| 61 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 54 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 62 | pub enum Parity { | 55 | pub enum Parity { |
| @@ -68,16 +61,6 @@ pub enum Parity { | |||
| 68 | ParityOdd, | 61 | ParityOdd, |
| 69 | } | 62 | } |
| 70 | 63 | ||
| 71 | impl Parity { | ||
| 72 | fn bits(&self) -> u8 { | ||
| 73 | match self { | ||
| 74 | Self::ParityNone => 0b00, | ||
| 75 | Self::ParityEven => 0b10, | ||
| 76 | Self::ParityOdd => 0b11, | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Stop bits. | 64 | /// Stop bits. |
| 82 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | 65 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] |
| 83 | pub enum StopBits { | 66 | pub enum StopBits { |
| @@ -87,15 +70,6 @@ pub enum StopBits { | |||
| 87 | Stop2, | 70 | Stop2, |
| 88 | } | 71 | } |
| 89 | 72 | ||
| 90 | impl StopBits { | ||
| 91 | fn bits(&self) -> bool { | ||
| 92 | return match self { | ||
| 93 | Self::Stop1 => false, | ||
| 94 | Self::Stop2 => true, | ||
| 95 | }; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /// UART config. | 73 | /// UART config. |
| 100 | #[non_exhaustive] | 74 | #[non_exhaustive] |
| 101 | #[derive(Clone, Debug)] | 75 | #[derive(Clone, Debug)] |
| @@ -117,7 +91,7 @@ pub struct Config { | |||
| 117 | impl Default for Config { | 91 | impl Default for Config { |
| 118 | fn default() -> Self { | 92 | fn default() -> Self { |
| 119 | Self { | 93 | Self { |
| 120 | baudrate: 9600, | 94 | baudrate: 115200, |
| 121 | data_bits: DataBits::DataBits8, | 95 | data_bits: DataBits::DataBits8, |
| 122 | stop_bits: StopBits::Stop1, | 96 | stop_bits: StopBits::Stop1, |
| 123 | parity: Parity::ParityNone, | 97 | parity: Parity::ParityNone, |
| @@ -131,59 +105,72 @@ impl Default for Config { | |||
| 131 | /// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time | 105 | /// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time |
| 132 | /// T: the peripheral instance type allowing usage of peripheral specific registers | 106 | /// T: the peripheral instance type allowing usage of peripheral specific registers |
| 133 | /// M: the operating mode of USART peripheral | 107 | /// M: the operating mode of USART peripheral |
| 134 | pub struct Usart<'d, T: Instance, M: Mode> { | 108 | pub struct Usart<'d, M: Mode> { |
| 135 | tx: UsartTx<'d, T, M>, | 109 | tx: UsartTx<'d, M>, |
| 136 | rx: UsartRx<'d, T, M>, | 110 | rx: UsartRx<'d, M>, |
| 137 | } | 111 | } |
| 138 | 112 | ||
| 139 | pub struct UsartTx<'d, T: Instance, M: Mode> { | 113 | pub struct UsartTx<'d, M: Mode> { |
| 140 | phantom: PhantomData<(&'d (), T, M)>, | 114 | info: &'static Info, |
| 115 | phantom: PhantomData<(&'d (), M)>, | ||
| 141 | } | 116 | } |
| 142 | 117 | ||
| 143 | pub struct UsartRx<'d, T: Instance, M: Mode> { | 118 | pub struct UsartRx<'d, M: Mode> { |
| 144 | phantom: PhantomData<(&'d (), T, M)>, | 119 | info: &'static Info, |
| 120 | phantom: PhantomData<(&'d (), M)>, | ||
| 145 | } | 121 | } |
| 146 | 122 | ||
| 147 | impl<'d, T: Instance, M: Mode> UsartTx<'d, T, M> { | 123 | impl<'d, M: Mode> UsartTx<'d, M> { |
| 148 | pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { | 124 | pub fn new<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { |
| 149 | Usart::<T, M>::init(Some(tx.into()), None, config); | 125 | Usart::<M>::init::<T>(Some(tx.into()), None, config); |
| 150 | Self::new_inner() | 126 | Self::new_inner(T::info()) |
| 151 | } | 127 | } |
| 152 | 128 | ||
| 153 | #[inline] | 129 | #[inline] |
| 154 | fn new_inner() -> Self { | 130 | fn new_inner(info: &'static Info) -> Self { |
| 155 | Self { phantom: PhantomData } | 131 | Self { |
| 132 | info, | ||
| 133 | phantom: PhantomData, | ||
| 134 | } | ||
| 156 | } | 135 | } |
| 157 | 136 | ||
| 158 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 137 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 159 | T::blocking_write(buffer) | 138 | for &b in buffer { |
| 139 | while !(self.info.usart_reg.fifostat().read().txnotfull()) {} | ||
| 140 | self.info.usart_reg.fifowr().write(|w| w.set_txdata(b as u16)); | ||
| 141 | } | ||
| 142 | Ok(()) | ||
| 160 | } | 143 | } |
| 161 | 144 | ||
| 162 | pub fn blocking_flush(&mut self) -> Result<(), Error> { | 145 | pub fn blocking_flush(&mut self) -> Result<(), Error> { |
| 163 | T::blocking_flush() | 146 | while !(self.info.usart_reg.fifostat().read().txempty()) {} |
| 147 | Ok(()) | ||
| 164 | } | 148 | } |
| 165 | 149 | ||
| 166 | pub fn tx_busy(&self) -> bool { | 150 | pub fn tx_busy(&self) -> bool { |
| 167 | T::tx_busy() | 151 | !(self.info.usart_reg.fifostat().read().txempty()) |
| 168 | } | 152 | } |
| 169 | } | 153 | } |
| 170 | 154 | ||
| 171 | impl<'d, T: Instance> UsartTx<'d, T, Blocking> { | 155 | impl<'d> UsartTx<'d, Blocking> { |
| 172 | pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { | 156 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { |
| 173 | Usart::<T, Blocking>::init(Some(tx.into()), None, config); | 157 | Usart::<Blocking>::init::<T>(Some(tx.into()), None, config); |
| 174 | Self::new_inner() | 158 | Self::new_inner(T::info()) |
| 175 | } | 159 | } |
| 176 | } | 160 | } |
| 177 | 161 | ||
| 178 | impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> { | 162 | impl<'d, M: Mode> UsartRx<'d, M> { |
| 179 | pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { | 163 | pub fn new<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { |
| 180 | Usart::<T, M>::init(None, Some(rx.into()), config); | 164 | Usart::<M>::init::<T>(None, Some(rx.into()), config); |
| 181 | Self::new_inner() | 165 | Self::new_inner(T::info()) |
| 182 | } | 166 | } |
| 183 | 167 | ||
| 184 | #[inline] | 168 | #[inline] |
| 185 | fn new_inner() -> Self { | 169 | fn new_inner(info: &'static Info) -> Self { |
| 186 | Self { phantom: PhantomData } | 170 | Self { |
| 171 | info, | ||
| 172 | phantom: PhantomData, | ||
| 173 | } | ||
| 187 | } | 174 | } |
| 188 | 175 | ||
| 189 | pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { | 176 | pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { |
| @@ -201,19 +188,35 @@ impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> { | |||
| 201 | /// - Ok(n) -> read n bytes | 188 | /// - Ok(n) -> read n bytes |
| 202 | /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte | 189 | /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte |
| 203 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { | 190 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { |
| 204 | T::drain_fifo(buffer) | 191 | for (i, b) in buffer.iter_mut().enumerate() { |
| 192 | while !(self.info.usart_reg.fifostat().read().rxnotempty()) {} | ||
| 193 | if self.info.usart_reg.fifostat().read().rxerr() { | ||
| 194 | return Err((i, Error::Overrun)); | ||
| 195 | } else if self.info.usart_reg.fifordnopop().read().parityerr() { | ||
| 196 | return Err((i, Error::Parity)); | ||
| 197 | } else if self.info.usart_reg.fifordnopop().read().framerr() { | ||
| 198 | return Err((i, Error::Framing)); | ||
| 199 | } else if self.info.usart_reg.fifordnopop().read().rxnoise() { | ||
| 200 | return Err((i, Error::Noise)); | ||
| 201 | } else if self.info.usart_reg.intstat().read().deltarxbrk() { | ||
| 202 | return Err((i, Error::Break)); | ||
| 203 | } | ||
| 204 | let dr = self.info.usart_reg.fiford().read().rxdata() as u8; | ||
| 205 | *b = dr; | ||
| 206 | } | ||
| 207 | Ok(buffer.len()) | ||
| 205 | } | 208 | } |
| 206 | } | 209 | } |
| 207 | 210 | ||
| 208 | impl<'d, T: Instance> UsartRx<'d, T, Blocking> { | 211 | impl<'d> UsartRx<'d, Blocking> { |
| 209 | pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { | 212 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { |
| 210 | Usart::<T, Blocking>::init(None, Some(rx.into()), config); | 213 | Usart::<Blocking>::init::<T>(None, Some(rx.into()), config); |
| 211 | Self::new_inner() | 214 | Self::new_inner(T::info()) |
| 212 | } | 215 | } |
| 213 | } | 216 | } |
| 214 | 217 | ||
| 215 | impl<'d, T: Instance> Usart<'d, T, Blocking> { | 218 | impl<'d> Usart<'d, Blocking> { |
| 216 | pub fn new_blocking( | 219 | pub fn new_blocking<T: Instance>( |
| 217 | usart: Peri<'d, T>, | 220 | usart: Peri<'d, T>, |
| 218 | tx: Peri<'d, impl TxPin<T>>, | 221 | tx: Peri<'d, impl TxPin<T>>, |
| 219 | rx: Peri<'d, impl RxPin<T>>, | 222 | rx: Peri<'d, impl RxPin<T>>, |
| @@ -223,29 +226,70 @@ impl<'d, T: Instance> Usart<'d, T, Blocking> { | |||
| 223 | } | 226 | } |
| 224 | } | 227 | } |
| 225 | 228 | ||
| 226 | impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { | 229 | impl<'d, M: Mode> Usart<'d, M> { |
| 227 | fn new_inner(_usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, config: Config) -> Self { | 230 | fn new_inner<T: Instance>( |
| 228 | Self::init(Some(tx.reborrow()), Some(rx.reborrow()), config); | 231 | _usart: Peri<'d, T>, |
| 232 | mut tx: Peri<'d, AnyPin>, | ||
| 233 | mut rx: Peri<'d, AnyPin>, | ||
| 234 | config: Config, | ||
| 235 | ) -> Self { | ||
| 236 | Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config); | ||
| 229 | Self { | 237 | Self { |
| 230 | tx: UsartTx::new_inner(), | 238 | tx: UsartTx::new_inner(T::info()), |
| 231 | rx: UsartRx::new_inner(), | 239 | rx: UsartRx::new_inner(T::info()), |
| 232 | } | 240 | } |
| 233 | } | 241 | } |
| 234 | 242 | ||
| 235 | fn init(_tx: Option<Peri<'_, AnyPin>>, _rx: Option<Peri<'_, AnyPin>>, config: Config) { | 243 | fn init<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>, config: Config) { |
| 236 | T::enable_clock(); | 244 | Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); |
| 237 | T::reset_flexcomm(); | 245 | Self::configure_clock::<T>(&config); |
| 238 | let source_clock: u32 = T::select_clock(config.baudrate); | 246 | Self::pin_config::<T>(tx, rx); |
| 239 | T::configure_flexcomm(); | 247 | Self::configure_usart(T::info(), &config); |
| 240 | T::tx_pin_config(); | ||
| 241 | T::rx_pin_config(); | ||
| 242 | Self::set_baudrate(source_clock, config.baudrate); | ||
| 243 | T::configure_usart(config); | ||
| 244 | T::disable_dma(); | ||
| 245 | T::enable_usart(); | ||
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | fn set_baudrate(source_clock: u32, baudrate: u32) { | 250 | fn configure_clock<T: Instance>(config: &Config) { |
| 251 | // Select source clock | ||
| 252 | |||
| 253 | // Adaptive clock choice based on baud rate | ||
| 254 | // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled' | ||
| 255 | // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) | ||
| 256 | // and fractional divider (fractional rate divider). | ||
| 257 | |||
| 258 | // By default, oversampling rate is 16 which is an industry standard. | ||
| 259 | // That means 16 clocks are used to deliver the byte to recipient. | ||
| 260 | // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well. | ||
| 261 | |||
| 262 | // Minimum and maximum values were computed taking these formulas into account: | ||
| 263 | // For minimum value, MULT = 0, BRGVAL = 0 | ||
| 264 | // For maximum value, MULT = 255, BRGVAL = 255 | ||
| 265 | // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV) | ||
| 266 | // By default, OSRVAL = 15 (see above) | ||
| 267 | // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) | ||
| 268 | let source_clock = match config.baudrate { | ||
| 269 | 750_001..=6_000_000 => { | ||
| 270 | SYSCON | ||
| 271 | .fcclksel(T::instance_number()) | ||
| 272 | .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X3)); // 96 MHz | ||
| 273 | 96_000_000 | ||
| 274 | } | ||
| 275 | 1501..=750_000 => { | ||
| 276 | SYSCON | ||
| 277 | .fcclksel(T::instance_number()) | ||
| 278 | .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); // 12 MHz | ||
| 279 | 12_000_000 | ||
| 280 | } | ||
| 281 | 121..=1500 => { | ||
| 282 | SYSCON | ||
| 283 | .fcclksel(T::instance_number()) | ||
| 284 | .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X4)); // 1 MHz | ||
| 285 | 1_000_000 | ||
| 286 | } | ||
| 287 | _ => { | ||
| 288 | panic!("{} baudrate is not permitted in this mode", config.baudrate); | ||
| 289 | } | ||
| 290 | }; | ||
| 291 | // Calculate MULT and BRG values based on baudrate | ||
| 292 | |||
| 249 | // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) | 293 | // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) |
| 250 | // and fractional divider (fractional rate divider). | 294 | // and fractional divider (fractional rate divider). |
| 251 | // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 | 295 | // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 |
| @@ -274,14 +318,167 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { | |||
| 274 | // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. | 318 | // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. |
| 275 | // The deduced formulas are written below. | 319 | // The deduced formulas are written below. |
| 276 | 320 | ||
| 277 | let brg_value = (source_clock / (16 * baudrate)).min(255); | 321 | let brg_value = (source_clock / (16 * config.baudrate)).min(255); |
| 278 | let raw_clock = source_clock / (16 * brg_value); | 322 | let raw_clock = source_clock / (16 * brg_value); |
| 279 | let mult_value = ((raw_clock * 256 / baudrate) - 256).min(255); | 323 | let mult_value = ((raw_clock * 256 / config.baudrate) - 256).min(255); |
| 280 | T::set_baudrate(mult_value as u8, brg_value as u8); | 324 | |
| 325 | // Write values to the registers | ||
| 326 | |||
| 327 | // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) | ||
| 328 | // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value | ||
| 329 | // to yield a denominator vale of 256. All other values are not supported | ||
| 330 | SYSCON.flexfrgctrl(T::instance_number()).modify(|w| { | ||
| 331 | w.set_div(0xFF); | ||
| 332 | w.set_mult(mult_value as u8); | ||
| 333 | }); | ||
| 334 | |||
| 335 | // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) | ||
| 336 | // By default, oversampling is 16x, i.e. OSRVAL = 15 | ||
| 337 | |||
| 338 | // Typical industry standard USARTs use a 16x oversample clock to transmit and receive | ||
| 339 | // asynchronous data. This is the number of BRG clocks used for one data bit. The | ||
| 340 | // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x | ||
| 341 | // oversample clock. There is no oversampling in synchronous modes. | ||
| 342 | T::info() | ||
| 343 | .usart_reg | ||
| 344 | .brg() | ||
| 345 | .modify(|w| w.set_brgval((brg_value - 1) as u16)); | ||
| 346 | } | ||
| 347 | |||
| 348 | fn pin_config<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>) { | ||
| 349 | if let Some(tx_pin) = tx { | ||
| 350 | match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), { | ||
| 351 | register.modify(|w| { | ||
| 352 | w.set_func(T::tx_pin_func()); | ||
| 353 | w.set_mode(iocon::vals::PioMode::INACTIVE); | ||
| 354 | w.set_slew(iocon::vals::PioSlew::STANDARD); | ||
| 355 | w.set_invert(false); | ||
| 356 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); | ||
| 357 | w.set_od(iocon::vals::PioOd::NORMAL); | ||
| 358 | }); | ||
| 359 | }) | ||
| 360 | } | ||
| 361 | |||
| 362 | if let Some(rx_pin) = rx { | ||
| 363 | match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), { | ||
| 364 | register.modify(|w| { | ||
| 365 | w.set_func(T::rx_pin_func()); | ||
| 366 | w.set_mode(iocon::vals::PioMode::INACTIVE); | ||
| 367 | w.set_slew(iocon::vals::PioSlew::STANDARD); | ||
| 368 | w.set_invert(false); | ||
| 369 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); | ||
| 370 | w.set_od(iocon::vals::PioOd::NORMAL); | ||
| 371 | }); | ||
| 372 | }) | ||
| 373 | }; | ||
| 374 | } | ||
| 375 | |||
| 376 | fn configure_flexcomm(flexcomm_register: crate::pac::flexcomm::Flexcomm, instance_number: usize) { | ||
| 377 | critical_section::with(|_cs| { | ||
| 378 | if !(SYSCON.ahbclkctrl0().read().iocon()) { | ||
| 379 | SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true)); | ||
| 380 | } | ||
| 381 | }); | ||
| 382 | critical_section::with(|_cs| { | ||
| 383 | if !(SYSCON.ahbclkctrl1().read().fc(instance_number)) { | ||
| 384 | SYSCON.ahbclkctrl1().modify(|w| w.set_fc(instance_number, true)); | ||
| 385 | } | ||
| 386 | }); | ||
| 387 | SYSCON | ||
| 388 | .presetctrl1() | ||
| 389 | .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::ASSERTED)); | ||
| 390 | SYSCON | ||
| 391 | .presetctrl1() | ||
| 392 | .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED)); | ||
| 393 | flexcomm_register | ||
| 394 | .pselid() | ||
| 395 | .modify(|w| w.set_persel(flexcomm::vals::Persel::USART)); | ||
| 396 | } | ||
| 397 | |||
| 398 | fn configure_usart(info: &'static Info, config: &Config) { | ||
| 399 | let registers = info.usart_reg; | ||
| 400 | // See section 34.6.1 | ||
| 401 | registers.cfg().modify(|w| { | ||
| 402 | // LIN break mode enable | ||
| 403 | // Disabled. Break detect and generate is configured for normal operation. | ||
| 404 | w.set_linmode(false); | ||
| 405 | //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the | ||
| 406 | //input pin, or from the USART’s own RTS if loopback mode is enabled. | ||
| 407 | // No flow control. The transmitter does not receive any automatic flow control signal. | ||
| 408 | w.set_ctsen(false); | ||
| 409 | // Selects synchronous or asynchronous operation. | ||
| 410 | w.set_syncen(usart::vals::Syncen::ASYNCHRONOUS_MODE); | ||
| 411 | // Selects the clock polarity and sampling edge of received data in synchronous mode. | ||
| 412 | w.set_clkpol(usart::vals::Clkpol::RISING_EDGE); | ||
| 413 | // Synchronous mode Master select. | ||
| 414 | // When synchronous mode is enabled, the USART is a master. | ||
| 415 | w.set_syncmst(usart::vals::Syncmst::MASTER); | ||
| 416 | // Selects data loopback mode | ||
| 417 | w.set_loop_(usart::vals::Loop::NORMAL); | ||
| 418 | // Output Enable Turnaround time enable for RS-485 operation. | ||
| 419 | // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of | ||
| 420 | // the last stop bit of a transmission. | ||
| 421 | w.set_oeta(false); | ||
| 422 | // Output enable select. | ||
| 423 | // Standard. The RTS signal is used as the standard flow control function. | ||
| 424 | w.set_oesel(usart::vals::Oesel::STANDARD); | ||
| 425 | // Automatic address matching enable. | ||
| 426 | // Disabled. When addressing is enabled by ADDRDET, address matching is done by | ||
| 427 | // software. This provides the possibility of versatile addressing (e.g. respond to more | ||
| 428 | // than one address) | ||
| 429 | w.set_autoaddr(false); | ||
| 430 | // Output enable polarity. | ||
| 431 | // Low. If selected by OESEL, the output enable is active low. | ||
| 432 | w.set_oepol(usart::vals::Oepol::LOW); | ||
| 433 | }); | ||
| 434 | |||
| 435 | // Configurations based on the config written by a user | ||
| 436 | registers.cfg().modify(|w| { | ||
| 437 | w.set_datalen(match config.data_bits { | ||
| 438 | DataBits::DataBits7 => usart::vals::Datalen::BIT_7, | ||
| 439 | DataBits::DataBits8 => usart::vals::Datalen::BIT_8, | ||
| 440 | DataBits::DataBits9 => usart::vals::Datalen::BIT_9, | ||
| 441 | }); | ||
| 442 | w.set_paritysel(match config.parity { | ||
| 443 | Parity::ParityNone => usart::vals::Paritysel::NO_PARITY, | ||
| 444 | Parity::ParityEven => usart::vals::Paritysel::EVEN_PARITY, | ||
| 445 | Parity::ParityOdd => usart::vals::Paritysel::ODD_PARITY, | ||
| 446 | }); | ||
| 447 | w.set_stoplen(match config.stop_bits { | ||
| 448 | StopBits::Stop1 => usart::vals::Stoplen::BIT_1, | ||
| 449 | StopBits::Stop2 => usart::vals::Stoplen::BITS_2, | ||
| 450 | }); | ||
| 451 | w.set_rxpol(match config.invert_rx { | ||
| 452 | false => usart::vals::Rxpol::STANDARD, | ||
| 453 | true => usart::vals::Rxpol::INVERTED, | ||
| 454 | }); | ||
| 455 | w.set_txpol(match config.invert_tx { | ||
| 456 | false => usart::vals::Txpol::STANDARD, | ||
| 457 | true => usart::vals::Txpol::INVERTED, | ||
| 458 | }); | ||
| 459 | }); | ||
| 460 | |||
| 461 | // DMA-related settings | ||
| 462 | registers.fifocfg().modify(|w| { | ||
| 463 | w.set_dmatx(false); | ||
| 464 | w.set_dmatx(false); | ||
| 465 | }); | ||
| 466 | |||
| 467 | // Enabling USART | ||
| 468 | registers.fifocfg().modify(|w| { | ||
| 469 | w.set_enabletx(true); | ||
| 470 | w.set_enablerx(true); | ||
| 471 | }); | ||
| 472 | registers.cfg().modify(|w| w.set_enable(true)); | ||
| 473 | |||
| 474 | // Drain RX FIFO in case it still has some unrelevant data | ||
| 475 | while registers.fifostat().read().rxnotempty() { | ||
| 476 | let _ = registers.fiford().read().0; | ||
| 477 | } | ||
| 281 | } | 478 | } |
| 282 | } | 479 | } |
| 283 | 480 | ||
| 284 | impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { | 481 | impl<'d, M: Mode> Usart<'d, M> { |
| 285 | /// Transmit the provided buffer blocking execution until done. | 482 | /// Transmit the provided buffer blocking execution until done. |
| 286 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 483 | pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 287 | self.tx.blocking_write(buffer) | 484 | self.tx.blocking_write(buffer) |
| @@ -304,19 +501,19 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { | |||
| 304 | 501 | ||
| 305 | /// Split the Usart into a transmitter and receiver, which is particularly | 502 | /// Split the Usart into a transmitter and receiver, which is particularly |
| 306 | /// useful when having two tasks correlating to transmitting and receiving. | 503 | /// useful when having two tasks correlating to transmitting and receiving. |
| 307 | pub fn split(self) -> (UsartTx<'d, T, M>, UsartRx<'d, T, M>) { | 504 | pub fn split(self) -> (UsartTx<'d, M>, UsartRx<'d, M>) { |
| 308 | (self.tx, self.rx) | 505 | (self.tx, self.rx) |
| 309 | } | 506 | } |
| 310 | 507 | ||
| 311 | /// Split the Usart into a transmitter and receiver by mutable reference, | 508 | /// Split the Usart into a transmitter and receiver by mutable reference, |
| 312 | /// which is particularly useful when having two tasks correlating to | 509 | /// which is particularly useful when having two tasks correlating to |
| 313 | /// transmitting and receiving. | 510 | /// transmitting and receiving. |
| 314 | pub fn split_ref(&mut self) -> (&mut UsartTx<'d, T, M>, &mut UsartRx<'d, T, M>) { | 511 | pub fn split_ref(&mut self) -> (&mut UsartTx<'d, M>, &mut UsartRx<'d, M>) { |
| 315 | (&mut self.tx, &mut self.rx) | 512 | (&mut self.tx, &mut self.rx) |
| 316 | } | 513 | } |
| 317 | } | 514 | } |
| 318 | 515 | ||
| 319 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, T, M> { | 516 | impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> { |
| 320 | type Error = Error; | 517 | type Error = Error; |
| 321 | 518 | ||
| 322 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 519 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| @@ -328,7 +525,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for | |||
| 328 | } | 525 | } |
| 329 | } | 526 | } |
| 330 | 527 | ||
| 331 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, T, M> { | 528 | impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, M> { |
| 332 | type Error = Error; | 529 | type Error = Error; |
| 333 | 530 | ||
| 334 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | 531 | fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { |
| @@ -340,11 +537,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for | |||
| 340 | } | 537 | } |
| 341 | } | 538 | } |
| 342 | 539 | ||
| 343 | impl<'d, T: Instance> embedded_io::ErrorType for UsartTx<'d, T, Blocking> { | 540 | impl<'d> embedded_io::ErrorType for UsartTx<'d, Blocking> { |
| 344 | type Error = Error; | 541 | type Error = Error; |
| 345 | } | 542 | } |
| 346 | 543 | ||
| 347 | impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> { | 544 | impl<'d> embedded_io::Write for UsartTx<'d, Blocking> { |
| 348 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | 545 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 349 | self.blocking_write(buf).map(|_| buf.len()) | 546 | self.blocking_write(buf).map(|_| buf.len()) |
| 350 | } | 547 | } |
| @@ -354,21 +551,21 @@ impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> { | |||
| 354 | } | 551 | } |
| 355 | } | 552 | } |
| 356 | 553 | ||
| 357 | impl<'d, T: Instance> embedded_io::ErrorType for UsartRx<'d, T, Blocking> { | 554 | impl<'d> embedded_io::ErrorType for UsartRx<'d, Blocking> { |
| 358 | type Error = Error; | 555 | type Error = Error; |
| 359 | } | 556 | } |
| 360 | 557 | ||
| 361 | impl<'d, T: Instance> embedded_io::Read for UsartRx<'d, T, Blocking> { | 558 | impl<'d> embedded_io::Read for UsartRx<'d, Blocking> { |
| 362 | fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | 559 | fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { |
| 363 | self.blocking_read(buf).map(|_| buf.len()) | 560 | self.blocking_read(buf).map(|_| buf.len()) |
| 364 | } | 561 | } |
| 365 | } | 562 | } |
| 366 | 563 | ||
| 367 | impl<'d, T: Instance> embedded_io::ErrorType for Usart<'d, T, Blocking> { | 564 | impl<'d> embedded_io::ErrorType for Usart<'d, Blocking> { |
| 368 | type Error = Error; | 565 | type Error = Error; |
| 369 | } | 566 | } |
| 370 | 567 | ||
| 371 | impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> { | 568 | impl<'d> embedded_io::Write for Usart<'d, Blocking> { |
| 372 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { | 569 | fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { |
| 373 | self.blocking_write(buf).map(|_| buf.len()) | 570 | self.blocking_write(buf).map(|_| buf.len()) |
| 374 | } | 571 | } |
| @@ -378,468 +575,69 @@ impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> { | |||
| 378 | } | 575 | } |
| 379 | } | 576 | } |
| 380 | 577 | ||
| 381 | impl<'d, T: Instance> embedded_io::Read for Usart<'d, T, Blocking> { | 578 | impl<'d> embedded_io::Read for Usart<'d, Blocking> { |
| 382 | fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { | 579 | fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { |
| 383 | self.blocking_read(buf).map(|_| buf.len()) | 580 | self.blocking_read(buf).map(|_| buf.len()) |
| 384 | } | 581 | } |
| 385 | } | 582 | } |
| 386 | 583 | ||
| 387 | type UsartRegBlock = crate::pac::usart0::RegisterBlock; | 584 | struct Info { |
| 388 | 585 | usart_reg: UsartReg, | |
| 389 | mod sealed { | 586 | fc_reg: FlexcommReg, |
| 390 | use crate::usart::inner::UsartRegBlock; | 587 | } |
| 391 | use crate::usart::{Config, Error}; | ||
| 392 | pub trait SealedInstance { | ||
| 393 | fn usart_reg() -> &'static UsartRegBlock; | ||
| 394 | fn enable_clock(); | ||
| 395 | fn select_clock(baudrate: u32) -> u32; | ||
| 396 | fn configure_flexcomm(); | ||
| 397 | fn set_baudrate(mult_value: u8, brg_value: u8); | ||
| 398 | fn reset_flexcomm(); | ||
| 399 | fn tx_pin_config(); | ||
| 400 | fn rx_pin_config(); | ||
| 401 | |||
| 402 | fn configure_usart(config: Config) { | ||
| 403 | // See section 34.6.1 | ||
| 404 | Self::usart_reg().cfg.modify(|_, w| { | ||
| 405 | // LIN break mode enable | ||
| 406 | w.linmode() | ||
| 407 | // Disabled. Break detect and generate is configured for normal operation. | ||
| 408 | .disabled() | ||
| 409 | //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the | ||
| 410 | //input pin, or from the USART’s own RTS if loopback mode is enabled. | ||
| 411 | .ctsen() | ||
| 412 | // No flow control. The transmitter does not receive any automatic flow control signal. | ||
| 413 | .disabled() | ||
| 414 | // Selects synchronous or asynchronous operation. | ||
| 415 | .syncen() | ||
| 416 | .asynchronous_mode() | ||
| 417 | // Selects the clock polarity and sampling edge of received data in synchronous mode. | ||
| 418 | .clkpol() | ||
| 419 | .rising_edge() | ||
| 420 | // Synchronous mode Master select. | ||
| 421 | .syncmst() | ||
| 422 | // When synchronous mode is enabled, the USART is a master. | ||
| 423 | .master() | ||
| 424 | // Selects data loopback mode | ||
| 425 | .loop_() | ||
| 426 | // Normal operation | ||
| 427 | .normal() | ||
| 428 | // Output Enable Turnaround time enable for RS-485 operation. | ||
| 429 | .oeta() | ||
| 430 | // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of | ||
| 431 | // the last stop bit of a transmission. | ||
| 432 | .disabled() | ||
| 433 | // Output enable select. | ||
| 434 | .oesel() | ||
| 435 | // Standard. The RTS signal is used as the standard flow control function. | ||
| 436 | .standard() | ||
| 437 | // Automatic address matching enable. | ||
| 438 | .autoaddr() | ||
| 439 | // Disabled. When addressing is enabled by ADDRDET, address matching is done by | ||
| 440 | // software. This provides the possibility of versatile addressing (e.g. respond to more | ||
| 441 | // than one address) | ||
| 442 | .disabled() | ||
| 443 | // Output enable polarity. | ||
| 444 | .oepol() | ||
| 445 | // Low. If selected by OESEL, the output enable is active low. | ||
| 446 | .low() | ||
| 447 | }); | ||
| 448 | 588 | ||
| 449 | Self::usart_reg().cfg.modify(|_, w| unsafe { | 589 | trait SealedInstance { |
| 450 | w.datalen() | 590 | fn info() -> &'static Info; |
| 451 | .bits(config.data_bits.bits()) | 591 | fn instance_number() -> usize; |
| 452 | .paritysel() | 592 | fn tx_pin_func() -> PioFunc; |
| 453 | .bits(config.parity.bits()) | 593 | fn rx_pin_func() -> PioFunc; |
| 454 | .stoplen() | ||
| 455 | .bit(config.stop_bits.bits()) | ||
| 456 | .rxpol() | ||
| 457 | .bit(config.invert_rx) | ||
| 458 | .txpol() | ||
| 459 | .bit(config.invert_tx) | ||
| 460 | }); | ||
| 461 | } | ||
| 462 | fn disable_dma() { | ||
| 463 | Self::usart_reg() | ||
| 464 | .fifocfg | ||
| 465 | .modify(|_, w| w.dmatx().disabled().dmarx().disabled()); | ||
| 466 | } | ||
| 467 | fn enable_usart() { | ||
| 468 | Self::usart_reg() | ||
| 469 | .fifocfg | ||
| 470 | .modify(|_, w| w.enabletx().enabled().enablerx().enabled()); | ||
| 471 | Self::usart_reg().cfg.modify(|_, w| w.enable().enabled()); | ||
| 472 | while Self::usart_reg().fifostat.read().rxnotempty().bit_is_set() { | ||
| 473 | let _ = Self::usart_reg().fiford.read().bits(); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | fn blocking_write(buffer: &[u8]) -> Result<(), Error> { | ||
| 477 | for &b in buffer { | ||
| 478 | while Self::usart_reg().fifostat.read().txnotfull().bit_is_clear() {} | ||
| 479 | Self::usart_reg() | ||
| 480 | .fifowr | ||
| 481 | .modify(|_, w| unsafe { w.txdata().bits(b as u16) }); | ||
| 482 | } | ||
| 483 | Ok(()) | ||
| 484 | } | ||
| 485 | fn blocking_flush() -> Result<(), Error> { | ||
| 486 | while Self::usart_reg().fifostat.read().txempty().bit_is_clear() {} | ||
| 487 | Ok(()) | ||
| 488 | } | ||
| 489 | fn tx_busy() -> bool { | ||
| 490 | Self::usart_reg().fifostat.read().txempty().bit_is_clear() | ||
| 491 | } | ||
| 492 | fn drain_fifo(buffer: &mut [u8]) -> Result<usize, (usize, Error)> { | ||
| 493 | for (i, b) in buffer.iter_mut().enumerate() { | ||
| 494 | while Self::usart_reg().fifostat.read().rxnotempty().bit_is_clear() {} | ||
| 495 | |||
| 496 | if Self::usart_reg().fifostat.read().rxerr().bit_is_set() { | ||
| 497 | return Err((i, Error::Overrun)); | ||
| 498 | } else if Self::usart_reg().fifordnopop.read().parityerr().bit_is_set() { | ||
| 499 | return Err((i, Error::Parity)); | ||
| 500 | } else if Self::usart_reg().fifordnopop.read().framerr().bit_is_set() { | ||
| 501 | return Err((i, Error::Framing)); | ||
| 502 | } else if Self::usart_reg().fifordnopop.read().rxnoise().bit_is_set() { | ||
| 503 | return Err((i, Error::Noise)); | ||
| 504 | } else if Self::usart_reg().intstat.read().deltarxbrk().bit_is_set() { | ||
| 505 | return Err((i, Error::Break)); | ||
| 506 | } | ||
| 507 | let dr = Self::usart_reg().fiford.read().bits() as u8; | ||
| 508 | *b = dr; | ||
| 509 | } | ||
| 510 | Ok(buffer.len()) | ||
| 511 | } | ||
| 512 | } | ||
| 513 | } | 594 | } |
| 514 | 595 | ||
| 515 | /// UART instance. | 596 | /// UART instance. |
| 516 | #[allow(private_bounds)] | 597 | #[allow(private_bounds)] |
| 517 | pub trait Instance: sealed::SealedInstance + PeripheralType {} | 598 | pub trait Instance: SealedInstance + PeripheralType {} |
| 518 | 599 | ||
| 519 | #[macro_export] | ||
| 520 | macro_rules! impl_instance { | 600 | macro_rules! impl_instance { |
| 521 | ( | 601 | ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { |
| 522 | $inst:ident, | 602 | impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { |
| 523 | usart_peripheral: $USARTX:ident, | 603 | fn info() -> &'static Info { |
| 524 | usart_crate: $usartX:ident, | 604 | static INFO: Info = Info { |
| 525 | 605 | usart_reg: crate::pac::$inst, | |
| 526 | flexcomm: { | 606 | fc_reg: crate::pac::$fc, |
| 527 | field: $FLEXCOMM_FIELD:ident, | ||
| 528 | clock_field: $FLEXCOMM_CLK_FIELD:ident | ||
| 529 | }, | ||
| 530 | |||
| 531 | reset: { | ||
| 532 | bit: $RESET_BIT:ident | ||
| 533 | }, | ||
| 534 | |||
| 535 | clock: { | ||
| 536 | sel_field: $CLKSEL_FIELD:ident, | ||
| 537 | frg_field: $FRG_FIELD:ident | ||
| 538 | }, | ||
| 539 | |||
| 540 | pins: { | ||
| 541 | tx: $TX_IOCON:ident => $TX_FUNC:expr, | ||
| 542 | rx: $RX_IOCON:ident => $RX_FUNC:expr | ||
| 543 | } | ||
| 544 | |||
| 545 | ) => { | ||
| 546 | impl $crate::usart::SealedInstance for $crate::peripherals::$inst { | ||
| 547 | fn usart_reg() -> &'static UsartRegBlock { | ||
| 548 | unsafe { &*$crate::pac::$USARTX::ptr() } | ||
| 549 | } | ||
| 550 | |||
| 551 | fn enable_clock() { | ||
| 552 | critical_section::with(|_cs| { | ||
| 553 | if syscon_reg().ahbclkctrl0.read().iocon().is_disable() { | ||
| 554 | syscon_reg().ahbclkctrl0.modify(|_, w| w.iocon().enable()); | ||
| 555 | } | ||
| 556 | if syscon_reg().ahbclkctrl1.read().$FLEXCOMM_CLK_FIELD().is_disable() { | ||
| 557 | syscon_reg() | ||
| 558 | .ahbclkctrl1 | ||
| 559 | .modify(|_, w| w.$FLEXCOMM_CLK_FIELD().enable()); | ||
| 560 | } | ||
| 561 | }); | ||
| 562 | } | ||
| 563 | |||
| 564 | fn configure_flexcomm() { | ||
| 565 | let flexcomm = unsafe { &*$crate::pac::$FLEXCOMM_FIELD::ptr() }; | ||
| 566 | flexcomm.pselid.modify(|_, w| w.persel().usart()); | ||
| 567 | } | ||
| 568 | |||
| 569 | fn reset_flexcomm() { | ||
| 570 | syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().set_bit()); | ||
| 571 | syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().clear_bit()); | ||
| 572 | } | ||
| 573 | |||
| 574 | fn select_clock(baudrate: u32) -> u32 { | ||
| 575 | // Adaptive clock choice based on baud rate | ||
| 576 | // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled' | ||
| 577 | // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) | ||
| 578 | // and fractional divider (fractional rate divider). | ||
| 579 | |||
| 580 | // By default, oversampling rate is 16 which is an industry standard. | ||
| 581 | // That means 16 clocks are used to deliver the byte to recipient. | ||
| 582 | // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well. | ||
| 583 | |||
| 584 | // Minimum and maximum values were computed taking these formulas into account: | ||
| 585 | // For minimum value, MULT = 0, BRGVAL = 0 | ||
| 586 | // For maximum value, MULT = 255, BRGVAL = 255 | ||
| 587 | // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV) | ||
| 588 | // By default, OSRVAL = 15 (see above) | ||
| 589 | // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) | ||
| 590 | return match baudrate { | ||
| 591 | 750_001..=6000000 => { | ||
| 592 | syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x3()); // 96 MHz | ||
| 593 | 96_000_000 | ||
| 594 | } | ||
| 595 | 1501..=750_000 => { | ||
| 596 | syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x2()); // 12 MHz | ||
| 597 | 12_000_000 | ||
| 598 | } | ||
| 599 | 121..=1500 => { | ||
| 600 | syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x4()); // 1 MHz | ||
| 601 | 1_000_000 | ||
| 602 | } | ||
| 603 | _ => { | ||
| 604 | panic!("{} baudrate is not permitted in this mode", baudrate); | ||
| 605 | } | ||
| 606 | }; | 607 | }; |
| 608 | &INFO | ||
| 607 | } | 609 | } |
| 608 | 610 | #[inline] | |
| 609 | fn set_baudrate(mult_value: u8, brg_value: u8) { | 611 | fn instance_number() -> usize { |
| 610 | // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) | 612 | $fc_num |
| 611 | // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value | ||
| 612 | // to yield a denominator vale of 256. All other values are not supported | ||
| 613 | syscon_reg() | ||
| 614 | .$FRG_FIELD() | ||
| 615 | .modify(|_, w| unsafe { w.div().bits(0xFF).mult().bits(mult_value as u8) }); | ||
| 616 | |||
| 617 | // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1) | ||
| 618 | // By default, oversampling is 16x, i.e. OSRVAL = 15 | ||
| 619 | |||
| 620 | // Typical industry standard USARTs use a 16x oversample clock to transmit and receive | ||
| 621 | // asynchronous data. This is the number of BRG clocks used for one data bit. The | ||
| 622 | // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x | ||
| 623 | // oversample clock. There is no oversampling in synchronous modes. | ||
| 624 | Self::usart_reg() | ||
| 625 | .brg | ||
| 626 | .modify(|_, w| unsafe { w.brgval().bits((brg_value - 1) as u16) }); | ||
| 627 | } | 613 | } |
| 628 | 614 | #[inline] | |
| 629 | fn tx_pin_config() { | 615 | fn tx_pin_func() -> PioFunc { |
| 630 | iocon_reg().$TX_IOCON.modify(|_, w| unsafe { | 616 | PioFunc::$tx_pin |
| 631 | w.func() | ||
| 632 | .bits($TX_FUNC) | ||
| 633 | .digimode() | ||
| 634 | .digital() | ||
| 635 | .slew() | ||
| 636 | .standard() | ||
| 637 | .mode() | ||
| 638 | .inactive() | ||
| 639 | .invert() | ||
| 640 | .disabled() | ||
| 641 | .od() | ||
| 642 | .normal() | ||
| 643 | }); | ||
| 644 | } | 617 | } |
| 645 | 618 | #[inline] | |
| 646 | fn rx_pin_config() { | 619 | fn rx_pin_func() -> PioFunc { |
| 647 | iocon_reg().$RX_IOCON.modify(|_, w| unsafe { | 620 | PioFunc::$rx_pin |
| 648 | w.func() | ||
| 649 | .bits($RX_FUNC) | ||
| 650 | .digimode() | ||
| 651 | .digital() | ||
| 652 | .slew() | ||
| 653 | .standard() | ||
| 654 | .mode() | ||
| 655 | .inactive() | ||
| 656 | .invert() | ||
| 657 | .disabled() | ||
| 658 | .od() | ||
| 659 | .normal() | ||
| 660 | }); | ||
| 661 | } | 621 | } |
| 662 | } | 622 | } |
| 663 | |||
| 664 | impl $crate::usart::Instance for $crate::peripherals::$inst {} | 623 | impl $crate::usart::Instance for $crate::peripherals::$inst {} |
| 665 | }; | 624 | }; |
| 666 | } | 625 | } |
| 667 | 626 | ||
| 668 | impl_instance!(USART0, usart_peripheral: USART0, usart_crate: usart0, | 627 | impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0); |
| 669 | flexcomm: { | 628 | impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1); |
| 670 | field: FLEXCOMM0, | 629 | impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2); |
| 671 | clock_field: fc0 | 630 | impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3); |
| 672 | }, | 631 | impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4); |
| 673 | 632 | impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5); | |
| 674 | reset: { | 633 | impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6); |
| 675 | bit: fc0_rst | 634 | impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7); |
| 676 | }, | ||
| 677 | |||
| 678 | clock: { | ||
| 679 | sel_field: fcclksel0, | ||
| 680 | frg_field: flexfrg0ctrl | ||
| 681 | }, | ||
| 682 | |||
| 683 | pins: { | ||
| 684 | tx: pio1_6 => 1, | ||
| 685 | rx: pio1_5 => 1 | ||
| 686 | } | ||
| 687 | ); | ||
| 688 | |||
| 689 | impl_instance!(USART1, usart_peripheral: USART1, usart_crate: usart1, | ||
| 690 | flexcomm: { | ||
| 691 | field: FLEXCOMM1, | ||
| 692 | clock_field: fc1 | ||
| 693 | }, | ||
| 694 | |||
| 695 | reset: { | ||
| 696 | bit: fc1_rst | ||
| 697 | }, | ||
| 698 | |||
| 699 | clock: { | ||
| 700 | sel_field: fcclksel1, | ||
| 701 | frg_field: flexfrg1ctrl | ||
| 702 | }, | ||
| 703 | |||
| 704 | pins: { | ||
| 705 | tx: pio1_11 => 2, | ||
| 706 | rx: pio1_10 => 2 | ||
| 707 | } | ||
| 708 | ); | ||
| 709 | |||
| 710 | impl_instance!(USART2, usart_peripheral: USART2, usart_crate: usart2, | ||
| 711 | flexcomm: { | ||
| 712 | field: FLEXCOMM2, | ||
| 713 | clock_field: fc2 | ||
| 714 | }, | ||
| 715 | |||
| 716 | reset: { | ||
| 717 | bit: fc2_rst | ||
| 718 | }, | ||
| 719 | |||
| 720 | clock: { | ||
| 721 | sel_field: fcclksel2, | ||
| 722 | frg_field: flexfrg2ctrl | ||
| 723 | }, | ||
| 724 | |||
| 725 | pins: { | ||
| 726 | tx: pio0_27 => 1, | ||
| 727 | rx: pio1_24 => 1 | ||
| 728 | } | ||
| 729 | ); | ||
| 730 | |||
| 731 | impl_instance!(USART3, usart_peripheral: USART3, usart_crate: usart3, | ||
| 732 | flexcomm: { | ||
| 733 | field: FLEXCOMM3, | ||
| 734 | clock_field: fc3 | ||
| 735 | }, | ||
| 736 | |||
| 737 | reset: { | ||
| 738 | bit: fc3_rst | ||
| 739 | }, | ||
| 740 | |||
| 741 | clock: { | ||
| 742 | sel_field: fcclksel3, | ||
| 743 | frg_field: flexfrg3ctrl | ||
| 744 | }, | ||
| 745 | |||
| 746 | pins: { | ||
| 747 | tx: pio0_2 => 1, | ||
| 748 | rx: pio0_3 => 1 | ||
| 749 | } | ||
| 750 | ); | ||
| 751 | |||
| 752 | impl_instance!(USART4, usart_peripheral: USART4, usart_crate: usart4, | ||
| 753 | flexcomm: { | ||
| 754 | field: FLEXCOMM4, | ||
| 755 | clock_field: fc4 | ||
| 756 | }, | ||
| 757 | |||
| 758 | reset: { | ||
| 759 | bit: fc4_rst | ||
| 760 | }, | ||
| 761 | |||
| 762 | clock: { | ||
| 763 | sel_field: fcclksel4, | ||
| 764 | frg_field: flexfrg4ctrl | ||
| 765 | }, | ||
| 766 | |||
| 767 | pins: { | ||
| 768 | tx: pio0_16 => 1, | ||
| 769 | rx: pio0_5 => 2 | ||
| 770 | } | ||
| 771 | ); | ||
| 772 | |||
| 773 | impl_instance!(USART5, usart_peripheral: USART5, usart_crate: usart5, | ||
| 774 | flexcomm: { | ||
| 775 | field: FLEXCOMM5, | ||
| 776 | clock_field: fc5 | ||
| 777 | }, | ||
| 778 | |||
| 779 | reset: { | ||
| 780 | bit: fc5_rst | ||
| 781 | }, | ||
| 782 | |||
| 783 | clock: { | ||
| 784 | sel_field: fcclksel5, | ||
| 785 | frg_field: flexfrg5ctrl | ||
| 786 | }, | ||
| 787 | |||
| 788 | pins: { | ||
| 789 | tx: pio0_9 => 3, | ||
| 790 | rx: pio0_8 => 3 | ||
| 791 | } | ||
| 792 | ); | ||
| 793 | |||
| 794 | impl_instance!(USART6, usart_peripheral: USART6, usart_crate: usart6, | ||
| 795 | flexcomm: { | ||
| 796 | field: FLEXCOMM6, | ||
| 797 | clock_field: fc6 | ||
| 798 | }, | ||
| 799 | |||
| 800 | reset: { | ||
| 801 | bit: fc6_rst | ||
| 802 | }, | ||
| 803 | |||
| 804 | clock: { | ||
| 805 | sel_field: fcclksel6, | ||
| 806 | frg_field: flexfrg6ctrl | ||
| 807 | }, | ||
| 808 | |||
| 809 | pins: { | ||
| 810 | tx: pio1_16 => 2, | ||
| 811 | rx: pio1_13 => 2 | ||
| 812 | } | ||
| 813 | ); | ||
| 814 | |||
| 815 | impl_instance!(USART7, usart_peripheral: USART7, usart_crate: usart7, | ||
| 816 | flexcomm: { | ||
| 817 | field: FLEXCOMM7, | ||
| 818 | clock_field: fc7 | ||
| 819 | }, | ||
| 820 | |||
| 821 | reset: { | ||
| 822 | bit: fc7_rst | ||
| 823 | }, | ||
| 824 | |||
| 825 | clock: { | ||
| 826 | sel_field: fcclksel7, | ||
| 827 | frg_field: flexfrg7ctrl | ||
| 828 | }, | ||
| 829 | |||
| 830 | pins: { | ||
| 831 | tx: pio0_19 => 7, | ||
| 832 | rx: pio0_20 => 7 | ||
| 833 | } | ||
| 834 | ); | ||
| 835 | 635 | ||
| 836 | /// Trait for TX pins. | 636 | /// Trait for TX pins. |
| 837 | pub trait TxPin<T: Instance>: crate::gpio::Pin {} | 637 | pub trait TxPin<T: Instance>: crate::gpio::Pin {} |
| 838 | /// Trait for RX pins. | 638 | /// Trait for RX pins. |
| 839 | pub trait RxPin<T: Instance>: crate::gpio::Pin {} | 639 | pub trait RxPin<T: Instance>: crate::gpio::Pin {} |
| 840 | 640 | ||
| 841 | // TODO: Add RTS, CTS and CLK pin traits | ||
| 842 | |||
| 843 | macro_rules! impl_pin { | 641 | macro_rules! impl_pin { |
| 844 | ($pin:ident, $instance:ident, Tx) => { | 642 | ($pin:ident, $instance:ident, Tx) => { |
| 845 | impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} | 643 | impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} |
| @@ -849,37 +647,19 @@ macro_rules! impl_pin { | |||
| 849 | }; | 647 | }; |
| 850 | } | 648 | } |
| 851 | 649 | ||
| 852 | impl_pin!(PIO1_5, USART0, Rx); | ||
| 853 | impl_pin!(PIO1_6, USART0, Tx); | 650 | impl_pin!(PIO1_6, USART0, Tx); |
| 854 | impl_pin!(PIO1_10, USART1, Rx); | 651 | impl_pin!(PIO1_5, USART0, Rx); |
| 855 | impl_pin!(PIO1_11, USART1, Tx); | 652 | impl_pin!(PIO1_11, USART1, Tx); |
| 653 | impl_pin!(PIO1_10, USART1, Rx); | ||
| 856 | impl_pin!(PIO0_27, USART2, Tx); | 654 | impl_pin!(PIO0_27, USART2, Tx); |
| 857 | impl_pin!(PIO1_24, USART2, Rx); | 655 | impl_pin!(PIO1_24, USART2, Rx); |
| 858 | impl_pin!(PIO0_2, USART3, Tx); | 656 | impl_pin!(PIO0_2, USART3, Tx); |
| 859 | impl_pin!(PIO0_3, USART3, Rx); | 657 | impl_pin!(PIO0_3, USART3, Rx); |
| 860 | impl_pin!(PIO0_16, USART4, Tx); | 658 | impl_pin!(PIO0_16, USART4, Tx); |
| 861 | impl_pin!(PIO0_5, USART4, Rx); | 659 | impl_pin!(PIO0_5, USART4, Rx); |
| 862 | impl_pin!(PIO0_8, USART5, Rx); | ||
| 863 | impl_pin!(PIO0_9, USART5, Tx); | 660 | impl_pin!(PIO0_9, USART5, Tx); |
| 661 | impl_pin!(PIO0_8, USART5, Rx); | ||
| 864 | impl_pin!(PIO1_16, USART6, Tx); | 662 | impl_pin!(PIO1_16, USART6, Tx); |
| 865 | impl_pin!(PIO1_13, USART6, Rx); | 663 | impl_pin!(PIO1_13, USART6, Rx); |
| 866 | impl_pin!(PIO0_20, USART7, Rx); | ||
| 867 | impl_pin!(PIO0_19, USART7, Tx); | 664 | impl_pin!(PIO0_19, USART7, Tx); |
| 868 | 665 | impl_pin!(PIO0_20, USART7, Rx); | |
| 869 | /// Get the SYSCON register block. | ||
| 870 | /// | ||
| 871 | /// # Safety | ||
| 872 | /// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO | ||
| 873 | /// registers are not accessed concurrently by multiple threads. | ||
| 874 | pub(crate) fn syscon_reg() -> &'static crate::pac::syscon::RegisterBlock { | ||
| 875 | unsafe { &*crate::pac::SYSCON::ptr() } | ||
| 876 | } | ||
| 877 | |||
| 878 | /// Get the IOCON register block. | ||
| 879 | /// | ||
| 880 | /// # Safety | ||
| 881 | /// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO | ||
| 882 | /// registers are not accessed concurrently by multiple threads. | ||
| 883 | pub(crate) fn iocon_reg() -> &'static crate::pac::iocon::RegisterBlock { | ||
| 884 | unsafe { &*crate::pac::IOCON::ptr() } | ||
| 885 | } | ||
