Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds SPI support. #39

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion accel-mma84/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl<'a> Accelerometer<'a> {
}

try!(self.set_scale_range(ScaleRange::Scale2G));
try!(self.set_sample_rate(SampleRate::Rate100));
try!(self.set_sample_rate(SampleRate::Rate6_25));

Ok(())
}
Expand Down
171 changes: 134 additions & 37 deletions tessel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ extern crate unix_socket;
extern crate bit_set;

pub mod protocol;
pub mod pin_select;

pub use pin_select::PinSelect;
use atomic_option::AtomicOption;
use protocol::{Command, reply, PortSocket};
use std::fs::File;
Expand Down Expand Up @@ -107,6 +109,17 @@ impl Port {
}
(I2cPort::new(self.socket.clone()), Gpio::new(self.socket.clone(), available))
}

pub fn spi<'b>(self) -> (SpiPort<'b>, Gpio<'b>) {
let mut available = BitSet::new();
for i in 0..2 {
available.insert(i);
}
for i in 5..8 {
available.insert(i);
}
(SpiPort::new(self.socket.clone()), Gpio::new(self.socket.clone(), available))
}
}

/// Gpio is a selection of pins.
Expand Down Expand Up @@ -135,43 +148,6 @@ impl<'a> Gpio<'a> {
}
}

/// Pin tuple conversion for gpio:pins(..)
pub trait PinSelect<'a> {
type Output;
fn validate(&self, &BitSet<usize>) -> bool;
fn select(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output;
}

impl<'a> PinSelect<'a> for usize {
type Output = Pin<'a>;
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(*self)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
Pin::new(*self, socket)
}
}

impl<'a> PinSelect<'a> for (usize, usize) {
type Output = (Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0) || set.contains(self.1)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()), Pin::new(self.1, socket))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0) || set.contains(self.1) || set.contains(self.2)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()), Pin::new(self.1, socket.clone()), Pin::new(self.2, socket))
}
}

/// A GPIO pin usable as an input or output.
pub struct Pin<'a> {
index: usize,
Expand Down Expand Up @@ -311,6 +287,127 @@ impl<'p> I2cPort<'p> {
}
}


/// A SPI Port.
pub struct SpiPort<'a> {
socket: Arc<Mutex<PortSocket>>,
_phantom: PhantomData<&'a Port>,
}

impl<'p> SpiPort<'p> {
// TODO: make frequency optional
fn new<'a>(socket: Arc<Mutex<PortSocket>>) -> SpiPort<'a> {
let mut spi = SpiPort {
socket: socket,
_phantom: PhantomData,
};

// Use 1Mhz as default frequency.
let (reg, div) = SpiPort::compute_baud(1_000_000);
spi.enable(0, reg, div);

spi
}

/// Computes the baudrate as used on the Atmel SAMD21 SPI register
/// to set the frequency of the SPI Clock. Returns (register, divisor)
fn compute_baud(frequency: u32) -> (u8, u8) {
// spi baud rate is set by the following equation:
// f_baud = f_ref/(2*(baud_reg+1))

// Max baud rate is 24MHz for the SAMD21, min baud rate is 93750 without a clock divisor.
// With a max clock divisor of 255, slowest clock is 368Hz.
// (If we switch from 48MHz xtal to 32KHz xtal, this assumption changes.)
if frequency < 368 || frequency > 24_000_000 {
panic!("SPI clock must be between 368Hz and 24MHz");
}

let reg: u32 = (48_000_000 / (2 * frequency)) - 1;

// if speed is slower than 93750 then we need a clock divisor.
// Find the smallest clock divider such that reg is <= 255.
if reg > 255 {
// find the clock divider, make sure its at least 1
let mut div = 48_000_000 / (frequency * (2 * 255 + 2));
if div == 0 {
div = 1;
}

// if the speed is still too low, set the clock divider to max and set baud accordingly
if div > 255 {
let mut reg = frequency / 255;
if reg == 0 {
reg = 1;
}
(reg as u8, 255)
} else {
// if we can set a clock divider < 255, max out register.
(reg as u8, div as u8)
}
} else {
// divider == 1
(reg as u8, 1)
}
}

fn enable(&mut self, mode: u8, reg: u8, div: u8) {
let mut sock = self.socket.lock().unwrap();
sock.write_command(Command::EnableSpi {
mode: mode,
freq: reg,
div: div,
}).unwrap();
}

fn tx(sock: &mut MutexGuard<PortSocket>, write_buf: &[u8]) {
// Write the command and data
sock.write_command(Command::Tx(write_buf)).unwrap();
}

fn rx(sock: &mut MutexGuard<PortSocket>, read_buf: &mut [u8]) {
// Write the command and transfer length
sock.write_command(Command::Rx(read_buf.len() as u8)).unwrap();
}

pub fn set_frequency(&mut self, frequency: u32) {
// Use 1Mhz as default frequency.
let (reg, div) = SpiPort::compute_baud(frequency);
self.enable(0, reg, div);
}

pub fn send(&mut self, write_buf: &[u8]) {
let mut sock = self.socket.lock().unwrap();
SpiPort::tx(&mut sock, write_buf);
}

pub fn read(&mut self, read_buf: &mut [u8]) -> io::Result<()> {
let mut sock = self.socket.lock().unwrap();
SpiPort::rx(&mut sock, read_buf);

// TODO: this is not how async reads should be handled.
// Read in first byte.
let mut read_byte = [0];
try!(sock.read_exact(&mut read_byte));
assert_eq!(read_byte[0], reply::DATA.0);
// Read in data from the socket
return sock.read_exact(read_buf);
}

pub fn transfer(&mut self, write_buf: &[u8], read_buf: &mut [u8]) -> io::Result<()> {
let mut sock = self.socket.lock().unwrap();
SpiPort::tx(&mut sock, write_buf);
SpiPort::rx(&mut sock, read_buf);

// TODO: this is not how async reads should be handled.
// Read in first byte.
let mut read_byte = [0];
try!(sock.read_exact(&mut read_byte));
assert_eq!(read_byte[0], reply::DATA.0);
// Read in data from the socket
return sock.read_exact(read_buf);
}
}

