Added PoC serial interface and host application

This commit is contained in:
Sebastian 2023-12-20 13:28:25 +01:00
parent 87f84d5254
commit 2cc6651aca
3 changed files with 166 additions and 21 deletions

View File

@ -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]

37
scripts/plot.py Normal file
View File

@ -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()

View File

@ -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<Output<PushPull>>,
@ -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<usb_device::bus::UsbBusAllocator<UsbBusType>> = 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<B: usb_device::bus::UsbBus>(
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();
};
}
_ => {}
}
}
}