Created
August 3, 2022 14:00
-
-
Save barafael/9de1de5e41026519d2a12a6aa3c78a3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_main] | |
#![no_std] | |
use defmt_rtt as _; // global logger | |
// same panicking *behavior* as `panic-probe` but doesn't print a panic message | |
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked | |
#[defmt::panic_handler] | |
fn panic() -> ! { | |
cortex_m::asm::udf() | |
} | |
use panic_probe as _; | |
#[rtic::app(device = stm32f3xx_hal::pac, dispatchers = [TIM20_BRK, TIM20_UP, TIM20_TRG_COM])] | |
mod app { | |
use stm32f3xx_hal::{ | |
gpio::{self, Output, PushPull, AF7}, | |
pac, | |
prelude::*, | |
serial::{Event, Serial}, | |
Toggle, | |
}; | |
use systick_monotonic::*; | |
#[monotonic(binds = SysTick, default = true)] | |
type AppMono = Systick<100>; // 100 Hz / 10 ms granularity | |
type SerialType = Serial<pac::USART1, (gpio::PA9<AF7<PushPull>>, gpio::PA10<AF7<PushPull>>)>; | |
// The LED that will light up when data is received via serial | |
type Led = gpio::PB3<Output<PushPull>>; | |
#[shared] | |
struct Shared { | |
led: Led, | |
} | |
#[local] | |
struct Local { | |
serial: SerialType, | |
} | |
#[init] | |
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { | |
let mut flash = cx.device.FLASH.constrain(); | |
let mut rcc = cx.device.RCC.constrain(); | |
let systick = cx.core.SYST; | |
defmt::info!("pre init"); | |
// Initialize the clocks | |
let clocks = rcc.cfgr.sysclk(48.MHz()).freeze(&mut flash.acr); | |
let mono = Systick::new(systick, 48_000_000); | |
let mut gpiob = cx.device.GPIOB.split(&mut rcc.ahb); | |
let mut led: Led = gpiob | |
.pb3 | |
.into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper); | |
led.set_low().unwrap(); | |
// SERIAL | |
let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); | |
let mut pins = ( | |
gpioa | |
// Tx pin | |
.pa9 | |
// configure this pin to make use of its `USART1_TX` alternative function | |
// (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at | |
// https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html) | |
.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), | |
gpioa | |
// Rx pin | |
.pa10 | |
// configure this pin to make use of its `USART1_RX` alternative function | |
// (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at | |
// https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html) | |
.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), | |
); | |
pins.1.internal_pull_up(&mut gpioa.pupdr, true); | |
let mut serial: SerialType = | |
Serial::new(cx.device.USART1, pins, 9600.Bd(), clocks, &mut rcc.apb2); | |
serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Toggle::On); | |
defmt::info!("post init"); | |
// A kick of for the infitinte loop in protocol_serial_task() | |
nb::block!(serial.write(b'c')).unwrap(); | |
blink::spawn().unwrap(); | |
(Shared { led }, Local { serial }, init::Monotonics(mono)) | |
} | |
#[task(binds = USART1_EXTI25, local = [serial])] | |
fn protocol_serial_task(cx: protocol_serial_task::Context) { | |
let serial = cx.local.serial; | |
if serial.is_event_triggered(Event::ReceiveDataRegisterNotEmpty) { | |
serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Toggle::Off); | |
match nb::block!(serial.read()) { | |
Ok(byte) => { | |
serial.write(byte).unwrap(); | |
defmt::info!("{:?}", char::from_u32(byte.into()).unwrap_or('?')); | |
serial.configure_interrupt(Event::TransmissionComplete, Toggle::On); | |
} | |
Err(error) => match error { | |
stm32f3xx_hal::serial::Error::Framing => defmt::info!("framing"), | |
stm32f3xx_hal::serial::Error::Overrun => defmt::info!("overrun"), | |
_ => defmt::info!("other"), | |
}, | |
}; | |
} | |
// It is perfectly viable to just use `is_event_triggered` here, | |
// but this is a showcase, to also be able to used `triggered_events` | |
// and other functions enabled by the "enumset" feature. | |
let events = serial.triggered_events(); | |
if events.contains(Event::TransmissionComplete) { | |
//cx.shared.led.lock(|led| led.set_low().unwrap()); | |
let interrupts = { | |
let mut interrupts = enumset::EnumSet::new(); | |
interrupts.insert(Event::ReceiveDataRegisterNotEmpty); | |
interrupts | |
}; | |
serial.clear_event(Event::TransmissionComplete); | |
// Disable all interrupts, except ReceiveDataRegisterNotEmpty. | |
serial.configure_interrupts(interrupts); | |
} | |
} | |
#[task(shared = [led], priority = 1)] | |
fn blink(mut cx: blink::Context) { | |
cx.shared.led.lock(|led| led.toggle().unwrap()); | |
blink::spawn_after(500.millis()).unwrap(); | |
} | |
#[idle] | |
fn idle(_: idle::Context) -> ! { | |
defmt::info!("idle"); | |
loop { | |
cortex_m::asm::nop(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment