Created
February 20, 2020 21:53
-
-
Save dflemstr/a51798ef7ec70138ea89c5f574829dc3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Demonstrates an SPI master. We try to read data from | |
//! an Adafruit AirLift. | |
#![no_std] | |
#![no_main] | |
extern crate panic_halt; | |
use bsp::hal::gpio::IntoGpio; | |
use core::fmt::Debug; | |
use embedded_hal::blocking::spi::{Transfer, Write}; | |
use embedded_hal::digital::v2::InputPin; | |
use embedded_hal::digital::v2::OutputPin; | |
use embedded_hal::spi::FullDuplex; | |
use teensy4_bsp as bsp; | |
const START_CMD: u8 = 0xe0; | |
const END_CMD: u8 = 0xee; | |
const ERR_CMD: u8 = 0xef; | |
const REPLY_FLAG: u8 = 1 << 7; | |
const GET_FW_VERSION_CMD: u8 = 0x37; | |
const GET_CONN_STATUS_CMD: u8 = 0x20; | |
const SET_PIN_MODE: u8 = 0x50; | |
const SET_DIGITAL_WRITE: u8 = 0x51; | |
const SET_ANALOG_WRITE: u8 = 0x52; | |
const LOW: u8 = 0x00; | |
const HIGH: u8 = 0x01; | |
const INPUT: u8 = 0x00; | |
const OUTPUT: u8 = 0x01; | |
const INPUT_PULLUP: u8 = 0x02; | |
#[bsp::rt::entry] | |
fn main() -> ! { | |
let mut peripherals = bsp::Peripherals::take().unwrap(); | |
peripherals.usb.init(Default::default()); | |
bsp::delay(5000); | |
log::info!("Enabling SPI clocks..."); | |
let (_, _, _, spi4_builder) = peripherals.spi.clock( | |
&mut peripherals.ccm.handle, | |
bsp::hal::ccm::spi::ClockSelect::Pll3Pfd0, | |
bsp::hal::ccm::spi::PrescalarSelect::LPSPI_PODF_2, | |
); | |
log::info!("Constructing SPI instance on pins 11, 12 and 13..."); | |
let mut spi = spi4_builder.build( | |
peripherals.pins.p11.alt3(), | |
peripherals.pins.p12.alt3(), | |
peripherals.pins.p13.alt3(), | |
); | |
let mut esp_gpio0 = peripherals.pins.p2.into_gpio().output(); | |
let esp_busy = peripherals.pins.p3.into_gpio(); | |
let mut esp_rst = peripherals.pins.p4.into_gpio().output(); | |
let mut esp_cs = peripherals.pins.p5.into_gpio().output(); | |
esp_gpio0.set_high().unwrap(); | |
esp_rst.set_low().unwrap(); | |
bsp::delay(100); | |
esp_rst.set_high().unwrap(); | |
log::info!("Starting I/O loop..."); | |
let mut buffer = [0; 1024]; | |
loop { | |
send_cmd( | |
&mut spi, | |
&esp_busy, | |
&mut esp_cs, | |
&get_connection_status_cmd(), | |
); | |
let mut resp = [0]; | |
if wait_response( | |
&mut spi, | |
&esp_busy, | |
&mut esp_cs, | |
GET_CONN_STATUS_CMD, | |
&mut resp, | |
) { | |
if resp[0] == 255 { | |
log::error!("No module detected"); | |
} | |
if resp[0] == 0 { | |
break; | |
} | |
} | |
bsp::delay(1000); | |
} | |
log::info!("Configure remote pins"); | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &pin_mode_cmd(25, OUTPUT)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_PIN_MODE, &mut [0]) {} | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &pin_mode_cmd(26, OUTPUT)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_PIN_MODE, &mut [0]) {} | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &pin_mode_cmd(27, OUTPUT)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_PIN_MODE, &mut [0]) {} | |
loop { | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &analog_write_cmd(25, 128)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_ANALOG_WRITE, &mut [0]) {} | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &analog_write_cmd(26, 128)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_ANALOG_WRITE, &mut [0]) {} | |
send_cmd(&mut spi, &esp_busy, &mut esp_cs, &analog_write_cmd(27, 128)); | |
while !wait_response(&mut spi, &esp_busy, &mut esp_cs, SET_ANALOG_WRITE, &mut [0]) {} | |
bsp::delay(1000); | |
} | |
} | |
fn get_connection_status_cmd() -> [u8; 4] { | |
[START_CMD, GET_CONN_STATUS_CMD & !REPLY_FLAG, 0, END_CMD] | |
} | |
fn analog_write_cmd(pin: u8, value: u8) -> [u8; 8] { | |
[ | |
START_CMD, | |
SET_ANALOG_WRITE & !REPLY_FLAG, | |
2, | |
1, | |
pin, | |
1, | |
value, | |
END_CMD, | |
] | |
} | |
fn pin_mode_cmd(pin: u8, mode: u8) -> [u8; 8] { | |
[ | |
START_CMD, | |
SET_PIN_MODE & !REPLY_FLAG, | |
2, | |
1, | |
pin, | |
1, | |
mode, | |
END_CMD, | |
] | |
} | |
fn send_cmd<W, BSY, CS>(spi: &mut W, esp_busy: &BSY, esp_cs: &mut CS, cmd: &[u8]) | |
where | |
W: Write<u8>, | |
<W as Write<u8>>::Error: Debug, | |
BSY: InputPin, | |
BSY::Error: Debug, | |
CS: OutputPin, | |
CS::Error: Debug, | |
{ | |
log::debug!("Waiting for ESP to be ready for request"); | |
while esp_busy.is_high().unwrap() {} | |
esp_cs.set_low().unwrap(); | |
spi.write(cmd).unwrap(); | |
esp_cs.set_high().unwrap(); | |
if cmd.len() > 32 { | |
log::debug!("Sent cmd (truncated): {:02x?}...", &cmd[..32]); | |
} else { | |
log::debug!("Sent cmd: {:02x?}", cmd); | |
} | |
} | |
fn read<W>(spi: &mut W) -> u8 | |
where | |
W: FullDuplex<u8>, | |
<W as FullDuplex<u8>>::Error: Debug, | |
{ | |
nb::block!(spi.send(0x00)).unwrap(); // dummy | |
let data = nb::block!(spi.read()).unwrap(); | |
log::trace!("read {:02x}", data); | |
data | |
} | |
fn wait_response<W, BSY, CS>( | |
spi: &mut W, | |
esp_busy: &BSY, | |
esp_cs: &mut CS, | |
cmd: u8, | |
param: &mut [u8], | |
) -> bool | |
where | |
W: FullDuplex<u8>, | |
<W as FullDuplex<u8>>::Error: Debug, | |
BSY: InputPin, | |
BSY::Error: Debug, | |
CS: OutputPin, | |
CS::Error: Debug, | |
{ | |
log::debug!("Waiting for ESP to be ready for response"); | |
while esp_busy.is_high().unwrap() {} | |
esp_cs.set_low().unwrap(); | |
loop { | |
let mut num_attempts = 0; | |
loop { | |
let data = read(spi); | |
num_attempts += 1; | |
if data == START_CMD { | |
break; | |
} | |
if data == ERR_CMD { | |
log::warn!("Received error response"); | |
esp_cs.set_high().unwrap(); | |
return false; | |
} | |
if num_attempts >= 256 { | |
log::warn!("Timed out"); | |
esp_cs.set_high().unwrap(); | |
return false; | |
} | |
} | |
let data = read(spi); | |
let expected = cmd | REPLY_FLAG; | |
if data == expected { | |
break; | |
} else { | |
log::warn!("Reply command: expected {:x} but got {:x}", expected, data); | |
esp_cs.set_high().unwrap(); | |
return false; | |
} | |
} | |
let data = read(spi) as usize; | |
let expected = param.len(); | |
if data != expected { | |
log::warn!("Reply len: expected {:x} but got {:x}", expected, data); | |
esp_cs.set_high().unwrap(); | |
return false; | |
} | |
for b in param { | |
*b = read(spi); | |
} | |
let data = read(spi); | |
if data != END_CMD { | |
log::warn!("Reply end command: expected END_CMD but got {:x}", data); | |
esp_cs.set_high().unwrap(); | |
return false; | |
} | |
esp_cs.set_high().unwrap(); | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment