From bf482e740d2d856bc3c7c34c1648e75f7f63bb1d Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Fri, 24 Mar 2023 20:54:50 -0600 Subject: [PATCH] firmware: add UART --- firmware/Cargo.toml | 3 ++ firmware/memory.x | 4 +-- firmware/src/eth.rs | 2 +- firmware/src/main.rs | 13 +++++--- firmware/src/uart.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 firmware/src/uart.rs diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 0602858..edde5e4 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -9,3 +9,6 @@ edition = "2021" riscv-rt = "0.11.0" panic-halt = "0.2.0" embedded-hal = "0.2.7" + +[profile.release] +debug = true diff --git a/firmware/memory.x b/firmware/memory.x index 11e0748..30e765b 100644 --- a/firmware/memory.x +++ b/firmware/memory.x @@ -1,7 +1,7 @@ MEMORY { - RAM : ORIGIN = 0x01001000, LENGTH = 4K - FLASH : ORIGIN = 0x01000000, LENGTH = 4K + RAM : ORIGIN = 0x01002000, LENGTH = 4K + FLASH : ORIGIN = 0x01000000, LENGTH = 8K } REGION_ALIAS("REGION_TEXT", FLASH); diff --git a/firmware/src/eth.rs b/firmware/src/eth.rs index cb9c2b2..a0b0247 100644 --- a/firmware/src/eth.rs +++ b/firmware/src/eth.rs @@ -1,6 +1,6 @@ //! Quick and hacky ethernet thing to test -const LITEETH_BASE: u32 = 0x0200_0000; +const LITEETH_BASE: u32 = 0x0300_0000; const ETHMAC_SRAM_WRITER_EV_PENDING: u32 = LITEETH_BASE + 0x810; const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = LITEETH_BASE + 0x814; diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 46acc60..4ae1a0c 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -4,12 +4,14 @@ extern crate panic_halt; use core::{arch::asm, ptr::{write, read}}; +use core::fmt::Write; use embedded_hal::prelude::_embedded_hal_blocking_i2c_Write; use riscv_rt::entry; mod eth; mod i2c; +mod uart; // use `main` as the entry point of this application // `main` is not allowed to return @@ -26,12 +28,15 @@ fn main() -> ! { //}; let blink_period = 10_000_000u32; - let mut i2c = i2c::AmlibI2c::new(0x01003000); - let data = [0u8, 2u8]; - i2c.write(0xAA, &data).unwrap(); + //let mut i2c = i2c::AmlibI2c::new(0x0200_0000); + //let data = [0u8, 2u8]; + //i2c.write(0xAA, &data).unwrap(); + + let mut uart = uart::AmlibUart::new(0x0200_0040); loop { //eth::tranmsit(); + uart.write_str("Hello world!\r\n"); write_led(0); busy_wait(blink_period); write_led(1); @@ -48,7 +53,7 @@ fn busy_wait(num_nops: u32) { } fn write_led(val: u32) { - unsafe { write_reg(0x0100200, val); } + unsafe { write_reg(0x01003000, val); } } unsafe fn write_reg(addr: u32, value: T) { diff --git a/firmware/src/uart.rs b/firmware/src/uart.rs new file mode 100644 index 0000000..89e6cf1 --- /dev/null +++ b/firmware/src/uart.rs @@ -0,0 +1,75 @@ +//! Quick and dirty uart driver + +/// TODO repr(C) a register bank, and add instances +/// +use core::ptr::{read_volatile, write_volatile}; +use core::fmt::{Write}; + +// TODO these offsets may be wrong. I'm still unsure about CSR semantics +const REG_DIVISOR_OFFSET: u32 = 0; +const REG_SR_OFFSET: u32 = 2; +const REG_DR_OFFSET: u32 = 3; + +pub const FLAG_SR_TX_FULL: u8 = (1 << 0); +pub const FLAG_SR_TX_EMPTY: u8 = (1 << 1); +pub const FLAG_SR_RX_FULL: u8 = (1 << 2); +pub const FLAG_SR_RX_EMPTY: u8 = (1 << 3); + +pub enum Error { + TxFull, + RxEmpty, +} + +pub struct AmlibUart { + base_addr: u32, +} + +impl AmlibUart { + pub fn new(base_addr: u32) -> Self { + Self { + base_addr, + } + } + + + pub fn read_status(&mut self) -> u8 { + unsafe { + read_volatile((self.base_addr + REG_SR_OFFSET) as *const u8) + } + } + + pub fn try_get_char(&mut self) -> Result { + if self.read_status() & FLAG_SR_RX_EMPTY != 0 { + return Err(Error::RxEmpty); + } + + unsafe { + Ok(read_volatile((self.base_addr + REG_DR_OFFSET) as *const u8)) + } + } + + pub fn try_put_char(&mut self, c: u8) -> Result<(), Error> { + if self.read_status() & FLAG_SR_TX_FULL != 0 { + return Err(Error::TxFull); + } + + unsafe { + write_volatile((self.base_addr + REG_DR_OFFSET) as *mut u8, c); + } + Ok(()) + } + +} + +// Blocking implementation of write +impl Write for AmlibUart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for b in s.as_bytes() { + // It's okay to loop on this because we'll always clear the buffer + while let Err(Error::TxFull) = self.try_put_char(*b) {} + //self.try_put_char(*b); + } + + Ok(()) + } +}