Added pwm plot

This commit is contained in:
Sebastian 2023-12-24 23:06:03 +01:00
parent c5bec82d59
commit 3673c14cdb
4 changed files with 99 additions and 75 deletions

View File

@ -37,9 +37,9 @@ mod app {
use heapless::Vec; use heapless::Vec;
use postcard::{from_bytes_cobs, to_vec_cobs}; use postcard::{from_bytes_cobs, to_vec_cobs};
use cheapsdo_protocol::{*, DeviceMessage}; use cheapsdo_protocol::{DeviceMessage, HostMessage, StatusMessage};
const USB_BUFFER_SIZE : usize = 64; const USB_BUFFER_SIZE: usize = 64;
#[local] #[local]
struct Local { struct Local {
@ -53,8 +53,7 @@ mod app {
struct Shared { struct Shared {
usb_dev: UsbDevice<'static, UsbBusType>, usb_dev: UsbDevice<'static, UsbBusType>,
serial: usbd_serial::SerialPort<'static, UsbBusType>, serial: usbd_serial::SerialPort<'static, UsbBusType>,
current_freq: f64, device_status: StatusMessage,
short_avg: f64,
buffer: Vec<u8, USB_BUFFER_SIZE>, buffer: Vec<u8, USB_BUFFER_SIZE>,
} }
@ -204,8 +203,7 @@ mod app {
Shared { Shared {
serial, serial,
usb_dev, usb_dev,
current_freq: 0.0f64, device_status: StatusMessage::default(),
short_avg: 0.0f64,
buffer: Vec::new(), buffer: Vec::new(),
}, },
Local { Local {
@ -217,10 +215,9 @@ 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=[device_status])]
async fn update_pwm(mut cx: update_pwm::Context) { async fn update_pwm(mut cx: update_pwm::Context) {
defmt::info!("Update Task started"); defmt::info!("Update Task started");
@ -278,8 +275,8 @@ mod app {
continue; continue;
} }
cx.shared.current_freq.lock(|current_freq| { cx.shared.device_status.lock(|device_status| {
*current_freq = freq; device_status.measured_frequency = freq;
}); });
short_avg += freq / WINDOW_LEN as f64; short_avg += freq / WINDOW_LEN as f64;
@ -289,8 +286,8 @@ mod app {
} }
defmt::info!("short_avg:\t{} MHz", short_avg); defmt::info!("short_avg:\t{} MHz", short_avg);
cx.shared.short_avg.lock(|avg| { cx.shared.device_status.lock(|device_status| {
*avg = short_avg; device_status.average_frequency = short_avg;
}); });
let diff = (TARGET_FREQ - short_avg) * 1_000_000.0; let diff = (TARGET_FREQ - short_avg) * 1_000_000.0;
@ -305,6 +302,10 @@ mod app {
cur_pwm = if cur_pwm < 0 { 0 } else { cur_pwm }; cur_pwm = if cur_pwm < 0 { 0 } else { cur_pwm };
cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm }; cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm };
cx.shared.device_status.lock(|device_status| {
device_status.pwm = cur_pwm as u16;
});
pwm.set_duty(Channel::C1, cur_pwm as u16); pwm.set_duty(Channel::C1, cur_pwm as u16);
defmt::info!("pwm:\t{}", cur_pwm); defmt::info!("pwm:\t{}", cur_pwm);
@ -312,52 +313,39 @@ mod app {
} }
} }
#[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, buffer, current_freq, short_avg])] #[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, buffer, device_status])]
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 buffer = cx.shared.buffer;
let mut current_freq = cx.shared.current_freq; let mut device_status = cx.shared.device_status;
let mut short_avg = cx.shared.short_avg;
( (&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock(
&mut usb_dev, |usb_dev, serial, buffer, device_status| {
&mut serial, usb_poll(usb_dev, serial, buffer, device_status);
&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, buffer, current_freq, short_avg])] #[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, buffer, device_status])]
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 buffer = cx.shared.buffer;
let mut current_freq = cx.shared.current_freq; let mut device_status = cx.shared.device_status;
let mut short_avg = cx.shared.short_avg;
( (&mut usb_dev, &mut serial, &mut buffer, &mut device_status).lock(
&mut usb_dev, |usb_dev, serial, buffer, device_status| {
&mut serial, usb_poll(usb_dev, serial, buffer, device_status);
&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>,
buffer: &mut Vec<u8, USB_BUFFER_SIZE>, buffer: &mut Vec<u8, USB_BUFFER_SIZE>,
current_freq: &mut f64, device_status: &StatusMessage,
short_avg: &mut f64,
) { ) {
if !usb_dev.poll(&mut [serial]) { if !usb_dev.poll(&mut [serial]) {
return; return;
@ -376,7 +364,7 @@ mod app {
loop { loop {
if let Some(idx) = buffer.iter().position(|&x| x == 0) { if let Some(idx) = buffer.iter().position(|&x| x == 0) {
let (msg, rest) = buffer.split_at(idx+1); let (msg, rest) = buffer.split_at(idx + 1);
let mut message = [0u8; 128]; let mut message = [0u8; 128];
message[0..msg.len()].clone_from_slice(msg); message[0..msg.len()].clone_from_slice(msg);
@ -385,19 +373,15 @@ mod app {
match host_msg { match host_msg {
Ok(host_msg) => match host_msg { Ok(host_msg) => match host_msg {
HostMessage::RequestStatus => { HostMessage::RequestStatus => {
let device_msg = DeviceMessage::Status(StatusMessage{ let device_msg = DeviceMessage::Status(device_status.clone());
measured_frequency: *current_freq, let bytes =
average_frequency: *short_avg, to_vec_cobs::<DeviceMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
pwm: 0,
});
let bytes = to_vec_cobs::<DeviceMessage, USB_BUFFER_SIZE>(&device_msg).unwrap();
serial.write(bytes.as_slice()).unwrap(); serial.write(bytes.as_slice()).unwrap();
},
HostMessage::SetPLLOutputs => {
defmt::error!("PLL output is not implemented yet")
} }
} HostMessage::SetPLLOutputs => {
defmt::error!("PLL output is not implemented yet")
}
},
Err(err) => defmt::error!("Unable to parse host message: {}", err), Err(err) => defmt::error!("Unable to parse host message: {}", err),
}; };

View File

@ -0,0 +1,12 @@
pub fn frequency(freq: f64) -> String {
let rest = (freq * 1_000_000_000.0) as u64;
let milli_hz = rest % 1000;
let rest = rest / 1000;
let hz = rest % 1000;
let rest = rest / 1000;
let khz = rest % 1000;
let rest = rest / 1000;
let mhz = rest % 1000;
format!("{:02}.{:03} {:03} {:03} MHz", mhz, khz, hz, milli_hz)
}

View File

@ -11,6 +11,8 @@ use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
use cheapsdo_protocol::*; use cheapsdo_protocol::*;
use postcard::{from_bytes_cobs, to_stdvec_cobs}; use postcard::{from_bytes_cobs, to_stdvec_cobs};
mod formatters;
fn main() -> Result<(), eframe::Error> { fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions { let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default(), viewport: egui::ViewportBuilder::default(),
@ -27,6 +29,7 @@ struct SharedState {
device_state: StatusMessage, device_state: StatusMessage,
average_points: Vec<[f64; 2]>, average_points: Vec<[f64; 2]>,
measured_points: Vec<[f64; 2]>, measured_points: Vec<[f64; 2]>,
pwm_points: Vec<[f64; 2]>,
} }
impl Default for SharedState { impl Default for SharedState {
@ -35,6 +38,7 @@ impl Default for SharedState {
device_state: StatusMessage::default(), device_state: StatusMessage::default(),
average_points: Vec::<[f64; 2]>::new(), average_points: Vec::<[f64; 2]>::new(),
measured_points: Vec::<[f64; 2]>::new(), measured_points: Vec::<[f64; 2]>::new(),
pwm_points: Vec::<[f64; 2]>::new(),
} }
} }
} }
@ -100,38 +104,62 @@ impl eframe::App for CheapsdoControl {
{ {
let mut state = self.shared_state.lock().unwrap(); let mut state = self.shared_state.lock().unwrap();
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label(format!( ui.label(
"Measured: {}", egui::RichText::new(format!(
state.device_state.measured_frequency "Measured: {}",
)); formatters::frequency(state.device_state.measured_frequency)
ui.label(format!("Average: {}", state.device_state.average_frequency)); ))
.family(egui::FontFamily::Monospace)
.size(20.0),
);
ui.add_space(100.0);
ui.label(
egui::RichText::new(format!(
"Average: {}",
formatters::frequency(state.device_state.average_frequency)
))
.family(egui::FontFamily::Monospace)
.size(20.0),
);
}); });
ui.add_space(20.0);
let average_line = Line::new(PlotPoints::new(state.average_points.clone())); let average_line = Line::new(PlotPoints::new(state.average_points.clone()));
let measured_line = Line::new(PlotPoints::new(state.measured_points.clone())); let measured_line = Line::new(PlotPoints::new(state.measured_points.clone()));
Plot::new("my_plot") Plot::new("frequency_plot")
.view_aspect(4.0)
.allow_zoom(false) .allow_zoom(false)
.allow_scroll(false) .allow_scroll(false)
.allow_drag(false) .allow_drag(false)
.allow_boxed_zoom(false) .allow_boxed_zoom(false)
.y_axis_width(20) .y_axis_width(12)
.y_axis_formatter(|val, _, _| { .y_axis_formatter(|val, _, _| formatters::frequency(val))
let rest = (val * 1_000_000_000.0) as u64; .label_formatter(|name, value| {
let milli_hz = rest % 1000; format!("{}: {}", name, formatters::frequency(value.y))
let rest = rest / 1000;
let hz = rest % 1000;
let rest = rest / 1000;
let khz = rest % 1000;
let rest = rest / 1000;
let mhz = rest % 1000;
format!("{:02}.{:03} {:03} {:03}", mhz, khz, hz, milli_hz)
}) })
.show(ui, |plot_ui| { .show(ui, |plot_ui| {
plot_ui.set_auto_bounds([true, true].into()); plot_ui.set_auto_bounds([true, true].into());
plot_ui.line(average_line); plot_ui.line(average_line);
//plot_ui.line(measured_line); //plot_ui.line(measured_line);
}) });
ui.add_space(20.0);
let pwm_line = Line::new(PlotPoints::new(state.pwm_points.clone()));
Plot::new("pwm_plot")
.view_aspect(4.0)
.allow_zoom(false)
.allow_scroll(false)
.allow_drag(false)
.allow_boxed_zoom(false)
.y_axis_width(12)
.show(ui, |plot_ui| {
plot_ui.set_auto_bounds([true, true].into());
plot_ui.line(pwm_line);
});
} }
}); });
} }
@ -165,6 +193,7 @@ fn poll_device(port: String, state: Arc<Mutex<SharedState>>, ctx: egui::Context)
state state
.measured_points .measured_points
.push([x, status_msg.measured_frequency]); .push([x, status_msg.measured_frequency]);
state.pwm_points.push([x, status_msg.pwm as f64]);
state.device_state = status_msg; state.device_state = status_msg;
ctx.request_repaint() ctx.request_repaint()

View File

@ -1,6 +1,6 @@
#![no_std] #![no_std]
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[derive(Serialize, Deserialize, Debug, PartialEq)]
pub enum DeviceMessage { pub enum DeviceMessage {
@ -13,14 +13,13 @@ pub enum HostMessage {
SetPLLOutputs, SetPLLOutputs,
} }
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct StatusMessage { pub struct StatusMessage {
pub measured_frequency: f64, pub measured_frequency: f64,
pub average_frequency: f64, pub average_frequency: f64,
pub pwm: u16, pub pwm: u16,
} }
impl Default for StatusMessage { impl Default for StatusMessage {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -29,4 +28,4 @@ impl Default for StatusMessage {
pwm: 0u16, pwm: 0u16,
} }
} }
} }