Skip to content

Commit 99ad3f0

Browse files
committed
Expose some structs for the IO ports
1 parent 0619bb1 commit 99ad3f0

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed

src/io/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod port;
2+
3+
pub const PORT_B: port::Port<port::B> = port::Port::new();
4+
pub const PORT_C: port::Port<port::C> = port::Port::new();
5+
pub const PORT_D: port::Port<port::D> = port::Port::new();

src/io/port.rs

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
use core::prelude::v1::*;
2+
use core::ptr::{read_volatile, write_volatile};
3+
use core::marker::PhantomData;
4+
5+
use Bit;
6+
7+
pub trait Information {
8+
const DDR: *mut u8;
9+
const IO: *mut u8;
10+
const PIN: *mut u8;
11+
}
12+
13+
#[derive(Copy, Clone)]
14+
pub struct B;
15+
16+
impl Information for B {
17+
const DDR: *mut u8 = ::DDRB;
18+
const IO: *mut u8 = ::PORTB;
19+
const PIN: *mut u8 = ::PINB;
20+
}
21+
22+
#[derive(Copy, Clone)]
23+
pub struct C;
24+
25+
impl Information for C {
26+
const DDR: *mut u8 = ::DDRC;
27+
const IO: *mut u8 = ::PORTC;
28+
const PIN: *mut u8 = ::PINC;
29+
}
30+
31+
#[derive(Copy, Clone)]
32+
pub struct D;
33+
34+
impl Information for D {
35+
const DDR: *mut u8 = ::DDRD;
36+
const IO: *mut u8 = ::PORTD;
37+
const PIN: *mut u8 = ::PIND;
38+
}
39+
40+
#[derive(Copy, Clone)]
41+
enum Direction {
42+
Output,
43+
Input,
44+
}
45+
46+
const BITS_IN_BYTE: usize = 8;
47+
48+
pub struct Configuration<P: Information> {
49+
_port: PhantomData<P>,
50+
direction: [Option<Direction>; BITS_IN_BYTE],
51+
pullup: [Option<bool>; BITS_IN_BYTE],
52+
}
53+
54+
impl<P> Configuration<P>
55+
where
56+
P: Information
57+
{
58+
#[inline]
59+
pub fn new() -> Configuration<P> {
60+
Configuration {
61+
_port: PhantomData,
62+
direction: Default::default(),
63+
pullup: Default::default(),
64+
}
65+
}
66+
67+
#[inline]
68+
pub fn set_all_as_output(&mut self) -> &mut Self {
69+
self.direction = [Some(Direction::Output); 8];
70+
self
71+
}
72+
73+
#[inline]
74+
pub fn set_all_as_input(&mut self) -> &mut Self {
75+
self.direction = [Some(Direction::Input); 8];
76+
self
77+
}
78+
79+
#[inline]
80+
pub fn set_as_output(&mut self, bit: Bit) -> &mut Self {
81+
self.direction[bit as usize] = Some(Direction::Output);
82+
self
83+
}
84+
85+
#[inline]
86+
pub fn set_as_input(&mut self, bit: Bit) -> &mut Self {
87+
self.direction[bit as usize] = Some(Direction::Input);
88+
self
89+
}
90+
91+
#[inline]
92+
pub fn enable_pullup(&mut self, bit: Bit) -> &mut Self {
93+
self.pullup[bit as usize] = Some(true);
94+
self
95+
}
96+
97+
#[inline]
98+
pub fn disable_pullup(&mut self, bit: Bit) -> &mut Self {
99+
self.pullup[bit as usize] = Some(false);
100+
self
101+
}
102+
103+
#[inline]
104+
pub fn configure(&self) {
105+
// FIXME: Both of these loops are wasteful if we are
106+
// setting all 8 bits, when we could set the entire IO
107+
// register at once. Is there a way we can track that?
108+
109+
// We use `zip` instead of `enumerate` to guarantee it's a constant
110+
111+
for (&p, i) in self.direction.iter().zip(0..BITS_IN_BYTE) {
112+
if let Some(enabled) = p {
113+
if let Direction::Output = enabled {
114+
unsafe { asm!("sbi $0 $1" : : "n"(P::DDR), "n"(i)) }
115+
} else {
116+
unsafe { asm!("cbi $0 $1; A" : : "n"(P::DDR), "n"(i)) }
117+
}
118+
}
119+
}
120+
121+
for (&p, i) in self.pullup.iter().zip(0..BITS_IN_BYTE) {
122+
if let Some(enabled) = p {
123+
if enabled {
124+
unsafe { asm!("sbi $0 $1" : : "n"(P::IO), "n"(i)) }
125+
} else {
126+
unsafe { asm!("cbi $0 $1; B" : : "n"(P::IO), "n"(i)) }
127+
}
128+
}
129+
}
130+
}
131+
}
132+
133+
#[derive(Copy, Clone)]
134+
pub struct Data<P: Information> {
135+
_port: PhantomData<P>,
136+
}
137+
138+
impl<P> Data<P>
139+
where
140+
P: Information
141+
{
142+
#[inline]
143+
pub fn new() -> Data<P> { Data { _port: PhantomData } }
144+
145+
#[inline]
146+
pub fn get(&self) -> u8 {
147+
unsafe { read_volatile(P::PIN) }
148+
}
149+
150+
#[inline]
151+
pub fn set(&self, value: u8) {
152+
unsafe { write_volatile(P::IO, value) };
153+
}
154+
155+
#[inline]
156+
pub fn bit_is_set(&self, bit: Bit) -> bool {
157+
bit.is_set(self.get())
158+
}
159+
160+
#[inline]
161+
pub fn set_bit(&self, bit: Bit) {
162+
unsafe { asm!("sbi $0 $1" : : "n"(P::IO), "n"(bit as u8)) }
163+
}
164+
165+
#[inline]
166+
pub fn clear_bit(&self, bit: Bit) {
167+
unsafe { asm!("cbi $0 $1; C" : : "n"(P::IO), "n"(bit as u8)) }
168+
}
169+
170+
#[inline]
171+
pub fn toggle_bit(&self, bit: Bit) {
172+
unsafe { asm!("sbi $0 $1" : : "n"(P::PIN), "n"(bit as u8)) }
173+
}
174+
}
175+
176+
#[derive(Copy, Clone)]
177+
pub struct Port<P>(PhantomData<P>);
178+
179+
impl<P: Information> Port<P> {
180+
pub(crate) const fn new() -> Port<P> { Port(PhantomData) }
181+
pub fn configuration(&self) -> Configuration<P> { Configuration::new() }
182+
pub fn data(&self) -> Data<P> { Data::new() }
183+
}

