| 
 | 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_PORT = 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 at a time).  | 
 | 39 | +*/  | 
 | 40 | +static GSERIAL: Mutex<RefCell<Option<SERIAL_PORT>>> = 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 | +        *GSERIAL.borrow(cs).borrow_mut() =  | 
 | 63 | +            Some(Serial::usart1(dp.USART1, (tx, rx), 9_600.bps(), &mut rcc));  | 
 | 64 | + | 
 | 65 | +        if let Some(ser) = GSERIAL.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 | +    static mut SERIAL: Option<SERIAL_PORT> = None;  | 
 | 89 | + | 
 | 90 | +    /*  | 
 | 91 | +    Once the main function has initialized the serial port,  | 
 | 92 | +    we move it into this interrupt handler, giving  | 
 | 93 | +    it exclusive access to the serial port.  | 
 | 94 | +    */  | 
 | 95 | +    let ser = SERIAL.get_or_insert_with(|| {  | 
 | 96 | +        cortex_m::interrupt::free(|cs| {  | 
 | 97 | +            if let Some(ser) = GSERIAL.borrow(cs).take() {  | 
 | 98 | +                ser  | 
 | 99 | +            } else {  | 
 | 100 | +                /*  | 
 | 101 | +                This means the main function failed to initialize  | 
 | 102 | +                the serial port.  | 
 | 103 | +
  | 
 | 104 | +                For this example, we will panic.  | 
 | 105 | +                */  | 
 | 106 | +                panic!();  | 
 | 107 | +            }  | 
 | 108 | +        })  | 
 | 109 | +    });  | 
 | 110 | + | 
 | 111 | +    if let Ok(data) = block!(ser.read()) {  | 
 | 112 | +        block!(ser.write(data)).ok();  | 
 | 113 | +    } else {  | 
 | 114 | +        /*  | 
 | 115 | +        Failed to read a byte:  | 
 | 116 | +
  | 
 | 117 | +        There could be some kind of alignment error or the UART  | 
 | 118 | +        was disconnected or something.  | 
 | 119 | +        */  | 
 | 120 | +    }  | 
 | 121 | +}  | 
0 commit comments