mirror of
https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials.git
synced 2024-11-11 07:10:59 +00:00
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:
parent
a584fa4dfa
commit
0ce1cde72c
Binary file not shown.
@ -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.
@ -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)) {
|
||||||
|
@ -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.
@ -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)) {
|
||||||
|
@ -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.
@ -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)) {
|
||||||
|
@ -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.
@ -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)) {
|
||||||
|
@ -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.
@ -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)) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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' {
|
||||||
|
Loading…
Reference in New Issue
Block a user