use super::teensy_common::SetClockError;
use crate::hw::mcu::kinetis::mkl26z64::{
Clock, Mcg, Osc, OscRange, PeripheralClockSource, Sim, SysTick, UartClockSource, UsbClockSource,
};
use core::{
ptr::write_volatile,
sync::atomic::{AtomicUsize, Ordering},
};
pub mod digital;
pub mod io;
pub mod time;
static PLL_FREQ: AtomicUsize = AtomicUsize::new(0);
static CPU_FREQ: AtomicUsize = AtomicUsize::new(0);
static BUS_FREQ: AtomicUsize = AtomicUsize::new(0);
pub fn set_clock(clock: usize) -> Result<(), SetClockError> {
let (core, bus, pll_num, pll_den) = match clock {
48_000_000 => (2, 2, 24, 4),
32_000_000 => (3, 2, 24, 4),
24_000_000 => (4, 1, 24, 4),
16_000_000 => (6, 1, 24, 4),
12_000_000 => (8, 1, 24, 4),
8_000_000 => (12, 1, 24, 4),
6_000_000 => (16, 1, 24, 4),
_ => return Err(SetClockError::InvalidClockRate),
};
let mut mcg = Mcg::get().ok_or(SetClockError::McgInUse)?;
let mut sim = Sim::get().ok_or(SetClockError::SimInUse)?;
let fbe = match mcg.clock() {
Clock::Fei(fei) => {
let osc_token = Osc::get()
.ok_or(SetClockError::OscInUse)?
.enable(10)
.map_err(|e| SetClockError::Osc(e))?;
fei.use_external(512, OscRange::VeryHigh, Some(osc_token))
.map_err(|e| SetClockError::Mcg(e))?
}
Clock::Fbe(fbe) => fbe,
Clock::Pbe(pbe) => pbe.disable_pll(),
Clock::Pee(pee) => pee.bypass_pll().disable_pll(),
};
sim.set_dividers(core, bus);
fbe.enable_pll(pll_num, pll_den)
.map_err(|e| SetClockError::Mcg(e))?
.use_pll();
sim.set_usb_source(UsbClockSource::PllFll);
sim.set_uart0_source(Some(UartClockSource::PllFll));
sim.set_peripheral_source(PeripheralClockSource::Pll);
if let Some(mut systick) = SysTick::get() {
systick.enable(false);
let reload = (clock / 1000) - 1;
systick.set_reload_value(reload as u32);
systick.set_current_value(0);
systick.enable(true);
}
PLL_FREQ.store(clock * core as usize, Ordering::Relaxed);
CPU_FREQ.store(clock, Ordering::Relaxed);
BUS_FREQ.store(clock * core as usize / bus as usize, Ordering::Relaxed);
Ok(())
}
#[cfg_attr(board = "teensy_lc", export_name = "__cntrlr_board_start")]
pub unsafe extern "C" fn start() {
Sim::get()
.expect("Could not acquire SIM to disable watchdog")
.disable_cop();
}
#[cfg_attr(board = "teensy_lc", export_name = "__cntrlr_board_init")]
pub unsafe extern "C" fn init() {
if let Some(mut systick) = SysTick::get() {
systick.use_core_clock(true);
systick.enable_interrupt(true);
}
set_clock(48_000_000).expect("Could not set core clock at init");
const NVIC_ISER: *mut u32 = 0xE000_E100 as *mut _;
for intr in &[12, 13, 14] {
let reg = intr / 32;
let bit = intr % 32;
write_volatile(NVIC_ISER.add(reg), 1 << bit);
}
}
use crate::runtime::unused_interrupt;
#[cfg_attr(board = "teensy_lc", link_section = ".__CNTRLR_INTERRUPTS")]
#[cfg_attr(board = "teensy_lc", export_name = "__cntrlr_interrupts")]
pub static INTERRUPTS: [unsafe extern "C" fn(); 32] = [
unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, io::serial_1_intr, io::serial_2_intr, io::serial_3_intr, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, ];
#[cfg_attr(board = "teensy_lc", link_section = ".__CNTRLR_EXCEPTIONS")]
#[cfg_attr(board = "teensy_lc", export_name = "__cntrlr_exceptions")]
pub static ARM_EXCEPTIONS: [unsafe extern "C" fn(); 14] = [
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
unused_interrupt,
time::systick_intr,
];