Skip to content

Commit

Permalink
usb almost working
Browse files Browse the repository at this point in the history
  • Loading branch information
sky-dragn committed Mar 1, 2024
1 parent 36d55df commit b8a3ef3
Show file tree
Hide file tree
Showing 34 changed files with 153 additions and 10,494 deletions.
10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@ 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.0", features = [ "thumbv7-backend" ] }
stm32l4xx-hal = { version = "0.7.1", features = ["stm32l442"] }
stm32l4xx-hal = { version = "0.7.1", features = ["stm32l442", "stm32-usbd"] }
rtic-monotonics = { version = "1.0.0", features = ["cortex-m-systick", "systick-100hz"]}
thiserror = { version = "1.0.50", package = "thiserror-core", default-features = false }
embedded-graphics = "0.8.1"
tinyvec = "1.6.0"
ublox = { version = "0.4.5", default-features = false }
nb = "1.1.0"
bytemuck = { version = "1.14.3", features = ["derive"] }
stm32-usbd = "0.6.0"
usb-device = { version = "0.2.9", features = ["defmt"] }
usbd-serial = "0.1.0"
# spin = "0.9.8"
rtic-sync = "1.3.0"

# cargo build/run
[profile.dev]
Expand Down Expand Up @@ -60,7 +65,8 @@ overflow-checks = false # <-

[patch.crates-io]
stm32l4xx-hal = { path = "./stm32l4xx-hal" }
ublox = { path = "./ublox/ublox" }
# ublox = { path = "./ublox/ublox" }
# usb-device = { path = "./usb-device" }

# uncomment this to switch from the crates.io version of defmt to its git version
# check app-template's README for instructions
Expand Down
162 changes: 116 additions & 46 deletions src/bin/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@

use gps_watch as _;

use hal::gpio::PA1;
use hal::gpio::{PA1, PA11, PA12};
use stm32l4xx_hal::{self as hal, pac, prelude::*};
use rtic_monotonics::create_systick_token;
use rtic_monotonics::systick::Systick;
use stm32l4xx_hal::gpio::{Alternate, Output, PA10, PA9, PB3, PB4, PB5, PushPull};
use stm32l4xx_hal::hal::spi::{Mode, Phase, Polarity};
use stm32l4xx_hal::pac::{SPI1, USART1};
use stm32l4xx_hal::spi::Spi;
use defmt::{trace, info};
use defmt::{trace, info, error};
use embedded_graphics::prelude::*;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::text::Text;
use stm32l4xx_hal::serial::Serial;
use usb_device::bus::UsbBusAllocator;
use core::fmt::Write;
use stm32l4xx_hal::rcc::{ClockSecuritySystem, CrystalBypass};
use stm32l4xx_hal::rtc::{Event, RtcClockSource, RtcConfig};
Expand All @@ -26,6 +27,12 @@ use gps_watch::gps::Gps;
use embedded_graphics::mono_font::{ascii::FONT_10X20, MonoTextStyle};
use gps_watch::FmtBuf;
use core::num::Wrapping;
use embedded_graphics::mono_font::iso_8859_2::FONT_4X6;
use hal::pac::{Interrupt, USB};
use tinyvec::ArrayVec;
use usb_device::device::{UsbDeviceBuilder, UsbVidPid};
use usbd_serial::USB_CLASS_CDC;
use rtic_sync::make_channel;

