Compare commits
7 Commits
2fcae2cdee
...
82b6e8e179
Author | SHA1 | Date |
---|---|---|
Astro | 82b6e8e179 | |
Astro | 057ddbdbf6 | |
Astro | 4437a4195e | |
Astro | 44f48f6e0f | |
Astro | 9c7ca0df87 | |
Astro | f04bbd8726 | |
Astro | 4bf52b093e |
|
@ -120,6 +120,7 @@ dependencies = [
|
|||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=cd893e6)",
|
||||
"tm4c129x 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -13,6 +13,7 @@ cortex-m-rt = "0.6"
|
|||
crc = { version = "1.7", default-features = false }
|
||||
tm4c129x = { version = "0.8", features = ["rt"] }
|
||||
embedded-hal = { version = "0.2", features = ["unproven"] }
|
||||
nb = "0.1"
|
||||
|
||||
[dependencies.smoltcp]
|
||||
git = "https://github.com/m-labs/smoltcp"
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
use embedded_hal::digital::v2::OutputPin;
|
||||
use embedded_hal::blocking::spi::Transfer;
|
||||
|
||||
#[allow(unused)]
|
||||
#[repr(u8)]
|
||||
pub enum Register {
|
||||
Status = 0x00,
|
||||
AdcMode = 0x01,
|
||||
IfMode = 0x02,
|
||||
RegCheck = 0x03,
|
||||
Data = 0x04,
|
||||
GpioCon = 0x06,
|
||||
Id = 0x07,
|
||||
Ch0 = 0x10,
|
||||
Ch1 = 0x11,
|
||||
Ch2 = 0x12,
|
||||
Ch3 = 0x13,
|
||||
SetupCon0 = 0x20,
|
||||
SetupCon1 = 0x21,
|
||||
SetupCon2 = 0x22,
|
||||
SetupCon3 = 0x23,
|
||||
FiltCon0 = 0x28,
|
||||
FiltCon1 = 0x29,
|
||||
FiltCon2 = 0x2A,
|
||||
FiltCon3 = 0x2B,
|
||||
Offset0 = 0x30,
|
||||
Offset1 = 0x31,
|
||||
Offset2 = 0x32,
|
||||
Offset3 = 0x33,
|
||||
Gain0 = 0x38,
|
||||
Gain1 = 0x39,
|
||||
Gain2 = 0x3A,
|
||||
Gain3 = 0x3B,
|
||||
}
|
||||
|
||||
pub struct Adc<SPI: Transfer<u8>, NSS: OutputPin> {
|
||||
spi: SPI,
|
||||
nss: NSS,
|
||||
}
|
||||
|
||||
impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
|
||||
pub fn new(spi: SPI, nss: NSS) -> Result<Self, SPI::Error> {
|
||||
let mut adc = Adc { spi, nss};
|
||||
|
||||
let mut buf = [0, 0, 0];
|
||||
adc.write_reg(Register::AdcMode, &mut buf)?;
|
||||
let mut buf = [0, 1, 0];
|
||||
adc.write_reg(Register::IfMode, &mut buf)?;
|
||||
let mut buf = [0, 0, 0];
|
||||
adc.write_reg(Register::GpioCon, &mut buf)?;
|
||||
|
||||
Ok(adc)
|
||||
}
|
||||
|
||||
/// Returns the channel the data is from
|
||||
pub fn data_ready(&mut self) -> Option<u8> {
|
||||
let mut buf = [0u8; 2];
|
||||
match self.read_reg(Register::Status, &mut buf) {
|
||||
Err(_) => None,
|
||||
Ok(()) => {
|
||||
if buf[1] & 0x80 == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(buf[1] & 0x3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get data
|
||||
pub fn read_data(&mut self) -> Result<u32, SPI::Error> {
|
||||
let mut buf = [0u8; 4];
|
||||
self.read_reg(Register::Data, &mut buf)?;
|
||||
let result =
|
||||
(u32::from(buf[1]) << 16) |
|
||||
(u32::from(buf[2]) << 8) |
|
||||
u32::from(buf[3]);
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], SPI::Error> {
|
||||
let _ = self.nss.set_low();
|
||||
let result = self.spi.transfer(words);
|
||||
let _ = self.nss.set_high();
|
||||
result
|
||||
}
|
||||
|
||||
fn read_reg(&mut self, reg: Register, buffer: &'_ mut [u8]) -> Result<(), SPI::Error> {
|
||||
buffer[0] = reg as u8;
|
||||
self.transfer(buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_reg(&mut self, reg: Register, buffer: &'_ mut [u8]) -> Result<(), SPI::Error> {
|
||||
buffer[0] = 0x40 | (reg as u8);
|
||||
self.transfer(buffer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
|
||||
use cortex_m::peripheral::syst::SystClkSource;
|
||||
use cortex_m::peripheral::SYST;
|
||||
use tm4c129x::CorePeripherals;
|
||||
|
||||
/// precision internal oscillator
|
||||
const PIOSC: u32 = 16_000_000;
|
||||
|
||||
pub struct Delay {
|
||||
syst: SYST,
|
||||
}
|
||||
|
||||
impl Delay {
|
||||
/// unsafe: must only be used once to avoid concurrent use of systick
|
||||
pub unsafe fn new() -> Self {
|
||||
let mut syst = CorePeripherals::steal().SYST;
|
||||
// PIOSC
|
||||
syst.set_clock_source(SystClkSource::External);
|
||||
syst.disable_interrupt();
|
||||
Delay { syst }
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u32> for Delay {
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
self.delay_us(ms * 1_000);
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u16> for Delay {
|
||||
fn delay_ms(&mut self, ms: u16) {
|
||||
self.delay_ms(u32::from(ms));
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u8> for Delay {
|
||||
fn delay_ms(&mut self, ms: u8) {
|
||||
self.delay_ms(u32::from(ms));
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u32> for Delay {
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
// The SysTick Reload Value register supports values between 1 and 0x00FFFFFF.
|
||||
const MAX_RVR: u32 = 0x00FF_FFFF;
|
||||
|
||||
let mut total_rvr = us * (PIOSC / 1_000_000);
|
||||
|
||||
while total_rvr != 0 {
|
||||
let current_rvr = total_rvr.min(MAX_RVR);
|
||||
|
||||
self.syst.set_reload(current_rvr);
|
||||
self.syst.clear_current();
|
||||
self.syst.enable_counter();
|
||||
|
||||
// Update the tracking variable while we are waiting...
|
||||
total_rvr -= current_rvr;
|
||||
|
||||
while !self.syst.has_wrapped() {}
|
||||
|
||||
self.syst.disable_counter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u16> for Delay {
|
||||
fn delay_us(&mut self, us: u16) {
|
||||
self.delay_us(u32::from(us))
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayUs<u8> for Delay {
|
||||
fn delay_us(&mut self, us: u8) {
|
||||
self.delay_us(u32::from(us))
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
use cortex_m;
|
||||
use tm4c129x;
|
||||
|
||||
mod gpio;
|
||||
pub mod gpio;
|
||||
pub mod softspi;
|
||||
pub mod delay;
|
||||
|
||||
|
||||
const LED1: u8 = 0x10; // PK4
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
use embedded_hal::spi::FullDuplex;
|
||||
use embedded_hal::digital::v2::{InputPin, OutputPin};
|
||||
use embedded_hal::blocking::spi::Transfer;
|
||||
use embedded_hal::blocking::delay::DelayUs;
|
||||
use nb::Error::WouldBlock;
|
||||
|
||||
/// Bit-banged SPI
|
||||
pub struct SoftSpi<SCK, MOSI, MISO> {
|
||||
sck: SCK,
|
||||
mosi: MOSI,
|
||||
miso: MISO,
|
||||
state: State,
|
||||
input: Option<u8>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum State {
|
||||
Idle,
|
||||
Transfer {
|
||||
clock_phase: bool,
|
||||
mask: u8,
|
||||
output: u8,
|
||||
input: u8,
|
||||
},
|
||||
}
|
||||
|
||||
impl<SCK: OutputPin, MOSI: OutputPin, MISO: InputPin> SoftSpi<SCK, MOSI, MISO> {
|
||||
pub fn new(mut sck: SCK, mut mosi: MOSI, miso: MISO) -> Self {
|
||||
let _ = sck.set_high();
|
||||
let _ = mosi.set_low();
|
||||
SoftSpi {
|
||||
sck, mosi, miso,
|
||||
state: State::Idle,
|
||||
input: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this at twice the data rate
|
||||
pub fn tick(&mut self) {
|
||||
match self.state {
|
||||
State::Idle => {}
|
||||
State::Transfer { clock_phase: false,
|
||||
mask, output, input } => {
|
||||
if output & mask != 0 {
|
||||
let _ = self.mosi.set_high();
|
||||
} else {
|
||||
let _ = self.mosi.set_low();
|
||||
}
|
||||
let _ = self.sck.set_low();
|
||||
|
||||
self.state = State::Transfer {
|
||||
clock_phase: true,
|
||||
mask, output, input,
|
||||
};
|
||||
}
|
||||
State::Transfer { clock_phase: true,
|
||||
mask, output, mut input } => {
|
||||
let _ = self.sck.set_high();
|
||||
if self.miso.is_high().unwrap_or(false) {
|
||||
input |= mask;
|
||||
}
|
||||
|
||||
if mask != 1 {
|
||||
self.state = State::Transfer {
|
||||
clock_phase: false,
|
||||
mask: mask >> 1,
|
||||
output, input,
|
||||
};
|
||||
} else {
|
||||
self.input = Some(input);
|
||||
self.state = State::Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<F: FnMut()>(&mut self, delay: &'_ mut F) {
|
||||
while self.state != State::Idle {
|
||||
self.tick();
|
||||
delay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<SCK: OutputPin, MOSI: OutputPin, MISO: InputPin> FullDuplex<u8> for SoftSpi<SCK, MOSI, MISO> {
|
||||
type Error = ();
|
||||
|
||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||
match self.input.take() {
|
||||
Some(input) =>
|
||||
Ok(input),
|
||||
None if self.state == State::Idle =>
|
||||
Err(nb::Error::Other(())),
|
||||
None =>
|
||||
Err(WouldBlock),
|
||||
}
|
||||
}
|
||||
|
||||
fn send(&mut self, output: u8) -> Result<(), nb::Error<Self::Error>> {
|
||||
match self.state {
|
||||
State::Idle => {
|
||||
self.state = State::Transfer {
|
||||
clock_phase: false,
|
||||
mask: 0x80,
|
||||
output,
|
||||
input: 0,
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(WouldBlock)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SyncSoftSpi<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> {
|
||||
spi: SoftSpi<SCK, MOSI, MISO>,
|
||||
delay: &'d mut D,
|
||||
}
|
||||
|
||||
impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> SyncSoftSpi<'d, SCK, MOSI, MISO, D> {
|
||||
pub fn new(spi: SoftSpi<SCK, MOSI, MISO>, delay: &'d mut D) -> Self {
|
||||
SyncSoftSpi { spi, delay }
|
||||
}
|
||||
|
||||
fn retry<R, E, F>(&mut self, f: &F) -> Result<R, E>
|
||||
where
|
||||
F: Fn(&'_ mut SoftSpi<SCK, MOSI, MISO>) -> Result<R, nb::Error<E>>
|
||||
{
|
||||
loop {
|
||||
match f(&mut self.spi) {
|
||||
Ok(r) => return Ok(r),
|
||||
Err(nb::Error::Other(e)) => return Err(e),
|
||||
Err(WouldBlock) => self.spi.run(self.delay),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> Transfer<u8> for SyncSoftSpi<'d, SCK, MOSI, MISO, D> {
|
||||
// TODO: proper type
|
||||
type Error = ();
|
||||
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
||||
for b in words.iter_mut() {
|
||||
self.retry(&|spi| spi.send(*b))?;
|
||||
*b = self.retry(&|spi| spi.read())?;
|
||||
}
|
||||
Ok(words)
|
||||
}
|
||||
}
|
|
@ -11,9 +11,12 @@ extern crate tm4c129x;
|
|||
extern crate smoltcp;
|
||||
extern crate crc;
|
||||
extern crate embedded_hal;
|
||||
extern crate nb;
|
||||
|
||||
use core::cell::{Cell, RefCell};
|
||||
use core::fmt;
|
||||
use core::fmt::{self, Write};
|
||||
use embedded_hal::digital::{InputPin, OutputPin};
|
||||
use embedded_hal::blocking::delay::DelayUs;
|
||||
use cortex_m::interrupt::Mutex;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::EthernetAddress;
|
||||
|
@ -43,18 +46,11 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
|||
|
||||
#[macro_use]
|
||||
mod board;
|
||||
use board::gpio::Gpio;
|
||||
mod eeprom;
|
||||
mod config;
|
||||
mod ethmac;
|
||||
|
||||
static ADC_IRQ_COUNT: Mutex<Cell<u64>> = Mutex::new(Cell::new(0));
|
||||
|
||||
fn get_time_ms() -> u64 {
|
||||
let adc_irq_count = cortex_m::interrupt::free(|cs| {
|
||||
ADC_IRQ_COUNT.borrow(cs).get()
|
||||
});
|
||||
adc_irq_count*24/125
|
||||
}
|
||||
mod ad7172;
|
||||
|
||||
pub struct UART0;
|
||||
|
||||
|
@ -111,6 +107,21 @@ fn main() -> ! {
|
|||
| |
|
||||
|_|
|
||||
"#);
|
||||
let mut delay = unsafe { board::delay::Delay::new() };
|
||||
// CSn
|
||||
let pb4 = board::gpio::PB4.into_output();
|
||||
// SCLK
|
||||
let pb5 = board::gpio::PB5.into_output();
|
||||
// MOSI
|
||||
let pe4 = board::gpio::PE4.into_output();
|
||||
// MISO
|
||||
let pe5 = board::gpio::PE5.into_input();
|
||||
let mut delay_fn = || delay.delay_us(1u32);
|
||||
let spi = board::softspi::SyncSoftSpi::new(
|
||||
board::softspi::SoftSpi::new(pb5, pe4, pe5),
|
||||
&mut delay_fn
|
||||
);
|
||||
let mut adc = ad7172::Adc::new(spi, pb4).unwrap();
|
||||
|
||||
let mut hardware_addr = EthernetAddress(board::get_mac_address());
|
||||
if hardware_addr.is_multicast() {
|
||||
|
@ -149,98 +160,48 @@ fn main() -> ! {
|
|||
create_socket!(sockets, tcp_rx_storage5, tcp_tx_storage5, tcp_handle5);
|
||||
create_socket!(sockets, tcp_rx_storage6, tcp_tx_storage6, tcp_handle6);
|
||||
create_socket!(sockets, tcp_rx_storage7, tcp_tx_storage7, tcp_handle7);
|
||||
let handles = [
|
||||
tcp_handle0,
|
||||
tcp_handle1,
|
||||
tcp_handle2,
|
||||
tcp_handle3,
|
||||
tcp_handle4,
|
||||
tcp_handle5,
|
||||
tcp_handle6,
|
||||
tcp_handle7,
|
||||
];
|
||||
|
||||
/*let mut sessions = [
|
||||
(http::Request::new(), tcp_handle0),
|
||||
(http::Request::new(), tcp_handle1),
|
||||
(http::Request::new(), tcp_handle2),
|
||||
(http::Request::new(), tcp_handle3),
|
||||
(http::Request::new(), tcp_handle4),
|
||||
(http::Request::new(), tcp_handle5),
|
||||
(http::Request::new(), tcp_handle6),
|
||||
(http::Request::new(), tcp_handle7),
|
||||
];*/
|
||||
|
||||
/*board::set_hv_pwm(board::PWM_LOAD / 2);
|
||||
board::set_fv_pwm(board::PWM_LOAD / 2);
|
||||
board::set_fbv_pwm(board::PWM_LOAD / 2);*/
|
||||
board::start_adc();
|
||||
|
||||
let mut fast_blink_count = 0;
|
||||
let mut next_blink = 0;
|
||||
let mut led_state = true;
|
||||
let mut latch_reset_time = None;
|
||||
let mut time = 0i64;
|
||||
let mut data = 0;
|
||||
let mut socket_pending = [false; 8];
|
||||
loop {
|
||||
let time = get_time_ms();
|
||||
|
||||
/*for &mut(ref mut request, tcp_handle) in sessions.iter_mut() {
|
||||
adc.data_ready()
|
||||
.map(|channel| {
|
||||
adc.read_data()
|
||||
.map(|new_data| {
|
||||
data = new_data;
|
||||
if channel == 0 {
|
||||
for p in socket_pending.iter_mut() {
|
||||
*p = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
for (&tcp_handle, pending) in (handles.iter().zip(socket_pending.iter_mut())) {
|
||||
let socket = &mut *sockets.get::<TcpSocket>(tcp_handle);
|
||||
if !socket.is_open() {
|
||||
socket.listen(80).unwrap()
|
||||
socket.listen(23).unwrap()
|
||||
}
|
||||
|
||||
if socket.may_recv() {
|
||||
match socket.recv(|data| (data.len(), request.input(data))).unwrap() {
|
||||
Ok(true) => {
|
||||
if socket.can_send() {
|
||||
pages::serve(socket, &request, &mut config, &LOOP_ANODE, &LOOP_CATHODE, &ELECTROMETER);
|
||||
}
|
||||
request.reset();
|
||||
socket.close();
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(err) => {
|
||||
println!("failed HTTP request: {}", err);
|
||||
request.reset();
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
} else if socket.may_send() {
|
||||
request.reset();
|
||||
socket.close();
|
||||
if socket.may_send() && *pending {
|
||||
let _ = writeln!(socket, "{}\r", data);
|
||||
*pending = false;
|
||||
}
|
||||
}*/
|
||||
match iface.poll(&mut sockets, Instant::from_millis(time as i64)) {
|
||||
}
|
||||
match iface.poll(&mut sockets, Instant::from_millis(time)) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("poll error: {}", e)
|
||||
}
|
||||
|
||||
board::process_errors();
|
||||
if board::error_latched() {
|
||||
match latch_reset_time {
|
||||
None => {
|
||||
println!("Protection latched");
|
||||
latch_reset_time = Some(time + 5000);
|
||||
}
|
||||
Some(t) => if time > t {
|
||||
latch_reset_time = None;
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
board::reset_error();
|
||||
});
|
||||
println!("Protection reset");
|
||||
}
|
||||
}
|
||||
}
|
||||
time += 1;
|
||||
}
|
||||
}
|
||||
|
||||
interrupt!(ADC0SS0, adc0_ss0);
|
||||
fn adc0_ss0() {
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let adc0 = unsafe { &*tm4c129x::ADC0::ptr() };
|
||||
if adc0.ostat.read().ov0().bit() {
|
||||
panic!("ADC FIFO overflowed")
|
||||
}
|
||||
adc0.isc.write(|w| w.in0().bit(true));
|
||||
|
||||
let ic_sample = adc0.ssfifo0.read().data().bits();
|
||||
let fbi_sample = adc0.ssfifo0.read().data().bits();
|
||||
let fv_sample = adc0.ssfifo0.read().data().bits();
|
||||
let fd_sample = adc0.ssfifo0.read().data().bits();
|
||||
let av_sample = adc0.ssfifo0.read().data().bits();
|
||||
let fbv_sample = adc0.ssfifo0.read().data().bits();
|
||||
|
||||
let adc_irq_count = ADC_IRQ_COUNT.borrow(cs);
|
||||
adc_irq_count.set(adc_irq_count.get() + 1);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue