~ruther/simple-clock

e2a425e4f4e066a41d7926b2c2608e05b64e27bc — František Boháček 1 year, 8 months ago 6fbd046
feat(src): split main into multiple functions
2 files changed, 160 insertions(+), 90 deletions(-)

M README.md
M source/src/main.rs
M README.md => README.md +0 -5
@@ 67,8 67,3 @@ currently test sending and receiving data using the USB, that is the reason
why the current program does not even support USB. In the future, the firmware
should support USB communication and a program for a computer should be made,
with some kind of CLI for communication with the board.

Another thing that could be done is a bit of a refactoring of the main function.
I am quite new to Rust and I don't know how to split the initialization of peripherals
to multiple functions _naturally_. Now the main function is very long, because all initialization
is in there.

M source/src/main.rs => source/src/main.rs +160 -85
@@ 36,15 36,17 @@ use embedded_alloc::Heap;
use embedded_hal::digital::v2::OutputPin;
use fugit::MicrosDurationU32;
use stm32f1xx_hal::{
    gpio::{Cr, Floating, Input, Pin},
    pac,
    pac::interrupt,
    prelude::*,
    rcc::Clocks,
    rtc::{
        RestoredOrNewRtc::{New, Restored},
        Rtc,
    },
    time::MonoTimer,
    timer::{Event, Tim1NoRemap, Tim2NoRemap, Tim3NoRemap, TimerExt},
    timer::{Event, Tim1NoRemap, Tim2NoRemap, Tim3NoRemap, TimerExt, SysDelay}, afio::MAPR,
};

use defmt_rtt as _;


@@ 74,94 76,67 @@ fn TIM4() {
    });
}

#[entry]
fn main() -> ! {
    {
        use core::mem::MaybeUninit;
        const HEAP_SIZE: usize = 512;
        static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
        unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
    }

    // Get access to the core peripherals from the cortex-m crate
    let cp = cortex_m::Peripherals::take().unwrap();
    // Get access to the device specific peripherals from the peripheral access crate
    let dp = pac::Peripherals::take().unwrap();

    // Take ownership over the raw flash and rcc devices and convert them into the corresponding
    // HAL structs
    let mut pwr = dp.PWR;
    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();
    let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut pwr);

    // Freeze the configuration of all the clocks in the system and store the frozen frequencies in
    // `clocks`
    let clocks = rcc
        .cfgr
        .use_hse(8.MHz())
        .sysclk(24.MHz())
        .pclk1(24.MHz())
        .pclk2(24.MHz())
        .freeze(&mut flash.acr);

    let mut gpiob = dp.GPIOB.split();
    let mut gpioa = dp.GPIOA.split();
    let mut gpioc = dp.GPIOC.split();
    let mut afio = dp.AFIO.constrain();

    let (_, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4);

    let mut led1 = gpiob.pb12.into_open_drain_output(&mut gpiob.crh);
    let mut led2 = gpiob.pb11.into_open_drain_output(&mut gpiob.crh);
    let mut led3 = gpiob.pb1.into_open_drain_output(&mut gpiob.crl);
    let mut led4 = gpiob.pb0.into_open_drain_output(&mut gpiob.crl);

    let leds: [&mut dyn OutputPin<Error = Infallible>; 4] =
        [&mut led1, &mut led2, &mut led3, &mut led4];

    let btn1 = Button::<ActiveHigh>::new(Box::new(gpiob.pb15.into_pull_down_input(&mut gpiob.crh)));
    let btn2 = Button::<ActiveHigh>::new(Box::new(gpiob.pb14.into_pull_down_input(&mut gpiob.crh)));
    let btn3 = Button::<ActiveHigh>::new(Box::new(gpiob.pb13.into_pull_down_input(&mut gpiob.crh)));
    let btn4 = Button::<ActiveHigh>::new(Box::new(gpioc.pc13.into_pull_down_input(&mut gpioc.crh)));

    let mut btns: [Button<ActiveHigh>; 4] = [btn1, btn2, btn3, btn4];

    let a = gpiob.pb10.into_open_drain_output(&mut gpiob.crh);
    let b = gpiob.pb2.into_open_drain_output(&mut gpiob.crl);
    let c = gpiob.pb8.into_open_drain_output(&mut gpiob.crh);
    let d = gpiob.pb6.into_open_drain_output(&mut gpiob.crl);
    let e = gpiob.pb9.into_open_drain_output(&mut gpiob.crh);
    let f = pb3.into_open_drain_output(&mut gpiob.crl);
    let g = pb4.into_open_drain_output(&mut gpiob.crl);
    let dpp = gpiob.pb7.into_open_drain_output(&mut gpiob.crl);

    let dig1 = gpioa.pa6.into_alternate_open_drain(&mut gpioa.crl);
    let dig2 = gpioa.pa3.into_alternate_open_drain(&mut gpioa.crl);
    let dig3 = gpioa.pa7.into_alternate_open_drain(&mut gpioa.crl);
    let dig4 = gpioa.pa8.into_alternate_open_drain(&mut gpioa.crh);
    let dig5 = gpioa.pa9.into_alternate_open_drain(&mut gpioa.crh);
    let dig6 = gpioa.pa2.into_alternate_open_drain(&mut gpioa.crl);
    let dig7 = gpioa.pa10.into_alternate_open_drain(&mut gpioa.crh);
    let dig8 = gpioa.pa1.into_alternate_open_drain(&mut gpioa.crl);
/// Puts given pins into open drain,
/// then makes PWM out of digit pins,
/// lastly, timer 4 is constructed for refreshing the display,
/// and ClockDisplayViewer is created.
fn init_segment_display(
    pb10: Pin<'B', 10, Input<Floating>>,
    pb2: Pin<'B', 2, Input<Floating>>,
    pb8: Pin<'B', 8, Input<Floating>>,
    pb6: Pin<'B', 6, Input<Floating>>,
    pb9: Pin<'B', 9, Input<Floating>>,
    pb3: Pin<'B', 3, Input<Floating>>,
    pb4: Pin<'B', 4, Input<Floating>>,
    pb7: Pin<'B', 7, Input<Floating>>,
    pa6: Pin<'A', 6, Input<Floating>>,
    pa3: Pin<'A', 3, Input<Floating>>,
    pa7: Pin<'A', 7, Input<Floating>>,
    pa8: Pin<'A', 8, Input<Floating>>,
    pa9: Pin<'A', 9, Input<Floating>>,
    pa2: Pin<'A', 2, Input<Floating>>,
    pa10: Pin<'A', 10, Input<Floating>>,
    pa1: Pin<'A', 1, Input<Floating>>,
    tim1: pac::TIM1,
    tim2: pac::TIM2,
    tim3: pac::TIM3,
    tim4: pac::TIM4,
    gpioa_crl: &mut Cr<'A', false>,
    gpioa_crh: &mut Cr<'A', true>,
    gpiob_crl: &mut Cr<'B', false>,
    gpiob_crh: &mut Cr<'B', true>,
    afio_mapr: &mut MAPR,
    clocks: &Clocks,
) -> ClockDisplayViewer {
    let a = pb10.into_open_drain_output(gpiob_crh);
    let b = pb2.into_open_drain_output(gpiob_crl);
    let c = pb8.into_open_drain_output(gpiob_crh);
    let d = pb6.into_open_drain_output(gpiob_crl);
    let e = pb9.into_open_drain_output(gpiob_crh);
    let f = pb3.into_open_drain_output(gpiob_crl);
    let g = pb4.into_open_drain_output(gpiob_crl);
    let dpp = pb7.into_open_drain_output(gpiob_crl);

    let dig1 = pa6.into_alternate_open_drain(gpioa_crl);
    let dig2 = pa3.into_alternate_open_drain(gpioa_crl);
    let dig3 = pa7.into_alternate_open_drain(gpioa_crl);
    let dig4 = pa8.into_alternate_open_drain(gpioa_crh);
    let dig5 = pa9.into_alternate_open_drain(gpioa_crh);
    let dig6 = pa2.into_alternate_open_drain(gpioa_crl);
    let dig7 = pa10.into_alternate_open_drain(gpioa_crh);
    let dig8 = pa1.into_alternate_open_drain(gpioa_crl);

    let pwm_freq = 2.kHz();
    let pins1 = (dig4, dig5, dig7);
    let pwm1 = dp
        .TIM1
        .pwm_hz::<Tim1NoRemap, _, _>(pins1, &mut afio.mapr, pwm_freq, &clocks);
    let pwm1 = tim1.pwm_hz::<Tim1NoRemap, _, _>(pins1, afio_mapr, pwm_freq, &clocks);

    let pins2 = (dig8, dig6, dig2);
    let pwm2 = dp
        .TIM2
        .pwm_hz::<Tim2NoRemap, _, _>(pins2, &mut afio.mapr, pwm_freq, &clocks);
    let pwm2 = tim2.pwm_hz::<Tim2NoRemap, _, _>(pins2, afio_mapr, pwm_freq, &clocks);

    let pins3 = (dig1, dig3);
    let pwm3 = dp
        .TIM3
        .pwm_hz::<Tim3NoRemap, _, _>(pins3, &mut afio.mapr, pwm_freq, &clocks);
    let pwm3 = tim3.pwm_hz::<Tim3NoRemap, _, _>(pins3, afio_mapr, pwm_freq, &clocks);

    let mut tim4 = dp.TIM4.counter_us(&clocks);
    let mut tim4 = tim4.counter_us(&clocks);
    tim4.listen(Event::Update);
    tim4.start(10.micros()).unwrap();



@@ 197,14 172,111 @@ fn main() -> ! {
    );

    let display = ClockDisplay::new(display);
    let mut display = ClockDisplayViewer::new(display);
    ClockDisplayViewer::new(display)
}

