use super::teensy_common::SetClockError;
use crate::hw::mcu::kinetis::mk66fx1m0::{
Clock, Mcg, Osc, OscRange, PeripheralClockSource, Sim, Smc, SysTick, UsbClockSource, Watchdog,
};
use core::{
ptr::write_volatile,
sync::atomic::{AtomicUsize, Ordering},
};
pub mod digital;
pub mod io;
pub mod time;
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, flex, flash, usb_num, usb_den, pll_num, pll_den) = match clock {
256_000_000 => (1, 4, 4, 8, 1, None, 32, 1),
240_000_000 => (1, 4, 4, 8, 1, Some(5), 30, 1),
216_000_000 => (1, 4, 4, 8, 1, None, 27, 1),
192_000_000 => (1, 4, 4, 8, 1, Some(4), 24, 1),
180_000_000 => (1, 3, 3, 8, 1, None, 45, 2),
168_000_000 => (1, 3, 3, 7, 1, None, 21, 1),
144_000_000 => (1, 3, 3, 6, 1, None, 18, 1),
120_000_000 => (1, 2, 3, 5, 2, Some(5), 30, 2),
96_000_000 => (1, 2, 2, 4, 1, Some(2), 24, 2),
72_000_000 => (2, 2, 2, 3, 2, Some(3), 18, 2),
48_000_000 => (2, 2, 2, 4, 1, Some(2), 24, 2),
32_000_000 => (3, 3, 3, 6, 1, Some(2), 24, 2),
24_000_000 => (4, 4, 4, 4, 1, Some(2), 24, 2),
16_000_000 => (6, 6, 6, 6, 1, Some(2), 24, 2),
12_000_000 => (8, 8, 8, 8, 1, Some(2), 24, 2),
_ => return Err(SetClockError::InvalidClockRate),
};
let mut mcg = Mcg::get().ok_or(SetClockError::McgInUse)?;
let mut sim = Sim::get().ok_or(SetClockError::SimInUse)?;
let mut smc = Smc::get().ok_or(SetClockError::SmcInUse)?;
if clock > 120_000_000 {
smc.enter_hsrun();
}
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, flex, flash);
sim.set_usb_source(UsbClockSource::PllFll);
if let Some(usb_den) = usb_den {
sim.set_peripheral_source(PeripheralClockSource::Pll);
sim.set_usb_dividers(usb_num, usb_den);
} else {
sim.set_peripheral_source(PeripheralClockSource::Irc48);
sim.set_usb_dividers(1, 1);
}
fbe.enable_pll(pll_num, pll_den)
.map_err(|e| SetClockError::Mcg(e))?
.use_pll();
if clock <= 120_000_000 {
smc.exit_hsrun();
}
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);
}
CPU_FREQ.store(clock, Ordering::Relaxed);
BUS_FREQ.store(clock * core as usize / bus as usize, Ordering::Relaxed);
Ok(())
}
#[cfg_attr(board = "teensy_36", export_name = "__cntrlr_board_start")]
pub unsafe extern "C" fn start() {
Watchdog::get().disable();
}
#[cfg_attr(board = "teensy_36", 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);
}
if let Some(mut smc) = Smc::get() {
smc.allow_all_modes();
}
set_clock(120_000_000).expect("Could not set core clock at init");
const NVIC_ISER: *mut u32 = 0xE000_E100 as *mut _;
for intr in &[31, 33, 35, 37, 66, 68] {
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_36", link_section = ".__CNTRLR_INTERRUPTS")]
#[cfg_attr(board = "teensy_36", export_name = "__cntrlr_interrupts")]
pub static INTERRUPTS: [unsafe extern "C" fn(); 100] = [
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, 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, io::serial_1_intr, unused_interrupt, io::serial_2_intr, unused_interrupt, io::serial_3_intr, unused_interrupt, io::serial_4_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, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, unused_interrupt, io::serial_5_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, 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_36", link_section = ".__CNTRLR_EXCEPTIONS")]
#[cfg_attr(board = "teensy_36", 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,
];
unsafe fn enable_led() {
use core::ptr::write_volatile;
const fn bitband_address<T>(addr: u32, bit: u32) -> *mut T {
(0x4200_0000 + (addr - 0x4000_0000) * 32 + bit * 4) as _
}
const SIM_SCGC5_BIT_11: *mut u32 = bitband_address(0x4004_8038, 11);
const PORTC_GPCLR: *mut u32 = 0x4004_B080 as _;
const GPIOC_PDDR_BIT_5: *mut u32 = bitband_address(0x400F_F094, 5);
const GPIOC_PSOR: *mut u32 = 0x400F_F084 as _;
write_volatile(SIM_SCGC5_BIT_11, 1);
write_volatile(PORTC_GPCLR, 0x0020_0100); write_volatile(GPIOC_PDDR_BIT_5, 1);
write_volatile(GPIOC_PSOR, 1 << 5);
}