src/lib.rs

+36
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,50 @@
22
33
#![feature(asm)]
44
#![feature(no_core)]
5+
#![feature(const_fn)]
6+
#![feature(associated_consts)]
7+
58
#![no_core]
69

710
extern crate core;
811

12+
// Look like we have a standard library
13+
#[allow(unused_imports)]
14+
use core::{option, iter, fmt, ops, clone, marker};
15+
916
pub mod prelude;
1017
pub mod timer0;
1118
pub mod timer1;
1219
pub mod serial;
20+
pub mod io;
21+
22+
#[derive(Copy, Clone)]
23+
pub enum Bit {
24+
Bit0 = 0,
25+
Bit1 = 1,
26+
Bit2 = 2,
27+
Bit3 = 3,
28+
Bit4 = 4,
29+
Bit5 = 5,
30+
Bit6 = 6,
31+
Bit7 = 7,
32+
}
33+
34+
impl Bit {
35+
fn as_mask(&self) -> u8 { 1 << *self as u8 }
36+
37+
pub fn is_set(&self, value: u8) -> bool {
38+
(value & self.as_mask()) != 0
39+
}
40+
41+
pub fn set(&self, value: u8) -> u8 {
42+
value | self.as_mask()
43+
}
44+
45+
pub fn unset(&self, value: u8) -> u8 {
46+
value & !self.as_mask()
47+
}
48+
}
1349

1450
macro_rules! bit {
1551
(-, $pos:expr) => {};

src/prelude.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use core::prelude::v1::*;
22
use core::marker::PhantomData;
33

4+
pub use io::{PORT_B, PORT_C, PORT_D};
5+
46
pub struct DisableInterrupts(PhantomData<()>);
57

68
impl DisableInterrupts {

0 commit comments

Comments
 (0)