|
| 1 | +//! Interrupt Driven Serial Echo Example |
| 2 | +//! For NUCLEO-F031K6 |
| 3 | +
|
| 4 | +#![no_main] |
| 5 | +#![no_std] |
| 6 | +#![deny(unsafe_code)] |
| 7 | +#![allow(non_camel_case_types)] |
| 8 | + |
| 9 | +use core::cell::RefCell; |
| 10 | +use nb::block; |
| 11 | +use panic_halt as _; |
| 12 | + |
| 13 | +use cortex_m::interrupt::Mutex; |
| 14 | +use cortex_m_rt::entry; |
| 15 | + |
| 16 | +use hal::{ |
| 17 | + delay::Delay, |
| 18 | + gpio::{ |
| 19 | + gpioa::{PA15, PA2}, |
| 20 | + Alternate, AF1, |
| 21 | + }, |
| 22 | + pac::{self, interrupt, Interrupt, USART1}, |
| 23 | + prelude::*, |
| 24 | + serial::Serial, |
| 25 | +}; |
| 26 | +use stm32f0xx_hal as hal; |
| 27 | + |
| 28 | +type SERIAL = Serial<USART1, PA2<Alternate<AF1>>, PA15<Alternate<AF1>>>; |
| 29 | + |
| 30 | +/* |
| 31 | +Create our global variables: |
| 32 | +
|
| 33 | +We use a Mutex because Mutexes require a CriticalSection |
| 34 | +context in order to be borrowed. Since CriticalSection |
| 35 | +contexts cannot overlap (by definition) we can rest assured |
| 36 | +that the resource inside the Mutex will not violate |
| 37 | +the RefMut's runtime borrowing rules (Given that we do not |
| 38 | +try to borrow the RefMut more than once per CriticalSection). |
| 39 | + */ |
| 40 | +static SER_PORT: Mutex<RefCell<Option<SERIAL>>> = Mutex::new(RefCell::new(None)); |
| 41 | + |
| 42 | +#[entry] |
| 43 | +fn main() -> ! { |
| 44 | + let (mut delay, mut led) = cortex_m::interrupt::free(|cs| { |
| 45 | + let dp = pac::Peripherals::take().unwrap(); // might as well panic if this doesn't work |
| 46 | + let cp = cortex_m::peripheral::Peripherals::take().unwrap(); |
| 47 | + let mut flash = dp.FLASH; |
| 48 | + let mut rcc = dp.RCC.configure().sysclk(48.mhz()).freeze(&mut flash); |
| 49 | + |
| 50 | + let gpioa = dp.GPIOA.split(&mut rcc); |
| 51 | + let gpiob = dp.GPIOB.split(&mut rcc); |
| 52 | + |
| 53 | + let delay = Delay::new(cp.SYST, &rcc); |
| 54 | + |
| 55 | + // setup UART |
| 56 | + let (tx, rx) = ( |
| 57 | + gpioa.pa2.into_alternate_af1(cs), |
| 58 | + gpioa.pa15.into_alternate_af1(cs), |
| 59 | + ); |
| 60 | + |
| 61 | + // initialize global serial |
| 62 | + *SER_PORT.borrow(cs).borrow_mut() = |
| 63 | + Some(Serial::usart1(dp.USART1, (tx, rx), 9_600.bps(), &mut rcc)); |
| 64 | + |
| 65 | + if let Some(ser) = SER_PORT.borrow(cs).borrow_mut().as_mut() { |
| 66 | + ser.listen(hal::serial::Event::Rxne); // trigger the USART1 interrupt when bytes are available (receive buffer not empty) |
| 67 | + } |
| 68 | + |
| 69 | + let led = gpiob.pb3.into_push_pull_output(cs); |
| 70 | + |
| 71 | + (delay, led) |
| 72 | + }); |
| 73 | + |
| 74 | + #[allow(unsafe_code)] // just this once ;) |
| 75 | + unsafe { |
| 76 | + cortex_m::peripheral::NVIC::unmask(Interrupt::USART1); |
| 77 | + } |
| 78 | + |
| 79 | + loop { |
| 80 | + led.toggle().ok(); |
| 81 | + |
| 82 | + delay.delay_ms(1_000u16); |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +#[interrupt] |
| 87 | +fn USART1() { |
| 88 | + cortex_m::interrupt::free(|cs| { |
| 89 | + if let Some(ser) = SER_PORT.borrow(cs).borrow_mut().as_mut() { |
| 90 | + if let Ok(data) = block!(ser.read()) { |
| 91 | + block!(ser.write(data)).ok(); |
| 92 | + } else { |
| 93 | + /* |
| 94 | + Failed to read a byte: |
| 95 | +
|
| 96 | + There could be some kind of alignment error or the UART |
| 97 | + was disconnected or something. |
| 98 | + */ |
| 99 | + } |
| 100 | + } |
| 101 | + }); |
| 102 | +} |
0 commit comments