fn init_buttons(
    pb15: Pin<'B', 15, Input<Floating>>,
    pb14: Pin<'B', 14, Input<Floating>>,
    pb13: Pin<'B', 13, Input<Floating>>,
    pc13: Pin<'C', 13, Input<Floating>>,
    gpiob_crh: &mut Cr<'B', true>,
    gpioc_crh: &mut Cr<'C', true>,
) -> [Button<ActiveHigh>; 4] {
    let btn1 = Button::<ActiveHigh>::new(Box::new(pb15.into_pull_down_input(gpiob_crh)));
    let btn2 = Button::<ActiveHigh>::new(Box::new(pb14.into_pull_down_input(gpiob_crh)));
    let btn3 = Button::<ActiveHigh>::new(Box::new(pb13.into_pull_down_input(gpiob_crh)));
    let btn4 = Button::<ActiveHigh>::new(Box::new(pc13.into_pull_down_input(gpioc_crh)));

    [btn1, btn2, btn3, btn4]
}

fn init_leds<'a>(
    pb12: Pin<'B', 12, Input<Floating>>,
    pb11: Pin<'B', 11, Input<Floating>>,
    pb1: Pin<'B', 1, Input<Floating>>,
    pb0: Pin<'B', 0, Input<Floating>>,
    gpiob_crl: &mut Cr<'B', false>,
    gpiob_crh: &mut Cr<'B', true>,
) -> [Box<dyn OutputPin<Error = Infallible> + Send>; 4] {
    let led1 = pb12.into_open_drain_output(gpiob_crh);
    let led2 = pb11.into_open_drain_output(gpiob_crh);
    let led3 = pb1.into_open_drain_output(gpiob_crl);
    let led4 = pb0.into_open_drain_output(gpiob_crl);

    [Box::new(led1), Box::new(led2), Box::new(led3), Box::new(led4)]
}

fn init_heap() {
    use core::mem::MaybeUninit;
    const HEAP_SIZE: usize = 512;
    static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
    unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
}

#[entry]
fn main() -> ! {
    init_heap();

    let cp = cortex_m::Peripherals::take().unwrap();
    let dp = pac::Peripherals::take().unwrap();

    let mut pwr = dp.PWR;
    let mut flash = dp.FLASH.constrain();
    let rcc = dp.RCC.constrain();
    let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut pwr);

    let clocks = rcc
        .cfgr
        .use_hse(8.MHz())
        .sysclk(24.MHz())
        .pclk1(24.MHz())
        .pclk2(24.MHz())
        .freeze(&mut flash.acr);

    let mut gpiob = dp.GPIOB.split();
    let mut gpioa = dp.GPIOA.split();
    let mut gpioc = dp.GPIOC.split();
    let mut afio = dp.AFIO.constrain();
    let (_, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4);

    let leds = init_leds(gpiob.pb12, gpiob.pb11, gpiob.pb1, gpiob.pb0, &mut gpiob.crl, &mut gpiob.crh);
    let btns = init_buttons(gpiob.pb15, gpiob.pb14, gpiob.pb13, gpioc.pc13, &mut gpiob.crh, &mut gpioc.crh);

    let mut display = init_segment_display(
        gpiob.pb10,
        gpiob.pb2,
        gpiob.pb8,
        gpiob.pb6,
        gpiob.pb9,
        pb3,
        pb4,
        gpiob.pb7,
        gpioa.pa6,
        gpioa.pa3,
        gpioa.pa7,
        gpioa.pa8,
        gpioa.pa9,
        gpioa.pa2,
        gpioa.pa10,
        gpioa.pa1,
        dp.TIM1,
        dp.TIM2,
        dp.TIM3,
        dp.TIM4,
        &mut gpioa.crl,
        &mut gpioa.crh,
        &mut gpiob.crl,
        &mut gpiob.crh,
        &mut afio.mapr,
        &clocks
    );
    display.set_current_view(DisplayViews::ClockSecondsView);

    let mut rtc = match Rtc::restore_or_new(dp.RTC, &mut backup_domain) {
        Restored(rtc) => rtc,
        New(rtc) => rtc,
    };

    rtc.listen_seconds();

    // Initialize the state inside of a critical section,


@@ 219,7 291,7 @@ fn main() -> ! {
        }

        let state = ClockState::new(
            Calendar::from_seconds(Calendar::new(0, 0, 0, 1, 7, 2023), current_time),
            Calendar::from_seconds(Calendar::new(0, 0, 0, 1, 8, 2023), current_time),
            MonoTimer::new(cp.DWT, cp.DCB, clocks),
        );



@@ 231,8 303,11 @@ fn main() -> ! {
        cortex_m::peripheral::NVIC::unmask(interrupt::TIM4);
    }

    let mut delay = cp.SYST.delay(&clocks);
    let delay = cp.SYST.delay(&clocks);
    main_loop(delay, btns, leds)
}

fn main_loop(mut delay: SysDelay, mut btns: [Button<ActiveHigh>; 4], mut leds: [Box<dyn OutputPin<Error = Infallible> + Send>; 4]) -> ! {
    loop {
        for (i, btn) in btns.iter_mut().enumerate() {
            btn.update();

Do not follow this link