Setup embassy, usb-serial and display drivers
This commit is contained in:
commit
7a4e4a89cb
17
.cargo/config.toml
Normal file
17
.cargo/config.toml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||||
|
runner = "probe-run --chip STM32F103C8"
|
||||||
|
rustflags = [
|
||||||
|
"-C", "linker=flip-link",
|
||||||
|
"-C", "link-arg=-Tlink.x",
|
||||||
|
"-C", "link-arg=-Tdefmt.x",
|
||||||
|
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||||
|
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||||
|
"-C", "link-arg=--nmagic",
|
||||||
|
]
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "thumbv7m-none-eabi" # Cortex-M3
|
||||||
|
|
||||||
|
[alias]
|
||||||
|
rb = "run --bin"
|
||||||
|
rrb = "run --release --bin"
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1365
Cargo.lock
generated
Normal file
1365
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
36
Cargo.toml
Normal file
36
Cargo.toml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
[package]
|
||||||
|
name = "rotor-control-stm32"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
embassy-util = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
||||||
|
embassy-executor = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt", "integrated-timers"] }
|
||||||
|
embassy-time = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] }
|
||||||
|
embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] }
|
||||||
|
embassy-usb = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
||||||
|
embassy-usb-serial = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy.git", features = ["defmt"] }
|
||||||
|
|
||||||
|
defmt = "0.3.2"
|
||||||
|
defmt-rtt = "0.3.2"
|
||||||
|
panic-probe = { version = "0.3.0"}
|
||||||
|
|
||||||
|
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
||||||
|
cortex-m-rt = "0.7.0"
|
||||||
|
embedded-hal = "0.2.6"
|
||||||
|
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||||
|
heapless = { version = "0.7.5", default-features = false }
|
||||||
|
nb = "1.0.0"
|
||||||
|
|
||||||
|
ssd1306 = "0.7.1"
|
||||||
|
embedded-graphics = "0.7.1"
|
||||||
|
profont = "0.6.1"
|
||||||
|
arrayvec = { version = "0.7.2", default-features = false}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = "s"
|
6
memory.x
Normal file
6
memory.x
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/* Linker script for the STM32F103C8T6 */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 20K
|
||||||
|
}
|
161
src/main.rs
Normal file
161
src/main.rs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use defmt::panic;
|
||||||
|
use defmt_rtt as _;
|
||||||
|
use panic_probe as _;
|
||||||
|
|
||||||
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
|
use embassy_stm32::time::Hertz;
|
||||||
|
use embassy_stm32::usb::{Driver, Instance};
|
||||||
|
use embassy_stm32::{i2c, interrupt, Config};
|
||||||
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
|
use embassy_usb::driver::EndpointError;
|
||||||
|
use embassy_usb::Builder;
|
||||||
|
use embassy_usb_serial::{CdcAcmClass, State};
|
||||||
|
use futures::future::join;
|
||||||
|
|
||||||
|
use embedded_graphics::{
|
||||||
|
mono_font::MonoTextStyle, pixelcolor::BinaryColor, prelude::*, text::Text,
|
||||||
|
};
|
||||||
|
use profont::PROFONT_12_POINT;
|
||||||
|
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
||||||
|
|
||||||
|
use arrayvec::ArrayString;
|
||||||
|
|
||||||
|
#[embassy_executor::main]
|
||||||
|
async fn main(_spawner: Spawner) {
|
||||||
|
let mut config = Config::default();
|
||||||
|
config.rcc.hse = Some(Hertz(8_000_000));
|
||||||
|
config.rcc.sys_ck = Some(Hertz(48_000_000));
|
||||||
|
config.rcc.pclk1 = Some(Hertz(24_000_000));
|
||||||
|
let mut p = embassy_stm32::init(config);
|
||||||
|
|
||||||
|
defmt::info!("Startup");
|
||||||
|
|
||||||
|
{
|
||||||
|
// BluePill board has a pull-up resistor on the D+ line.
|
||||||
|
// Pull the D+ pin down to send a RESET condition to the USB bus.
|
||||||
|
// This forced reset is needed only for development, without it host
|
||||||
|
// will not reset your device when you upload new firmware.
|
||||||
|
let _dp = Output::new(&mut p.PA12, Level::Low, Speed::Low);
|
||||||
|
Timer::after(Duration::from_millis(10)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the driver, from the HAL.
|
||||||
|
let irq = interrupt::take!(USB_LP_CAN1_RX0);
|
||||||
|
let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
|
||||||
|
|
||||||
|
// Create embassy-usb Config
|
||||||
|
let config = embassy_usb::Config::new(0xc0de, 0xcafe);
|
||||||
|
//config.max_packet_size_0 = 64;
|
||||||
|
|
||||||
|
// Create embassy-usb DeviceBuilder using the driver and config.
|
||||||
|
// It needs some buffers for building the descriptors.
|
||||||
|
let mut device_descriptor = [0; 256];
|
||||||
|
let mut config_descriptor = [0; 256];
|
||||||
|
let mut bos_descriptor = [0; 256];
|
||||||
|
let mut control_buf = [0; 7];
|
||||||
|
|
||||||
|
let mut state = State::new();
|
||||||
|
|
||||||
|
let mut builder = Builder::new(
|
||||||
|
driver,
|
||||||
|
config,
|
||||||
|
&mut device_descriptor,
|
||||||
|
&mut config_descriptor,
|
||||||
|
&mut bos_descriptor,
|
||||||
|
&mut control_buf,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create classes on the builder.
|
||||||
|
let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
|
||||||
|
|
||||||
|
// Build the builder.
|
||||||
|
let mut usb = builder.build();
|
||||||
|
|
||||||
|
// Run the USB device.
|
||||||
|
let usb_fut = usb.run();
|
||||||
|
|
||||||
|
let i2c = i2c::I2c::new(
|
||||||
|
p.I2C1,
|
||||||
|
p.PB6,
|
||||||
|
p.PB7,
|
||||||
|
Hertz::hz(100_000),
|
||||||
|
i2c::Config::default(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let interface = I2CDisplayInterface::new(i2c);
|
||||||
|
|
||||||
|
let display_fut = async {
|
||||||
|
let mut display = Ssd1306::new(interface, DisplaySize128x32, DisplayRotation::Rotate0)
|
||||||
|
.into_buffered_graphics_mode();
|
||||||
|
display.init().unwrap();
|
||||||
|
|
||||||
|
let text_style = MonoTextStyle::new(&PROFONT_12_POINT, BinaryColor::On);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
display.clear();
|
||||||
|
|
||||||
|
Text::new("Hello world", Point::new(0, 7), text_style)
|
||||||
|
.draw(&mut display)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let now = Instant::now().as_millis();
|
||||||
|
|
||||||
|
let mut buf = ArrayString::<20>::new();
|
||||||
|
write!(&mut buf, "{}", now).expect("Can't write");
|
||||||
|
Text::new(&buf, Point::new(0, 20), text_style)
|
||||||
|
.draw(&mut display)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
display.flush().unwrap();
|
||||||
|
|
||||||
|
Timer::after(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Do stuff with the class!
|
||||||
|
let echo_fut = async {
|
||||||
|
loop {
|
||||||
|
class.wait_connection().await;
|
||||||
|
defmt::info!("Connected");
|
||||||
|
let _ = echo(&mut class).await;
|
||||||
|
defmt::info!("Disconnected");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run everything concurrently.
|
||||||
|
// If we had made everything `'static` above instead, we could do this using separate tasks instead.
|
||||||
|
join(join(usb_fut, display_fut), echo_fut).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Disconnected {}
|
||||||
|
|
||||||
|
impl From<EndpointError> for Disconnected {
|
||||||
|
fn from(val: EndpointError) -> Self {
|
||||||
|
match val {
|
||||||
|
EndpointError::BufferOverflow => panic!("Buffer overflow"),
|
||||||
|
EndpointError::Disabled => Disconnected {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn echo<'d, T: Instance + 'd>(
|
||||||
|
class: &mut CdcAcmClass<'d, Driver<'d, T>>,
|
||||||
|
) -> Result<(), Disconnected> {
|
||||||
|
let mut buf = [0; 64];
|
||||||
|
loop {
|
||||||
|
let n = class.read_packet(&mut buf).await?;
|
||||||
|
let data = &buf[..n];
|
||||||
|
defmt::info!("data: {:x}", data);
|
||||||
|
class.write_packet(">".as_bytes()).await?;
|
||||||
|
class.write_packet(data).await?;
|
||||||
|
class.write_packet("\n".as_bytes()).await?;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue