From 9fbfbef474e510cb8eb364116e90f8759d49d9ac Mon Sep 17 00:00:00 2001 From: Stephen D <webmaster@scd31.com> Date: Sat, 8 Jul 2023 23:23:35 -0300 Subject: [PATCH] more progress --- Cargo.lock | 1 + Cargo.toml | 1 + src/main.rs | 127 +++++++++++++++++++++++++++++------------------- src/spi_data.rs | 43 ++++++++++++++++ 4 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 src/spi_data.rs diff --git a/Cargo.lock b/Cargo.lock index bc8866c..c87e012 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,6 +270,7 @@ dependencies = [ "rf4463", "ringbuffer", "stm32f4xx-hal", + "systick-monotonic", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 91a85a6..567f884 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,4 +22,5 @@ panic-semihosting = "0.6" rf4463 = { path = "../rf4463" } cortex-m-rtic = { version = "1.1.4" } ringbuffer = { version = "0.13.0", default_features = false } +systick-monotonic = "1.0.1" #panic-reset = "0.1.1" diff --git a/src/main.rs b/src/main.rs index e7c4b11..5f54fe0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,9 @@ extern crate panic_semihosting; extern crate stm32f4xx_hal as hal; mod packet; +mod spi_data; -#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true)] +#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [USART6])] mod app { use hal::dma; use hal::gpio::{self, Speed}; @@ -21,9 +22,11 @@ mod app { use rf4463::config::RADIO_CONFIG_500_2; use rf4463::Rf4463; use ringbuffer::{ConstGenericRingBuffer, RingBuffer, RingBufferRead, RingBufferWrite}; + use systick_monotonic::*; use crate::packet::Packet; use crate::packet::PACKET_LEN; + use crate::spi_data::{self, SpiData}; // in # packets const BUFFER_LEN: usize = 50; @@ -33,7 +36,9 @@ mod app { const PI_RX_BUFFER_LEN: usize = 256; // in bytes - const PI_TX_BUFFER_LEN: usize = 1; + const PI_TX_BUFFER_LEN: usize = spi_data::LEN; + + const SYS_CLK: u32 = 100_000_000; const MODE: Mode = Mode { polarity: Polarity::IdleLow, @@ -67,14 +72,12 @@ mod app { #[derive(Debug)] enum SlaveCmd { SendPacket, - GetTemp, } impl SlaveCmd { pub fn from_u8(i: u8) -> Option<Self> { match i { 0x01 => Some(Self::SendPacket), - 0x02 => Some(Self::GetTemp), _ => None, } } @@ -89,11 +92,11 @@ mod app { #[shared] struct Shared { radio: Radio, - radio_temp: f32, tx_buf: ConstGenericRingBuffer<Packet, BUFFER_LEN>, pi_tx: TxTransfer, other_tx_buf: Option<&'static mut [u8; PI_TX_BUFFER_LEN]>, + spi_data: SpiData, } #[local] @@ -105,6 +108,9 @@ mod app { other_rx_buf: Option<&'static mut [u8; PI_RX_BUFFER_LEN]>, } + #[monotonic(binds = SysTick, default = true)] + type Tonic = Systick<1000>; + #[init] fn init(mut ctx: init::Context) -> (Shared, Local, init::Monotonics) { let rcc = ctx.device.RCC.constrain(); @@ -116,7 +122,7 @@ mod app { let clocks = rcc .cfgr .use_hse(25.MHz()) - .sysclk(100.MHz()) + .sysclk(SYS_CLK.Hz()) .pclk1(48.MHz()) .pclk2(48.MHz()) .freeze(); @@ -158,10 +164,10 @@ mod app { let streams = dma::StreamsTuple::new(ctx.device.DMA1); - let tx_buffer = - cortex_m::singleton!(: [u8; PI_TX_BUFFER_LEN] = [0x02; PI_TX_BUFFER_LEN]).unwrap(); + let spi_data = SpiData::new(0.0, true); + let tx_buffer = cortex_m::singleton!(: [u8; PI_TX_BUFFER_LEN] = spi_data.into()).unwrap(); let other_tx_buf = - Some(cortex_m::singleton!(: [u8; PI_TX_BUFFER_LEN] = [0u8; PI_TX_BUFFER_LEN]).unwrap()); + Some(cortex_m::singleton!(: [u8; PI_TX_BUFFER_LEN] = spi_data.into()).unwrap()); let mut pi_tx = dma::Transfer::init_memory_to_peripheral( streams.4, @@ -169,11 +175,18 @@ mod app { tx_buffer, None, dma::config::DmaConfig::default() - .memory_increment(false) + .memory_increment(true) .fifo_enable(true) .fifo_error_interrupt(true), ); + // Enable circular mode + // safety: probably? + unsafe { + let dma1 = &*pac::DMA1::ptr(); + dma1.st[4].cr.modify(|_, w| w.circ().set_bit()); + } + pi_tx.start(|_tx| {}); let rx_buffer = @@ -195,14 +208,18 @@ mod app { pi_rx.start(|_rx| {}); + // start our radio temp loop + get_radio_temp::spawn_after(1u64.secs()).unwrap(); + ( Shared { radio, - radio_temp: 0.0, tx_buf: ConstGenericRingBuffer::new(), pi_tx, other_tx_buf, + + spi_data, }, Local { radio_irq, @@ -211,13 +228,12 @@ mod app { pi_rx, other_rx_buf, }, - init::Monotonics(), + init::Monotonics(Systick::new(ctx.core.SYST, SYS_CLK)), ) } - #[idle(shared=[radio, tx_buf, radio_temp, pi_tx, other_tx_buf])] + #[idle(shared=[radio, tx_buf, pi_tx, other_tx_buf, spi_data])] fn idle(mut ctx: idle::Context) -> ! { - let mut i = 0; let mut iterations_since_last_packet = 0; loop { if let Some(pkt) = ctx.shared.tx_buf.lock(|buf| buf.dequeue()) { @@ -247,33 +263,44 @@ mod app { } // update our SPI bus to say if we have free space or not - let b = if ctx.shared.tx_buf.lock(|b| b.len() >= b.capacity() - 2) { - 0x01 // not enough space for packet - } else { - 0x02 // space for packet - }; + let free = ctx.shared.tx_buf.lock(|b| b.len() < b.capacity() - 2); + let mut new_spi_data = ctx.shared.spi_data.lock(|sd| *sd); + new_spi_data.set_free(free); - set_spi_tx_byte(b, &mut ctx.shared.pi_tx, &mut ctx.shared.other_tx_buf); + set_spi_tx( + &mut ctx.shared.pi_tx, + &mut ctx.shared.other_tx_buf, + &mut ctx.shared.spi_data, + new_spi_data, + ); iterations_since_last_packet = 0; } else { iterations_since_last_packet += 1; } + } + } - i += 1; + #[task(shared = [radio, spi_data, pi_tx, other_tx_buf])] + fn get_radio_temp(mut ctx: get_radio_temp::Context) { + // get temp every second - // get temp every 500 packets, or whenever when idle - if i >= 500 { - i = 0; + if let Ok(new_temp) = ctx.shared.radio.lock(|r| r.get_temp()) { + let mut new_spi_data = ctx.shared.spi_data.lock(|sd| *sd); + new_spi_data.set_temp(new_temp); - if let Ok(new_temp) = ctx.shared.radio.lock(|r| r.get_temp()) { - ctx.shared.radio_temp.lock(|cur_temp| *cur_temp = new_temp); - } - } + set_spi_tx( + &mut ctx.shared.pi_tx, + &mut ctx.shared.other_tx_buf, + &mut ctx.shared.spi_data, + new_spi_data, + ); } + + get_radio_temp::spawn_after(1u64.secs()).unwrap(); } - #[task(binds = DMA1_STREAM3, priority = 2, local = [state, pi_rx, other_rx_buf], shared = [tx_buf, pi_tx, other_tx_buf])] + #[task(binds = DMA1_STREAM3, priority = 2, local = [state, pi_rx, other_rx_buf], shared = [tx_buf, pi_tx, other_tx_buf, spi_data])] fn pi_spi_recv(mut ctx: pi_spi_recv::Context) { let rx = ctx.local.pi_rx; @@ -288,6 +315,7 @@ mod app { &mut ctx.shared.tx_buf, &mut ctx.shared.pi_tx, &mut ctx.shared.other_tx_buf, + &mut ctx.shared.spi_data, ); } @@ -316,36 +344,28 @@ mod app { T: rtic::Mutex<T = ConstGenericRingBuffer<Packet, BUFFER_LEN>>, A: rtic::Mutex<T = TxTransfer>, B: rtic::Mutex<T = Option<&'static mut [u8; PI_TX_BUFFER_LEN]>>, + C: rtic::Mutex<T = SpiData>, >( x: u8, state: &mut SlaveState, buf: &mut T, tx: &mut A, other_tx: &mut B, + spi_data: &mut C, ) { match state { SlaveState::Idle => { if let Some(cmd) = SlaveCmd::from_u8(x) { match cmd { SlaveCmd::SendPacket => { - let b = if buf.lock(|b| b.len() >= b.capacity() - 2) { - 0x01 // not enough space for packet - } else { - 0x02 // space for packet - }; + let free = buf.lock(|b| b.len() < b.capacity() - 2); - set_spi_tx_byte(b, tx, other_tx); - - *state = SlaveState::RecvPacket(Packet::default()); - } + let mut new_spi_data = spi_data.lock(|sd| *sd); + new_spi_data.set_free(free); - SlaveCmd::GetTemp => { - todo!(); + set_spi_tx(tx, other_tx, spi_data, new_spi_data); - /* - let temp = ctx.shared.radio_temp.lock(|x| *x); - usart.bwrite_all(&temp.to_le_bytes()).unwrap(); - */ + *state = SlaveState::RecvPacket(Packet::default()); } } } @@ -362,15 +382,26 @@ mod app { }; } - fn set_spi_tx_byte< + fn set_spi_tx< A: rtic::Mutex<T = TxTransfer>, B: rtic::Mutex<T = Option<&'static mut [u8; PI_TX_BUFFER_LEN]>>, + C: rtic::Mutex<T = SpiData>, >( - b: u8, tx: &mut A, other_tx: &mut B, + spi_data: &mut C, + new_spi_data: SpiData, ) { - other_tx.lock(|t| t.as_mut().unwrap()[0] = b); + let bytes: [u8; spi_data::LEN] = new_spi_data.into(); + + // if the new data is equal to the old data, do nothing + if spi_data.lock(|sd| <[u8; spi_data::LEN]>::from(*sd)) == bytes { + return; + } + + spi_data.lock(|sd| *sd = new_spi_data); + + other_tx.lock(|t| t.as_mut().unwrap().clone_from_slice(&bytes)); other_tx.lock(|t| { let (tx, _) = @@ -380,5 +411,3 @@ mod app { }); } } - -// TODO need an interrupt to clear TX errors diff --git a/src/spi_data.rs b/src/spi_data.rs new file mode 100644 index 0000000..4c2655b --- /dev/null +++ b/src/spi_data.rs @@ -0,0 +1,43 @@ +// Represents the data that we repeatedly put on the SPI bus +pub const LEN: usize = 7; + +#[derive(Copy, Clone, Debug)] +pub struct SpiData { + temp: f32, + free_space: bool, +} + +impl SpiData { + pub fn new(temp: f32, free_space: bool) -> Self { + Self { temp, free_space } + } + + pub fn set_temp(&mut self, temp: f32) { + self.temp = temp + } + + pub fn set_free(&mut self, free_space: bool) { + self.free_space = free_space; + } + + pub fn free_space(&self) -> bool { + self.free_space + } +} + +// There's probably a better way to do this +// if the temp happens to have some 0xE5 or 0xAA/0x55 in there, it might be possible to cause problems? +// could just use 7 bits per byte and have the extra bit cleared in the data, and set in the pre/post-amble +impl From<SpiData> for [u8; LEN] { + fn from(data: SpiData) -> Self { + let free = if data.free_space { 0xAA } else { 0x55 }; + + let temp = data.temp.to_le_bytes(); + + let mut out = [0xE5, free, 0, 0, 0, 0, 0xE5]; + + out[2..6].copy_from_slice(&temp); + + out + } +} -- GitLab