// Rename type to squash generics
type SharpMemDisplay = gps_watch::display::SharpMemDisplay<
Expand All @@ -46,6 +53,8 @@ type GpsUart = Serial<USART1, (PA9<Alternate<PushPull, 7>>, PA10<Alternate<PushP
)]
mod app {

use defmt::debug;
use rtic_sync::channel::{Receiver, Sender};

use super::*;

Expand All @@ -59,12 +68,11 @@ mod app {
// Local resources go here
#[local]
struct Local {
count: usize
// TODO: Add resources
}

#[init]
fn init(mut cx: init::Context) -> (Shared, Local) {
fn init(cx: init::Context) -> (Shared, Local) {
trace!("init enter");

// #[cfg(debug_assertions)]
Expand Down Expand Up @@ -119,7 +127,7 @@ mod app {
polarity: Polarity::IdleLow
},
true,
1.MHz(),
2.MHz(),
clocks,
&mut rcc.apb2
);
Expand Down Expand Up @@ -151,31 +159,31 @@ mod app {
);
gps_uart.listen(serial::Event::Rxne);

// Initialize USB Serial
// let dm = gpioa.pa11.into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
// let dp = gpioa.pa12.into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
// Enable the USB interrupt
// let usb = unsafe {hal::pac::Peripherals::steal()}.USB;
// usb.cntr.write(|w| w.wkupm().enabled());

// let usb = hal::usb::Peripheral {
// usb: cx.device.USB,
// pin_dm: dm,
// pin_dp: dp
// };
// Initialize USB Serial
let dm = gpioa.pa11.into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);
let dp = gpioa.pa12.into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh);

// static USB_BUS: Once<UsbBus> = Once::new();
// USB_BUS.set(hal::usb::UsbBus::new(usb));
// Turn on USB power
unsafe { pac::Peripherals::steal().PWR.cr2.modify(|_, w| w.usv().set_bit())};

// // let _: () = USB_BUS.get().unwrap();
// let usb_serial = usbd_serial::SerialPort::new(USB_BUS.get().unwrap());
// Create USB peripheral object
let usb = hal::usb::Peripheral {
usb: cx.device.USB,
pin_dm: dm,
pin_dp: dp
};

// let usb_dev = UsbDeviceBuilder::new(USB_BUS.get().unwrap(), UsbVidPid(0x1209, 0x0001))
// .manufacturer("ECE500")
// .product("Landhopper")
// .serial_number("TEST")
// .device_class(USB_CLASS_CDC)
// .build();
let (usb_tx, usb_rx) = make_channel!(u8, 16);
// Pass to task for remaining initialization
let _ = usb_poll::spawn(usb, usb_rx);

// Spawn tasks
display_task::spawn().unwrap();
display_task::spawn(usb_tx.clone()).unwrap();
// gps_status::spawn().unwrap();

info!("done initializing!");
trace!("init exit");
Expand All @@ -186,7 +194,7 @@ mod app {
},
Local {
// Initialization of local resources go here
count: 0
// count: 0
},
)
}
Expand All @@ -197,11 +205,7 @@ mod app {
trace!("idle enter");

loop {

trace!("usb");


trace!("sleep");
// trace!("sleep");
// Only sleep in release mode, since the debugger doesn't interact with sleep very nice
#[cfg(debug_assertions)]
core::hint::spin_loop();
Expand All @@ -210,45 +214,111 @@ mod app {
}
}

#[task(binds = USART1, shared = [gps], local = [count])]
#[task(priority = 1)]
async fn usb_poll(_cx: usb_poll::Context, usb: hal::usb::Peripheral, mut rx: Receiver<'static, u8, 16>) {
trace!("usb_poll enter");

let usb_bus = hal::usb::UsbBus::new(usb);

let mut serial = usbd_serial::SerialPort::new(&usb_bus);

let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
.manufacturer("ECE500")
.product("Landhopper")
.serial_number("TEST")
.device_class(USB_CLASS_CDC)
.build();

let mut tx_buf = ArrayVec::<[u8; 16]>::new();

loop {
Systick::delay(10.millis()).await;

debug!("usb_poll loop");

while tx_buf.len() < tx_buf.capacity() {
if let Ok(b) = rx.try_recv() {
tx_buf.push(b);
} else { break; }
}
trace!("usb state: {}", usb_dev.state());

if !usb_dev.poll(&mut [&mut serial]) {
continue;
}

match serial.write(&tx_buf) {
Ok(count) => {
trace!("sent {} bytes to usb", count);
tx_buf.drain(0..count).for_each(|_| ());
},
Err(_) => error!("usb error")
}
}
}

#[task(binds = USART1, priority = 10, shared = [gps])]
fn on_uart(mut cx: on_uart::Context) {
// cx.shared.gps.lock(|gps| {
// gps.handle();
// });
cx.shared.gps.lock(|gps| {
if let Ok(b) = gps.serial.read() {
*cx.local.count += 1;
info!("got {:x} #{}", b, cx.local.count);
}
})
gps.handle();
});
// cx.shared.gps.lock(|gps| {
// while let Ok(b) = gps.serial.read() {
// let _ = cx.shared.recv_buf.lock(|(buf, started)| {
// if b == 0xB5 || *started {
// buf.try_push(b);
// *started = true;
// }
// });
// }
// })
}

// #[task(priority = 1, shared = [recv_buf])]
// async fn gps_status(mut cx: gps_status::Context) {
// loop {
// Systick::delay(1000.millis()).await;
// cx.shared.recv_buf.lock(|x| {
// info!("received: {:x}", x.as_slice());
// x.clear();
// });
// }
// }

#[task(binds = RTC_WKUP)]
fn on_rtc(_cx: on_rtc::Context) {
info!("rtc wakeup!");
}

