Skip to content

Instantly share code, notes, and snippets.

@barafael
Created August 3, 2022 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barafael/9de1de5e41026519d2a12a6aa3c78a3d to your computer and use it in GitHub Desktop.
Save barafael/9de1de5e41026519d2a12a6aa3c78a3d to your computer and use it in GitHub Desktop.
#![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