From 2cc6651aca2b1a36ee35af0126b526cbffa5dc6c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 20 Dec 2023 13:28:25 +0100 Subject: [PATCH] Added PoC serial interface and host application --- Cargo.toml | 9 ++-- scripts/plot.py | 37 +++++++++++++ src/main.rs | 141 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 166 insertions(+), 21 deletions(-) create mode 100644 scripts/plot.py diff --git a/Cargo.toml b/Cargo.toml index 39a5e52..e4f335f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,16 +8,19 @@ version = "0.1.0" [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 = {version = "0.2.3"} +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} +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] diff --git a/scripts/plot.py b/scripts/plot.py new file mode 100644 index 0000000..deddc7e --- /dev/null +++ b/scripts/plot.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import sys +import time +import serial +import matplotlib.pyplot as plt + + +def main(): + ser = serial.Serial(sys.argv[1]) + + + short_term = [] + long_term = [] + + while True: + ser.write(b"?") + + line = ser.readline() + line = line.strip() + + f1, f2 = line.split(b'|') + short_term += [float(f1)] + long_term += [float(f2)] + + print(float(f2)) + + plt.clf() + plt.ylim((10 - 0.000_001, 10 + 0.000_001)) + plt.plot(short_term) + plt.plot(long_term) + plt.draw() + plt.pause(1.0) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9278e9b..a296cac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,9 +18,12 @@ use rtic::app; #[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [SPI3])] mod app { + use core::fmt::Write; + + use cortex_m::asm::delay; + use embedded_hal::digital::v2::OutputPin; use rtic_monotonics::systick::*; - use embedded_hal::digital::v2::OutputPin; use stm32f1xx_hal::{ gpio::{self, gpioa, gpioc, Alternate, Output, PushPull}, pac, @@ -31,6 +34,9 @@ mod app { timer::{self, Channel, PwmHz, Tim4NoRemap}, }; + use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType}; + use usb_device::prelude::*; + #[local] struct Local { board_led: gpioc::PC13>, @@ -40,13 +46,18 @@ mod app { } #[shared] - struct Shared {} + struct Shared { + usb_dev: UsbDevice<'static, UsbBusType>, + serial: usbd_serial::SerialPort<'static, UsbBusType>, + current_freq: f64, + short_avg: f64, + } - const target_freq: f64 = 10.0f64; + const TARGET_FREQ: f64 = 10.0f64; #[init] fn init(cx: init::Context) -> (Shared, Local) { - let mut rcc = cx.device.RCC.constrain(); + let rcc = cx.device.RCC.constrain(); let mut flash = cx.device.FLASH.constrain(); let clocks = rcc @@ -56,6 +67,7 @@ mod app { .pclk1(24.MHz()) .freeze(&mut flash.acr); + assert!(clocks.usbclk_valid()); defmt::info!("Clock Setup done"); // Initialize the systick interrupt & obtain the token to prove that we did @@ -148,10 +160,49 @@ mod app { defmt::info!("Timer Setup done"); + static mut USB_BUS: Option> = None; + + let mut gpioa = cx.device.GPIOA.split(); + + let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh); + usb_dp.set_low(); + delay(clocks.sysclk().raw() / 100); + + let usb_dm = gpioa.pa11; + let usb_dp = usb_dp.into_floating_input(&mut gpioa.crh); + + let usb = Peripheral { + usb: cx.device.USB, + pin_dm: usb_dm, + pin_dp: usb_dp, + }; + + unsafe { + USB_BUS.replace(UsbBus::new(usb)); + } + + let serial = usbd_serial::SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() }); + + let usb_dev = UsbDeviceBuilder::new( + unsafe { USB_BUS.as_ref().unwrap() }, + UsbVidPid(0x16c0, 0x27dd), + ) + .manufacturer("Arbitrary Precision Instruments") + .product("cheapsdo") + .serial_number("1337") + .device_class(usbd_serial::USB_CLASS_CDC) + .build(); + + update_pwm::spawn().unwrap(); ( - Shared {}, + Shared { + serial, + usb_dev, + current_freq: 0.0f64, + short_avg: 0.0f64, + }, Local { board_led, tim2, @@ -161,10 +212,10 @@ mod app { ) } - const WINDOW_LEN : usize = 60; + const WINDOW_LEN: usize = 100; - #[task(local=[tim2, tim3, pwm, board_led])] - async fn update_pwm(cx: update_pwm::Context) { + #[task(local=[tim2, tim3, pwm, board_led], shared=[current_freq, short_avg])] + async fn update_pwm(mut cx: update_pwm::Context) { defmt::info!("Update Task started"); let tim2 = cx.local.tim2; @@ -172,7 +223,6 @@ mod app { let pwm = cx.local.pwm; let board_led = cx.local.board_led; - let mut avg = 10f64; let max_pwm = pwm.get_max_duty() as i32; let mut cur_pwm = max_pwm / 2; @@ -187,6 +237,7 @@ mod app { loop { let mut short_avg = 0.0f64; + let mut last_freq = 10.0f64; let mut count = 0; while count < WINDOW_LEN { @@ -214,28 +265,35 @@ mod app { let freq = (diff_ic as f64) / 1_000_000f64; defmt::info!("freq:\t{} MHz", freq); - let diff = freq - avg; + let diff = freq - last_freq; + last_freq = freq; if diff > 0.000_100 || diff < -0.000_100 { defmt::info!("Out of range, dropping sample."); continue; } - short_avg += freq / WINDOW_LEN as f64; - avg = avg * 0.999 + freq * 0.001; + cx.shared.current_freq.lock(|current_freq| { + *current_freq = freq; + }); + short_avg += freq / WINDOW_LEN as f64; count += 1; board_led.toggle(); } defmt::info!("short_avg:\t{} MHz", short_avg); + cx.shared.short_avg.lock(|avg| { + *avg = short_avg; + }); - let diff = (10.0 - short_avg) * 1_000_000.0; + + let diff = (TARGET_FREQ - short_avg) * 1_000_000.0; if diff > 1.0 || diff < -1.0 { - cur_pwm += diff as i32 * 10; - } else if short_avg > 10.0 { + cur_pwm += diff as i32 * 15; + } else if diff < -0.001 { cur_pwm -= 1; - } else if short_avg < 10.0 { + } else if diff > 0.001 { cur_pwm += 1; } @@ -243,11 +301,58 @@ mod app { cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm }; pwm.set_duty(Channel::C1, cur_pwm as u16); - - defmt::info!("avg:\t{} MHz", avg); defmt::info!("pwm:\t{}", cur_pwm); Systick::delay(500.millis()).await; } } + + #[task(binds = USB_HP_CAN_TX, shared = [usb_dev, serial, current_freq, short_avg])] + fn usb_tx(cx: usb_tx::Context) { + let mut usb_dev = cx.shared.usb_dev; + let mut serial = cx.shared.serial; + let mut current_freq = cx.shared.current_freq; + 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); + }); + } + + #[task(binds = USB_LP_CAN_RX0, shared = [usb_dev, serial, current_freq, short_avg])] + fn usb_rx0(cx: usb_rx0::Context) { + let mut usb_dev = cx.shared.usb_dev; + let mut serial = cx.shared.serial; + let mut current_freq = cx.shared.current_freq; + 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); + }); + } + + fn usb_poll( + usb_dev: &mut usb_device::prelude::UsbDevice<'static, B>, + serial: &mut usbd_serial::SerialPort<'static, B>, + current_freq: &mut f64, + short_avg: &mut f64, + ) { + if !usb_dev.poll(&mut [serial]) { + return; + } + + let mut buf = [0u8; 8]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + if buf[0] == b'?' { + + let mut data = arrayvec::ArrayString::<32>::new(); + write!(data, "{}|{}\n\r", current_freq, short_avg).unwrap(); + serial.write(data.as_bytes()).unwrap(); + }; + } + _ => {} + } + } }