-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
373 additions
and
5 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
edition = "2021" | ||
name = "cerberus" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
cortex-m.workspace = true | ||
cortex-m-rt.workspace = true | ||
defmt.workspace = true | ||
defmt-rtt.workspace = true | ||
embassy-embedded-hal.workspace = true | ||
embassy-executor.workspace = true | ||
embassy-stm32.workspace = true | ||
embassy-sync.workspace = true | ||
embassy-time.workspace = true | ||
embassy-futures.workspace = true | ||
heapless.workspace = true | ||
panic-probe.workspace = true | ||
static_cell.workspace = true | ||
pca9539-ner = { version = "0.1.0", path = "../crates/pca9539-ner" } |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use embassy_futures::select::select; | ||
use embassy_stm32::can::Frame; | ||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal}; | ||
use embassy_time::Timer; | ||
|
||
use crate::FaultCode; | ||
|
||
#[embassy_executor::task] | ||
pub async fn bms_handler( | ||
recved: &'static Signal<CriticalSectionRawMutex, Frame>, | ||
fault: &'static Signal<CriticalSectionRawMutex, FaultCode>, | ||
) { | ||
loop { | ||
match select(recved.wait(), Timer::after_secs(4)).await { | ||
embassy_futures::select::Either::First(_) => continue, | ||
embassy_futures::select::Either::Second(_) => { | ||
fault.signal(FaultCode::BmsCanMonitorFault) | ||
} | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
use defmt::{trace, unwrap, warn}; | ||
use embassy_futures::select; | ||
use embassy_futures::select::select; | ||
use embassy_stm32::can::{ | ||
filter::{BankConfig, ListEntry16}, | ||
Can, Frame, StandardId, | ||
}; | ||
use embassy_sync::{ | ||
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex}, | ||
channel::Receiver, | ||
signal::Signal, | ||
}; | ||
|
||
#[embassy_executor::task] | ||
pub async fn can_handler( | ||
mut can: Can<'static>, | ||
bms_callback: &'static Signal<CriticalSectionRawMutex, Frame>, | ||
dti_callback: &'static Signal<CriticalSectionRawMutex, Frame>, | ||
recv: Receiver<'static, ThreadModeRawMutex, Frame, 25>, | ||
) { | ||
can.set_bitrate(500_000); | ||
can.modify_filters().enable_bank( | ||
0, | ||
embassy_stm32::can::Fifo::Fifo0, | ||
BankConfig::List16([ | ||
ListEntry16::data_frames_with_id(unwrap!(StandardId::new(0x156))), | ||
ListEntry16::data_frames_with_id(unwrap!(StandardId::new(0x416))), | ||
ListEntry16::data_frames_with_id(unwrap!(StandardId::new(0x1))), // TODO needed? | ||
ListEntry16::data_frames_with_id(unwrap!(StandardId::new(0x2))), | ||
]), | ||
); | ||
can.enable().await; | ||
|
||
loop { | ||
match select(recv.receive(), can.read()).await { | ||
select::Either::First(frame) => { | ||
trace!("Sending frame: {}", frame); | ||
can.write(&frame).await; | ||
} | ||
select::Either::Second(res) => match res { | ||
Ok(got) => match got.frame.header().id() { | ||
embassy_stm32::can::Id::Standard(header) => match header.as_raw() { | ||
0x416 => dti_callback.signal(got.frame), | ||
0x156 => bms_callback.signal(got.frame), | ||
_ => warn!("Ignored message of id {}", header.as_raw()), | ||
}, | ||
embassy_stm32::can::Id::Extended(header) => { | ||
warn!("Ignored message of ext. id {}", header.as_raw()) | ||
} | ||
}, | ||
Err(err) => warn!("Bus error! {}", err), | ||
}, | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use defmt::{debug, unwrap, warn}; | ||
use embassy_futures::select::select; | ||
use embassy_stm32::can::{Frame, StandardId}; | ||
use embassy_sync::{ | ||
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex}, | ||
channel::Sender, | ||
signal::Signal, | ||
}; | ||
use embassy_time::Timer; | ||
|
||
use crate::FaultCode; | ||
|
||
#[embassy_executor::task] | ||
pub async fn fault_handler( | ||
can_send: Sender<'static, ThreadModeRawMutex, Frame, 25>, | ||
fault: &'static Signal<CriticalSectionRawMutex, FaultCode>, | ||
) { | ||
let mut last_fault = FaultCode::FaultsClear; | ||
|
||
let status_id: StandardId = unwrap!(StandardId::new(0x502)); | ||
|
||
let mut fault_bits: [u8; 5] = [0u8; 5]; | ||
|
||
loop { | ||
last_fault = match select(fault.wait(), Timer::after_millis(250)).await { | ||
embassy_futures::select::Either::First(event) => { | ||
match event.get_severity() { | ||
crate::FaultSeverity::Defcon1 | ||
| crate::FaultSeverity::Defcon2 | ||
| crate::FaultSeverity::Defcon3 => todo!("Fault"), | ||
crate::FaultSeverity::Defcon4 => warn!("Non critical fault!"), | ||
crate::FaultSeverity::Defcon5 => debug!("Faults clear!"), | ||
} | ||
event | ||
} | ||
embassy_futures::select::Either::Second(_) => last_fault, | ||
}; | ||
|
||
fault_bits[3..4].copy_from_slice(&(last_fault.get_severity() as u8).to_be_bytes()); | ||
fault_bits[0..3].copy_from_slice(&(last_fault as u32).to_be_bytes()); | ||
|
||
can_send | ||
.send(unwrap!(Frame::new_data(status_id, &fault_bits))) | ||
.await; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#![no_std] | ||
|
||
pub mod bms; | ||
pub mod can_handler; | ||
pub mod fault; | ||
|
||
pub type SharedI2c = embassy_sync::mutex::Mutex< | ||
embassy_sync::blocking_mutex::raw::NoopRawMutex, | ||
embassy_stm32::i2c::I2c<'static, embassy_stm32::mode::Async>, | ||
>; | ||
|
||
#[derive(Copy, Clone)] | ||
pub enum FunctionalType { | ||
READY, | ||
/* F means functional */ | ||
FPit, | ||
FPerformance, | ||
FEfficiency, | ||
REVERSE, | ||
FAULTED, | ||
} | ||
#[derive(Copy, Clone)] | ||
pub enum NeroType { | ||
OFF, | ||
PIT, //SPEED_LIMITIED | ||
PERFORMANCE, //AUTOCROSS | ||
EFFICIENCY, //ENDURANCE | ||
DEBUG, | ||
CONFIGURATION, | ||
FlappyBird, | ||
EXIT, | ||
} | ||
#[derive(Copy, Clone)] | ||
pub enum StateTransition { | ||
Functional(FunctionalType), | ||
Nero(NeroType), | ||
} | ||
|
||
// TODO: this is a breaking change and is also ugly and non-exhuastive in terms of IDs | ||
// However it is centralized which is better than the C impl | ||
|
||
pub enum FaultSeverity { | ||
Defcon1 = 1, | ||
Defcon2 = 2, | ||
Defcon3 = 3, | ||
Defcon4 = 4, | ||
Defcon5 = 5, | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub enum FaultCode { | ||
FaultsClear = 0x0, | ||
BmsCanMonitorFault = 0x800, | ||
} | ||
|
||
impl FaultCode { | ||
fn get_severity(&self) -> FaultSeverity { | ||
match self { | ||
FaultCode::FaultsClear => FaultSeverity::Defcon5, | ||
FaultCode::BmsCanMonitorFault => FaultSeverity::Defcon4, | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
#![no_std] | ||
#![no_main] | ||
|
||
use core::fmt::Write; | ||
|
||
use cerberus::{bms, can_handler, fault, FaultCode, SharedI2c, StateTransition}; | ||
use cortex_m::{peripheral::SCB, singleton}; | ||
use cortex_m_rt::{exception, ExceptionFrame}; | ||
use defmt::{info, unwrap, warn}; | ||
use embassy_executor::Spawner; | ||
use embassy_stm32::{ | ||
adc::{Adc, SampleTime, Sequence}, | ||
bind_interrupts, | ||
can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}, | ||
i2c::{self, I2c}, | ||
peripherals::CAN1, | ||
time::Hertz, | ||
}; | ||
use embassy_stm32::{ | ||
can::Frame, | ||
gpio::{Level, Output, Speed}, | ||
peripherals, | ||
usart::{self, Uart}, | ||
wdg::IndependentWatchdog, | ||
Config, | ||
}; | ||
use embassy_sync::{ | ||
blocking_mutex::raw::{CriticalSectionRawMutex, ThreadModeRawMutex}, | ||
channel::Channel, | ||
mutex::Mutex, | ||
signal::Signal, | ||
}; | ||
use embassy_time::Timer; | ||
use heapless::String; | ||
use static_cell::StaticCell; | ||
use {defmt_rtt as _, panic_probe as _}; | ||
|
||
bind_interrupts!(struct IrqsCAN { | ||
CAN1_RX0 => Rx0InterruptHandler<CAN1>; | ||
CAN1_RX1 => Rx1InterruptHandler<CAN1>; | ||
CAN1_SCE => SceInterruptHandler<CAN1>; | ||
CAN1_TX => TxInterruptHandler<CAN1>; | ||
}); | ||
|
||
bind_interrupts!(struct IrqsUsart { | ||
USART3 => usart::InterruptHandler<peripherals::USART3>; | ||
}); | ||
|
||
bind_interrupts!(struct IrqsI2c1 { | ||
I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>; | ||
I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>; | ||
}); | ||
|
||
bind_interrupts!(struct IrqsI2c2 { | ||
I2C2_EV => i2c::EventInterruptHandler<peripherals::I2C2>; | ||
I2C2_ER => i2c::ErrorInterruptHandler<peripherals::I2C2>; | ||
}); | ||
|
||
static CAN_CHANNEL: Channel<ThreadModeRawMutex, Frame, 25> = Channel::new(); | ||
|
||
static CURRENT_STATE: Signal<CriticalSectionRawMutex, StateTransition> = Signal::new(); | ||
static FAULT: Signal<CriticalSectionRawMutex, FaultCode> = Signal::new(); | ||
|
||
static BMS_CALLBACK: Signal<CriticalSectionRawMutex, Frame> = Signal::new(); | ||
static DTI_CALLBACK: Signal<CriticalSectionRawMutex, Frame> = Signal::new(); | ||
|
||
#[embassy_executor::main] | ||
async fn main(spawner: Spawner) -> ! { | ||
info!("Initializing Cerberus..."); | ||
|
||
let mut p = embassy_stm32::init(Config::default()); | ||
|
||
let can = Can::new(p.CAN1, p.PA11, p.PA12, IrqsCAN); | ||
if let Err(err) = spawner.spawn(can_handler::can_handler( | ||
can, | ||
&BMS_CALLBACK, | ||
&DTI_CALLBACK, | ||
CAN_CHANNEL.receiver(), | ||
)) { | ||
warn!("Could not spawn CAN task: {}", err); | ||
} | ||
|
||
if let Err(err) = spawner.spawn(bms::bms_handler(&BMS_CALLBACK, &FAULT)) { | ||
warn!("Could not spawn BMS task: {}", err); | ||
} | ||
|
||
if let Err(err) = spawner.spawn(fault::fault_handler(CAN_CHANNEL.sender(), &FAULT)) { | ||
warn!("Could not spawn fault task: {}", err); | ||
} | ||
|
||
static I2C_BUS_1: StaticCell<SharedI2c> = StaticCell::new(); | ||
let i2c_1 = I2c::new( | ||
p.I2C1, | ||
p.PB6, | ||
p.PB7, | ||
IrqsI2c1, | ||
p.DMA1_CH6, | ||
p.DMA1_CH0, | ||
Hertz(100_000), | ||
i2c::Config::default(), | ||
); | ||
let i2c_bus_1 = I2C_BUS_1.init(Mutex::new(i2c_1)); | ||
|
||
static I2C_BUS_2: StaticCell<SharedI2c> = StaticCell::new(); | ||
let i2c_2 = I2c::new( | ||
p.I2C2, | ||
p.PB10, | ||
p.PB11, | ||
IrqsI2c2, | ||
p.DMA1_CH7, | ||
p.DMA1_CH2, | ||
Hertz(100_000), | ||
i2c::Config::default(), | ||
); | ||
let i2c_bus_2 = I2C_BUS_2.init(Mutex::new(i2c_2)); | ||
|
||
const ADC_BUF_SIZE: usize = 1024; | ||
|
||
let adc1 = Adc::new(p.ADC1); | ||
let adc_data_1 = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]) | ||
.expect("Could not init adc buffer"); | ||
let mut adc1 = adc1.into_ring_buffered(p.DMA2_CH4, adc_data_1); | ||
adc1.set_sample_sequence(Sequence::One, &mut p.PB0, SampleTime::CYCLES112); // | ||
|
||
let adc3 = Adc::new(p.ADC3); | ||
let adc_data_3 = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]) | ||
.expect("Could not init adc buffer"); | ||
let mut adc3 = adc3.into_ring_buffered(p.DMA2_CH0, adc_data_3); | ||
adc3.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112); // | ||
adc3.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112); // | ||
adc3.set_sample_sequence(Sequence::One, &mut p.PA2, SampleTime::CYCLES112); // | ||
adc3.set_sample_sequence(Sequence::One, &mut p.PA3, SampleTime::CYCLES112); // | ||
|
||
let mut usart = Uart::new( | ||
p.USART3, | ||
p.PC11, | ||
p.PC10, | ||
IrqsUsart, | ||
p.DMA1_CH3, | ||
p.DMA1_CH1, | ||
usart::Config::default(), | ||
) | ||
.unwrap(); | ||
let mut s: String<128> = String::new(); | ||
core::write!(&mut s, "Hello DMA World!\r\n",).unwrap(); | ||
unwrap!(usart.write(s.as_bytes()).await); | ||
|
||
let mut watchdog = IndependentWatchdog::new(p.IWDG, 4000000); | ||
watchdog.unleash(); | ||
let mut led_pin = Output::new(p.PC8, Level::Low, Speed::Low); | ||
loop { | ||
info!("Status: Alive"); | ||
led_pin.toggle(); | ||
Timer::after_secs(3).await; | ||
watchdog.pet(); | ||
} | ||
} | ||
|
||
#[exception] | ||
unsafe fn HardFault(_frame: &ExceptionFrame) -> ! { | ||
SCB::sys_reset() // <- you could do something other than reset | ||
} |
This file contains 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
Oops, something went wrong.