Skip to content

Commit

Permalink
Implement strain-gauge-via-CAN
Browse files Browse the repository at this point in the history
  • Loading branch information
KoffeinFlummi committed Sep 19, 2024
1 parent d3382a3 commit 3939470
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 64 deletions.
2 changes: 1 addition & 1 deletion firmware/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ cortex-m-rt = "0.7"
alloc-cortex-m = "0.4"

embassy-stm32 = { version = "0.1", features = ["stm32f103rc", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
embassy-executor = { version = "0.5", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt", "integrated-timers"] }
embassy-executor = { version = "0.5", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt", "integrated-timers"] }
embassy-time = { version = "0.3", features = ["tick-hz-32_768"] }
embassy-embedded-hal = "0.1"
embassy-sync = "0.5"
Expand Down
6 changes: 3 additions & 3 deletions firmware/src/can.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber};
use shared_types::{CanBusMessage, CanBusMessageId, FlightMode, TelemetryToPayloadMessage};
use static_cell::StaticCell;

pub const CAN_QUEUE_SIZE: usize = 5; // TODO
pub const NUM_CAN_SUBSCRIBERS: usize = 3; // TODO
pub const NUM_CAN_PUBLISHERS: usize = 5; // TODO
pub const CAN_QUEUE_SIZE: usize = 3; // TODO
pub const NUM_CAN_SUBSCRIBERS: usize = 1; // TODO
pub const NUM_CAN_PUBLISHERS: usize = 1; // TODO

pub type CanFrame = (u16, [u8; 8]);
pub type CanInChannel = PubSubChannel::<CriticalSectionRawMutex, CanFrame, CAN_QUEUE_SIZE, NUM_CAN_SUBSCRIBERS, 1>;
Expand Down
3 changes: 1 addition & 2 deletions firmware/src/leds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ pub async fn run(
boot_animation(&mut leds).await;

loop {
if let Some(new_fm) = flight_mode_subscriber.try_next_message_pure() {
defmt::println!("{:?}", defmt::Debug2Format(&new_fm));
while let Some(new_fm) = flight_mode_subscriber.try_next_message_pure() {
flight_mode = new_fm;
}

Expand Down
24 changes: 20 additions & 4 deletions firmware/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use embassy_executor::Spawner;
use embassy_stm32::adc::Adc;
use embassy_stm32::Config;
use embassy_stm32::gpio::Input;
use embassy_stm32::peripherals::*;
use embassy_stm32::time::Hertz;
use embassy_stm32::wdg::IndependentWatchdog;
Expand Down Expand Up @@ -51,9 +52,14 @@ async fn main(low_priority_spawner: Spawner) {

// Remap CAN to be on PB8/9
embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_spi3_remap(true));

defmt::info!("Fin startup");
let addr0 = Input::new(p.PA8, embassy_stm32::gpio::Pull::Up);
let addr1 = Input::new(p.PA9, embassy_stm32::gpio::Pull::Up);
let address = (addr0.is_low() as u8) << 1 + (addr1.is_low() as u8);
// Fin #1 has a broken jumper, so hardcode this when flashing.
//let address = 1;

defmt::info!("Fin #{} startup", address);

// Start watchdog
let mut iwdg = IndependentWatchdog::new(p.IWDG, 512_000); // 512ms timeout
Expand All @@ -79,6 +85,16 @@ async fn main(low_priority_spawner: Spawner) {
let mut adc = Adc::new(p.ADC1, &mut Delay);
adc.set_sample_time(embassy_stm32::adc::SampleTime::Cycles239_5);

low_priority_spawner.spawn(strain_gauge::run(adc, p.PC0, p.PC1, p.PC2, p.PC3, flight_mode.subscriber().unwrap(),
p.SPI2, p.PC6, p.PB13, p.PB14, p.PB15, p.DMA1_CH5, p.DMA1_CH4)).unwrap();
low_priority_spawner.spawn(
strain_gauge::run(
address,
adc,
p.PC0,
p.PC1,
p.PC2,
p.PC3,
flight_mode.subscriber().unwrap(),
can_out.publisher().unwrap()
)
).unwrap();
}
114 changes: 60 additions & 54 deletions firmware/src/strain_gauge.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,86 @@
use embassy_executor;
use embassy_stm32::adc::Adc;
use embassy_stm32::gpio::{Output, Level, Speed};
use embassy_stm32::spi::{Config, Phase, Polarity, Spi};
use embassy_stm32::time::Hertz;
use embassy_stm32::peripherals::*;
use embassy_time::{with_timeout, Delay, Duration, Ticker, Timer};
use smart_leds::RGB8;
use w25q::prelude;
use w25q::series25::Flash;
use ws2812_spi::Ws2812;
use smart_leds::SmartLedsWrite;

fn to_millivolts(vref_sample: u16, sample: u16) -> u16 {
const VREFINT_MV: u32 = 1200; // mV
(u32::from(sample) * VREFINT_MV / u32::from(vref_sample)) as u16
use embassy_time::{with_timeout, Duration, Ticker};
use shared_types::{CanBusMessage, CanBusMessageId, FinBoardDataMessage, FlightMode};

const PRIMARY_STRAIN_GAUGE_SAMPLE_RATE_HZ: u64 = 1000;
const SECONDARY_STRAIN_GAUGE_SAMPLE_RATE_HZ: u64 = 100;

const DIVISOR: i16 = 4; // 1 => no loss in quality, clipping after sample > +/- 128
// 16 => no clipping inside ADC range

pub async fn sample_strain_gauges(
adc: &mut Adc<'static, ADC1>,
sg_vout0_pin: &mut PC1,
_sg_ref_pin: &mut PC2,
sg_vout1_pin: &mut PC3,
) -> (u8, u8) {
const TIMEOUT: Duration = Duration::from_micros(100);

let sg0_sample = with_timeout(TIMEOUT, adc.read(sg_vout0_pin)).await.unwrap_or_default();
let sg1_sample = with_timeout(TIMEOUT, adc.read(sg_vout1_pin)).await.unwrap_or_default();

let sg0 = ((sg0_sample as i16 - 2048) / DIVISOR + 128) as u8;
let sg1 = ((sg1_sample as i16 - 2048) / DIVISOR + 128) as u8;

(sg0, sg1)
}

#[embassy_executor::task]
pub async fn run(
address: u8,
mut adc: Adc<'static, ADC1>,
sg_en_pin: PC0,
mut sg_vout0_pin: PC1,
_sg_ref_pin: PC2,
mut sg_ref_pin: PC2,
mut sg_vout1_pin: PC3,
flight_mode_subscriber: crate::can::FlightModeSubscriber,
spi: SPI2,
cs: PC6,
sck: PB13,
miso: PB14,
mosi: PB15,
dma_out: DMA1_CH5,
dma_in: DMA1_CH4
mut flight_mode_subscriber: crate::can::FlightModeSubscriber,
can_out: crate::can::CanOutPublisher,
) -> ! {
const TIMEOUT: Duration = Duration::from_micros(100);

let mut enable = Output::new(sg_en_pin, Level::Low, Speed::Low);
let mut fm = FlightMode::default();

// 2000 Hz
let mut ticker = Ticker::every(Duration::from_micros(50000));

let mut config = Config::default();
config.frequency = Hertz::mhz(2);
let mut spi_bus = embassy_stm32::spi::Spi::new(spi, sck, mosi, miso, dma_out, dma_in, config);
let mut cs = Output::new(cs, Level::High, Speed::Low);
//let mut flash = Flash::init(spi_bus, out).unwrap();
let sg0_id = CanBusMessageId::FinBoardInput(address, 0); // TODO: fin id
let sg1_id = CanBusMessageId::FinBoardInput(address, 1); // TODO: fin id

let mut data0 = [0; 6];
let mut data1 = [0; 6];
let mut i = 0;

let mut ticker = if address == 0 {
Ticker::every(Duration::from_micros(1_000_000 / PRIMARY_STRAIN_GAUGE_SAMPLE_RATE_HZ))
} else {
Ticker::every(Duration::from_micros(1_000_000 / SECONDARY_STRAIN_GAUGE_SAMPLE_RATE_HZ))
};

loop {
enable.set_high();
//let sg_ref_sample = with_timeout(TIMEOUT, adc.read(&mut sg_ref_pin)).await.unwrap_or_default();
let sg_vout0_sample = with_timeout(TIMEOUT, adc.read(&mut sg_vout0_pin)).await.unwrap_or_default();
let sg_vout1_sample = with_timeout(TIMEOUT, adc.read(&mut sg_vout1_pin)).await.unwrap_or_default();
enable.set_low();

i += 1;
if i > 100 {
defmt::println!("[SG] {:?} {:?}", sg_vout0_sample, sg_vout1_sample);
i = 0;
while let Some(new_fm) = flight_mode_subscriber.try_next_message_pure() {
fm = new_fm;
}

//let sg_ref_voltage = to_millivolts(vref_sample, sg_ref_sample);
//let sg_vout0_voltage = to_millivolts(vref_sample, sg_vout0_sample);
//let sg_vout1_voltage = to_millivolts(vref_sample, sg_vout1_sample);
if fm >= FlightMode::ArmedLaunchImminent && fm < FlightMode::Landed { // TODO
enable.set_high();

let (sg0, sg1) = sample_strain_gauges(&mut adc, &mut sg_vout0_pin, &mut sg_ref_pin, &mut sg_vout1_pin).await;
data0[i % 6] = sg0;
data1[i % 6] = sg1;
i += 1;

//defmt::println!("{:?} {:?} {:?}", sg_ref_voltage, sg_vout0_voltage, sg_vout1_voltage);
if i >= 6 {
let sg0_message = FinBoardDataMessage { data: data0.try_into().unwrap_or_default() };
can_out.publish((sg0_id.into(), sg0_message.serialize_with_crc())).await;
let sg1_message = FinBoardDataMessage { data: data1.try_into().unwrap_or_default() };
can_out.publish((sg1_id.into(), sg1_message.serialize_with_crc())).await;
i = 0;
}
} else {
i = 0;
enable.set_low();
}

cs.set_low();
Timer::after(Duration::from_micros(100)).await;
let mut read: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let mut write: [u8; 4] = [0x9f, 0x00, 0x00, 0x00];
let res = spi_bus.transfer(&mut read, &write).await.unwrap();
Timer::after(Duration::from_micros(100)).await;
cs.set_high();
defmt::println!("{:?} {:?}", read, write);

// TODO read strain gauge value and write to flash
ticker.next().await;
}
}

0 comments on commit 3939470

Please sign in to comment.