diff --git a/accel-mma84/src/lib.rs b/accel-mma84/src/lib.rs index 430d0ea..8189486 100644 --- a/accel-mma84/src/lib.rs +++ b/accel-mma84/src/lib.rs @@ -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(()) } diff --git a/tessel/src/lib.rs b/tessel/src/lib.rs index 87d40ca..e2a10ab 100644 --- a/tessel/src/lib.rs +++ b/tessel/src/lib.rs @@ -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; @@ -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. @@ -135,43 +148,6 @@ impl<'a> Gpio<'a> { } } -/// Pin tuple conversion for gpio:pins(..) -pub trait PinSelect<'a> { - type Output; - fn validate(&self, &BitSet) -> bool; - fn select(&self, socket: Arc>) -> Self::Output; -} - -impl<'a> PinSelect<'a> for usize { - type Output = Pin<'a>; - fn validate(&self, set: &BitSet) -> bool { - set.contains(*self) - } - fn select<'b>(&self, socket: Arc>) -> Self::Output { - Pin::new(*self, socket) - } -} - -impl<'a> PinSelect<'a> for (usize, usize) { - type Output = (Pin<'a>, Pin<'a>); - fn validate(&self, set: &BitSet) -> bool { - set.contains(self.0) || set.contains(self.1) - } - fn select<'b>(&self, socket: Arc>) -> 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) -> bool { - set.contains(self.0) || set.contains(self.1) || set.contains(self.2) - } - fn select<'b>(&self, socket: Arc>) -> 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, @@ -311,6 +287,127 @@ impl<'p> I2cPort<'p> { } } + +/// A SPI Port. +pub struct SpiPort<'a> { + socket: Arc>, + _phantom: PhantomData<&'a Port>, +} + +impl<'p> SpiPort<'p> { + // TODO: make frequency optional + fn new<'a>(socket: Arc>) -> 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, write_buf: &[u8]) { + // Write the command and data + sock.write_command(Command::Tx(write_buf)).unwrap(); + } + + fn rx(sock: &mut MutexGuard, 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. diff --git a/tessel/src/pin_select.rs b/tessel/src/pin_select.rs new file mode 100644 index 0000000..d930ecf --- /dev/null +++ b/tessel/src/pin_select.rs @@ -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) -> bool; + fn select(&self, socket: Arc>) -> Self::Output; +} + +impl<'a> PinSelect<'a> for usize { + type Output = Pin<'a>; + fn validate(&self, set: &BitSet) -> bool { + set.contains(*self) + } + fn select<'b>(&self, socket: Arc>) -> Self::Output { + Pin::new(*self, socket) + } +} + +impl<'a> PinSelect<'a> for (usize, usize) { + type Output = (Pin<'a>, Pin<'a>); + fn validate(&self, set: &BitSet) -> bool { + set.contains(self.0) + || set.contains(self.1) + } + fn select<'b>(&self, socket: Arc>) -> 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) -> bool { + set.contains(self.0) + || set.contains(self.1) + || set.contains(self.2) + } + fn select<'b>(&self, socket: Arc>) -> 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) -> bool { + set.contains(self.0) + || set.contains(self.1) + || set.contains(self.2) + || set.contains(self.3) + } + fn select<'b>(&self, socket: Arc>) -> 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) -> 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>) -> 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) -> 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>) -> 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) -> 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>) -> 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) -> 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>) -> 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())) + } +} diff --git a/test/src/index.html b/test/src/index.html index 387d124..364e48b 100644 --- a/test/src/index.html +++ b/test/src/index.html @@ -1,7 +1,6 @@ -Acceleration - +Acceleration Visualizer