From 037c48fba084f49dbc18fb3bd9214425c2828a9f Mon Sep 17 00:00:00 2001 From: Histausse Date: Fri, 14 Oct 2022 13:21:36 +0200 Subject: [PATCH] implement verry basic unsafe UART --- src/bsp/rpi3/gpio.rs | 16 +- src/bsp/rpi3/memory_map.rs | 703 ++++++++++++++++++++++++++----------- src/bsp/rpi3/mod.rs | 2 + src/bsp/rpi3/uart.rs | 146 ++++++++ src/main.rs | 31 +- src/traits/console.rs | 2 + 6 files changed, 684 insertions(+), 216 deletions(-) create mode 100644 src/bsp/rpi3/uart.rs diff --git a/src/bsp/rpi3/gpio.rs b/src/bsp/rpi3/gpio.rs index 100b5bc..fac60e3 100644 --- a/src/bsp/rpi3/gpio.rs +++ b/src/bsp/rpi3/gpio.rs @@ -1,8 +1,6 @@ //! GPIO module. -use super::memory_map; -use crate::println; - +use super::memory_map::gpio::*; /// The number of pin for the raspberry 3. const NUMBER_PIN: usize = 54; @@ -67,13 +65,12 @@ pub fn set_pin_fonction(n: usize, function: PinFunction) -> Result<(), &'static if n >= NUMBER_PIN { return Err("The pin does not exist."); } - let field = memory_map::get_fsel(n); + let field = get_fsel(n); // TODO: SYNC - let mut val = unsafe { core::ptr::read_volatile(field.get_address() as *mut u32) }; + let address = field.get_address(); + let mut val = unsafe { core::ptr::read_volatile(address as *mut u32) }; val &= !field.get_mask(); val |= Into::::into(function) << field.get_offset(); - let address = field.get_address(); - println!("Set {val:b} at 0x{address:x}"); unsafe { core::ptr::write_volatile(address as *mut u32, val); } Ok(()) } @@ -89,12 +86,11 @@ pub fn set_pin_output_state(n: usize, state: PinOutputState) -> Result<(), &'sta return Err("The pin does not exist."); } let field = match state { - PinOutputState::High => memory_map::get_set(n), - PinOutputState::Low => memory_map::get_clr(n), + PinOutputState::High => get_set(n), + PinOutputState::Low => get_clr(n), }; let val = field.get_mask(); let address = field.get_address(); - println!("Set {val:b} at 0x{address:x}"); // 0 has no effect on this field: no nead to read-modify-write unsafe { core::ptr::write_volatile(address as *mut u32, val); } Ok(()) diff --git a/src/bsp/rpi3/memory_map.rs b/src/bsp/rpi3/memory_map.rs index f600600..cf0328c 100644 --- a/src/bsp/rpi3/memory_map.rs +++ b/src/bsp/rpi3/memory_map.rs @@ -2,219 +2,520 @@ use crate::utils::field::Field; -pub const GPIO_OFFSET: usize = 0x0020_0000; -pub const UART0_OFFSET: usize = 0x0020_1000; pub const START_PHYSICAL_ADDRESS: usize = 0x3F00_0000; -pub const UART0_START: usize = START_PHYSICAL_ADDRESS + UART0_OFFSET; - // ** GPIO addresses ** +/// Offset between the GPIO addresses and the beginning of the physical addresses +pub const GPIO_OFFSET: usize = 0x0020_0000; /// Beginning of the GPIO adresses pub const GPIO_START: usize = START_PHYSICAL_ADDRESS + GPIO_OFFSET; -// Function Select -/// GPIO Function Select 0, R/W register. -/// bits 29-27: FSEL9 -/// bits 26-24: FSEL8 -/// bits 23-21: FSEL7 -/// bits 20-18: FSEL6 -/// bits 17-15: FSEL5 -/// bits 14-12: FSEL4 -/// bits 11-9: FSEL3 -/// bits 8-6: FSEL2 -/// bits 5-3: FSEL1 -/// bits 2-0: FSEL0 -pub const GPFSEL0: usize = GPIO_START + 0x00; -/// GPIO Function Select 1, R/W register. -/// bits 29-27: FSEL19 -/// bits 26-24: FSEL18 -/// bits 23-21: FSEL17 -/// bits 20-18: FSEL16 -/// bits 17-15: FSEL15 -/// bits 14-12: FSEL14 -/// bits 11-9: FSEL13 -/// bits 8-6: FSEL12 -/// bits 5-3: FSEL11 -/// bits 2-0: FSEL10 -pub const GPFSEL1:usize = GPIO_START + 0x04; -/// GPIO Function Select 2, R/W register. -/// bits 29-27: FSEL29 -/// bits 26-24: FSEL28 -/// bits 23-21: FSEL27 -/// bits 20-18: FSEL26 -/// bits 17-15: FSEL25 -/// bits 14-12: FSEL24 -/// bits 11-9: FSEL23 -/// bits 8-6: FSEL22 -/// bits 5-3: FSEL21 -/// bits 2-0: FSEL20 -pub const GPFSEL2:usize = GPIO_START + 0x08; -/// GPIO Function Select 3, R/W register. -/// bits 29-27: FSEL39 -/// bits 26-24: FSEL38 -/// bits 23-21: FSEL37 -/// bits 20-18: FSEL36 -/// bits 17-15: FSEL35 -/// bits 14-12: FSEL34 -/// bits 11-9: FSEL33 -/// bits 8-6: FSEL32 -/// bits 5-3: FSEL31 -/// bits 2-0: FSEL30 -pub const GPFSEL3:usize = GPIO_START + 0x0C; -/// GPIO Function Select 4, R/W register. -/// bits 29-27: FSEL49 -/// bits 26-24: FSEL48 -/// bits 23-21: FSEL47 -/// bits 20-18: FSEL46 -/// bits 17-15: FSEL45 -/// bits 14-12: FSEL44 -/// bits 11-9: FSEL43 -/// bits 8-6: FSEL42 -/// bits 5-3: FSEL41 -/// bits 2-0: FSEL40 -pub const GPFSEL4:usize = GPIO_START + 0x10; -/// GPIO Function Select 5, R/W register. -/// bits 11-9: FSEL53 -/// bits 8-6: FSEL52 -/// bits 5-3: FSEL51 -/// bits 2-0: FSEL50 -pub const GPFSEL5:usize = GPIO_START + 0x14; +/// GPIO memory map. +pub mod gpio { + use super::*; -/// Return the field FSELn. -/// -/// # Panic -/// -/// Panic if the pin `n` does not exist. -pub const fn get_fsel(n: usize) -> Field { - if n > 53 { - panic!("The PIN does not exist"); + // Function Select + /// GPIO Function Select 0, R/W register. + /// + /// # Bits distribution: + /// + /// - 29-27: FSEL9 + /// - 26-24: FSEL8 + /// - 23-21: FSEL7 + /// - 20-18: FSEL6 + /// - 17-15: FSEL5 + /// - 14-12: FSEL4 + /// - 11-9: FSEL3 + /// - 8-6: FSEL2 + /// - 5-3: FSEL1 + /// - 2-0: FSEL0 + pub const GPFSEL0: usize = GPIO_START + 0x00; + /// GPIO Function Select 1, R/W register. + /// + /// # Bits distribution: + /// + /// - 29-27: FSEL19 + /// - 26-24: FSEL18 + /// - 23-21: FSEL17 + /// - 20-18: FSEL16 + /// - 17-15: FSEL15 + /// - 14-12: FSEL14 + /// - 11-9: FSEL13 + /// - 8-6: FSEL12 + /// - 5-3: FSEL11 + /// - 2-0: FSEL10 + pub const GPFSEL1:usize = GPIO_START + 0x04; + /// GPIO Function Select 2, R/W register. + /// + /// # Bits distribution: + /// + /// - 29-27: FSEL29 + /// - 26-24: FSEL28 + /// - 23-21: FSEL27 + /// - 20-18: FSEL26 + /// - 17-15: FSEL25 + /// - 14-12: FSEL24 + /// - 11-9: FSEL23 + /// - 8-6: FSEL22 + /// - 5-3: FSEL21 + /// - 2-0: FSEL20 + pub const GPFSEL2:usize = GPIO_START + 0x08; + /// GPIO Function Select 3, R/W register. + /// + /// # Bits distribution: + /// + /// - 29-27: FSEL39 + /// - 26-24: FSEL38 + /// - 23-21: FSEL37 + /// - 20-18: FSEL36 + /// - 17-15: FSEL35 + /// - 14-12: FSEL34 + /// - 11-9: FSEL33 + /// - 8-6: FSEL32 + /// - 5-3: FSEL31 + /// - 2-0: FSEL30 + pub const GPFSEL3:usize = GPIO_START + 0x0C; + /// GPIO Function Select 4, R/W register. + /// + /// # Bits distribution: + /// + /// - 29-27: FSEL49 + /// - 26-24: FSEL48 + /// - 23-21: FSEL47 + /// - 20-18: FSEL46 + /// - 17-15: FSEL45 + /// - 14-12: FSEL44 + /// - 11-9: FSEL43 + /// - 8-6: FSEL42 + /// - 5-3: FSEL41 + /// - 2-0: FSEL40 + pub const GPFSEL4:usize = GPIO_START + 0x10; + /// GPIO Function Select 5, R/W register. + /// + /// # Bits distribution: + /// + /// - 11-9: FSEL53 + /// - 8-6: FSEL52 + /// - 5-3: FSEL51 + /// - 2-0: FSEL50 + pub const GPFSEL5:usize = GPIO_START + 0x14; + + /// Return the field FSELn. + /// + /// # Panic + /// + /// Panic if the pin `n` does not exist. + pub const fn get_fsel(n: usize) -> Field { + if n > 53 { + panic!("The PIN does not exist"); + } + let address = [GPFSEL0, GPFSEL1, GPFSEL2, GPFSEL3, GPFSEL4, GPFSEL5][n/10]; + let offset = 3*(n%10); + let size = 3; + Field::new(address, offset, size) } - let address = [GPFSEL0, GPFSEL1, GPFSEL2, GPFSEL3, GPFSEL4, GPFSEL5][n/10]; - let offset = 3*(n%10); - let size = 3; - Field::new(address, offset, size) -} - -// Pin Output Set -/// Pin Output Set 0, W register. -/// bit 31: SET31 -/// ... -/// bit 0: SET0 -pub const GPSET0:usize = GPIO_START + 0x1C; -/// Pin Output Set 1, W register. -/// bit 21: SET53 -/// ... -/// bit 0: SET32 -pub const GPSET1:usize = GPIO_START + 0x20; - -/// Return the field SETn. -/// -/// # Panic -/// -/// Panic if the pin `n` does not exist. -pub const fn get_set(n: usize) -> Field { - if n > 53 { - panic!("The PIN does not exist"); + + // Pin Output Set + /// Pin Output Set 0, W register. + /// + /// # Bits distribution: + /// + /// - 31: SET31 + /// - ... + /// - 0: SET0 + pub const GPSET0:usize = GPIO_START + 0x1C; + /// Pin Output Set 1, W register. + /// + /// # Bits distribution: + /// + /// - 21: SET53 + /// - ... + /// - 0: SET32 + pub const GPSET1:usize = GPIO_START + 0x20; + + /// Return the field SETn. + /// + /// # Panic + /// + /// Panic if the pin `n` does not exist. + pub const fn get_set(n: usize) -> Field { + if n > 53 { + panic!("The PIN does not exist"); + } + let (address, offset) = if n < 32 { + (GPSET0, n) + } else { + (GPSET1, n-32) + }; + let size = 1; + Field::new(address, offset, size) } - let (address, offset) = if n < 32 { - (GPSET0, n) - } else { - (GPSET1, n-32) - }; - let size = 1; - Field::new(address, offset, size) -} - -// Pin Output Clear -/// Pin Output Clear 0, W register. -/// bit 31: CLR31 -/// ... -/// bit 0: CLR0 -pub const GPCLR0:usize = GPIO_START + 0x28; -/// Pin Output Clear 1, W register. -/// bit 21: CLR53 -/// ... -/// bit 0: CLR32 -pub const GPCLR1:usize = GPIO_START + 0x2C; - -/// Return the field CLRn. -/// -/// # Panic -/// -/// Panic if the pin `n` does not exist. -pub const fn get_clr(n: usize) -> Field { - if n > 53 { - panic!("The PIN does not exist"); + + // Pin Output Clear + /// Pin Output Clear 0, W register. + /// + /// # Bits distribution: + /// + /// - 31: CLR31 + /// - ... + /// - 0: CLR0 + pub const GPCLR0:usize = GPIO_START + 0x28; + /// Pin Output Clear 1, W register. + /// + /// # Bits distribution: + /// + /// - 21: CLR53 + /// - ... + /// - 0: CLR32 + pub const GPCLR1:usize = GPIO_START + 0x2C; + + /// Return the field CLRn. + /// + /// # Panic + /// + /// Panic if the pin `n` does not exist. + pub const fn get_clr(n: usize) -> Field { + if n > 53 { + panic!("The PIN does not exist"); + } + let (address, offset) = if n < 32 { + (GPCLR0, n) + } else { + (GPCLR1, n-32) + }; + let size = 1; + Field::new(address, offset, size) } - let (address, offset) = if n < 32 { - (GPCLR0, n) - } else { - (GPCLR1, n-32) - }; - let size = 1; - Field::new(address, offset, size) + + // Pin Level + /// Pin Level 0, R register. + pub const GPLEV0:usize = GPIO_START + 0x34; + /// Pin Level 1, R register. + pub const GPLEV1:usize = GPIO_START + 0x38; + + // Pin Event Detect Status + /// Pin Event Detect Status 0, R/W register. + pub const GPEDS0:usize = GPIO_START + 0x40; + /// Pin Event Detect Status 1, R/W register. + pub const GPEDS1:usize = GPIO_START + 0x44; + + // Pin Rising Edge Detect Enable + /// Pin Rising Edge Detect Enable 0, R/W register. + pub const GPREN0:usize = GPIO_START + 0x4C; + /// Pin Rising Edge Detect Enable 1, R/W register. + pub const GPREN1:usize = GPIO_START + 0x50; + + // Pin Falling Edge Detect Enable + /// Pin Falling Edge Detect Enable 0, R/W register. + pub const GPFEN0:usize = GPIO_START + 0x58; + /// Pin Falling Edge Detect Enable 1, R/W register. + pub const GPFEN1:usize = GPIO_START + 0x5C; + + // Pin High Detect Enable + /// Pin High Detect Enable 0, R/W register. + pub const GPHEN0:usize = GPIO_START + 0x64; + /// Pin High Detect Enable 1, R/W register. + pub const GPHEN1:usize = GPIO_START + 0x68; + + // Pin Low Detect Enable + /// Pin Low Detect Enable 0, R/W register. + pub const GPLEN0:usize = GPIO_START + 0x70; + /// Pin Low Detect Enable 1, R/W register. + pub const GPLEN1:usize = GPIO_START + 0x74; + + // Pin Async, Rising Edge Detect + /// Pin Async, Rising Edge Detect 0, R/W register. + pub const GPAREN0:usize = GPIO_START + 0x7C; + /// Pin Async, Rising Edge Detect 1, R/W register. + pub const GPAREN1:usize = GPIO_START + 0x80; + + // Pin Async, Falling Edge Detect + /// Pin Async, Falling Edge Detect 0, R/W register. + pub const GPAFEN0:usize = GPIO_START + 0x88; + /// Pin Async, Falling Edge Detect1, R/W register. + pub const GPAFEN1:usize = GPIO_START + 0x8C; + + // Pin Pull-up/down Enable, R/W + /// Pin Pull-up/down Enable, R/W register. + pub const GPPUD:usize = GPIO_START + 0x94; + + // Pin Pull-up/down enable clock, R/W + /// Pin Pull-up/down enable clock 0, R/W register. + pub const GPPUDCLK0:usize = GPIO_START + 0x98; + /// Pin Pull-up/down enable clock 1, R/W register. + pub const GPPUDCLK1:usize = GPIO_START + 0x9C; + + // Test ?, R/W, 4 bits + /// Test register? only 4 bits long. + pub const GPIO_TEST:usize = GPIO_START + 0xB0; } +// ** GPIO addresses ** -// Pin Level -/// Pin Level 0, R register. -pub const GPLEV0:usize = GPIO_START + 0x34; -/// Pin Level 1, R register. -pub const GPLEV1:usize = GPIO_START + 0x38; - -// Pin Event Detect Status -/// Pin Event Detect Status 0, R/W register. -pub const GPEDS0:usize = GPIO_START + 0x40; -/// Pin Event Detect Status 1, R/W register. -pub const GPEDS1:usize = GPIO_START + 0x44; - -// Pin Rising Edge Detect Enable -/// Pin Rising Edge Detect Enable 0, R/W register. -pub const GPREN0:usize = GPIO_START + 0x4C; -/// Pin Rising Edge Detect Enable 1, R/W register. -pub const GPREN1:usize = GPIO_START + 0x50; - -// Pin Falling Edge Detect Enable -/// Pin Falling Edge Detect Enable 0, R/W register. -pub const GPFEN0:usize = GPIO_START + 0x58; -/// Pin Falling Edge Detect Enable 1, R/W register. -pub const GPFEN1:usize = GPIO_START + 0x5C; - -// Pin High Detect Enable -/// Pin High Detect Enable 0, R/W register. -pub const GPHEN0:usize = GPIO_START + 0x64; -/// Pin High Detect Enable 1, R/W register. -pub const GPHEN1:usize = GPIO_START + 0x68; - -// Pin Low Detect Enable -/// Pin Low Detect Enable 0, R/W register. -pub const GPLEN0:usize = GPIO_START + 0x70; -/// Pin Low Detect Enable 1, R/W register. -pub const GPLEN1:usize = GPIO_START + 0x74; - -// Pin Async, Rising Edge Detect -/// Pin Async, Rising Edge Detect 0, R/W register. -pub const GPAREN0:usize = GPIO_START + 0x7C; -/// Pin Async, Rising Edge Detect 1, R/W register. -pub const GPAREN1:usize = GPIO_START + 0x80; - -// Pin Async, Falling Edge Detect -/// Pin Async, Falling Edge Detect 0, R/W register. -pub const GPAFEN0:usize = GPIO_START + 0x88; -/// Pin Async, Falling Edge Detect1, R/W register. -pub const GPAFEN1:usize = GPIO_START + 0x8C; - -// Pin Pull-up/down Enable, R/W -/// Pin Pull-up/down Enable, R/W register. -pub const GPPUD:usize = GPIO_START + 0x94; +// ** UART addresses ** +/// Offset between the UART addresses and the beginning of the physical addresses +pub const UART_OFFSET: usize = 0x0020_1000; +/// Begeinning of the UART addresses. +pub const UART_START: usize = START_PHYSICAL_ADDRESS + UART_OFFSET; -// Pin Pull-up/down enable clock, R/W -/// Pin Pull-up/down enable clock 0, R/W register. -pub const GPPUDCLK0:usize = GPIO_START + 0x98; -/// Pin Pull-up/down enable clock 1, R/W register. -pub const GPPUDCLK1:usize = GPIO_START + 0x9C; +/// UART memory map. +pub mod uart { + use super::*; -// Test ?, R/W, 4 bits -/// Test register? only 4 bits long. -pub const GPIO_TEST:usize = GPIO_START + 0xB0; -// ** GPIO addresses ** + /// Data Register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W. + /// - 11: OE, Overrun Error. Set to 1 if data received with FIFO full, R/W. + /// - 10: BE, Break Error. Set to 1 if a break condition was detected, R/W. + /// - 9: PE, Parity Error. Set to 1 when the parity don't match data, R/W. + /// - 8: FE, Framing Error. Set to 1 when character don't have valid stop bit, R/W. + /// - 7-0: DATA, Data character. R/W. + pub const DR: usize = UART_START + 0x00; + /// Receive Status Register/Error Clear Register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-12: reserved. Write as 0, value read don't have meaning, R/W. + /// - 3: OE, Overrun Error. Set to 1 if data received with FIFO full, R/W. + /// - 2: BE, Break Error. Set to 1 if a break condition was detected, R/W. + /// - 1: PE, Parity Error. Set to 1 when the parity don't match data, R/W. + /// - 0: FE, Framing Error. Set to 1 when characteur don't have valid stop bit, R/W. + pub const RSRECR: usize = UART_START + 0x04; + /// Flag register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-9: reserved. Write as 0, value read don't have meaning, R/W. + /// - 8: RI, unsuported. Write as 0, value read don't have meaning, R/W. + /// - 7: TXFE, Transmit FIFO Empty. If FIFO disabled, set when tx holding register empty. + /// If FIFO enabled, set when tx FIFP is empty. R/W. + /// - 6: RXFF, Receive FIFO Full. If FIFO disabled, set when rx holding register is full. + /// If FIFO enabled, set when rx FIFO is full. R/W. + /// - 5: TXFF, Transmit FIFO Full. If FIFO disabled, set when tx holding register full. + /// If FIFO enabled, set when tx FIFP is full. R/W. + /// - 4: RXFE, Receive FIFO Empty. If FIFO disabled, set when rx holding register is empty. + /// If FIFO enabled, set when rx FIFO is empty. 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. + /// - 1: DSR, unsuported. Write as 0, value read don't have meaning, R/W. + /// - 0: CTS, Clear To Send. + pub const FR: usize = UART_START + 0x18; + /// Not in use. 32 bits long. + pub const ILPR: usize = UART_START + 0x20; + /// Integer Baud rate divisor, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-16: reserved. Write as 0, value read don't have meaning, R/W. + /// - 15-0: IBRD. The integer baud rate divisor, R/W. + pub const IBRD: usize = UART_START + 0x24; + /// Fractional Baud rate divisor, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-6: reserved. Write as 0, value read don't have meaning, R/W. + /// - 5-0: FBRD. The fractional baud rate divisor, R/W. + pub const FBRD: usize = UART_START + 0x28; + /// Line Constrol register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-8: reserved. Write as 0, value read don't have meaning, R/W. + /// - 7: SPS, Stick Parity Select. 0: the stick parity is disabled, 1: either + /// depending on EPS (Event Parity Select), R/W. + /// - 6-5: WLEN: World lenght. Number of data bits transmitted by frame (0b00 -> 5b, 0b11 -> + /// 8b), 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 + /// (rx logic is not affected), R/W. + /// - 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 + /// PEN disable parity check. R/W. + /// - 1: PEN, Parity Enable. 0: Don't add parity bit and don't check parity, 1: add parity bit + /// and check for parity, R/W. + /// - 0: BRK: Send break. If set, send continuous low level to TXD after the current char, R/W. + pub const LCRH: usize = UART_START + 0x2C; + /// Control register, 32 bits long. + /// + /// # Warning + /// + /// To program the CR: + /// + /// - 1) Disable UART + /// - 2) Wait for the end of tx/rx of the current char + /// - 3) Flush the transmit FIFO by setting `FEN` to 0 in [`LCRH`] + /// - 4) Reprogram `CR`. + /// - 5) Enable UART + /// + /// # Bits distribution: + /// + /// - 31-16: reserved. Write as 0, value read don't have meaning, R/W. + /// - 15: CTSEN, CTS hardware flow control enable. If set, data is only transmitted when + /// nUARTCTS is asserted, R/W. + /// - 14: RTSEN, RST hardware flow control enable. If set, data is only requested when there + /// is space in the receive FIFO, R/W. + /// - 13: OUT2, unsuported, Write as 0, value read don't have meaning, R. + /// - 12: OUT1, unsuported, Write as 0, value read don't have meaning, R. + /// - 11: RTS, Request To Send. When set to 1, nUARTRTS is low, R/W. + /// - 10: DTR, unsuported, Write as 0, value read don't have meaning, R. + /// - 9: RXE, Receive enable. If set, (and if UARTEN is set), the uart can read data, R/W. + /// - 8: TXE, Transmit enable. If set, (and if UARTEN is set), the uart can send data, R/W. + /// - 7: LBE, LoopBack Enable. If set, UARTTXD is fed through to the UARTRXD path, 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. + /// - 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. + pub const CR: usize = UART_START + 0x30; + /// Interrupt FIFO level Select register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 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. + /// - 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 + /// reveive interrupt is send: + /// - `0b000`: Send when FIFO becom 1/8 full + /// - `0b001`: Send when FIFO becom 1/4 full + /// - `0b010`: Send when FIFO becom 1/2 full + /// - `0b011`: Send when FIFO becom 3/4 full + /// - `0b100`: Send when FIFO becom 7/7 full + /// - Other values are reserved. + /// R/W. + /// - 2-0: TXIFLSEL, Transmit Interrupt FIFO Level Select. The level from which the + /// transmit interrupt is send: + /// - `0b000`: Send when FIFO becom 1/8 full + /// - `0b001`: Send when FIFO becom 1/4 full + /// - `0b010`: Send when FIFO becom 1/2 full + /// - `0b011`: Send when FIFO becom 3/4 full + /// - `0b100`: Send when FIFO becom 7/7 full + /// - Other values are reserved. + /// R/W. + pub const IFLS: usize = UART_START + 0x34; + /// Interupt Mask Set Clear register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-11: reserved. Write as 0, value read don't have meaning, R/W. + /// - 10: OEIM, Overrun Error Interrupt Mask. Value of the mask for OE Interrupt, R/W. + /// - 9: BEIM, Break Error Interrupt Mask. Value of the mask for BE Interrupt, R/W. + /// - 8: PEIM, Parity Error Interrupt Mask. Value of the mask for PE Interrupt, R/W. + /// - 7: FEIM, Framing Error Interrupt Mask. Value of the mask for FE Interrupt, R/W. + /// - 6: RT Interrupt, Receive Timeout Interrupt Mask. Value of the mask for RTIM, R/W. + /// - 5: TXIM, Transmit Interrupt Mask. Value of the mask for TX Interrupt, R/W. + /// - 4: RXIM, Receive Interrupt Mask. Value of the mask for RX Interrupt, R/W. + /// - 3: DSRMIM, unsuported, Write as 0, value read don't have meaning, R. + /// - 2: DCDMIM, unsuported, Write as 0, value read don't have meaning, R. + /// - 1: CTSMIM, nUARTCTS Modem Interrupt Mask. Value of the mask for CTS Interrupt, R/W. + /// - 0: RIMIM, unsuported, Write as 0, value read don't have meaning, R. + pub const IMSC: usize = UART_START + 0x38; + /// Raw Interupt Status register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-11: reserved. Write as 0, value read don't have meaning, R. + /// - 10: OERIS, Overrun Error Raw Interrupt Status. Raw interrupt state of the OE Interrupt, R. + /// - 9: BERIS, Break Error Raw Interrupt Status. Raw interrupt state of the BE Interrupt, R. + /// - 8: PERIS, Parity Error Raw Interrupt Status. Raw interrupt state of the PE Interrupt, R. + /// - 7: FERIS, Framing Error Raw Interrupt Status. Raw interrupt state of the FE Interrupt, R. + /// - 6: RT Interrupt, Receive Timeout Raw Interrupt Status. Raw interrupt state of the RTRIS, R. + /// - 5: TXRIS, Transmit Raw Interrupt Status. Raw interrupt state of the TX Interrupt, R. + /// - 4: RXRIS, Receive Raw Interrupt Status. Raw interrupt state of the RX Interrupt, R. + /// - 3: DSRMRIS, unsuported, Write as 0, value read don't have meaning, R. + /// - 2: DCDMRIS, unsuported, Write as 0, value read don't have meaning, R. + /// - 1: CTSMRIS, nUARTCTS Modem Raw Interrupt Status. Raw interrupt state of the CTS Interrupt, R. + /// - 0: RRISIM, unsuported, Write as 0, value read don't have meaning, R. + pub const RIS: usize = UART_START + 0x3C; + /// Masked Interupt Status register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-11: reserved. Write as 0, value read don't have meaning, R. + /// - 10: OEMIS, Overrun Error Masked Interrupt Status. Masked interrupt state of the OE Interrupt, R. + /// - 9: BEMIS, Break Error Masked Interrupt Status. Masked interrupt state of the BE Interrupt, R. + /// - 8: PEMIS, Parity Error Masked Interrupt Status. Masked interrupt state of the PE Interrupt, R. + /// - 7: FEMIS, Framing Error Masked Interrupt Status. Masked interrupt state of the FE Interrupt, R. + /// - 6: RT Interrupt, Receive Timeout Masked Interrupt Status. Masked interrupt state of the RTMIS, R. + /// - 5: TXMIS, Transmit Masked Interrupt Status. Masked interrupt state of the TX Interrupt, R. + /// - 4: RXMIS, Receive Masked Interrupt Status. Masked interrupt state of the RX Interrupt, R. + /// - 3: DSRMMIS, unsuported, Write as 0, value read don't have meaning, R. + /// - 2: DCDMMIS, unsuported, Write as 0, value read don't have meaning, R. + /// - 1: CTSMMIS, nUARTCTS Modem Masked Interrupt Status. Masked interrupt state of the CTS Interrupt, R. + /// - 0: RMISIM, unsuported, Write as 0, value read don't have meaning, R. + pub const MIS: usize = UART_START + 0x40; + /// Interupt Clear Register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-11: reserved. Write as 0, value read don't have meaning, R. + /// - 10: OEIC, Overrun Error Interrupt Clear. Clear the OE Interrupt, R. + /// - 9: BEIC, Break Error Interrupt Clear. Clear the BE Interrupt, R. + /// - 8: PEIC, Parity Error Interrupt Clear. Clear the PE Interrupt, R. + /// - 7: FEIC, Framing Error Interrupt Clear. Clear the FE Interrupt, R. + /// - 6: RT Interrupt, Receive Timeout Interrupt Clear. Clear the RTIC, R. + /// - 5: TXIC, Transmit Interrupt Clear. Clear the TX Interrupt, R. + /// - 4: RXIC, Receive Interrupt Clear. Clear the RX Interrupt, R. + /// - 3: DSRMIC, unsuported, Write as 0, value read don't have meaning, R. + /// - 2: DCDMIC, unsuported, Write as 0, value read don't have meaning, R. + /// - 1: CTSMIC, nUARTCTS Modem Interrupt Clear. Clear the CTS Interrupt, R. + /// - 0: RICIM, unsuported, Write as 0, value read don't have meaning, R. + pub const ICR: usize = UART_START + 0x44; + /// DMA Control Register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-3: reserved. Write as 0, value read don't have meaning, R. + /// - 2: DMAONERR, unsuported, Write as 0, value read don't have meaning, R. + /// - 1: TXDMAE, unsuported, Write as 0, value read don't have meaning, R. + /// - 0: RXDMAE, unsuported, Write as 0, value read don't have meaning, R. + pub const DMACR: usize = UART_START + 0x48; + /// Test Control register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-2: reserved. Write as 0, value read don't have meaning, R. + /// - 1: ITCR1, Test FIFO enable. If set, read/write directly to the FIFOs with TDR10_0, R/W. + /// - 0: ITCR0, Integration Test Enable. If set, the UART is placed in intergration test mode, + /// R/W. + pub const ITCR: usize = UART_START + 0x80; + /// Integration Test Input register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-4: reserved. Write as 0, value read don't have meaning, R. + /// - 3: ITIP3. Reads returns the value of nUARTCTS, R/W. + /// - 2-1: reserved. Write as 0, value read don't have meaning, R. + /// - 0: ITIP0. Reads the value of UARTRXD, R/W. + pub const ITIP: usize = UART_START + 0x84; + /// Integration Test Output register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 31-12: reserved. Write as 0, value read don't have meaning, R. + /// - 11: ITOP11, Intra-chip Output. Writes set the value to be driven on UARTLSINTR, Reads + /// returns the value of UARTLSINTR at the output of the test multiplexor, R/W. + /// - 10: ITOP10, Intra-chip Output. Writes set the value to be driven on UARTRXINTR, Reads + /// returns the value of UARTRXINTR at the output of the test multiplexor, R/W. + /// - 9: ITOP9, Intra-chip Output. Writes set the value to be driven on UARTTXINTR, Reads + /// returns the value of UARTTXINTR at the output of the test multiplexor, R/W. + /// - 8: ITOP8, Intra-chip Output. Writes set the value to be driven on UARTRTINTR, Reads + /// returns the value of UARTRTINTR at the output of the test multiplexor, R/W. + /// - 7: ITOP7, Intra-chip Output. Writes set the value to be driven on UARTEINTR, Reads + /// returns the value of UARTEINTR at the output of the test multiplexor, R/W. + /// - 6: ITOP6, Intra-chip Output. Writes set the value to be driven on UARTINTR, Reads + /// returns the value of UARTINTR at the output of the test multiplexor, R/W. + /// - 5-4: reserved. Write as 0, value read don't have meaning, R. + /// - 3: ITIP3: Primary Output. Writes specify the value on nUARTRTS, R/W. + /// - 2-1: reserved. Write as 0, value read don't have meaning, R. + /// - 0: ITIP0, Primary Output. Writes specify the value to be driven on UARTTXD, R/W. + pub const ITOP: usize = UART_START + 0x88; + /// Test Data register, 32 bits long. + /// + /// # Bits distribution: + /// + /// - 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. + pub const TDR: usize = UART_START + 0x8C; +} diff --git a/src/bsp/rpi3/mod.rs b/src/bsp/rpi3/mod.rs index 493e0ac..a52f5bd 100644 --- a/src/bsp/rpi3/mod.rs +++ b/src/bsp/rpi3/mod.rs @@ -4,3 +4,5 @@ pub(self) mod memory_map; pub mod gpio; + +pub mod uart; diff --git a/src/bsp/rpi3/uart.rs b/src/bsp/rpi3/uart.rs new file mode 100644 index 0000000..63f3390 --- /dev/null +++ b/src/bsp/rpi3/uart.rs @@ -0,0 +1,146 @@ +//! Driver for the UART. + +use core::arch::asm; +use core::fmt; +use core::ptr::{read_volatile, write_volatile}; + +use crate::utils::field::Field; +use crate::traits::console::{Write, Console}; + +use super::memory_map::uart::*; + + +pub struct Uart { + initialized: bool, +} + +const TMP_UARTEN: Field = Field::new(CR, 0, 1); +const TMP_TXE: Field = Field::new(CR, 8, 1); +const TMP_BUSY: Field = Field::new(FR, 3, 1); +const TMP_TXFF: Field = Field::new(FR, 5, 1); +const TMP_FEN: Field = Field::new(LCRH, 4, 1); +const TMP_WLEN: Field = Field::new(LCRH, 5, 2); +const TMP_IBRD: Field = Field::new(IBRD, 0, 16); +const TMP_FBRD: Field = Field::new(FBRD, 0, 6); +const TMP_DATA: Field = Field::new(DR, 0, 8); + +impl Uart { + // TODO: not sure this should be public outside of bsp. + /// Constructor for [`Uart`]. + pub const fn new() -> Self { + Uart { initialized: false } + } + + /// Initialise the UART. + pub fn init(&mut self) { + // TODO: Recover from possible previous test. + + self.flush(); + + // Stop UART + let mut cr_val = unsafe { read_volatile(TMP_UARTEN.get_address() as *mut u32) }; + cr_val &= !TMP_UARTEN.get_mask(); + unsafe { write_volatile(TMP_UARTEN.get_address() as *mut u32, cr_val); } + + // Flush the FIFOs + let mut lcrh_val = unsafe { read_volatile(TMP_FEN.get_address() as *mut u32) }; + lcrh_val &= !TMP_FEN.get_mask(); + unsafe { write_volatile(TMP_FEN.get_address() as *mut u32, lcrh_val); } + + // Clear all interrupt + unsafe { write_volatile(ICR as *mut u32, 0); } + + // Config UART + // 8N1 115_200 bauds. + + // divbaud = freq/16/baudrate = 48_000_000 / 16 / 115_200 = 26.041666666666668 + // => IBRD = 26 + // => FBRD = round(0.041666666666668 * 64) = 3 // TODO: why 64? + unsafe { write_volatile(TMP_IBRD.get_address() as *mut u32, 26 & TMP_IBRD.get_mask()); } + unsafe { write_volatile(TMP_FBRD.get_address() as *mut u32, 3 & TMP_FBRD.get_mask()); } + + lcrh_val = 0; + // Set word len to 8 + lcrh_val |= 0b11 << TMP_WLEN.get_offset(); + // Reenable the FIFOs + lcrh_val |= TMP_FEN.get_mask(); + unsafe { write_volatile(LCRH as *mut u32, lcrh_val); } + + let mut cr_val = 0; + cr_val |= TMP_TXE.get_mask(); // enable TX + unsafe { write_volatile(TMP_TXE.get_address() as *mut u32, cr_val); } + + // Start the UART + cr_val |= TMP_UARTEN.get_mask(); + unsafe { write_volatile(TMP_UARTEN.get_address() as *mut u32, cr_val); } + + self.initialized = true; + } + + /// Test if the UART is busy. + fn is_busy(&self) -> bool { + let fr_val = unsafe { read_volatile(TMP_BUSY.get_address() as *mut u32) }; + (fr_val & TMP_BUSY.get_mask()) != 0 + } + + /// Test if the the TX FIFO is full. + fn is_tx_full(&self) -> bool { + let fr_val = unsafe { read_volatile(TMP_TXFF.get_address() as *mut u32) }; + (fr_val & TMP_TXFF.get_mask()) != 0 + } +} + +// Allow the use of uart for fmt::Write::write_fmt. +impl fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + if c == '\n' { + Write::write_char(self, '\r'); + } + Write::write_char(self, c); + } + Ok(()) + } +} + +// TODO: add sync +impl Write for Uart { + fn write_char(&self, c: char) { + if !self.initialized { + //panic!("Cannot write to a non initialized UART"); + } + while self.is_tx_full() { + use super::gpio; + let _ = gpio::set_pin_output_state(20, gpio::PinOutputState::High); + unsafe { asm!("nop") }; + } + unsafe { write_volatile(TMP_DATA.get_address() as *mut u32, c as u32) }; + } + + fn write_fmt(&self, args: fmt::Arguments) -> fmt::Result { + // TODO: use syncronisation here + let mut new_uart = Uart { initialized: self.initialized }; + fmt::Write::write_fmt(&mut new_uart, args) + } + + fn flush(&self) { + while self.is_busy() { + unsafe { asm!("nop") }; + } + } +} + +impl Console for Uart {} + +static UART: Uart = Uart { initialized: true }; // TODO: use sync + +pub fn init() { + let mut uart = Uart::new(); + uart.init(); +} + +// TODO: move? +/// Return a reference to the Uart Output. +pub fn console() -> &'static dyn Console { + &UART +} diff --git a/src/main.rs b/src/main.rs index c50e683..3cfe69e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,8 @@ #![feature(format_args_nl)] #![feature(panic_info_message)] +#![allow(dead_code)] + mod traits; mod bsp; mod utils; @@ -21,7 +23,8 @@ use core::arch::global_asm; use core::arch::asm; // TODO: handle this with features -use crate::bsp::qemu::console::console; +//use crate::bsp::qemu::console::console; +use crate::bsp::rpi3::uart::console; use crate::bsp::rpi3::gpio; // TODO: move this to BSP @@ -39,21 +42,39 @@ global_asm!(include_str!("boot.s")); /// Start the rust part of the kernel #[no_mangle] pub unsafe fn _start_rust() -> ! { + + // Set TX and RX function for pin 14 and 15 + match gpio::set_pin_fonction(14, gpio::PinFunction::AltFunc0) { + _ => (), + } + match gpio::set_pin_fonction(15, gpio::PinFunction::AltFunc0) { + _ => (), + } + // Debut led + match gpio::set_pin_fonction(20, gpio::PinFunction::Output) { + _ => (), + } + match gpio::set_pin_output_state(20, gpio::PinOutputState::Low) { + _ => (), + } + bsp::rpi3::uart::init(); + println!("Hello there"); + match gpio::set_pin_fonction(21, gpio::PinFunction::Output) { Ok(()) => println!("Successfully set pin to output"), Err(err) => println!("Failled to set pin: {err}"), } loop { match gpio::set_pin_output_state(21, gpio::PinOutputState::High) { - Ok(()) => println!("Successfully set pin to HIGH"), - Err(err) => println!("Failled to set pin: {err}"), + Ok(()) => (), + Err(_err) => println!("Failled to set pin 21 to High"), } for _ in 0..5000000 { asm!("nop"); } match gpio::set_pin_output_state(21, gpio::PinOutputState::Low) { - Ok(()) => println!("Successfully set pin to HIGH"), - Err(err) => println!("Failled to set pin: {err}"), + Ok(()) => (), + Err(_err) => println!("Failled to set pin 21 to Low"), } for _ in 0..5000000 { asm!("nop"); diff --git a/src/traits/console.rs b/src/traits/console.rs index c0011ce..7d90ad6 100644 --- a/src/traits/console.rs +++ b/src/traits/console.rs @@ -31,3 +31,5 @@ impl Write for DummyConsole { fn flush(&self) {} } + +impl Console for DummyConsole {}