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
pull/4/head
Andre Richter 6 years ago
parent a584fa4dfa
commit 0ce1cde72c

Binary file not shown.

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

Binary file not shown.

@ -23,13 +23,14 @@
*/
use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
pub struct RegisterBlock {
READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04
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
// close our eyes and roll with it.
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 {
pub fn new() -> Mbox {
Mbox {
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
}
Mbox { buffer: [0; 36] }
}
/// 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
pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox
loop {
if (self.STATUS.read() & FULL) != FULL {
break;
}
unsafe {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break;
}
asm!("nop" :::: "volatile");
}
}
// write the address of our message to the mailbox with channel identifier
unsafe {
(*self.registers)
.WRITE
self.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
}
@ -110,15 +130,16 @@ impl Mbox {
loop {
// is there a response?
loop {
if (self.STATUS.read() & EMPTY) != EMPTY {
break;
}
unsafe {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break;
}
asm!("nop" :::: "volatile");
}
}
let resp: u32 = unsafe { (*self.registers).READ.read() };
let resp: u32 = self.READ.read();
// is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

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

Binary file not shown.

@ -23,13 +23,14 @@
*/
use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
pub struct RegisterBlock {
READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04
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
// close our eyes and roll with it.
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 {
pub fn new() -> Mbox {
Mbox {
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
}
Mbox { buffer: [0; 36] }
}
/// 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
pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox
loop {
unsafe {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break;
}
asm!("nop" :::: "volatile");
if (self.STATUS.read() & FULL) != FULL {
break;
}
unsafe { asm!("nop" :::: "volatile") };
}
// write the address of our message to the mailbox with channel identifier
unsafe {
(*self.registers)
.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
}
self.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
};
// now wait for the response
loop {
// is there a response?
loop {
unsafe {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break;
}
asm!("nop" :::: "volatile");
if (self.STATUS.read() & EMPTY) != EMPTY {
break;
}
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?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

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

Binary file not shown.

@ -23,13 +23,14 @@
*/
use super::MMIO_BASE;
use core::ops;
use volatile_register::{RO, WO};
const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
pub struct RegisterBlock {
READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04
POLL: RO<u32>, // 0x10
@ -80,50 +81,66 @@ pub struct Mbox {
// 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
// close our eyes and roll with it.
pub buffer: [u32; 10],
registers: *const Registers,
pub buffer: [u32; 36],
}
/// 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 {
pub fn new() -> Mbox {
Mbox {
buffer: [0; 10],
registers: VIDEOCORE_MBOX as *const Registers,
}
Mbox { buffer: [0; 36] }
}
/// 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
pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox
loop {
unsafe {
if ((*self.registers).STATUS.read() & FULL) != FULL {
break;
}
asm!("nop" :::: "volatile");
if (self.STATUS.read() & FULL) != FULL {
break;
}
unsafe { asm!("nop" :::: "volatile") };
}
// write the address of our message to the mailbox with channel identifier
unsafe {
(*self.registers)
.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
}
self.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
};
// now wait for the response
loop {
// is there a response?
loop {
unsafe {
if ((*self.registers).STATUS.read() & EMPTY) != EMPTY {
break;
}
asm!("nop" :::: "volatile");
if (self.STATUS.read() & EMPTY) != EMPTY {
break;
}
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?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

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

Binary file not shown.

@ -23,6 +23,7 @@
*/
use super::MMIO_BASE;
use core::ops;
use cortex_a::asm;
use volatile_register::{RO, WO};
@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
pub struct RegisterBlock {
READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04
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
// close our eyes and roll with it.
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 {
pub fn new() -> Mbox {
Mbox {
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
}
Mbox { buffer: [0; 36] }
}
/// 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
pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox
loop {
if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL {
if (self.STATUS.read() & FULL) != FULL {
break;
}
@ -107,23 +127,22 @@ impl Mbox {
// write the address of our message to the mailbox with channel identifier
unsafe {
(*self.registers)
.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
}
self.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
};
// now wait for the response
loop {
// is there a response?
loop {
if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY {
if (self.STATUS.read() & EMPTY) != EMPTY {
break;
}
asm::nop();
}
let resp: u32 = unsafe { (*self.registers).READ.read() };
let resp: u32 = self.READ.read();
// is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

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

Binary file not shown.

@ -23,6 +23,7 @@
*/
use super::MMIO_BASE;
use core::ops;
use cortex_a::asm;
use volatile_register::{RO, WO};
@ -30,7 +31,7 @@ const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880;
#[allow(non_snake_case)]
#[repr(C)]
struct Registers {
pub struct RegisterBlock {
READ: RO<u32>, // 0x00
__reserved_0: [u32; 3], // 0x04
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
// close our eyes and roll with it.
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 {
pub fn new() -> Mbox {
Mbox {
buffer: [0; 36],
registers: VIDEOCORE_MBOX as *const Registers,
}
Mbox { buffer: [0; 36] }
}
/// 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
pub fn call(&self, channel: u32) -> Result<()> {
// wait until we can write to the mailbox
loop {
if (unsafe { (*self.registers).STATUS.read() } & FULL) != FULL {
if (self.STATUS.read() & FULL) != FULL {
break;
}
@ -106,23 +126,22 @@ impl Mbox {
// write the address of our message to the mailbox with channel identifier
unsafe {
(*self.registers)
.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF));
}
self.WRITE
.write(((self.buffer.as_ptr() as u32) & !0xF) | (channel & 0xF))
};
// now wait for the response
loop {
// is there a response?
loop {
if (unsafe { (*self.registers).STATUS.read() } & EMPTY) != EMPTY {
if (self.STATUS.read() & EMPTY) != EMPTY {
break;
}
asm::nop();
}
let resp: u32 = unsafe { (*self.registers).READ.read() };
let resp: u32 = self.READ.read();
// is it a response to our message?
if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_ptr() as u32)) {

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

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

Loading…
Cancel
Save