Added PoC serial interface and host application
This commit is contained in:
parent
87f84d5254
commit
2cc6651aca
|
@ -8,16 +8,19 @@ version = "0.1.0"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||||
defmt = { version = "0.3", features = ["encoding-rzcobs"] }
|
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"] }
|
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||||
rtic = { version = "2.0.1", features = [ "thumbv7-backend" ] }
|
rtic = { version = "2.0.1", features = [ "thumbv7-backend" ] }
|
||||||
defmt-rtt = "0.4"
|
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"] }
|
stm32f1xx-hal = { version = "0.10.0", features = ["stm32f103", "rt", "medium"] }
|
||||||
nb = "1.0.0"
|
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"
|
systick-monotonic = "1.0.0"
|
||||||
rtic-monotonics = {version = "1.4.1", features = ["cortex-m-systick"] }
|
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
|
# cargo build/run
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
@ -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()
|
141
src/main.rs
141
src/main.rs
|
@ -18,9 +18,12 @@ 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 embedded_hal::digital::v2::OutputPin;
|
||||||
use rtic_monotonics::systick::*;
|
use rtic_monotonics::systick::*;
|
||||||
|
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
|
||||||
use stm32f1xx_hal::{
|
use stm32f1xx_hal::{
|
||||||
gpio::{self, gpioa, gpioc, Alternate, Output, PushPull},
|
gpio::{self, gpioa, gpioc, Alternate, Output, PushPull},
|
||||||
pac,
|
pac,
|
||||||
|
@ -31,6 +34,9 @@ mod app {
|
||||||
timer::{self, Channel, PwmHz, Tim4NoRemap},
|
timer::{self, Channel, PwmHz, Tim4NoRemap},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
|
||||||
|
use usb_device::prelude::*;
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
board_led: gpioc::PC13<Output<PushPull>>,
|
board_led: gpioc::PC13<Output<PushPull>>,
|
||||||
|
@ -40,13 +46,18 @@ mod app {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[shared]
|
#[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]
|
#[init]
|
||||||
fn init(cx: init::Context) -> (Shared, Local) {
|
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 mut flash = cx.device.FLASH.constrain();
|
||||||
|
|
||||||
let clocks = rcc
|
let clocks = rcc
|
||||||
|
@ -56,6 +67,7 @@ mod app {
|
||||||
.pclk1(24.MHz())
|
.pclk1(24.MHz())
|
||||||
.freeze(&mut flash.acr);
|
.freeze(&mut flash.acr);
|
||||||
|
|
||||||
|
assert!(clocks.usbclk_valid());
|
||||||
defmt::info!("Clock Setup done");
|
defmt::info!("Clock Setup done");
|
||||||
|
|
||||||
// Initialize the systick interrupt & obtain the token to prove that we did
|
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||||
|
@ -148,10 +160,49 @@ mod app {
|
||||||
|
|
||||||
defmt::info!("Timer Setup done");
|
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();
|
update_pwm::spawn().unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
Shared {},
|
Shared {
|
||||||
|
serial,
|
||||||
|
usb_dev,
|
||||||
|
current_freq: 0.0f64,
|
||||||
|
short_avg: 0.0f64,
|
||||||
|
},
|
||||||
Local {
|
Local {
|
||||||
board_led,
|
board_led,
|
||||||
tim2,
|
tim2,
|
||||||
|
@ -161,10 +212,10 @@ mod app {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const WINDOW_LEN : usize = 60;
|
const WINDOW_LEN: usize = 100;
|
||||||
|
|
||||||
#[task(local=[tim2, tim3, pwm, board_led])]
|
#[task(local=[tim2, tim3, pwm, board_led], shared=[current_freq, short_avg])]
|
||||||
async fn update_pwm(cx: update_pwm::Context) {
|
async fn update_pwm(mut cx: update_pwm::Context) {
|
||||||
defmt::info!("Update Task started");
|
defmt::info!("Update Task started");
|
||||||
|
|
||||||
let tim2 = cx.local.tim2;
|
let tim2 = cx.local.tim2;
|
||||||
|
@ -172,7 +223,6 @@ mod app {
|
||||||
let pwm = cx.local.pwm;
|
let pwm = cx.local.pwm;
|
||||||
let board_led = cx.local.board_led;
|
let board_led = cx.local.board_led;
|
||||||
|
|
||||||
let mut avg = 10f64;
|
|
||||||
let max_pwm = pwm.get_max_duty() as i32;
|
let max_pwm = pwm.get_max_duty() as i32;
|
||||||
let mut cur_pwm = max_pwm / 2;
|
let mut cur_pwm = max_pwm / 2;
|
||||||
|
|
||||||
|
@ -187,6 +237,7 @@ mod app {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut short_avg = 0.0f64;
|
let mut short_avg = 0.0f64;
|
||||||
|
let mut last_freq = 10.0f64;
|
||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while count < WINDOW_LEN {
|
while count < WINDOW_LEN {
|
||||||
|
@ -214,28 +265,35 @@ mod app {
|
||||||
let freq = (diff_ic as f64) / 1_000_000f64;
|
let freq = (diff_ic as f64) / 1_000_000f64;
|
||||||
defmt::info!("freq:\t{} MHz", freq);
|
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 {
|
if diff > 0.000_100 || diff < -0.000_100 {
|
||||||
defmt::info!("Out of range, dropping sample.");
|
defmt::info!("Out of range, dropping sample.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
short_avg += freq / WINDOW_LEN as f64;
|
cx.shared.current_freq.lock(|current_freq| {
|
||||||
avg = avg * 0.999 + freq * 0.001;
|
*current_freq = freq;
|
||||||
|
});
|
||||||
|
|
||||||
|
short_avg += freq / WINDOW_LEN as f64;
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
board_led.toggle();
|
board_led.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
defmt::info!("short_avg:\t{} MHz", short_avg);
|
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 {
|
if diff > 1.0 || diff < -1.0 {
|
||||||
cur_pwm += diff as i32 * 10;
|
cur_pwm += diff as i32 * 15;
|
||||||
} else if short_avg > 10.0 {
|
} else if diff < -0.001 {
|
||||||
cur_pwm -= 1;
|
cur_pwm -= 1;
|
||||||
} else if short_avg < 10.0 {
|
} else if diff > 0.001 {
|
||||||
cur_pwm += 1;
|
cur_pwm += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,11 +301,58 @@ mod app {
|
||||||
cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm };
|
cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm };
|
||||||
|
|
||||||
pwm.set_duty(Channel::C1, cur_pwm as u16);
|
pwm.set_duty(Channel::C1, cur_pwm as u16);
|
||||||
|
|
||||||
defmt::info!("avg:\t{} MHz", avg);
|
|
||||||
defmt::info!("pwm:\t{}", cur_pwm);
|
defmt::info!("pwm:\t{}", cur_pwm);
|
||||||
|
|
||||||
Systick::delay(500.millis()).await;
|
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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue