use crate::lcd::{BufLcd10168, Lcd10168}; use atmega_hal::{ clock::MHz16, pac::TC1, pins, port::*, usart::{BaudrateExt, Usart0}, Peripherals, }; use avr_device::interrupt::{CriticalSection, Mutex}; use avr_hal_generic::avr_device::{self, interrupt}; use core::cell::{RefCell, RefMut}; pub struct Devices { pub lcd: BufLcd10168, pub uart: Usart0, } static DEVICES: Mutex>> = Mutex::new(RefCell::new(None)); pub fn try_get(token: CriticalSection) -> Option> { let opt_devices = DEVICES.borrow(token).borrow_mut(); if opt_devices.is_some() { return Some(RefMut::map(opt_devices, |opt_devices| { opt_devices.as_mut().unwrap() })); } None } pub fn get(token: CriticalSection) -> RefMut { try_get(token).expect("devices have not been initialized") } pub fn init(dp: Peripherals) { let pins = pins!(dp); let lcd = Lcd10168::builder() .reset(pins.pc1) .chip_enable(pins.pc2) .data_command(pins.pc3) .data_in(pins.pc4) .clock(pins.pc5) .build() .into_buffered() .init(); let uart = Usart0::::new( dp.USART0, pins.pd0, pins.pd1.into_output(), 115200u32.into_baudrate(), ); init_timer_1(dp.TC1); interrupt::free(|token| { DEVICES .borrow(token) .borrow_mut() .replace(Devices { lcd, uart }); }) } fn init_timer_1(tc1: TC1) { const FREQUENCY: u32 = 16_000_000; const PRESCALER: u32 = 1024; const TICKS_PER_SECOND: u16 = 5; const CYCLES_PER_SECOND: u16 = (FREQUENCY / PRESCALER) as u16; const CYCLES_PER_TICK: u16 = CYCLES_PER_SECOND / TICKS_PER_SECOND; // WGM1 bits in TCCR1A and WGM1 bits in TCCR1B encode the mode of operation. // We set it to 0b0100 which corresponds to the CTC mode with TOP in OCR1A. // See https://maxembedded.com/2011/07/avr-timers-ctc-mode/. tc1.tccr1a.write(|w| w.wgm1().bits(0b00)); tc1.tccr1b .write(|w| w.cs1().prescale_1024().wgm1().bits(0b01)); tc1.ocr1a.write(|w| unsafe { w.bits(CYCLES_PER_TICK) }); tc1.timsk1.write(|w| w.ocie1a().set_bit()); // Enable TIMER1_COMPA interrupt }