diff --git a/bootloader/README.md b/bootloader/README.md index da85dc9..ee9b538 100644 --- a/bootloader/README.md +++ b/bootloader/README.md @@ -11,10 +11,10 @@ The bootloader uses the following memory map: | ------ | ---- | ---- | | 0x0 | Bootloader start | code up to 0x3FFC bytes | | 0x3FFC | Bootloader CRC | word | -| 0x4000 | App image A start | code up to 0x1DFFC (~120K) bytes | +| 0x4000 | App image A start | code up to 0x1DFF8 (~120K) bytes | | 0x21FF8 | App image A CRC check length | word | | 0x21FFC | App image A CRC check value | word | -| 0x22000 | App image B start | code up to 0x1DFFC (~120K) bytes | +| 0x22000 | App image B start | code up to 0x1DFF8 (~120K) bytes | | 0x3FFF8 | App image B CRC check length | word | | 0x3FFFC | App image B CRC check value | word | | 0x40000 | End of NVM | end | diff --git a/bootloader/src/main.rs b/bootloader/src/main.rs index b010ac9..ec67a41 100644 --- a/bootloader/src/main.rs +++ b/bootloader/src/main.rs @@ -53,7 +53,7 @@ const APP_A_START_ADDR: u32 = BOOTLOADER_END_ADDR; const APP_A_SIZE_ADDR: u32 = APP_B_END_ADDR - 8; // 0x21FFC const APP_A_CRC_ADDR: u32 = APP_B_END_ADDR - 4; -pub const APP_A_END_ADDR: u32 = APP_B_END_ADDR - BOOTLOADER_END_ADDR / 2; +pub const APP_A_END_ADDR: u32 = BOOTLOADER_END_ADDR + APP_IMG_SZ; // 0x22000 const APP_B_START_ADDR: u32 = APP_A_END_ADDR; diff --git a/examples/embassy/src/bin/uart-echo-with-irq.rs b/examples/embassy/src/bin/uart-echo-with-irq.rs index 94ba310..e4e97ee 100644 --- a/examples/embassy/src/bin/uart-echo-with-irq.rs +++ b/examples/embassy/src/bin/uart-echo-with-irq.rs @@ -86,7 +86,7 @@ async fn main(spawner: Spawner) { &clocks, ); let (mut tx, rx) = uart0.split(); - let mut rx = rx.to_rx_with_irq(); + let mut rx = rx.into_rx_with_irq(); rx.start(); RX.lock(|static_rx| { static_rx.borrow_mut().replace(rx); diff --git a/flashloader/src/main.rs b/flashloader/src/main.rs index f9746f6..3be9cc6 100644 --- a/flashloader/src/main.rs +++ b/flashloader/src/main.rs @@ -193,7 +193,7 @@ mod app { Mono::start(cx.core.SYST, clocks.sysclk().raw()); CLOCKS.set(clocks).unwrap(); - let mut rx = rx.to_rx_with_irq(); + let mut rx = rx.into_rx_with_irq(); let mut rx_context = IrqContextTimeoutOrMaxSize::new(MAX_TC_FRAME_SIZE); rx.read_fixed_len_or_timeout_based_using_irq(&mut rx_context) .expect("initiating UART RX failed"); diff --git a/scripts/memory_app_a.x b/scripts/memory_app_a.x index 9d8c317..6edd645 100644 --- a/scripts/memory_app_a.x +++ b/scripts/memory_app_a.x @@ -1,7 +1,7 @@ /* Special linker script for application slot A with an offset at address 0x4000 */ MEMORY { - FLASH : ORIGIN = 0x00004000, LENGTH = 256K + FLASH : ORIGIN = 0x00004000, LENGTH = 0x1DFF8 /* RAM is a mandatory region. This RAM refers to the SRAM_0 */ RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K diff --git a/scripts/memory_app_b.x b/scripts/memory_app_b.x index 4a9dcb0..e15b43f 100644 --- a/scripts/memory_app_b.x +++ b/scripts/memory_app_b.x @@ -1,7 +1,7 @@ /* Special linker script for application slot B with an offset at address 0x22000 */ MEMORY { - FLASH : ORIGIN = 0x00022000, LENGTH = 256K + FLASH : ORIGIN = 0x00022000, LENGTH = 0x1DFF8 /* RAM is a mandatory region. This RAM refers to the SRAM_0 */ RAM : ORIGIN = 0x1FFF8000, LENGTH = 32K SRAM_1 : ORIGIN = 0x20000000, LENGTH = 32K diff --git a/va416xx-hal/src/uart.rs b/va416xx-hal/src/uart.rs index a08418c..377c6e3 100644 --- a/va416xx-hal/src/uart.rs +++ b/va416xx-hal/src/uart.rs @@ -94,6 +94,36 @@ impl From for Error { } } +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl embedded_io::Error for RxError { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} +impl embedded_hal_nb::serial::Error for RxError { + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + match self { + RxError::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, + RxError::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, + RxError::Parity => embedded_hal_nb::serial::ErrorKind::Parity, + } + } +} + +impl embedded_hal_nb::serial::Error for Error { + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + match self { + Error::Rx(rx_error) => embedded_hal_nb::serial::Error::kind(rx_error), + Error::BreakCondition => embedded_hal_nb::serial::ErrorKind::Other, + } + } +} + #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Event { @@ -305,6 +335,50 @@ enum IrqReceptionMode { Pending, } +#[derive(Default, Debug, Copy, Clone)] +pub struct IrqUartError { + overflow: bool, + framing: bool, + parity: bool, + other: bool, +} + +impl IrqUartError { + #[inline(always)] + pub fn overflow(&self) -> bool { + self.overflow + } + + #[inline(always)] + pub fn framing(&self) -> bool { + self.framing + } + + #[inline(always)] + pub fn parity(&self) -> bool { + self.parity + } + + #[inline(always)] + pub fn other(&self) -> bool { + self.other + } +} + +impl IrqUartError { + #[inline(always)] + pub fn error(&self) -> bool { + self.overflow || self.framing || self.parity + } +} + +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct BufferTooShortError { + found: usize, + expected: usize, +} + //================================================================================================== // UART peripheral wrapper //================================================================================================== @@ -510,6 +584,40 @@ impl UartBase { } } +impl embedded_io::ErrorType for UartBase { + type Error = Error; +} + +impl embedded_hal_nb::serial::ErrorType for UartBase { + type Error = Error; +} + +impl embedded_hal_nb::serial::Read for UartBase { + fn read(&mut self) -> nb::Result { + self.rx.read().map_err(|e| e.map(Error::Rx)) + } +} + +impl embedded_hal_nb::serial::Write for UartBase { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.tx.write(word).map_err(|e| { + if let nb::Error::Other(_) = e { + unreachable!() + } + nb::Error::WouldBlock + }) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.tx.flush().map_err(|e| { + if let nb::Error::Other(_) = e { + unreachable!() + } + nb::Error::WouldBlock + }) + } +} + /// Serial abstraction. Entry point to create a new UART pub struct Uart { inner: UartBase, @@ -620,9 +728,7 @@ impl Rx { fn new(uart: Uart) -> Self { Self(uart) } -} -impl Rx { /// Direct access to the peripheral structure. /// /// # Safety @@ -674,7 +780,7 @@ impl Rx { self.0.data().read().bits() } - pub fn to_rx_with_irq(self) -> RxWithIrq { + pub fn into_rx_with_irq(self) -> RxWithIrq { RxWithIrq(self) } @@ -683,18 +789,69 @@ impl Rx { } } +impl embedded_io::ErrorType for Rx { + type Error = RxError; +} + +impl embedded_hal_nb::serial::ErrorType for Rx { + type Error = RxError; +} + +impl embedded_hal_nb::serial::Read for Rx { + fn read(&mut self) -> nb::Result { + let uart = unsafe { &(*Uart::ptr()) }; + let status_reader = uart.rxstatus().read(); + let err = if status_reader.rxovr().bit_is_set() { + Some(RxError::Overrun) + } else if status_reader.rxfrm().bit_is_set() { + Some(RxError::Framing) + } else if status_reader.rxpar().bit_is_set() { + Some(RxError::Parity) + } else { + None + }; + if let Some(err) = err { + // The status code is always related to the next bit for the framing + // and parity status bits. We have to read the DATA register + // so that the next status reflects the next DATA word + // For overrun error, we read as well to clear the peripheral + self.read_fifo_unchecked(); + return Err(err.into()); + } + self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| { + if let nb::Error::Other(_) = e { + unreachable!() + } + nb::Error::WouldBlock + }) + } +} + +impl embedded_io::Read for Rx { + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + for byte in buf.iter_mut() { + let w = nb::block!(>::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + /// Serial transmitter /// /// Can be created by using the [Uart::split] or [UartBase::split] API. pub struct Tx(Uart); -impl Tx { +impl Tx { fn new(uart: Uart) -> Self { Self(uart) } -} -impl Tx { /// Direct access to the peripheral structure. /// /// # Safety @@ -746,48 +903,47 @@ impl Tx { } } -#[derive(Default, Debug, Copy, Clone)] -pub struct IrqUartError { - overflow: bool, - framing: bool, - parity: bool, - other: bool, +impl embedded_io::ErrorType for Tx { + type Error = Infallible; } -impl IrqUartError { - #[inline(always)] - pub fn overflow(&self) -> bool { - self.overflow - } - - #[inline(always)] - pub fn framing(&self) -> bool { - self.framing - } +impl embedded_hal_nb::serial::ErrorType for Tx { + type Error = Infallible; +} - #[inline(always)] - pub fn parity(&self) -> bool { - self.parity +impl embedded_hal_nb::serial::Write for Tx { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.write_fifo(word as u32) } - #[inline(always)] - pub fn other(&self) -> bool { - self.other + fn flush(&mut self) -> nb::Result<(), Self::Error> { + // SAFETY: Only TX related registers are used. + let reader = unsafe { &(*Uart::ptr()) }.txstatus().read(); + if reader.wrbusy().bit_is_set() { + return Err(nb::Error::WouldBlock); + } + Ok(()) } } -impl IrqUartError { - #[inline(always)] - pub fn error(&self) -> bool { - self.overflow || self.framing || self.parity +impl embedded_io::Write for Tx { + fn write(&mut self, buf: &[u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + for byte in buf.iter() { + nb::block!(>::write( + self, *byte + ))?; + } + + Ok(buf.len()) } -} -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct BufferTooShortError { - found: usize, - expected: usize, + fn flush(&mut self) -> Result<(), Self::Error> { + nb::block!(>::flush(self)) + } } /// Serial receiver, using interrupts to offload reading to the hardware. @@ -1063,165 +1219,12 @@ impl RxWithIrq { context.rx_idx = 0; } - pub fn release(self) -> Uart { + /// # Safety + /// + /// This API allows creating multiple UART instances when releasing the TX structure as well. + /// The user must ensure that these instances are not used to create multiple overlapping + /// UART drivers. + pub unsafe fn release(self) -> Uart { self.0.release() } } - -impl embedded_io::Error for Error { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} - -impl embedded_io::Error for RxError { - fn kind(&self) -> embedded_io::ErrorKind { - embedded_io::ErrorKind::Other - } -} - -impl embedded_hal_nb::serial::Error for Error { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { - embedded_hal_nb::serial::ErrorKind::Other - } -} - -impl embedded_hal_nb::serial::Error for RxError { - fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { - match self { - RxError::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, - RxError::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, - RxError::Parity => embedded_hal_nb::serial::ErrorKind::Parity, - } - } -} - -impl embedded_io::ErrorType for Rx { - type Error = RxError; -} - -impl embedded_hal_nb::serial::ErrorType for Rx { - type Error = RxError; -} - -impl embedded_hal_nb::serial::Read for Rx { - fn read(&mut self) -> nb::Result { - let uart = unsafe { &(*Uart::ptr()) }; - let status_reader = uart.rxstatus().read(); - let err = if status_reader.rxovr().bit_is_set() { - Some(RxError::Overrun) - } else if status_reader.rxfrm().bit_is_set() { - Some(RxError::Framing) - } else if status_reader.rxpar().bit_is_set() { - Some(RxError::Parity) - } else { - None - }; - if let Some(err) = err { - // The status code is always related to the next bit for the framing - // and parity status bits. We have to read the DATA register - // so that the next status reflects the next DATA word - // For overrun error, we read as well to clear the peripheral - self.read_fifo_unchecked(); - return Err(err.into()); - } - self.read_fifo().map(|val| (val & 0xff) as u8).map_err(|e| { - if let nb::Error::Other(_) = e { - unreachable!() - } - nb::Error::WouldBlock - }) - } -} - -impl embedded_io::Read for Rx { - fn read(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } - - for byte in buf.iter_mut() { - let w = nb::block!(>::read(self))?; - *byte = w; - } - - Ok(buf.len()) - } -} - -impl embedded_io::ErrorType for Tx { - type Error = Infallible; -} - -impl embedded_hal_nb::serial::ErrorType for Tx { - type Error = Infallible; -} - -impl embedded_hal_nb::serial::Write for Tx { - fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { - self.write_fifo(word as u32) - } - - fn flush(&mut self) -> nb::Result<(), Self::Error> { - // SAFETY: Only TX related registers are used. - let reader = unsafe { &(*Uart::ptr()) }.txstatus().read(); - if reader.wrbusy().bit_is_set() { - return Err(nb::Error::WouldBlock); - } - Ok(()) - } -} - -impl embedded_io::Write for Tx { - fn write(&mut self, buf: &[u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } - - for byte in buf.iter() { - nb::block!(>::write( - self, *byte - ))?; - } - - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - nb::block!(>::flush(self)) - } -} - -impl embedded_io::ErrorType for UartBase { - type Error = Error; -} - -impl embedded_hal_nb::serial::ErrorType for UartBase { - type Error = Error; -} - -impl embedded_hal_nb::serial::Read for UartBase { - fn read(&mut self) -> nb::Result { - self.rx.read().map_err(|e| e.map(Error::Rx)) - } -} - -impl embedded_hal_nb::serial::Write for UartBase { - fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { - self.tx.write(word).map_err(|e| { - if let nb::Error::Other(_) = e { - unreachable!() - } - nb::Error::WouldBlock - }) - } - - fn flush(&mut self) -> nb::Result<(), Self::Error> { - self.tx.flush().map_err(|e| { - if let nb::Error::Other(_) = e { - unreachable!() - } - nb::Error::WouldBlock - }) - } -}