Start implementing LCD driver

This commit is contained in:
histausse 2022-11-21 22:12:30 +01:00
parent adc45f6aa2
commit e73303a757
Signed by: histausse
GPG key ID: 67486F107F62E9E9
14 changed files with 284 additions and 154 deletions

View file

@ -3,8 +3,8 @@
use core::arch::asm; use core::arch::asm;
use core::time::Duration; use core::time::Duration;
use crate::traits::time::TimeManager;
use crate::println; use crate::println;
use crate::traits::time::TimeManager;
const NS_PER_S: u64 = 1_000_000_000; const NS_PER_S: u64 = 1_000_000_000;
const CNTP_CTL_EL0_ENABLE_MASK: u64 = 0b001; const CNTP_CTL_EL0_ENABLE_MASK: u64 = 0b001;
@ -40,7 +40,7 @@ impl TimeManager for Timer {
asm!("ISB", options(nostack)); asm!("ISB", options(nostack));
asm!("mrs {0:x}, CNTPCT_EL0", out(reg) ticks, options(nomem, nostack)); asm!("mrs {0:x}, CNTPCT_EL0", out(reg) ticks, options(nomem, nostack));
} }
Duration::from_nanos((ticks*NS_PER_S)/self.frequency()) Duration::from_nanos((ticks * NS_PER_S) / self.frequency())
} }
fn sleep(&self, duration: Duration) { fn sleep(&self, duration: Duration) {
@ -66,7 +66,7 @@ impl TimeManager for Timer {
return; return;
} }
// Enable the timer and mask (disable) the interrupt // Enable the timer and mask (disable) the interrupt
let mut ctl: u64 = CNTP_CTL_EL0_ENABLE_MASK + CNTP_CTL_EL0_IMASK_MASK; let mut ctl: u64 = CNTP_CTL_EL0_ENABLE_MASK + CNTP_CTL_EL0_IMASK_MASK;
unsafe { unsafe {
// set the register values for the timer // set the register values for the timer

View file

@ -0,0 +1,141 @@
//! Driver for LiquidCrystal Displays plugs to the GPIO of the board.
//! The LCD need to be an Hitachi HD44780 chipset compatible.
//!
//! This driver inspired from the one from the arduino libriaries
//! (https://github.com/arduino-libraries/LiquidCrystal) and the
//! documentation from wikipedia (https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller)
use crate::gpio;
// TODO: change USIZE to a Pin struct (and implement the Pin struct :'( )
/// The structure handling the LCD periferic
pub struct Lcd {
/// The Register Select pinout.
rs_pin: usize,
/// The Read/Write pinout.
///
/// If set to None, assumes the rw pin of the lcd is connected to the ground (write state)
rw_pin: Option<usize>,
/// The Enable pinout.
///
/// TODO: wiki says falling-edge triggered, arduino comment says activated by a HIGH pulse.
e_pin: usize,
/// First 4 data bits pins.
///
/// Set to None if the lcd is in 4-bit mode.
first_data_bits_pins: Option<[usize; 4]>,
/// Last 4 data bits pins.
last_data_bits_pins: [usize; 4],
/// The number of line of the LCD.
nb_lines: usize,
/// The number of row of the LCD.
nb_rows: usize,
/// Weither or not the LCD has been initialized in the rigth state.
initialized: bool,
}
impl Lcd {
/// Instanciate a [`Lcd`] object in 4 bits mode.
pub const fn new_4bits_mode(
rs_pin: usize,
rw_pin: Option<usize>,
e_pin: usize,
db4: usize,
db5: usize,
db6: usize,
db7: usize,
nb_lines: usize,
nb_rows: usize,
) -> Self {
Self {
rs_pin,
rw_pin,
e_pin,
first_data_bits_pins: None,
last_data_bits_pins: [db4, db5, db6, db7],
nb_lines,
nb_rows,
initialized: false,
}
}
/// Instanciate a [`Lcd`] object in 8 bits mode.
pub const fn new_8bits_mode(
rs_pin: usize,
rw_pin: Option<usize>,
e_pin: usize,
db0: usize,
db1: usize,
db2: usize,
db3: usize,
db4: usize,
db5: usize,
db6: usize,
db7: usize,
nb_lines: usize,
nb_rows: usize,
) -> Self {
Self {
rs_pin,
rw_pin,
e_pin,
first_data_bits_pins: Some([db0, db1, db2, db3]),
last_data_bits_pins: [db4, db5, db6, db7],
nb_lines,
nb_rows,
initialized: false,
}
}
/// Initialize the LCD.
pub fn init(&mut self) -> Result::<(), &str> {
gpio::set_pin_fonction(self.rs_pin, gpio::PinFunction::Output)?;
gpio::set_pin_output_state(self.rs_pin, gpio::PinOutputState::Low)?;
if let Some(rw_pin) = self.rw_pin {
gpio::set_pin_fonction(rw_pin, gpio::PinFunction::Output)?;
gpio::set_pin_output_state(rw_pin, gpio::PinOutputState::Low)?;
}
gpio::set_pin_fonction(self.e_pin, gpio::PinFunction::Output)?;
gpio::set_pin_output_state(self.e_pin, gpio::PinOutputState::Low)?;
if let Some(first_data_bits_pins) = self.first_data_bits_pins {
for pin in first_data_bits_pins.into_iter() {
gpio::set_pin_fonction(pin, gpio::PinFunction::Output)?;
}
}
for pin in self.last_data_bits_pins.into_iter() {
gpio::set_pin_fonction(pin, gpio::PinFunction::Output)?;
}
// TODO: send 0b0011 3 times to make sure to be in 8bits mode 5x8 characters
// TODO: set the new mode with Function set (2 times if 4 bits modes, 1 to set DL=0,
// then the actual one)
self.initialized = true;
todo!();
}
/// Send an 'enable' signal.
fn enable(&self) {
todo!()
}
/// Send a Function Set instruction.
fn function_set(&self) {
todo!()
}
/// Send data to the lcd.
fn send_data(&self) {
todo!()
}
/// Send 8 bits of data.
fn send_8bit(&self) {
todo!()
}
/// Send 4 bits of data.
fn send_4bits(&self) {
// TODO: type?
todo!()
}
}

View file

@ -0,0 +1,3 @@
//! Generic driver for perifierics to plug to the GPIO.
pub mod lcd;

View file

@ -1,4 +1,4 @@
//! Board Support Package: module containing implementation //! Board Support Package: module containing implementation
//! specific to a board. //! specific to a board.
#[cfg(feature = "target_rpi3")] #[cfg(feature = "target_rpi3")]
@ -9,3 +9,6 @@ pub mod rpi4;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub mod aarch64; pub mod aarch64;
// TODO: only for bsp with support for GPIO
pub mod generic_gpio_drivers;

View file

@ -71,7 +71,9 @@ pub fn set_pin_fonction(n: usize, function: PinFunction) -> Result<(), &'static
let mut val = unsafe { core::ptr::read_volatile(address as *mut u32) }; let mut val = unsafe { core::ptr::read_volatile(address as *mut u32) };
val &= !field.get_mask(); val &= !field.get_mask();
val |= Into::<u32>::into(function) << field.get_offset(); val |= Into::<u32>::into(function) << field.get_offset();
unsafe { core::ptr::write_volatile(address as *mut u32, val); } unsafe {
core::ptr::write_volatile(address as *mut u32, val);
}
Ok(()) Ok(())
} }
@ -92,6 +94,8 @@ pub fn set_pin_output_state(n: usize, state: PinOutputState) -> Result<(), &'sta
let val = field.get_mask(); let val = field.get_mask();
let address = field.get_address(); let address = field.get_address();
// 0 has no effect on this field: no nead to read-modify-write // 0 has no effect on this field: no nead to read-modify-write
unsafe { core::ptr::write_volatile(address as *mut u32, val); } unsafe {
core::ptr::write_volatile(address as *mut u32, val);
}
Ok(()) Ok(())
} }

