Changed to a cargo workspace
Added postcard protocol definitions
This commit is contained in:
parent
2cc6651aca
commit
833e4d5a56
|
@ -1,19 +0,0 @@
|
||||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
|
||||||
# TODO(2) replace `$CHIP` with your chip's name (see `probe-run --list-chips` output)
|
|
||||||
runner = "probe-run --chip STM32F103CB"
|
|
||||||
rustflags = [
|
|
||||||
"-C", "linker=flip-link",
|
|
||||||
"-C", "link-arg=-Tlink.x",
|
|
||||||
"-C", "link-arg=-Tdefmt.x",
|
|
||||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
|
||||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
|
||||||
"-C", "link-arg=--nmagic",
|
|
||||||
]
|
|
||||||
|
|
||||||
[build]
|
|
||||||
target = "thumbv7m-none-eabi" # Cortex-M3
|
|
||||||
|
|
||||||
|
|
||||||
[alias]
|
|
||||||
rb = "run --bin"
|
|
||||||
rrb = "run --release --bin"
|
|
63
Cargo.toml
63
Cargo.toml
|
@ -1,61 +1,8 @@
|
||||||
[package]
|
[workspace]
|
||||||
# TODO(1) fix `authors` and `name` if you didn't use `cargo-generate`
|
resolver = "2"
|
||||||
authors = ["sebastian <sebastian@sebastians-site.de>"]
|
|
||||||
name = "cheapsdp"
|
|
||||||
edition = "2018"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
members = [
|
||||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
"firmware", "protocol",
|
||||||
defmt = { version = "0.3", features = ["encoding-rzcobs"] }
|
]
|
||||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
|
||||||
rtic = { version = "2.0.1", features = [ "thumbv7-backend" ] }
|
|
||||||
defmt-rtt = "0.4"
|
|
||||||
embedded-hal = "0.2.3"
|
|
||||||
stm32f1xx-hal = { version = "0.10.0", features = ["stm32f103", "rt", "medium"] }
|
|
||||||
nb = "1.0.0"
|
|
||||||
arrayvec = { version = "0.7.0", default-features = false }
|
|
||||||
systick-monotonic = "1.0.0"
|
|
||||||
rtic-monotonics = {version = "1.4.1", features = ["cortex-m-systick"] }
|
|
||||||
usb-device = "0.2.8"
|
|
||||||
usbd-serial = "0.1.1"
|
|
||||||
rtic-sync = {version = "1.1.1"}
|
|
||||||
ufmt = "0.2.0"
|
|
||||||
|
|
||||||
# cargo build/run
|
|
||||||
[profile.dev]
|
|
||||||
codegen-units = 1
|
|
||||||
debug = 2
|
|
||||||
debug-assertions = true # <-
|
|
||||||
incremental = false
|
|
||||||
opt-level = 'z' # <-
|
|
||||||
overflow-checks = true # <-
|
|
||||||
|
|
||||||
# cargo test
|
|
||||||
[profile.test]
|
|
||||||
codegen-units = 1
|
|
||||||
debug = 2
|
|
||||||
debug-assertions = true # <-
|
|
||||||
incremental = false
|
|
||||||
opt-level = 3 # <-
|
|
||||||
overflow-checks = true # <-
|
|
||||||
|
|
||||||
# cargo build/run --release
|
|
||||||
[profile.release]
|
|
||||||
codegen-units = 1
|
|
||||||
debug = 2
|
|
||||||
debug-assertions = false # <-
|
|
||||||
incremental = false
|
|
||||||
lto = 'fat'
|
|
||||||
opt-level = 3 # <-
|
|
||||||
overflow-checks = false # <-
|
|
||||||
|
|
||||||
# cargo test --release
|
|
||||||
[profile.bench]
|
|
||||||
codegen-units = 1
|
|
||||||
debug = 2
|
|
||||||
debug-assertions = false # <-
|
|
||||||
incremental = false
|
|
||||||
lto = 'fat'
|
|
||||||
opt-level = 3 # <-
|
|
||||||
overflow-checks = false # <-
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
# TODO(2) replace `$CHIP` with your chip's name (see `probe-run --list-chips` output)
|
||||||
|
runner = "probe-run --chip STM32F103CB"
|
||||||
|
rustflags = [
|
||||||
|
"-C", "linker=flip-link",
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
"-C", "link-arg=-Tdefmt.x",
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# cargo build/run
|
||||||
|
[profile.dev]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = true # <-
|
||||||
|
incremental = false
|
||||||
|
opt-level = 'z' # <-
|
||||||
|
overflow-checks = true # <-
|
||||||
|
|
||||||
|
# cargo test
|
||||||
|
[profile.test]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = true # <-
|
||||||
|
incremental = false
|
||||||
|
opt-level = 3 # <-
|
||||||
|
overflow-checks = true # <-
|
||||||
|
|
||||||
|
# cargo build/run --release
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = false # <-
|
||||||
|
incremental = false
|
||||||
|
lto = 'fat'
|
||||||
|
opt-level = 3 # <-
|
||||||
|
overflow-checks = false # <-
|
||||||
|
|
||||||
|
# cargo test --release
|
||||||
|
[profile.bench]
|
||||||
|
codegen-units = 1
|
||||||
|
debug = 2
|
||||||
|
debug-assertions = false # <-
|
||||||
|
incremental = false
|
||||||
|
lto = 'fat'
|
||||||
|
opt-level = 3 # <-
|
||||||
|
overflow-checks = false # <-
|
|
@ -0,0 +1,27 @@
|
||||||
|
cargo-features = ["per-package-target"]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
# TODO(1) fix `authors` and `name` if you didn't use `cargo-generate`
|
||||||
|
authors = ["sebastian <sebastian@sebastians-site.de>"]
|
||||||
|
name = "cheapsdo-firmware"
|
||||||
|
edition = "2021"
|
||||||
|
version = "0.1.0"
|
||||||
|
default-target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||||
|
defmt = { version = "0.3", features = ["encoding-rzcobs"] }
|
||||||
|
defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] }
|
||||||
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
|
rtic = { version = "2.0.1", features = [ "thumbv7-backend" ] }
|
||||||
|
defmt-rtt = "0.4"
|
||||||
|
embedded-hal = "0.2.3"
|
||||||
|
stm32f1xx-hal = { version = "0.10.0", features = ["stm32f103", "rt", "medium"] }
|
||||||
|
nb = "1.0.0"
|
||||||
|
systick-monotonic = "1.0.0"
|
||||||
|
rtic-monotonics = {version = "1.4.1", features = ["cortex-m-systick"] }
|
||||||
|
usb-device = "0.2.8"
|
||||||
|
usbd-serial = "0.1.1"
|
||||||
|
cheapsdo-protocol = { path = "../protocol" }
|
||||||
|
postcard = {version = "1.0.8", features = ["use-defmt"]}
|
||||||
|
heapless = {version = "0.8.0", features = ["defmt-03"]}
|
|
@ -1,6 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![feature(slice_split_once)]
|
||||||
use defmt_rtt as _; // global logger
|
use defmt_rtt as _; // global logger
|
||||||
|
|
||||||
use panic_probe as _;
|
use panic_probe as _;
|
||||||
|
@ -18,10 +19,7 @@ use rtic::app;
|
||||||
#[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [SPI3])]
|
#[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [SPI3])]
|
||||||
mod app {
|
mod app {
|
||||||
|
|
||||||
use core::fmt::Write;
|
|
||||||
|
|
||||||
use cortex_m::asm::delay;
|
use cortex_m::asm::delay;
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
|
||||||
use rtic_monotonics::systick::*;
|
use rtic_monotonics::systick::*;
|
||||||
|
|
||||||
use stm32f1xx_hal::{
|
use stm32f1xx_hal::{
|
||||||
|
@ -37,6 +35,13 @@ mod app {
|
||||||
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
|
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
|
||||||
use usb_device::prelude::*;
|
use usb_device::prelude::*;
|
||||||
|
|
||||||
|
use heapless::Vec;
|
||||||
|
use postcard::{from_bytes_cobs, to_vec_cobs};
|
||||||
|
|
||||||
|
use cheapsdo_protocol::{*, DeviceMessage};
|
||||||
|
|
||||||
|
const USB_BUFFER_SIZE : usize = 64;
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
board_led: gpioc::PC13<Output<PushPull>>,
|
board_led: gpioc::PC13<Output<PushPull>>,
|
||||||
|
@ -51,6 +56,7 @@ mod app {
|
||||||
serial: usbd_serial::SerialPort<'static, UsbBusType>,
|
serial: usbd_serial::SerialPort<'static, UsbBusType>,
|
||||||
current_freq: f64,
|
current_freq: f64,
|
||||||
short_avg: f64,
|
short_avg: f64,
|
||||||
|
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TARGET_FREQ: f64 = 10.0f64;
|
const TARGET_FREQ: f64 = 10.0f64;
|
||||||
|
@ -193,7 +199,6 @@ mod app {
|
||||||
.device_class(usbd_serial::USB_CLASS_CDC)
|
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
update_pwm::spawn().unwrap();
|
update_pwm::spawn().unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -202,6 +207,7 @@ mod app {
|
||||||
usb_dev,
|
usb_dev,
|
||||||
current_freq: 0.0f64,
|
current_freq: 0.0f64,
|
||||||
short_avg: 0.0f64,
|
short_avg: 0.0f64,
|
||||||
|
buffer: Vec::new(),
|
||||||
},
|
},
|
||||||
Local {
|
Local {
|
||||||
board_led,
|
board_led,
|
||||||
|
@ -212,6 +218,7 @@ mod app {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const WINDOW_LEN: usize = 100;
|
const WINDOW_LEN: usize = 100;
|
||||||
|
|
||||||
#[task(local=[tim2, tim3, pwm, board_led], shared=[current_freq, short_avg])]
|
#[task(local=[tim2, tim3, pwm, board_led], shared=[current_freq, short_avg])]
|
||||||
|
@ -287,7 +294,6 @@ mod app {
|
||||||
*avg = short_avg;
|
*avg = short_avg;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
let diff = (TARGET_FREQ - short_avg) * 1_000_000.0;
|
let diff = (TARGET_FREQ - short_avg) * 1_000_000.0;
|
||||||
if diff > 1.0 || diff < -1.0 {
|
if diff > 1.0 || diff < -1.0 {
|
||||||
cur_pwm += diff as i32 * 15;
|
cur_pwm += diff as i32 * 15;
|
||||||
|
@ -307,52 +313,97 @@ mod app {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, current_freq, short_avg])]
|
#[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, buffer, current_freq, short_avg])]
|
||||||
fn usb_tx(cx: usb_tx::Context) {
|
fn usb_tx(cx: usb_tx::Context) {
|
||||||
let mut usb_dev = cx.shared.usb_dev;
|
let mut usb_dev = cx.shared.usb_dev;
|
||||||
let mut serial = cx.shared.serial;
|
let mut serial = cx.shared.serial;
|
||||||
|
let mut buffer = cx.shared.buffer;
|
||||||
let mut current_freq = cx.shared.current_freq;
|
let mut current_freq = cx.shared.current_freq;
|
||||||
let mut short_avg = cx.shared.short_avg;
|
let mut short_avg = cx.shared.short_avg;
|
||||||
|
|
||||||
(&mut usb_dev, &mut serial, &mut current_freq, &mut short_avg).lock(|usb_dev, serial, current_freq, short_avg| {
|
(
|
||||||
usb_poll(usb_dev, serial, current_freq, short_avg);
|
&mut usb_dev,
|
||||||
});
|
&mut serial,
|
||||||
|
&mut buffer,
|
||||||
|
&mut current_freq,
|
||||||
|
&mut short_avg,
|
||||||
|
)
|
||||||
|
.lock(|usb_dev, serial, buffer, current_freq, short_avg| {
|
||||||
|
usb_poll(usb_dev, serial, buffer, current_freq, short_avg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, current_freq, short_avg])]
|
#[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, buffer, current_freq, short_avg])]
|
||||||
fn usb_rx0(cx: usb_rx0::Context) {
|
fn usb_rx0(cx: usb_rx0::Context) {
|
||||||
let mut usb_dev = cx.shared.usb_dev;
|
let mut usb_dev = cx.shared.usb_dev;
|
||||||
let mut serial = cx.shared.serial;
|
let mut serial = cx.shared.serial;
|
||||||
|
let mut buffer = cx.shared.buffer;
|
||||||
let mut current_freq = cx.shared.current_freq;
|
let mut current_freq = cx.shared.current_freq;
|
||||||
let mut short_avg = cx.shared.short_avg;
|
let mut short_avg = cx.shared.short_avg;
|
||||||
|
|
||||||
(&mut usb_dev, &mut serial, &mut current_freq, &mut short_avg).lock(|usb_dev, serial, current_freq, short_avg| {
|
(
|
||||||
usb_poll(usb_dev, serial, current_freq, short_avg);
|
&mut usb_dev,
|
||||||
});
|
&mut serial,
|
||||||
|
&mut buffer,
|
||||||
|
&mut current_freq,
|
||||||
|
&mut short_avg,
|
||||||
|
)
|
||||||
|
.lock(|usb_dev, serial, buffer, current_freq, short_avg| {
|
||||||
|
usb_poll(usb_dev, serial, buffer, current_freq, short_avg);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usb_poll<B: usb_device::bus::UsbBus>(
|
fn usb_poll<B: usb_device::bus::UsbBus>(
|
||||||
usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>,
|
usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>,
|
||||||
serial: &mut usbd_serial::SerialPort<'static, B>,
|
serial: &mut usbd_serial::SerialPort<'static, B>,
|
||||||
current_freq: &mut f64,
|
buffer: &mut Vec<u8, USB_BUFFER_SIZE>,
|
||||||
|
current_freq: &mut f64,
|
||||||
short_avg: &mut f64,
|
short_avg: &mut f64,
|
||||||
) {
|
) {
|
||||||
if !usb_dev.poll(&mut [serial]) {
|
if !usb_dev.poll(&mut [serial]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = [0u8; 8];
|
let mut tmp = [0u8; 16];
|
||||||
|
match serial.read(&mut tmp) {
|
||||||
match serial.read(&mut buf) {
|
|
||||||
Ok(count) if count > 0 => {
|
Ok(count) if count > 0 => {
|
||||||
if buf[0] == b'?' {
|
if buffer.extend_from_slice(&tmp[0..count]).is_err() {
|
||||||
|
buffer.clear();
|
||||||
let mut data = arrayvec::ArrayString::<32>::new();
|
defmt::error!("Buffer overflow while waiting for the end of the packet");
|
||||||
write!(data, "{}|{}\n\r", current_freq, short_avg).unwrap();
|
}
|
||||||
serial.write(data.as_bytes()).unwrap();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some((msg, rest)) = buffer.split_once(|&x| x == 0) {
|
||||||
|
let mut message = [0u8; 128];
|
||||||
|
message.clone_from_slice(msg);
|
||||||
|
let host_msg = from_bytes_cobs::<HostMessage>(&mut message);
|
||||||
|
|
||||||
|
match host_msg {
|
||||||
|
Ok(host_msg) => match host_msg {
|
||||||
|
HostMessage::RequestStatus => {
|
||||||
|
let device_msg = DeviceMessage::Status(StatusMessage{
|
||||||
|
measured_frequency: *current_freq,
|
||||||
|
average_frequency: *short_avg,
|
||||||
|
pwm: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
let bytes = to_vec_cobs::<DeviceMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
|
||||||
|
serial.write(bytes.as_slice()).unwrap();
|
||||||
|
},
|
||||||
|
HostMessage::SetPLLOutputs => {
|
||||||
|
defmt::error!("PLL output is not implemented yet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => defmt::error!("Unable to parse host message: {}", err),
|
||||||
|
};
|
||||||
|
|
||||||
|
*buffer = Vec::<u8, USB_BUFFER_SIZE>::from_slice(rest).unwrap();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "cheapsdo-protocol"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = {version = "1.0.193", default-features = false, features = ["derive"]}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
pub enum DeviceMessage {
|
||||||
|
Status(StatusMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
pub enum HostMessage {
|
||||||
|
RequestStatus,
|
||||||
|
SetPLLOutputs,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
pub struct StatusMessage {
|
||||||
|
pub measured_frequency: f64,
|
||||||
|
pub average_frequency: f64,
|
||||||
|
pub pwm: u16,
|
||||||
|
}
|
Loading…
Reference in New Issue