firmware: add UART
This commit is contained in:
parent
a05af8739c
commit
bf482e740d
@ -9,3 +9,6 @@ edition = "2021"
|
|||||||
riscv-rt = "0.11.0"
|
riscv-rt = "0.11.0"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
embedded-hal = "0.2.7"
|
embedded-hal = "0.2.7"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
RAM : ORIGIN = 0x01001000, LENGTH = 4K
|
RAM : ORIGIN = 0x01002000, LENGTH = 4K
|
||||||
FLASH : ORIGIN = 0x01000000, LENGTH = 4K
|
FLASH : ORIGIN = 0x01000000, LENGTH = 8K
|
||||||
}
|
}
|
||||||
|
|
||||||
REGION_ALIAS("REGION_TEXT", FLASH);
|
REGION_ALIAS("REGION_TEXT", FLASH);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Quick and hacky ethernet thing to test
|
//! 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_PENDING: u32 = LITEETH_BASE + 0x810;
|
||||||
const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = LITEETH_BASE + 0x814;
|
const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = LITEETH_BASE + 0x814;
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
|
|
||||||
use core::{arch::asm, ptr::{write, read}};
|
use core::{arch::asm, ptr::{write, read}};
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
use embedded_hal::prelude::_embedded_hal_blocking_i2c_Write;
|
use embedded_hal::prelude::_embedded_hal_blocking_i2c_Write;
|
||||||
use riscv_rt::entry;
|
use riscv_rt::entry;
|
||||||
|
|
||||||
mod eth;
|
mod eth;
|
||||||
mod i2c;
|
mod i2c;
|
||||||
|
mod uart;
|
||||||
|
|
||||||
// use `main` as the entry point of this application
|
// use `main` as the entry point of this application
|
||||||
// `main` is not allowed to return
|
// `main` is not allowed to return
|
||||||
@ -26,12 +28,15 @@ fn main() -> ! {
|
|||||||
//};
|
//};
|
||||||
let blink_period = 10_000_000u32;
|
let blink_period = 10_000_000u32;
|
||||||
|
|
||||||
let mut i2c = i2c::AmlibI2c::new(0x01003000);
|
//let mut i2c = i2c::AmlibI2c::new(0x0200_0000);
|
||||||
let data = [0u8, 2u8];
|
//let data = [0u8, 2u8];
|
||||||
i2c.write(0xAA, &data).unwrap();
|
//i2c.write(0xAA, &data).unwrap();
|
||||||
|
|
||||||
|
let mut uart = uart::AmlibUart::new(0x0200_0040);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
//eth::tranmsit();
|
//eth::tranmsit();
|
||||||
|
uart.write_str("Hello world!\r\n");
|
||||||
write_led(0);
|
write_led(0);
|
||||||
busy_wait(blink_period);
|
busy_wait(blink_period);
|
||||||
write_led(1);
|
write_led(1);
|
||||||
@ -48,7 +53,7 @@ fn busy_wait(num_nops: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_led(val: u32) {
|
fn write_led(val: u32) {
|
||||||
unsafe { write_reg(0x0100200, val); }
|
unsafe { write_reg(0x01003000, val); }
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write_reg<T>(addr: u32, value: T) {
|
unsafe fn write_reg<T>(addr: u32, value: T) {
|
||||||
|
75
firmware/src/uart.rs
Normal file
75
firmware/src/uart.rs
Normal file
@ -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<u8, Error> {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user