// TODO: Figure out how to override the path secretly so the example
// can actually be run.
/// A LED models an LED on the Tessel board.
Expand Down
154 changes: 154 additions & 0 deletions tessel/src/pin_select.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//! TODO: make this a macro
//! TODO: we make two expensive runtime checks, which is ensuring that the
//! possible set of pins is valid (this can be eliminated) and ensuring that the
//! tuple contains only non-duplicate values (which can't be eliminated). We
//! can probably get this down to a single SSE instruction, if we wanted...

use bit_set::BitSet;
use std::sync::{Arc, Mutex};
use Pin;
use protocol::PortSocket;

/// Pin tuple conversion for gpio:pins(..)
pub trait PinSelect<'a> {
type Output;
fn validate(&self, &BitSet<usize>) -> bool;
fn select(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output;
}

impl<'a> PinSelect<'a> for usize {
type Output = Pin<'a>;
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(*self)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
Pin::new(*self, socket)
}
}

impl<'a> PinSelect<'a> for (usize, usize) {
type Output = (Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
|| set.contains(self.3)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()),
Pin::new(self.3, socket.clone()))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
|| set.contains(self.3)
|| set.contains(self.4)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()),
Pin::new(self.3, socket.clone()),
Pin::new(self.4, socket.clone()))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize, usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
|| set.contains(self.3)
|| set.contains(self.4)
|| set.contains(self.5)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()),
Pin::new(self.3, socket.clone()),
Pin::new(self.4, socket.clone()),
Pin::new(self.5, socket.clone()))
}
}

impl<'a> PinSelect<'a> for (usize, usize, usize, usize, usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
|| set.contains(self.3)
|| set.contains(self.4)
|| set.contains(self.5)
|| set.contains(self.6)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()),
Pin::new(self.3, socket.clone()),
Pin::new(self.4, socket.clone()),
Pin::new(self.5, socket.clone()),
Pin::new(self.6, socket.clone()))
}
}


impl<'a> PinSelect<'a> for (usize, usize, usize, usize, usize, usize, usize, usize) {
type Output = (Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>, Pin<'a>);
fn validate(&self, set: &BitSet<usize>) -> bool {
set.contains(self.0)
|| set.contains(self.1)
|| set.contains(self.2)
|| set.contains(self.3)
|| set.contains(self.4)
|| set.contains(self.5)
|| set.contains(self.6)
|| set.contains(self.7)
}
fn select<'b>(&self, socket: Arc<Mutex<PortSocket>>) -> Self::Output {
(Pin::new(self.0, socket.clone()),
Pin::new(self.1, socket.clone()),
Pin::new(self.2, socket.clone()),
Pin::new(self.3, socket.clone()),
Pin::new(self.4, socket.clone()),
Pin::new(self.5, socket.clone()),
Pin::new(self.6, socket.clone()),
Pin::new(self.7, socket.clone()))
}
}
Loading