Add Deref trait in the spirit of cortex-m peripherals

Improves code readability; Reduces need for unsafe blocks on register
reads.

https://github.com/japaric/cortex-m/blob/master/src/peripheral/mod.rs
This commit is contained in:
Andre Richter 2018-04-13 21:58:59 +02:00
parent a584fa4dfa
commit 0ce1cde72c
18 changed files with 411 additions and 256 deletions

Binary file not shown.

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use gpio; use gpio;
use volatile_register::*; use volatile_register::*;
@ -31,7 +32,7 @@ const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000;
/// Auxilary mini UART registers /// Auxilary mini UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
__reserved_0: u32, // 0x00 __reserved_0: u32, // 0x00
ENABLES: RW<u32>, // 0x04 ENABLES: RW<u32>, // 0x04
__reserved_1: [u32; 14], // 0x08 __reserved_1: [u32; 14], // 0x08
@ -48,29 +49,38 @@ struct Registers {
MU_BAUD: RW<u32>, // 0x68 MU_BAUD: RW<u32>, // 0x68
} }
pub struct MiniUart { pub struct MiniUart;
registers: *const Registers,
impl ops::Deref for MiniUart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl MiniUart { impl MiniUart {
pub fn new() -> MiniUart { pub fn new() -> MiniUart {
MiniUart { MiniUart
registers: MINI_UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
MINI_UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self) { pub fn init(&self) {
// initialize UART // initialize UART
unsafe { unsafe {
(*self.registers).ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart self.ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart
(*self.registers).MU_IER.write(0); self.MU_IER.write(0);
(*self.registers).MU_CNTL.write(0); self.MU_CNTL.write(0);
(*self.registers).MU_LCR.write(3); // 8 bits self.MU_LCR.write(3); // 8 bits
(*self.registers).MU_MCR.write(0); self.MU_MCR.write(0);
(*self.registers).MU_IER.write(0); self.MU_IER.write(0);
(*self.registers).MU_IIR.write(0xC6); // disable interrupts self.MU_IIR.write(0xC6); // disable interrupts
(*self.registers).MU_BAUD.write(270); // 115200 baud self.MU_BAUD.write(270); // 115200 baud
// map UART1 to GPIO pins // map UART1 to GPIO pins
(*gpio::GPFSEL1).modify(|x| { (*gpio::GPFSEL1).modify(|x| {
@ -92,40 +102,38 @@ impl MiniUart {
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
} }
(*gpio::GPPUDCLK0).write(0); // flush GPIO setup (*gpio::GPPUDCLK0).write(0); // flush GPIO setup
(*self.registers).MU_CNTL.write(3); // enable Tx, Rx self.MU_CNTL.write(3); // enable Tx, Rx
} }
} }
/// Send a character /// Send a character
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
unsafe {
// wait until we can send // wait until we can send
loop { loop {
if ((*self.registers).MU_LSR.read() & 0x20) == 0x20 { if (self.MU_LSR.read() & 0x20) == 0x20 {
break; break;
} }
asm!("nop" :::: "volatile");
unsafe { asm!("nop" :::: "volatile") };
} }
// write the character to the buffer // write the character to the buffer
(*self.registers).MU_IO.write(c as u32); unsafe { self.MU_IO.write(c as u32) };
}
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> char { pub fn getc(&self) -> char {
unsafe {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if ((*self.registers).MU_LSR.read() & 0x01) == 0x01 { if (self.MU_LSR.read() & 0x01) == 0x01 {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
// read it and return // read it and return
let mut ret = unsafe { (*self.registers).MU_IO.read() as u8 as char }; let mut ret = self.MU_IO.read() as u8 as char;
// convert carrige return to newline // convert carrige return to newline
if ret == '\r' { if ret == '\r' {

Binary file not shown.

View File

@ -23,13 +23,14 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO}; use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
READ: RO<u32>, // 0x00 READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04 __reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10 POLL: RO<u32>, // 0x10
@ -76,33 +77,52 @@ pub struct Mbox {
// data structures in Rust is a bit of a hassle right now, we just // data structures in Rust is a bit of a hassle right now, we just
// close our eyes and roll with it. // close our eyes and roll with it.
pub buffer: [u32; 36], pub buffer: [u32; 36],
registers: *const Registers, }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.STATUS.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Mbox::ptr()).STATUS.read() }
/// ```
impl ops::Deref for Mbox {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Mbox { impl Mbox {
pub fn new() -> Mbox { pub fn new() -> Mbox {
Mbox { Mbox { buffer: [0; 36] }
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
VIDEOCORE_MBOX as *const _
} }
/// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success
pub fn call(&self, channel: u32) -> Result<()> { pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox // wait until we can write to the mailbox
loop { loop {
unsafe { if (self.STATUS.read() & FULL) != FULL {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break; break;
} }
unsafe {
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
} }
} }
// write the address of our message to the mailbox with channel identifier // write the address of our message to the mailbox with channel identifier
unsafe { unsafe {
(*self.registers) self.WRITE
.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
} }
@ -110,15 +130,16 @@ impl Mbox {
loop { loop {
// is there a response? // is there a response?
loop { loop {
unsafe { if (self.STATUS.read() & EMPTY) != EMPTY {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break; break;
} }
unsafe {
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
} }
} }
let resp: u32 = unsafe { (*self.registers).READ.read() }; let resp: u32 = self.READ.read();
// is it a response to our message? // is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use gpio; use gpio;
use volatile_register::*; use volatile_register::*;
@ -31,7 +32,7 @@ const MINI_UART_BASE: u32 = MMIO_BASE + 0x21_5000;
/// Auxilary mini UART registers /// Auxilary mini UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
__reserved_0: u32, // 0x00 __reserved_0: u32, // 0x00
ENABLES: RW<u32>, // 0x04 ENABLES: RW<u32>, // 0x04
__reserved_1: [u32; 14], // 0x08 __reserved_1: [u32; 14], // 0x08
@ -48,29 +49,38 @@ struct Registers {
MU_BAUD: RW<u32>, // 0x68 MU_BAUD: RW<u32>, // 0x68
} }
pub struct MiniUart { pub struct MiniUart;
registers: *const Registers,
impl ops::Deref for MiniUart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl MiniUart { impl MiniUart {
pub fn new() -> MiniUart { pub fn new() -> MiniUart {
MiniUart { MiniUart
registers: MINI_UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
MINI_UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self) { pub fn init(&self) {
// initialize UART // initialize UART
unsafe { unsafe {
(*self.registers).ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart self.ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart
(*self.registers).MU_IER.write(0); self.MU_IER.write(0);
(*self.registers).MU_CNTL.write(0); self.MU_CNTL.write(0);
(*self.registers).MU_LCR.write(3); // 8 bits self.MU_LCR.write(3); // 8 bits
(*self.registers).MU_MCR.write(0); self.MU_MCR.write(0);
(*self.registers).MU_IER.write(0); self.MU_IER.write(0);
(*self.registers).MU_IIR.write(0xC6); // disable interrupts self.MU_IIR.write(0xC6); // disable interrupts
(*self.registers).MU_BAUD.write(270); // 115200 baud self.MU_BAUD.write(270); // 115200 baud
// map UART1 to GPIO pins // map UART1 to GPIO pins
(*gpio::GPFSEL1).modify(|x| { (*gpio::GPFSEL1).modify(|x| {
@ -92,40 +102,38 @@ impl MiniUart {
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
} }
(*gpio::GPPUDCLK0).write(0); // flush GPIO setup (*gpio::GPPUDCLK0).write(0); // flush GPIO setup
(*self.registers).MU_CNTL.write(3); // enable Tx, Rx self.MU_CNTL.write(3); // enable Tx, Rx
} }
} }
/// Send a character /// Send a character
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
unsafe {
// wait until we can send // wait until we can send
loop { loop {
if ((*self.registers).MU_LSR.read() & 0x20) == 0x20 { if (self.MU_LSR.read() & 0x20) == 0x20 {
break; break;
} }
asm!("nop" :::: "volatile");
unsafe { asm!("nop" :::: "volatile") };
} }
// write the character to the buffer // write the character to the buffer
(*self.registers).MU_IO.write(c as u32); unsafe { self.MU_IO.write(c as u32) };
}
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> char { pub fn getc(&self) -> char {
unsafe {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if ((*self.registers).MU_LSR.read() & 0x01) == 0x01 { if (self.MU_LSR.read() & 0x01) == 0x01 {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
// read it and return // read it and return
let mut ret = unsafe { (*self.registers).MU_IO.read() as u8 as char }; let mut ret = self.MU_IO.read() as u8 as char;
// convert carrige return to newline // convert carrige return to newline
if ret == '\r' { if ret == '\r' {

Binary file not shown.

View File

@ -23,13 +23,14 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO}; use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
READ: RO<u32>, // 0x00 READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04 __reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10 POLL: RO<u32>, // 0x10
@ -82,49 +83,65 @@ pub struct Mbox {
// data structures in Rust is a bit of a hassle right now, we just // data structures in Rust is a bit of a hassle right now, we just
// close our eyes and roll with it. // close our eyes and roll with it.
pub buffer: [u32; 36], pub buffer: [u32; 36],
registers: *const Registers, }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.STATUS.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Mbox::ptr()).STATUS.read() }
/// ```
impl ops::Deref for Mbox {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Mbox { impl Mbox {
pub fn new() -> Mbox { pub fn new() -> Mbox {
Mbox { Mbox { buffer: [0; 36] }
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
VIDEOCORE_MBOX as *const _
} }
/// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success
pub fn call(&self, channel: u32) -> Result<()> { pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox // wait until we can write to the mailbox
loop { loop {
unsafe { if (self.STATUS.read() & FULL) != FULL {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
// write the address of our message to the mailbox with channel identifier // write the address of our message to the mailbox with channel identifier
unsafe { unsafe {
(*self.registers) self.WRITE
.WRITE .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); };
}
// now wait for the response // now wait for the response
loop { loop {
// is there a response? // is there a response?
loop { loop {
unsafe { if (self.STATUS.read() & EMPTY) != EMPTY {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
let resp: u32 = unsafe { (*self.registers).READ.read() }; let resp: u32 = self.READ.read();
// is it a response to our message? // is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use gpio; use gpio;
use mbox; use mbox;
@ -33,7 +34,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000;
// PL011 UART registers // PL011 UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
DR: RW<u32>, // 0x00 DR: RW<u32>, // 0x00
__reserved_0: [u32; 5], // 0x04 __reserved_0: [u32; 5], // 0x04
FR: RO<u32>, // 0x18 FR: RO<u32>, // 0x18
@ -51,21 +52,30 @@ pub enum UartError {
} }
pub type Result<T> = ::core::result::Result<T, UartError>; pub type Result<T> = ::core::result::Result<T, UartError>;
pub struct Uart { pub struct Uart;
registers: *const Registers,
impl ops::Deref for Uart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Uart { impl Uart {
pub fn new() -> Uart { pub fn new() -> Uart {
Uart { Uart
registers: UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> {
// turn off UART0 // turn off UART0
unsafe { (*self.registers).CR.write(0) }; unsafe { self.CR.write(0) };
// set up clock for consistent divisor values // set up clock for consistent divisor values
mbox.buffer[0] = 9 * 4; mbox.buffer[0] = 9 * 4;
@ -109,11 +119,11 @@ impl Uart {
} }
(*gpio::GPPUDCLK0).write(0); (*gpio::GPPUDCLK0).write(0);
(*self.registers).ICR.write(0x7FF); // clear interrupts self.ICR.write(0x7FF); // clear interrupts
(*self.registers).IBRD.write(2); // 115200 baud self.IBRD.write(2); // 115200 baud
(*self.registers).FBRD.write(0xB); self.FBRD.write(0xB);
(*self.registers).LCRH.write(0b11 << 5); // 8n1 self.LCRH.write(0b11 << 5); // 8n1
(*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO self.CR.write(0x301); // enable Tx, Rx, FIFO
} }
Ok(()) Ok(())
@ -121,34 +131,32 @@ impl Uart {
/// Send a character /// Send a character
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
unsafe {
// wait until we can send // wait until we can send
loop { loop {
if ((*self.registers).FR.read() & 0x20) != 0x20 { if (self.FR.read() & 0x20) != 0x20 {
break; break;
} }
asm!("nop" :::: "volatile");
unsafe { asm!("nop" :::: "volatile") };
} }
// write the character to the buffer // write the character to the buffer
(*self.registers).DR.write(c as u32); unsafe { self.DR.write(c as u32) };
}
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> char { pub fn getc(&self) -> char {
unsafe {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if ((*self.registers).FR.read() & 0x10) != 0x10 { if (self.FR.read() & 0x10) != 0x10 {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
// read it and return // read it and return
let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; let mut ret = self.DR.read() as u8 as char;
// convert carrige return to newline // convert carrige return to newline
if ret == '\r' { if ret == '\r' {

Binary file not shown.

View File

@ -23,13 +23,14 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO}; use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
READ: RO<u32>, // 0x00 READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04 __reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10 POLL: RO<u32>, // 0x10
@ -80,50 +81,66 @@ pub struct Mbox {
// to achieve that, but for now it just works. Since alignment of // to achieve that, but for now it just works. Since alignment of
// data structures in Rust is a bit of a hassle right now, we just // data structures in Rust is a bit of a hassle right now, we just
// close our eyes and roll with it. // close our eyes and roll with it.
pub buffer: [u32; 10], pub buffer: [u32; 36],
registers: *const Registers, }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.STATUS.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Mbox::ptr()).STATUS.read() }
/// ```
impl ops::Deref for Mbox {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Mbox { impl Mbox {
pub fn new() -> Mbox { pub fn new() -> Mbox {
Mbox { Mbox { buffer: [0; 36] }
buffer: [0; 10],
registers: VIDEOCORE_MBOX as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
VIDEOCORE_MBOX as *const _
} }
/// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success
pub fn call(&self, channel: u32) -> Result<()> { pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox // wait until we can write to the mailbox
loop { loop {
unsafe { if (self.STATUS.read() & FULL) != FULL {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
// write the address of our message to the mailbox with channel identifier // write the address of our message to the mailbox with channel identifier
unsafe { unsafe {
(*self.registers) self.WRITE
.WRITE .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); };
}
// now wait for the response // now wait for the response
loop { loop {
// is there a response? // is there a response?
loop { loop {
unsafe { if (self.STATUS.read() & EMPTY) != EMPTY {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break; break;
} }
asm!("nop" :::: "volatile");
} unsafe { asm!("nop" :::: "volatile") };
} }
let resp: u32 = unsafe { (*self.registers).READ.read() }; let resp: u32 = self.READ.read();
// is it a response to our message? // is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use gpio; use gpio;
use mbox; use mbox;
@ -33,7 +34,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000;
// PL011 UART registers // PL011 UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
DR: RW<u32>, // 0x00 DR: RW<u32>, // 0x00
__reserved_0: [u32; 5], // 0x04 __reserved_0: [u32; 5], // 0x04
FR: RO<u32>, // 0x18 FR: RO<u32>, // 0x18
@ -51,21 +52,30 @@ pub enum UartError {
} }
pub type Result<T> = ::core::result::Result<T, UartError>; pub type Result<T> = ::core::result::Result<T, UartError>;
pub struct Uart { pub struct Uart;
registers: *const Registers,
impl ops::Deref for Uart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Uart { impl Uart {
pub fn new() -> Uart { pub fn new() -> Uart {
Uart { Uart
registers: UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> {
// turn off UART0 // turn off UART0
unsafe { (*self.registers).CR.write(0) }; unsafe { self.CR.write(0) };
// set up clock for consistent divisor values // set up clock for consistent divisor values
mbox.buffer[0] = 9 * 4; mbox.buffer[0] = 9 * 4;
@ -109,11 +119,11 @@ impl Uart {
} }
(*gpio::GPPUDCLK0).write(0); (*gpio::GPPUDCLK0).write(0);
(*self.registers).ICR.write(0x7FF); // clear interrupts self.ICR.write(0x7FF); // clear interrupts
(*self.registers).IBRD.write(2); // 115200 baud self.IBRD.write(2); // 115200 baud
(*self.registers).FBRD.write(0xB); self.FBRD.write(0xB);
(*self.registers).LCRH.write(0b11 << 5); // 8n1 self.LCRH.write(0b11 << 5); // 8n1
(*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO self.CR.write(0x301); // enable Tx, Rx, FIFO
} }
Ok(()) Ok(())
@ -121,33 +131,31 @@ impl Uart {
/// Send a character /// Send a character
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
unsafe {
// wait until we can send // wait until we can send
loop { loop {
if ((*self.registers).FR.read() & 0x20) != 0x20 { if (self.FR.read() & 0x20) != 0x20 {
break; break;
} }
asm!("nop" :::: "volatile");
unsafe { asm!("nop" :::: "volatile") };
} }
// write the character to the buffer // write the character to the buffer
(*self.registers).DR.write(c as u32); unsafe { self.DR.write(c as u32) };
}
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> u8 { pub fn getc(&self) -> u8 {
unsafe {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if ((*self.registers).FR.read() & 0x10) != 0x10 { if (self.FR.read() & 0x10) != 0x10 {
break; break;
} }
asm!("nop" :::: "volatile");
unsafe { asm!("nop" :::: "volatile") };
} }
// read it and return // read it and return
(*self.registers).DR.read() as u8 self.DR.read() as u8
}
} }
} }

Binary file not shown.

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use cortex_a::asm; use cortex_a::asm;
use volatile_register::{RO, WO}; use volatile_register::{RO, WO};
@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
READ: RO<u32>, // 0x00 READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04 __reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10 POLL: RO<u32>, // 0x10
@ -83,22 +84,41 @@ pub struct Mbox {
// data structures in Rust is a bit of a hassle right now, we just // data structures in Rust is a bit of a hassle right now, we just
// close our eyes and roll with it. // close our eyes and roll with it.
pub buffer: [u32; 36], pub buffer: [u32; 36],
registers: *const Registers, }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.STATUS.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Mbox::ptr()).STATUS.read() }
/// ```
impl ops::Deref for Mbox {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Mbox { impl Mbox {
pub fn new() -> Mbox { pub fn new() -> Mbox {
Mbox { Mbox { buffer: [0; 36] }
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
VIDEOCORE_MBOX as *const _
} }
/// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success
pub fn call(&self, channel: u32) -> Result<()> { pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox // wait until we can write to the mailbox
loop { loop {
if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL { if (self.STATUS.read() & FULL) != FULL {
break; break;
} }
@ -107,23 +127,22 @@ impl Mbox {
// write the address of our message to the mailbox with channel identifier // write the address of our message to the mailbox with channel identifier
unsafe { unsafe {
(*self.registers) self.WRITE
.WRITE .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); };
}
// now wait for the response // now wait for the response
loop { loop {
// is there a response? // is there a response?
loop { loop {
if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY { if (self.STATUS.read() & EMPTY) != EMPTY {
break; break;
} }
asm::nop(); asm::nop();
} }
let resp: u32 = unsafe { (*self.registers).READ.read() }; let resp: u32 = self.READ.read();
// is it a response to our message? // is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use cortex_a::asm; use cortex_a::asm;
use gpio; use gpio;
@ -34,7 +35,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000;
// PL011 UART registers // PL011 UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
DR: RW<u32>, // 0x00 DR: RW<u32>, // 0x00
__reserved_0: [u32; 5], // 0x04 __reserved_0: [u32; 5], // 0x04
FR: RO<u32>, // 0x18 FR: RO<u32>, // 0x18
@ -52,21 +53,30 @@ pub enum UartError {
} }
pub type Result<T> = ::core::result::Result<T, UartError>; pub type Result<T> = ::core::result::Result<T, UartError>;
pub struct Uart { pub struct Uart;
registers: *const Registers,
impl ops::Deref for Uart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Uart { impl Uart {
pub fn new() -> Uart { pub fn new() -> Uart {
Uart { Uart
registers: UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> {
// turn off UART0 // turn off UART0
unsafe { (*self.registers).CR.write(0) }; unsafe { self.CR.write(0) };
// set up clock for consistent divisor values // set up clock for consistent divisor values
mbox.buffer[0] = 9 * 4; mbox.buffer[0] = 9 * 4;
@ -110,11 +120,11 @@ impl Uart {
} }
(*gpio::GPPUDCLK0).write(0); (*gpio::GPPUDCLK0).write(0);
(*self.registers).ICR.write(0x7FF); // clear interrupts self.ICR.write(0x7FF); // clear interrupts
(*self.registers).IBRD.write(2); // 115200 baud self.IBRD.write(2); // 115200 baud
(*self.registers).FBRD.write(0xB); self.FBRD.write(0xB);
(*self.registers).LCRH.write(0b11 << 5); // 8n1 self.LCRH.write(0b11 << 5); // 8n1
(*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO self.CR.write(0x301); // enable Tx, Rx, FIFO
} }
Ok(()) Ok(())
@ -124,7 +134,7 @@ impl Uart {
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
// wait until we can send // wait until we can send
loop { loop {
if (unsafe { (*self.registers).FR.read() } & 0x20) != 0x20 { if (self.FR.read() & 0x20) != 0x20 {
break; break;
} }
@ -132,14 +142,14 @@ impl Uart {
} }
// write the character to the buffer // write the character to the buffer
unsafe { (*self.registers).DR.write(c as u32) }; unsafe { self.DR.write(c as u32) };
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> char { pub fn getc(&self) -> char {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if (unsafe { (*self.registers).FR.read() } & 0x10) != 0x10 { if (self.FR.read() & 0x10) != 0x10 {
break; break;
} }
@ -147,7 +157,7 @@ impl Uart {
} }
// read it and return // read it and return
let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; let mut ret = self.DR.read() as u8 as char;
// convert carrige return to newline // convert carrige return to newline
if ret == '\r' { if ret == '\r' {

Binary file not shown.

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use cortex_a::asm; use cortex_a::asm;
use volatile_register::{RO, WO}; use volatile_register::{RO, WO};
@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
READ: RO<u32>, // 0x00 READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04 __reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10 POLL: RO<u32>, // 0x10
@ -82,22 +83,41 @@ pub struct Mbox {
// data structures in Rust is a bit of a hassle right now, we just // data structures in Rust is a bit of a hassle right now, we just
// close our eyes and roll with it. // close our eyes and roll with it.
pub buffer: [u32; 36], pub buffer: [u32; 36],
registers: *const Registers, }
/// Deref to RegisterBlock
///
/// Allows writing
/// ```
/// self.STATUS.read()
/// ```
/// instead of something along the lines of
/// ```
/// unsafe { (*Mbox::ptr()).STATUS.read() }
/// ```
impl ops::Deref for Mbox {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Mbox { impl Mbox {
pub fn new() -> Mbox { pub fn new() -> Mbox {
Mbox { Mbox { buffer: [0; 36] }
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
VIDEOCORE_MBOX as *const _
} }
/// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success
pub fn call(&self, channel: u32) -> Result<()> { pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox // wait until we can write to the mailbox
loop { loop {
if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL { if (self.STATUS.read() & FULL) != FULL {
break; break;
} }
@ -106,23 +126,22 @@ impl Mbox {
// write the address of our message to the mailbox with channel identifier // write the address of our message to the mailbox with channel identifier
unsafe { unsafe {
(*self.registers) self.WRITE
.WRITE .write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF)); };
}
// now wait for the response // now wait for the response
loop { loop {
// is there a response? // is there a response?
loop { loop {
if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY { if (self.STATUS.read() & EMPTY) != EMPTY {
break; break;
} }
asm::nop(); asm::nop();
} }
let resp: u32 = unsafe { (*self.registers).READ.read() }; let resp: u32 = self.READ.read();
// is it a response to our message? // is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) { if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use cortex_a::asm; use cortex_a::asm;
use volatile_register::*; use volatile_register::*;
@ -30,7 +31,7 @@ const RNG_BASE: u32 = MMIO_BASE + 0x104_000;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
CTRL: RW<u32>, // 0x00 CTRL: RW<u32>, // 0x00
STATUS: RW<u32>, // 0x04 STATUS: RW<u32>, // 0x04
DATA: RO<u32>, // 0x08 DATA: RO<u32>, // 0x08
@ -39,42 +40,51 @@ struct Registers {
} }
/// Public interface to the RNG /// Public interface to the RNG
pub struct Rng { pub struct Rng;
registers: *const Registers,
impl ops::Deref for Rng {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Rng { impl Rng {
pub fn new() -> Rng { pub fn new() -> Rng {
Rng { Rng
registers: RNG_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
RNG_BASE as *const _
} }
/// Initialize the RNG /// Initialize the RNG
pub fn init(&self) { pub fn init(&self) {
unsafe { unsafe {
(*self.registers).STATUS.write(0x40_000); self.STATUS.write(0x40_000);
// mask interrupt // mask interrupt
(*self.registers).INT_MASK.modify(|x| x | 1); self.INT_MASK.modify(|x| x | 1);
// enable // enable
(*self.registers).CTRL.modify(|x| x | 1); self.CTRL.modify(|x| x | 1);
}
// wait for gaining some entropy // wait for gaining some entropy
loop { loop {
if ((*self.registers).STATUS.read() >> 24) != 0 { if (self.STATUS.read() >> 24) != 0 {
break; break;
} }
asm::nop(); asm::nop();
} }
} }
}
/// Return a random number between [min..max] /// Return a random number between [min..max]
pub fn rand(&self, min: u32, max: u32) -> u32 { pub fn rand(&self, min: u32, max: u32) -> u32 {
let r = unsafe { (*self.registers).DATA.read() }; let r = self.DATA.read();
r % (max - min) + min r % (max - min) + min
} }

View File

@ -23,6 +23,7 @@
*/ */
use super::MMIO_BASE; use super::MMIO_BASE;
use core::ops;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use cortex_a::asm; use cortex_a::asm;
use gpio; use gpio;
@ -34,7 +35,7 @@ const UART_BASE: u32 = MMIO_BASE + 0x20_1000;
// PL011 UART registers // PL011 UART registers
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[repr(C)] #[repr(C)]
struct Registers { pub struct RegisterBlock {
DR: RW<u32>, // 0x00 DR: RW<u32>, // 0x00
__reserved_0: [u32; 5], // 0x04 __reserved_0: [u32; 5], // 0x04
FR: RO<u32>, // 0x18 FR: RO<u32>, // 0x18
@ -52,21 +53,30 @@ pub enum UartError {
} }
pub type Result<T> = ::core::result::Result<T, UartError>; pub type Result<T> = ::core::result::Result<T, UartError>;
pub struct Uart { pub struct Uart;
registers: *const Registers,
impl ops::Deref for Uart {
type Target = RegisterBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*Self::ptr() }
}
} }
impl Uart { impl Uart {
pub fn new() -> Uart { pub fn new() -> Uart {
Uart { Uart
registers: UART_BASE as *const Registers,
} }
/// Returns a pointer to the register block
fn ptr() -> *const RegisterBlock {
UART_BASE as *const _
} }
///Set baud rate and characteristics (115200 8N1) and map to GPIO ///Set baud rate and characteristics (115200 8N1) and map to GPIO
pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> {
// turn off UART0 // turn off UART0
unsafe { (*self.registers).CR.write(0) }; unsafe { self.CR.write(0) };
// set up clock for consistent divisor values // set up clock for consistent divisor values
mbox.buffer[0] = 9 * 4; mbox.buffer[0] = 9 * 4;
@ -110,11 +120,11 @@ impl Uart {
} }
(*gpio::GPPUDCLK0).write(0); (*gpio::GPPUDCLK0).write(0);
(*self.registers).ICR.write(0x7FF); // clear interrupts self.ICR.write(0x7FF); // clear interrupts
(*self.registers).IBRD.write(2); // 115200 baud self.IBRD.write(2); // 115200 baud
(*self.registers).FBRD.write(0xB); self.FBRD.write(0xB);
(*self.registers).LCRH.write(0b11 << 5); // 8n1 self.LCRH.write(0b11 << 5); // 8n1
(*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO self.CR.write(0x301); // enable Tx, Rx, FIFO
} }
Ok(()) Ok(())
@ -124,7 +134,7 @@ impl Uart {
pub fn send(&self, c: char) { pub fn send(&self, c: char) {
// wait until we can send // wait until we can send
loop { loop {
if (unsafe { (*self.registers).FR.read() } & 0x20) != 0x20 { if (self.FR.read() & 0x20) != 0x20 {
break; break;
} }
@ -132,14 +142,14 @@ impl Uart {
} }
// write the character to the buffer // write the character to the buffer
unsafe { (*self.registers).DR.write(c as u32) }; unsafe { self.DR.write(c as u32) };
} }
/// Receive a character /// Receive a character
pub fn getc(&self) -> char { pub fn getc(&self) -> char {
// wait until something is in the buffer // wait until something is in the buffer
loop { loop {
if (unsafe { (*self.registers).FR.read() } & 0x10) != 0x10 { if (self.FR.read() & 0x10) != 0x10 {
break; break;
} }
@ -147,7 +157,7 @@ impl Uart {
} }
// read it and return // read it and return
let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; let mut ret = self.DR.read() as u8 as char;
// convert carrige return to newline // convert carrige return to newline
if ret == '\r' { if ret == '\r' {