View file

@ -2,7 +2,6 @@
use crate::utils::field::Field; use crate::utils::field::Field;
pub const START_PHYSICAL_ADDRESS: usize = 0x3F00_0000; pub const START_PHYSICAL_ADDRESS: usize = 0x3F00_0000;
// ** GPIO addresses ** // ** GPIO addresses **
@ -45,7 +44,7 @@ pub mod gpio {
/// - 8-6: FSEL12 /// - 8-6: FSEL12
/// - 5-3: FSEL11 /// - 5-3: FSEL11
/// - 2-0: FSEL10 /// - 2-0: FSEL10
pub const GPFSEL1:usize = GPIO_START + 0x04; pub const GPFSEL1: usize = GPIO_START + 0x04;
/// GPIO Function Select 2, R/W register. /// GPIO Function Select 2, R/W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -60,7 +59,7 @@ pub mod gpio {
/// - 8-6: FSEL22 /// - 8-6: FSEL22
/// - 5-3: FSEL21 /// - 5-3: FSEL21
/// - 2-0: FSEL20 /// - 2-0: FSEL20
pub const GPFSEL2:usize = GPIO_START + 0x08; pub const GPFSEL2: usize = GPIO_START + 0x08;
/// GPIO Function Select 3, R/W register. /// GPIO Function Select 3, R/W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -75,7 +74,7 @@ pub mod gpio {
/// - 8-6: FSEL32 /// - 8-6: FSEL32
/// - 5-3: FSEL31 /// - 5-3: FSEL31
/// - 2-0: FSEL30 /// - 2-0: FSEL30
pub const GPFSEL3:usize = GPIO_START + 0x0C; pub const GPFSEL3: usize = GPIO_START + 0x0C;
/// GPIO Function Select 4, R/W register. /// GPIO Function Select 4, R/W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -90,7 +89,7 @@ pub mod gpio {
/// - 8-6: FSEL42 /// - 8-6: FSEL42
/// - 5-3: FSEL41 /// - 5-3: FSEL41
/// - 2-0: FSEL40 /// - 2-0: FSEL40
pub const GPFSEL4:usize = GPIO_START + 0x10; pub const GPFSEL4: usize = GPIO_START + 0x10;
/// GPIO Function Select 5, R/W register. /// GPIO Function Select 5, R/W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -99,23 +98,23 @@ pub mod gpio {
/// - 8-6: FSEL52 /// - 8-6: FSEL52
/// - 5-3: FSEL51 /// - 5-3: FSEL51
/// - 2-0: FSEL50 /// - 2-0: FSEL50
pub const GPFSEL5:usize = GPIO_START + 0x14; pub const GPFSEL5: usize = GPIO_START + 0x14;
/// Return the field FSELn. /// Return the field FSELn.
/// ///
/// # Panic /// # Panic
/// ///
/// Panic if the pin `n` does not exist. /// Panic if the pin `n` does not exist.
pub const fn get_fsel(n: usize) -> Field { pub const fn get_fsel(n: usize) -> Field {
if n > 53 { if n > 53 {
panic!("The PIN does not exist"); panic!("The PIN does not exist");
} }
let address = [GPFSEL0, GPFSEL1, GPFSEL2, GPFSEL3, GPFSEL4, GPFSEL5][n/10]; let address = [GPFSEL0, GPFSEL1, GPFSEL2, GPFSEL3, GPFSEL4, GPFSEL5][n / 10];
let offset = 3*(n%10); let offset = 3 * (n % 10);
let size = 3; let size = 3;
Field::new(address, offset, size) Field::new(address, offset, size)
} }
// Pin Output Set // Pin Output Set
/// Pin Output Set 0, W register. /// Pin Output Set 0, W register.
/// ///
@ -124,7 +123,7 @@ pub mod gpio {
/// - 31: SET31 /// - 31: SET31
/// - ... /// - ...
/// - 0: SET0 /// - 0: SET0
pub const GPSET0:usize = GPIO_START + 0x1C; pub const GPSET0: usize = GPIO_START + 0x1C;
/// Pin Output Set 1, W register. /// Pin Output Set 1, W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -132,12 +131,12 @@ pub mod gpio {
/// - 21: SET53 /// - 21: SET53
/// - ... /// - ...
/// - 0: SET32 /// - 0: SET32
pub const GPSET1:usize = GPIO_START + 0x20; pub const GPSET1: usize = GPIO_START + 0x20;
/// Return the field SETn. /// Return the field SETn.
/// ///
/// # Panic /// # Panic
/// ///
/// Panic if the pin `n` does not exist. /// Panic if the pin `n` does not exist.
pub const fn get_set(n: usize) -> Field { pub const fn get_set(n: usize) -> Field {
if n > 53 { if n > 53 {
@ -146,12 +145,12 @@ pub mod gpio {
let (address, offset) = if n < 32 { let (address, offset) = if n < 32 {
(GPSET0, n) (GPSET0, n)
} else { } else {
(GPSET1, n-32) (GPSET1, n - 32)
}; };
let size = 1; let size = 1;
Field::new(address, offset, size) Field::new(address, offset, size)
} }
// Pin Output Clear // Pin Output Clear
/// Pin Output Clear 0, W register. /// Pin Output Clear 0, W register.
/// ///
@ -160,7 +159,7 @@ pub mod gpio {
/// - 31: CLR31 /// - 31: CLR31
/// - ... /// - ...
/// - 0: CLR0 /// - 0: CLR0
pub const GPCLR0:usize = GPIO_START + 0x28; pub const GPCLR0: usize = GPIO_START + 0x28;
/// Pin Output Clear 1, W register. /// Pin Output Clear 1, W register.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -168,12 +167,12 @@ pub mod gpio {
/// - 21: CLR53 /// - 21: CLR53
/// - ... /// - ...
/// - 0: CLR32 /// - 0: CLR32
pub const GPCLR1:usize = GPIO_START + 0x2C; pub const GPCLR1: usize = GPIO_START + 0x2C;
/// Return the field CLRn. /// Return the field CLRn.
/// ///
/// # Panic /// # Panic
/// ///
/// Panic if the pin `n` does not exist. /// Panic if the pin `n` does not exist.
pub const fn get_clr(n: usize) -> Field { pub const fn get_clr(n: usize) -> Field {
if n > 53 { if n > 53 {
@ -182,73 +181,73 @@ pub mod gpio {
let (address, offset) = if n < 32 { let (address, offset) = if n < 32 {
(GPCLR0, n) (GPCLR0, n)
} else { } else {
(GPCLR1, n-32) (GPCLR1, n - 32)
}; };
let size = 1; let size = 1;
Field::new(address, offset, size) Field::new(address, offset, size)
} }
// Pin Level // Pin Level
/// Pin Level 0, R register. /// Pin Level 0, R register.
pub const GPLEV0:usize = GPIO_START + 0x34; pub const GPLEV0: usize = GPIO_START + 0x34;
/// Pin Level 1, R register. /// Pin Level 1, R register.
pub const GPLEV1:usize = GPIO_START + 0x38; pub const GPLEV1: usize = GPIO_START + 0x38;
// Pin Event Detect Status // Pin Event Detect Status
/// Pin Event Detect Status 0, R/W register. /// Pin Event Detect Status 0, R/W register.
pub const GPEDS0:usize = GPIO_START + 0x40; pub const GPEDS0: usize = GPIO_START + 0x40;
/// Pin Event Detect Status 1, R/W register. /// Pin Event Detect Status 1, R/W register.
pub const GPEDS1:usize = GPIO_START + 0x44; pub const GPEDS1: usize = GPIO_START + 0x44;
// Pin Rising Edge Detect Enable // Pin Rising Edge Detect Enable
/// Pin Rising Edge Detect Enable 0, R/W register. /// Pin Rising Edge Detect Enable 0, R/W register.
pub const GPREN0:usize = GPIO_START + 0x4C; pub const GPREN0: usize = GPIO_START + 0x4C;
/// Pin Rising Edge Detect Enable 1, R/W register. /// Pin Rising Edge Detect Enable 1, R/W register.
pub const GPREN1:usize = GPIO_START + 0x50; pub const GPREN1: usize = GPIO_START + 0x50;
// Pin Falling Edge Detect Enable // Pin Falling Edge Detect Enable
/// Pin Falling Edge Detect Enable 0, R/W register. /// Pin Falling Edge Detect Enable 0, R/W register.
pub const GPFEN0:usize = GPIO_START + 0x58; pub const GPFEN0: usize = GPIO_START + 0x58;
/// Pin Falling Edge Detect Enable 1, R/W register. /// Pin Falling Edge Detect Enable 1, R/W register.
pub const GPFEN1:usize = GPIO_START + 0x5C; pub const GPFEN1: usize = GPIO_START + 0x5C;
// Pin High Detect Enable // Pin High Detect Enable
/// Pin High Detect Enable 0, R/W register. /// Pin High Detect Enable 0, R/W register.
pub const GPHEN0:usize = GPIO_START + 0x64; pub const GPHEN0: usize = GPIO_START + 0x64;
/// Pin High Detect Enable 1, R/W register. /// Pin High Detect Enable 1, R/W register.
pub const GPHEN1:usize = GPIO_START + 0x68; pub const GPHEN1: usize = GPIO_START + 0x68;
// Pin Low Detect Enable // Pin Low Detect Enable
/// Pin Low Detect Enable 0, R/W register. /// Pin Low Detect Enable 0, R/W register.
pub const GPLEN0:usize = GPIO_START + 0x70; pub const GPLEN0: usize = GPIO_START + 0x70;
/// Pin Low Detect Enable 1, R/W register. /// Pin Low Detect Enable 1, R/W register.
pub const GPLEN1:usize = GPIO_START + 0x74; pub const GPLEN1: usize = GPIO_START + 0x74;
// Pin Async, Rising Edge Detect // Pin Async, Rising Edge Detect
/// Pin Async, Rising Edge Detect 0, R/W register. /// Pin Async, Rising Edge Detect 0, R/W register.
pub const GPAREN0:usize = GPIO_START + 0x7C; pub const GPAREN0: usize = GPIO_START + 0x7C;
/// Pin Async, Rising Edge Detect 1, R/W register. /// Pin Async, Rising Edge Detect 1, R/W register.
pub const GPAREN1:usize = GPIO_START + 0x80; pub const GPAREN1: usize = GPIO_START + 0x80;
// Pin Async, Falling Edge Detect // Pin Async, Falling Edge Detect
/// Pin Async, Falling Edge Detect 0, R/W register. /// Pin Async, Falling Edge Detect 0, R/W register.
pub const GPAFEN0:usize = GPIO_START + 0x88; pub const GPAFEN0: usize = GPIO_START + 0x88;
/// Pin Async, Falling Edge Detect1, R/W register. /// Pin Async, Falling Edge Detect1, R/W register.
pub const GPAFEN1:usize = GPIO_START + 0x8C; pub const GPAFEN1: usize = GPIO_START + 0x8C;
// Pin Pull-up/down Enable, R/W // Pin Pull-up/down Enable, R/W
/// Pin Pull-up/down Enable, R/W register. /// Pin Pull-up/down Enable, R/W register.
pub const GPPUD:usize = GPIO_START + 0x94; pub const GPPUD: usize = GPIO_START + 0x94;
// Pin Pull-up/down enable clock, R/W // Pin Pull-up/down enable clock, R/W
/// Pin Pull-up/down enable clock 0, R/W register. /// Pin Pull-up/down enable clock 0, R/W register.
pub const GPPUDCLK0:usize = GPIO_START + 0x98; pub const GPPUDCLK0: usize = GPIO_START + 0x98;
/// Pin Pull-up/down enable clock 1, R/W register. /// Pin Pull-up/down enable clock 1, R/W register.
pub const GPPUDCLK1:usize = GPIO_START + 0x9C; pub const GPPUDCLK1: usize = GPIO_START + 0x9C;
// Test ?, R/W, 4 bits // Test ?, R/W, 4 bits
/// Test register? only 4 bits long. /// Test register? only 4 bits long.
pub const GPIO_TEST:usize = GPIO_START + 0xB0; pub const GPIO_TEST: usize = GPIO_START + 0xB0;
} }
// ** GPIO addresses ** // ** GPIO addresses **
@ -276,31 +275,30 @@ pub mod uart {
pub dr: Field, pub dr: Field,
/// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W. /// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
/// ///
/// Field located inside the Data Register [`dr`]. /// Field located inside the Data Register [`dr`].
pub dr_oe: Field, pub dr_oe: Field,
/// BE, Break Error. Set to 1 if a break condition was detected, R/W. /// BE, Break Error. Set to 1 if a break condition was detected, R/W.
/// ///
/// Field located inside the Data Register [`dr`]. /// Field located inside the Data Register [`dr`].
pub dr_be: Field, pub dr_be: Field,
/// PE, Parity Error. Set to 1 when the parity don't match data, R/W. /// PE, Parity Error. Set to 1 when the parity don't match data, R/W.
/// ///
/// Field located inside the Data Register [`dr`]. /// Field located inside the Data Register [`dr`].
pub dr_pe: Field, pub dr_pe: Field,
/// FE, Framing Error. Set to 1 when character don't have valid stop bit, R/W. /// FE, Framing Error. Set to 1 when character don't have valid stop bit, R/W.
/// ///
/// Field located inside the Data Register [`dr`]. /// Field located inside the Data Register [`dr`].
pub dr_fe: Field, pub dr_fe: Field,
/// DATA, Data character. R/W. /// DATA, Data character. R/W.
/// ///
/// Field located inside the Data Register [`dr`]. /// Field located inside the Data Register [`dr`].
pub dr_data: Field, pub dr_data: Field,
/// Receive Status Register/Error Clear Register, 32 bits long. /// Receive Status Register/Error Clear Register, 32 bits long.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -313,22 +311,22 @@ pub mod uart {
pub rsrecr: Field, pub rsrecr: Field,
/// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W. /// OE, Overrun Error. Set to 1 if data received with FIFO full, R/W.
/// ///
/// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`]. /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
pub rsrecr_oe: Field, pub rsrecr_oe: Field,
/// BE, Break Error. Set to 1 if a break condition was detected, R/W. /// BE, Break Error. Set to 1 if a break condition was detected, R/W.
/// ///
/// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`]. /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
pub rsrecr_be: Field, pub rsrecr_be: Field,
/// PE, Parity Error. Set to 1 when the parity don't match data, R/W. /// PE, Parity Error. Set to 1 when the parity don't match data, R/W.
/// ///
/// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`]. /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
pub rsrecr_pe: Field, pub rsrecr_pe: Field,
/// FE, Framing Error. Set to 1 when characteur don't have valid stop bit, R/W. /// FE, Framing Error. Set to 1 when characteur don't have valid stop bit, R/W.
/// ///
/// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`]. /// Field located inside the Receive Status Register/Error Clear Register [`rsrecr`].
pub rsrecr_fe: Field, pub rsrecr_fe: Field,
@ -349,7 +347,7 @@ pub mod uart {
/// - 3: BUSY. Is set, UART is busy transmitting data. R/W. /// - 3: BUSY. Is set, UART is busy transmitting data. R/W.
/// - 2: DCD, unsuported. Write as 0, value read don't have meaning, R/W. /// - 2: DCD, unsuported. Write as 0, value read don't have meaning, R/W.
/// - 1: DSR, unsuported. Write as 0, value read don't have meaning, R/W. /// - 1: DSR, unsuported. Write as 0, value read don't have meaning, R/W.
/// - 0: CTS, Clear To Send. /// - 0: CTS, Clear To Send.
pub fr: Field, pub fr: Field,
/// RI, unsuported. Write as 0, value read don't have meaning, R/W. /// RI, unsuported. Write as 0, value read don't have meaning, R/W.
@ -396,7 +394,7 @@ pub mod uart {
/// Field located inside the Flag Register [`fr`]. /// Field located inside the Flag Register [`fr`].
pub fr_dsr: Field, pub fr_dsr: Field,
/// CTS, Clear To Send. /// CTS, Clear To Send.
/// ///
/// Field located inside the Flag Register [`fr`]. /// Field located inside the Flag Register [`fr`].
pub fr_cts: Field, pub fr_cts: Field,
@ -430,7 +428,7 @@ pub mod uart {
/// - 6-5: WLEN: World lenght. Number of data bits transmitted by frame (0b00 -> 5b, 0b11 -> /// - 6-5: WLEN: World lenght. Number of data bits transmitted by frame (0b00 -> 5b, 0b11 ->
/// 8b), R/W. /// 8b), R/W.
/// - 4: FEN, Enable FIFOs. 0: FIFOs disabled, 1: FIFO buffers are enables, R/W. /// - 4: FEN, Enable FIFOs. 0: FIFOs disabled, 1: FIFO buffers are enables, R/W.
/// - 3: STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame /// - 3: STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame
/// (rx logic is not affected), R/W. /// (rx logic is not affected), R/W.
/// - 2: EPS, Event Parity Select. 0: odd parity, check for odd number of 1 in data+parity /// - 2: EPS, Event Parity Select. 0: odd parity, check for odd number of 1 in data+parity
/// bits, 1: event parity, check for even number of 1 in data+parity. No effect when /// bits, 1: event parity, check for even number of 1 in data+parity. No effect when
@ -457,7 +455,7 @@ pub mod uart {
/// Field located inside the Line Constrol Register [`lcrh`]. /// Field located inside the Line Constrol Register [`lcrh`].
pub lcrh_fen: Field, pub lcrh_fen: Field,
/// STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame /// STP2, 2 Stop bit select. 1: 2 stop bits are transmitted at the end of the frame
/// (rx logic is not affected), R/W. /// (rx logic is not affected), R/W.
/// ///
/// Field located inside the Line Constrol Register [`lcrh`]. /// Field located inside the Line Constrol Register [`lcrh`].
@ -486,7 +484,7 @@ pub mod uart {
/// # Warning /// # Warning
/// ///
/// To program the CR: /// To program the CR:
/// ///
/// - 1) Disable UART /// - 1) Disable UART
/// - 2) Wait for the end of tx/rx of the current char /// - 2) Wait for the end of tx/rx of the current char
/// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`] /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`]
@ -510,7 +508,7 @@ pub mod uart {
/// - 6-3: reserved. Write as 0, value read don't have meaning, R/W. /// - 6-3: reserved. Write as 0, value read don't have meaning, R/W.
/// - 2: SIRLP, unsuported, Write as 0, value read don't have meaning, R. /// - 2: SIRLP, unsuported, Write as 0, value read don't have meaning, R.
/// - 1: SIREN, unsuported, Write as 0, value read don't have meaning, R. /// - 1: SIREN, unsuported, Write as 0, value read don't have meaning, R.
/// - 0: UARTEN, UART enable. If set, the UART is enable, R/W. /// - 0: UARTEN, UART enable. If set, the UART is enable, R/W.
pub cr: Field, pub cr: Field,
/// CTSEN, CTS hardware flow control enable. If set, data is only transmitted when /// CTSEN, CTS hardware flow control enable. If set, data is only transmitted when
@ -639,7 +637,7 @@ pub mod uart {
/// Field located inside the Control Register [`cr`]. /// Field located inside the Control Register [`cr`].
pub cr_siren: Field, pub cr_siren: Field,
/// UARTEN, UART enable. If set, the UART is enable, R/W. /// UARTEN, UART enable. If set, the UART is enable, R/W.
/// ///
/// Field located inside the Control Register [`cr`]. /// Field located inside the Control Register [`cr`].
/// ///
@ -658,7 +656,6 @@ pub mod uart {
pub cr_uarten: Field, pub cr_uarten: Field,
// TODO: Finish detailling the registers // TODO: Finish detailling the registers
/// Interrupt FIFO Level Select register, 32 bits long. /// Interrupt FIFO Level Select register, 32 bits long.
/// ///
/// # Bits distribution: /// # Bits distribution:
@ -666,7 +663,7 @@ pub mod uart {
/// - 31-12: reserved. Write as 0, value read don't have meaning, R/W. /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W.
/// - 11-9: RXIFPSEL, unsuported, Write as 0, value read don't have meaning, R. /// - 11-9: RXIFPSEL, unsuported, Write as 0, value read don't have meaning, R.
/// - 8-6: TXIFPSEL, unsuported, Write as 0, value read don't have meaning, R. /// - 8-6: TXIFPSEL, unsuported, Write as 0, value read don't have meaning, R.
/// - 5-3: RXIFLSEL, Receive Interrupt FIFO Level Select. The level from which the /// - 5-3: RXIFLSEL, Receive Interrupt FIFO Level Select. The level from which the
/// reveive interrupt is send: /// reveive interrupt is send:
/// - `0b000`: Send when FIFO becom 1/8 full /// - `0b000`: Send when FIFO becom 1/8 full
/// - `0b001`: Send when FIFO becom 1/4 full /// - `0b001`: Send when FIFO becom 1/4 full
@ -675,7 +672,7 @@ pub mod uart {
/// - `0b100`: Send when FIFO becom 7/7 full /// - `0b100`: Send when FIFO becom 7/7 full
/// - Other values are reserved. /// - Other values are reserved.
/// R/W. /// R/W.
/// - 2-0: TXIFLSEL, Transmit Interrupt FIFO Level Select. The level from which the /// - 2-0: TXIFLSEL, Transmit Interrupt FIFO Level Select. The level from which the
/// transmit interrupt is send: /// transmit interrupt is send:
/// - `0b000`: Send when FIFO becom 1/8 full /// - `0b000`: Send when FIFO becom 1/8 full
/// - `0b001`: Send when FIFO becom 1/4 full /// - `0b001`: Send when FIFO becom 1/4 full
@ -809,7 +806,6 @@ pub mod uart {
/// - 31-11: reserved. Write as 0, value read don't have meaning, R. /// - 31-11: reserved. Write as 0, value read don't have meaning, R.
/// - 10-0: TDR10_0. When ITCRI1 is set to 1, data read an write directly from the FIFOs, R/W. /// - 10-0: TDR10_0. When ITCRI1 is set to 1, data read an write directly from the FIFOs, R/W.
pub tdr: Field, pub tdr: Field,
} }
impl UartMemoryMap { impl UartMemoryMap {
@ -878,5 +874,4 @@ pub mod uart {
} }
pub const UART: UartMemoryMap = UartMemoryMap::new(UART_START); pub const UART: UartMemoryMap = UartMemoryMap::new(UART_START);
} }

View file

@ -20,15 +20,18 @@ pub struct UartInner<'a> {
impl<'a> UartInner<'a> { impl<'a> UartInner<'a> {
/// Constructor for [`Uart`]. /// Constructor for [`Uart`].
const fn new(memory_map: &'a mm::UartMemoryMap) -> Self { const fn new(memory_map: &'a mm::UartMemoryMap) -> Self {
Self { initialized: false, memory_map } Self {
initialized: false,
memory_map,
}
} }
/// Initialise the UART. /// Initialise the UART.
fn init(&mut self) { fn init(&mut self) {
// TODO: Recover from possible previous test. // TODO: Recover from possible previous test.
self.flush(); self.flush();
// Stop UART, see doc of CR register for the config process (P 185, doc BCM2835) // Stop UART, see doc of CR register for the config process (P 185, doc BCM2835)
self.memory_map.cr_uarten.read_and_write(0); self.memory_map.cr_uarten.read_and_write(0);
@ -54,10 +57,10 @@ impl<'a> UartInner<'a> {
self.memory_map.lcrh.write_without_read(lcrh_val); self.memory_map.lcrh.write_without_read(lcrh_val);
let cr_val = self.memory_map.cr_txe.read_and_write_to_u32(1, 0); let cr_val = self.memory_map.cr_txe.read_and_write_to_u32(1, 0);
let cr_val = self.memory_map.cr_rxe.read_and_write_to_u32(1, cr_val); let cr_val = self.memory_map.cr_rxe.read_and_write_to_u32(1, cr_val);
// Again, see doc of CR register for the config process (P 185, doc BCM2835) // Again, see doc of CR register for the config process (P 185, doc BCM2835)
self.memory_map.cr.write_without_read(cr_val); self.memory_map.cr.write_without_read(cr_val);
// Start the UART // Start the UART
self.memory_map.cr_uarten.read_and_write(1); self.memory_map.cr_uarten.read_and_write(1);
self.initialized = true; self.initialized = true;
@ -153,14 +156,11 @@ impl Read for Uart<'_> {
} }
impl<'a> Uart<'a> { impl<'a> Uart<'a> {
// TODO: not sure this should be public? public in bsp only? // TODO: not sure this should be public? public in bsp only?
/// Create a new UART object /// Create a new UART object
const fn new(memory_map: &'a mm::UartMemoryMap) -> Self { const fn new(memory_map: &'a mm::UartMemoryMap) -> Self {
Self { Self {
inner: DummyMutex::new( inner: DummyMutex::new(UartInner::new(memory_map)),
UartInner::new(memory_map)
)
} }
} }

View file

@ -12,4 +12,3 @@ pub const UART2_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1400;
pub const UART3_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1600; pub const UART3_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1600;
pub const UART4_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1800; pub const UART4_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1800;
pub const UART5_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1A00; pub const UART5_START: usize = START_LOW_PERIPHERAL_MODE + 0x0020_1A00;

View file

@ -9,35 +9,35 @@
#![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_std)]
#![feature(format_args_nl)] #![feature(format_args_nl)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![allow(dead_code)] #![allow(dead_code)]
mod traits;
mod bsp; mod bsp;
mod traits;
mod utils; mod utils;
#[cfg(not(test))]
mod log;
#[cfg(not(test))] #[cfg(not(test))]
mod panic; mod panic;
#[cfg(not(test))] #[cfg(not(test))]
mod print; mod print;
#[cfg(not(test))]
mod log;
#[cfg(not(test))]
use core::arch::global_asm;
#[cfg(not(test))] #[cfg(not(test))]
use core::arch::asm; use core::arch::asm;
#[cfg(not(test))]
use core::arch::global_asm;
use core::time::Duration; use core::time::Duration;
// TODO: handle this with features // TODO: handle this with features
#[cfg(not(test))] #[cfg(not(test))]
use crate::bsp::rpi3::uart::console; use crate::bsp::aarch64::time::time_manager;
#[cfg(not(test))] #[cfg(not(test))]
use crate::bsp::rpi3::gpio; use crate::bsp::rpi3::gpio;
#[cfg(not(test))] #[cfg(not(test))]
use crate::bsp::aarch64::time::time_manager; use crate::bsp::rpi3::uart::console;
use crate::bsp::generic_gpio_drivers::lcd::Lcd;
use crate::traits::time::TimeManager; use crate::traits::time::TimeManager;
// TODO: move this to BSP // TODO: move this to BSP
@ -46,7 +46,9 @@ use crate::traits::time::TimeManager;
#[inline(always)] #[inline(always)]
pub fn wait_forever() -> ! { pub fn wait_forever() -> ! {
loop { loop {
unsafe { asm!("wfe"); } unsafe {
asm!("wfe");
}
} }
} }
@ -58,7 +60,6 @@ global_asm!(include_str!("boot.s"));
#[cfg(not(test))] #[cfg(not(test))]
#[no_mangle] #[no_mangle]
pub unsafe fn _start_rust() -> ! { pub unsafe fn _start_rust() -> ! {
// Set TX and RX function for pin 14 and 15 // Set TX and RX function for pin 14 and 15
match gpio::set_pin_fonction(14, gpio::PinFunction::AltFunc0) { match gpio::set_pin_fonction(14, gpio::PinFunction::AltFunc0) {
_ => (), _ => (),
@ -82,6 +83,9 @@ pub unsafe fn _start_rust() -> ! {
error!("error"); error!("error");
fatal!("fatal"); fatal!("fatal");
let mut lcd = Lcd::new_8bits_mode(1, Some(2), 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 80);
let _ = lcd.init();
let mut buffer = ['X'; 200]; let mut buffer = ['X'; 200];
let mut i = 0; let mut i = 0;
let mut c = console().read_char(); let mut c = console().read_char();

View file

@ -36,7 +36,9 @@ fn panic(info: &PanicInfo) -> ! {
"Kernel panic!\n\n\ "Kernel panic!\n\n\
Panic location:\n File: '{}', line {}, column {}\n\n\ Panic location:\n File: '{}', line {}, column {}\n\n\
{}", {}",
location, line, column, location,
line,
column,
info.message().unwrap_or(&format_args!("")) info.message().unwrap_or(&format_args!(""))
); );
wait_forever() wait_forever()

View file

@ -27,7 +27,6 @@ pub trait Read {
fn flush_input(&self); fn flush_input(&self);
} }
/// A Dummy Console. /// A Dummy Console.
/// ///
/// The DummyConsole implement the [`Console`] trait, and do nothing. /// The DummyConsole implement the [`Console`] trait, and do nothing.
@ -51,5 +50,4 @@ impl Read for DummyConsole {
fn flush_input(&self) {} fn flush_input(&self) {}
} }
impl Console for DummyConsole {} impl Console for DummyConsole {}

View file

@ -2,7 +2,7 @@
//! //!
//! Most of those traits come with a dummy implementation. //! Most of those traits come with a dummy implementation.
//! Actual implementations are either in generic modules or //! Actual implementations are either in generic modules or
//! in target specific modules. //! in target specific modules.
//! //!
//! # TODO //! # TODO
//! //!

View file

@ -3,8 +3,7 @@
use core::time::Duration; use core::time::Duration;
pub trait TimeManager { pub trait TimeManager {
/// Return the clock frequency, meaning the resolution of the
/// Return the clock frequency, meaning the resolution of the
/// time mesurement. /// time mesurement.
fn frequency(&self) -> u64; fn frequency(&self) -> u64;

View file

@ -7,10 +7,10 @@ use core::ptr::{read_volatile, write_volatile};
/// is only descriptif. /// is only descriptif.
/// ///
/// Fields represent a continuous set of bits in an alligned /// Fields represent a continuous set of bits in an alligned
/// `u32`. This means that the address is a multiple of 4, /// `u32`. This means that the address is a multiple of 4,
/// the offset is < 32, and offset + size <= 32. /// the offset is < 32, and offset + size <= 32.
/// ///
/// The constructor of the is class ensure that the field is /// The constructor of the is class ensure that the field is
/// always inside the `u32` at `address`, and that `address` /// always inside the `u32` at `address`, and that `address`
/// is alligned. /// is alligned.
/// ///
@ -24,7 +24,7 @@ pub struct Field {
/// The size of the field in bit. /// The size of the field in bit.
size: usize, size: usize,
/// The mask for the field in the `u32` at `address`. /// The mask for the field in the `u32` at `address`.
mask: u32 mask: u32,
} }
impl Field { impl Field {
@ -32,7 +32,7 @@ impl Field {
/// The field is defined by the `size` bits at `offset` bits after /// The field is defined by the `size` bits at `offset` bits after
/// `address`. (**`address` is in bytes, not bits**) /// `address`. (**`address` is in bytes, not bits**)
pub const fn new(address: usize, offset: usize, size: usize) -> Self { pub const fn new(address: usize, offset: usize, size: usize) -> Self {
// align the address // align the address
let offset = offset + 8 * (address % 4); let offset = offset + 8 * (address % 4);
let address = address - (address % 4); let address = address - (address % 4);
// make sure the field is in the u32 at address // make sure the field is in the u32 at address
@ -45,7 +45,12 @@ impl Field {
let mask = Self::compute_mask(offset, size); let mask = Self::compute_mask(offset, size);
Self { address, offset, size, mask } Self {
address,
offset,
size,
mask,
}
} }
/// Compute mask for the field. /// Compute mask for the field.
@ -86,7 +91,11 @@ impl Field {
/// Set the value of the field in the provided u32. /// Set the value of the field in the provided u32.
#[inline] #[inline]
pub fn read_and_write_to_u32(&self, val: u32, register: u32) -> u32 { pub fn read_and_write_to_u32(&self, val: u32, register: u32) -> u32 {
assert_eq!(val & !(self.mask >> self.offset), 0, "Value greater than the field"); assert_eq!(
val & !(self.mask >> self.offset),
0,
"Value greater than the field"
);
register & !self.mask | (val << self.offset) register & !self.mask | (val << self.offset)
} }
@ -103,7 +112,7 @@ impl Field {
unsafe { write_volatile(self.address as *mut u32, register) }; unsafe { write_volatile(self.address as *mut u32, register) };
} }
/// Write the value in memory but override every other value of the /// Write the value in memory but override every other value of the
/// u32 (replace them by 0s). /// u32 (replace them by 0s).
pub fn write_without_read(&self, val: u32) { pub fn write_without_read(&self, val: u32) {
let register = self.read_and_write_to_u32(val, 0); let register = self.read_and_write_to_u32(val, 0);
@ -124,26 +133,17 @@ mod test {
#[test] #[test]
fn test_get_address() { fn test_get_address() {
// Test when the address is alligned // Test when the address is alligned
assert_eq!( assert_eq!(Field::new(0x1234_5678, 0, 1).get_address(), 0x1234_5678,);
Field::new(0x1234_5678, 0, 1).get_address(),
0x1234_5678,
);
} }
#[test] #[test]
fn test_get_offset() { fn test_get_offset() {
assert_eq!( assert_eq!(Field::new(0x1234_5678, 18, 1).get_offset(), 18,);
Field::new(0x1234_5678, 18, 1).get_offset(),
18,
);
} }
#[test] #[test]
fn test_get_size() { fn test_get_size() {
assert_eq!( assert_eq!(Field::new(0x1234_5678, 18, 1).get_size(), 1,);
Field::new(0x1234_5678, 18, 1).get_size(),
1,
);
} }
#[test] #[test]
@ -175,7 +175,7 @@ mod test {
assert_eq!(field.get_address(), 0x1111_1114); assert_eq!(field.get_address(), 0x1111_1114);
assert_eq!(field.get_offset(), 8); assert_eq!(field.get_offset(), 8);
let field = Field::new(0x1111_1112, 32+16, 1); let field = Field::new(0x1111_1112, 32 + 16, 1);
assert_eq!(field.get_address(), 0x1111_1118); assert_eq!(field.get_address(), 0x1111_1118);
assert_eq!(field.get_offset(), 0); assert_eq!(field.get_offset(), 0);
} }
@ -188,32 +188,17 @@ mod test {
#[test] #[test]
fn test_get_mask() { fn test_get_mask() {
assert_eq!( assert_eq!(Field::new(0, 0, 1).get_mask(), 0b0000_0001,);
Field::new(0, 0, 1).get_mask(), assert_eq!(Field::new(0, 0, 3).get_mask(), 0b0000_0111,);
0b0000_0001, assert_eq!(Field::new(0, 4, 1).get_mask(), 0b0001_0000,);
); assert_eq!(Field::new(0, 4, 3).get_mask(), 0b0111_0000,);
assert_eq!(
Field::new(0, 0, 3).get_mask(),
0b0000_0111,
);
assert_eq!(
Field::new(0, 4, 1).get_mask(),
0b0001_0000,
);
assert_eq!(
Field::new(0, 4, 3).get_mask(),
0b0111_0000,
);
} }
#[test] #[test]
fn test_read_and_write_to_u32() { fn test_read_and_write_to_u32() {
let field = Field::new(0, 3, 4); let field = Field::new(0, 3, 4);
let val = 0b0101_0101; let val = 0b0101_0101;
assert_eq!( assert_eq!(field.read_and_write_to_u32(0b0101, val), 0b0010_1101,);
field.read_and_write_to_u32(0b0101, val),
0b0010_1101,
);
} }
#[test] #[test]
@ -227,9 +212,6 @@ mod test {
fn test_read_from_u32() { fn test_read_from_u32() {
let field = Field::new(0, 3, 4); let field = Field::new(0, 3, 4);
let val = 0b1100_1111; let val = 0b1100_1111;
assert_eq!( assert_eq!(field.read_from_u32(val), 0b1001,);
field.read_from_u32(val),
0b1001,
);
} }
} }