// TODO: Add tasks
#[task(
priority = 1,
shared = [display, gps]
)]
async fn display_task(mut cx: display_task::Context) {
async fn display_task(mut cx: display_task::Context, tx: Sender<'static, u8, 16>) {
trace!("display_task enter");
cx.shared.display.lock(|display| display.clear());
cx.shared.display.lock(|display| display.clear_flush());

let mut i = Wrapping(0u8);
loop {
let pos = cx.shared.gps.lock(|gps| gps.position);
debug!("display_task loop");
// let pos = cx.shared.gps.lock(|gps| gps.position);
let mut txt = FmtBuf(Default::default());
write!(txt, "Lat: {}\nLon: {}", pos.latitude, pos.longitude).unwrap();
// write!(txt, "Lat: {}\nLon: {}", pos.latitude, pos.longitude).unwrap();
// cx.shared.recv_buf.lock(|(x, started)| {
// let _ = write!(txt, "{:x} {x:x?}", x.len());
// x.clear();
// *started = false;
// });
cx.shared.gps.lock(|gps| {
let _ = write!(txt, "{} {:x?}", gps.count, gps.last_packet);
});
// info!("formatted: {}", txt.as_str());
cx.shared.display.lock(|display| {
display.clear();
Text::new(
txt.as_str().unwrap(),
Point::new(30, 30),
MonoTextStyle::new(&FONT_10X20, BinaryColor::On)
MonoTextStyle::new(&FONT_4X6, BinaryColor::On)
).draw(display).unwrap();
display.flush();
});
Expand All @@ -260,7 +330,7 @@ mod app {
// rect_styled.draw(display).unwrap();
// display.flush();
// });
Systick::delay(500.millis()).await;
Systick::delay(1000.millis()).await;
i += 1;
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ impl<SPI, CS> SharpMemDisplay<SPI, CS>
self.dirty = [0xFF; HEIGHT_BYTES];
self.dirty_any = true;
}

pub fn clear_flush(&mut self) {
self.driver.clear_flush();
self.buf = [[0xFF; WIDTH_BYTES]; HEIGHT];
self.dirty = [0; HEIGHT_BYTES];
self.dirty_any = false;
}
}

impl<SPI, CS> DrawTarget for SharpMemDisplay<SPI, CS>
Expand Down
30 changes: 16 additions & 14 deletions src/gps.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use core::fmt::{self, Write};

use defmt::{error, info};
use defmt::{error, info, trace};
use stm32l4xx_hal::hal::serial;
use ublox::{CfgMsgAllPortsBuilder, CfgPrtUartBuilder, NavPvt, UartMode, UartPortId};
use tinyvec::ArrayVec;

use crate::{ubx::{UbxPacket, UbxParser}, FmtBuf};
use crate::{ubx::{UbxError, UbxPacket, UbxParser}, FmtBuf};

#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
pub struct Position {
pub latitude: i32,
pub longitude: i32,
Expand All @@ -18,19 +18,25 @@ pub struct Gps<SERIAL> {
pub parser: UbxParser,

pub position: Position,
count: usize
pub last_packet: Result<UbxPacket, UbxError>,
pub count: usize
}

impl<SERIAL> Gps<SERIAL>
where SERIAL: serial::Read<u8> + serial::Write<u8>,
<SERIAL as serial::Read<u8>>::Error: core::fmt::Debug,
<SERIAL as serial::Write<u8>>::Error: core::fmt::Debug,
{
pub fn new(serial: SERIAL) -> Self {
pub fn new(mut serial: SERIAL) -> Self {

// Busy loop waiting for the GPS to be alive
while let Err(_) = serial.read() {}

let mut s = Self {
serial,
parser: UbxParser::new(),
position: Position { latitude: 0, longitude: 0 },
last_packet: Ok(UbxPacket::OtherPacket),
count: 0
};

Expand Down Expand Up @@ -70,17 +76,13 @@ impl<SERIAL> Gps<SERIAL>
pub fn handle(&mut self) {
if let Ok(b) = self.serial.read() {
self.count += 1;
info!("got {:x} #{}", b, self.count);
trace!("got {:x} #{}", b, self.count);
if let Some(r) = self.parser.process_byte(b) {
match r {
Ok(p) => match p {
UbxPacket::AckAck {..} => info!("ubx AckAck"),
UbxPacket::AckNak {..} => info!("ubx AckNak"),
UbxPacket::NavPvt(n) => info!("ubx lat={}, lon={}", n.lat, n.lon),
UbxPacket::OtherPacket => info!("ubx other")
},
Err(e) => error!("ubx error: {:x}", e)
if let Ok(UbxPacket::NavPvt(ref navpvt)) = r {
self.position.latitude = navpvt.lat;
self.position.longitude = navpvt.lon;
}
self.last_packet = r;
}
}
}
Expand Down
Loading

0 comments on commit b8a3ef3

Please sign in to comment.