mirror of
https://github.com/laanwj/k210-sdk-stuff.git
synced 2024-11-22 09:26:21 +04:00
rust: sysctl PLL setting
Port over the terrible PLL frequency setting code, and use it to set up the clocks for every demo.
This commit is contained in:
parent
f8f7235daa
commit
d7eb8dd0e8
@ -55,6 +55,9 @@ fn sample_cirle(x: i32, y: i32, cx: i32, cy: i32, r: i32, rr: i32) -> bool {
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -60,6 +60,9 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -142,6 +142,9 @@ pub static BLOCK_SPRITE: [[u32; 4];8] = [
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -70,6 +70,9 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -44,6 +44,9 @@ fn my_trap_handler() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -47,6 +47,9 @@ fn io_set_power() {
|
|||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
// Configure clocks (TODO)
|
// Configure clocks (TODO)
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
|
@ -2,20 +2,25 @@
|
|||||||
use k210_hal::pac;
|
use k210_hal::pac;
|
||||||
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
use libm::F64Ext;
|
||||||
|
|
||||||
use crate::soc::utils::set_bit;
|
use crate::soc::utils::set_bit;
|
||||||
use crate::soc::sleep::usleep;
|
use crate::soc::sleep::usleep;
|
||||||
|
|
||||||
const SYSCTRL_CLOCK_FREQ_IN0: u32 = 26000000;
|
const SYSCTRL_CLOCK_FREQ_IN0: u32 = 26000000;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum pll {
|
pub enum pll {
|
||||||
|
/** PLL0 can usually be selected as alternative to IN0, for example the CPU
|
||||||
|
* clock speed. It can be used as source for PLL2. */
|
||||||
PLL0,
|
PLL0,
|
||||||
|
/** PLL1 is used for the KPU clock, and can be used as source for PLL2. */
|
||||||
PLL1,
|
PLL1,
|
||||||
|
/** PLL2 is used for I2S clocks. */
|
||||||
PLL2,
|
PLL2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum clock_source {
|
pub enum clock_source {
|
||||||
IN0,
|
IN0,
|
||||||
PLL0,
|
PLL0,
|
||||||
@ -24,7 +29,7 @@ pub enum clock_source {
|
|||||||
ACLK,
|
ACLK,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum clock {
|
pub enum clock {
|
||||||
PLL0,
|
PLL0,
|
||||||
PLL1,
|
PLL1,
|
||||||
@ -69,7 +74,7 @@ pub enum clock {
|
|||||||
IN0,
|
IN0,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum threshold {
|
pub enum threshold {
|
||||||
ACLK,
|
ACLK,
|
||||||
APB0,
|
APB0,
|
||||||
@ -100,7 +105,7 @@ pub enum threshold {
|
|||||||
WDT1,
|
WDT1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum clock_select {
|
pub enum clock_select {
|
||||||
PLL0_BYPASS,
|
PLL0_BYPASS,
|
||||||
PLL1_BYPASS,
|
PLL1_BYPASS,
|
||||||
@ -114,13 +119,13 @@ pub enum clock_select {
|
|||||||
SPI3_SAMPLE,
|
SPI3_SAMPLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum io_power_mode {
|
pub enum io_power_mode {
|
||||||
V33,
|
V33,
|
||||||
V18,
|
V18,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum power_bank {
|
pub enum power_bank {
|
||||||
BANK0 = 0,
|
BANK0 = 0,
|
||||||
BANK1,
|
BANK1,
|
||||||
@ -132,7 +137,7 @@ pub enum power_bank {
|
|||||||
BANK7,
|
BANK7,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum reset {
|
pub enum reset {
|
||||||
SOC,
|
SOC,
|
||||||
ROM,
|
ROM,
|
||||||
@ -305,6 +310,7 @@ pub fn sysctl_clock_disable(clock: clock) {
|
|||||||
|
|
||||||
/// Set clock divider
|
/// Set clock divider
|
||||||
pub fn clock_set_threshold(which: threshold, threshold: u32) {
|
pub fn clock_set_threshold(which: threshold, threshold: u32) {
|
||||||
|
// TODO: this should take a multiplier directly, not a peripheral specific value
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = pac::SYSCTL::ptr();
|
let ptr = pac::SYSCTL::ptr();
|
||||||
match which {
|
match which {
|
||||||
@ -351,6 +357,7 @@ pub fn clock_set_threshold(which: threshold, threshold: u32) {
|
|||||||
/// Get clock divider
|
/// Get clock divider
|
||||||
pub fn clock_get_threshold(which: threshold) -> u32 {
|
pub fn clock_get_threshold(which: threshold) -> u32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// TODO: this should return a multiplier directly, not a peripheral specific value
|
||||||
let ptr = pac::SYSCTL::ptr();
|
let ptr = pac::SYSCTL::ptr();
|
||||||
match which {
|
match which {
|
||||||
/* 2 bit wide */
|
/* 2 bit wide */
|
||||||
@ -416,6 +423,26 @@ pub fn set_spi0_dvp_data(status: bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Map PLL2 cksel value to clock source */
|
||||||
|
fn pll2_cksel_to_source(bits: u8) -> clock_source {
|
||||||
|
match bits {
|
||||||
|
0 => clock_source::IN0,
|
||||||
|
1 => clock_source::PLL0,
|
||||||
|
2 => clock_source::PLL1,
|
||||||
|
_ => panic!("invalid value for PLL2 ckin_sel"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Map clock source to PLL2 cksel value */
|
||||||
|
fn pll2_source_to_cksel(source: clock_source) -> u8 {
|
||||||
|
match source {
|
||||||
|
clock_source::IN0 => 0,
|
||||||
|
clock_source::PLL0 => 1,
|
||||||
|
clock_source::PLL1 => 2,
|
||||||
|
_ => panic!("unsupported clock source for PLL2"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pll_get_freq(pll: pll) -> u32 {
|
pub fn pll_get_freq(pll: pll) -> u32 {
|
||||||
let freq_in;
|
let freq_in;
|
||||||
let nr;
|
let nr;
|
||||||
@ -432,7 +459,6 @@ pub fn pll_get_freq(pll: pll) -> u32 {
|
|||||||
od = val.clkod().bits() + 1;
|
od = val.clkod().bits() + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pll::PLL1 => {
|
pll::PLL1 => {
|
||||||
freq_in = clock_source_get_freq(clock_source::IN0);
|
freq_in = clock_source_get_freq(clock_source::IN0);
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -444,12 +470,7 @@ pub fn pll_get_freq(pll: pll) -> u32 {
|
|||||||
}
|
}
|
||||||
pll::PLL2 => {
|
pll::PLL2 => {
|
||||||
/* Get input freq accrording to select register. */
|
/* Get input freq accrording to select register. */
|
||||||
freq_in = clock_source_get_freq(match clock_get_clock_select(clock_select::PLL2) {
|
freq_in = clock_source_get_freq(pll2_cksel_to_source(clock_get_clock_select(clock_select::PLL2)));
|
||||||
0 => clock_source::IN0,
|
|
||||||
1 => clock_source::PLL0,
|
|
||||||
2 => clock_source::PLL1,
|
|
||||||
_ => panic!("unknown PLL2 source"),
|
|
||||||
});
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = (*pac::SYSCTL::ptr()).pll2.read();
|
let val = (*pac::SYSCTL::ptr()).pll2.read();
|
||||||
nr = val.clkr().bits() + 1;
|
nr = val.clkr().bits() + 1;
|
||||||
@ -480,6 +501,8 @@ pub fn clock_source_get_freq(source: clock_source) -> u32 {
|
|||||||
pub fn clock_set_clock_select(which: clock_select, select: u8) {
|
pub fn clock_set_clock_select(which: clock_select, select: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = pac::SYSCTL::ptr();
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
// Seems that PLL2 is the only one that takes a non-boolean clock select
|
||||||
|
// TODO: take a clock_source directly when we know the meanings of these bits
|
||||||
match which {
|
match which {
|
||||||
clock_select::PLL0_BYPASS => (*ptr).pll0.modify(|_, w| w.bypass().bit(select != 0)),
|
clock_select::PLL0_BYPASS => (*ptr).pll0.modify(|_, w| w.bypass().bit(select != 0)),
|
||||||
clock_select::PLL1_BYPASS => (*ptr).pll1.modify(|_, w| w.bypass().bit(select != 0)),
|
clock_select::PLL1_BYPASS => (*ptr).pll1.modify(|_, w| w.bypass().bit(select != 0)),
|
||||||
@ -498,6 +521,14 @@ pub fn clock_set_clock_select(which: clock_select, select: u8) {
|
|||||||
pub fn clock_get_clock_select(which: clock_select) -> u8 {
|
pub fn clock_get_clock_select(which: clock_select) -> u8 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = pac::SYSCTL::ptr();
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
// Seems that PLL2 is the only one that has a non-boolean clock select
|
||||||
|
// TODO: return a clock_source directly when we know the meanings of these bits
|
||||||
|
// meaning seems to be usually:
|
||||||
|
// 0 IN0
|
||||||
|
// 1 PLL0
|
||||||
|
// (2 PLL1)
|
||||||
|
// it's likely different for _BYPASS, which, I suspect, wires the PLL output to the
|
||||||
|
// input (IN0 for PLL0 and PLL1, selectable for PLL2)
|
||||||
match which {
|
match which {
|
||||||
clock_select::PLL0_BYPASS => (*ptr).pll0.read().bypass().bit().into(),
|
clock_select::PLL0_BYPASS => (*ptr).pll0.read().bypass().bit().into(),
|
||||||
clock_select::PLL1_BYPASS => (*ptr).pll1.read().bypass().bit().into(),
|
clock_select::PLL1_BYPASS => (*ptr).pll1.read().bypass().bit().into(),
|
||||||
@ -646,3 +677,342 @@ pub fn dma_select(channel: dma_channel, select: dma_select)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return whether the selected PLL has achieved lock */
|
||||||
|
fn pll_is_lock(pll: pll) -> bool {
|
||||||
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
let pll_lock = unsafe { (*ptr).pll_lock.read() };
|
||||||
|
match pll {
|
||||||
|
pll::PLL0 => pll_lock.pll_lock0().bits() == 3,
|
||||||
|
pll::PLL1 => (pll_lock.pll_lock1().bits() & 1) == 1,
|
||||||
|
pll::PLL2 => (pll_lock.pll_lock2().bits() & 1) == 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clear PLL slip, this is done repeatedly until lock is achieved */
|
||||||
|
fn pll_clear_slip(pll: pll) -> bool {
|
||||||
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
unsafe {
|
||||||
|
(*ptr).pll_lock.modify(|_,w|
|
||||||
|
match pll {
|
||||||
|
pll::PLL0 => w.pll_slip_clear0().set_bit(),
|
||||||
|
pll::PLL1 => w.pll_slip_clear1().set_bit(),
|
||||||
|
pll::PLL2 => w.pll_slip_clear2().set_bit(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pll_is_lock(pll)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constants for PLL frequency computation */
|
||||||
|
const VCO_MIN: f64 = 3.5e+08;
|
||||||
|
const VCO_MAX: f64 = 1.75e+09;
|
||||||
|
const REF_MIN: f64 = 1.36719e+07;
|
||||||
|
const REF_MAX: f64 = 1.75e+09;
|
||||||
|
const NR_MIN: i32 = 1;
|
||||||
|
const NR_MAX: i32 = 16;
|
||||||
|
const NF_MIN: i32 = 1;
|
||||||
|
const NF_MAX: i32 = 64;
|
||||||
|
const NO_MIN: i32 = 1;
|
||||||
|
const NO_MAX: i32 = 16;
|
||||||
|
const NB_MIN: i32 = 1;
|
||||||
|
const NB_MAX: i32 = 64;
|
||||||
|
const MAX_VCO: bool = true;
|
||||||
|
const REF_RNG: bool = true;
|
||||||
|
|
||||||
|
fn pll_source_set_freq(pll: pll, source: clock_source, freq: u32) -> Result<u32,()> {
|
||||||
|
use pll::*;
|
||||||
|
/* PLL0 and 1 can only source from IN0 */
|
||||||
|
if (pll == PLL0 || pll == PLL1) && source != clock_source::IN0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let freq_in = clock_source_get_freq(source);
|
||||||
|
if freq_in == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate PLL registers' value by finding closest matching parameters
|
||||||
|
* NOTE: this uses floating point math ... this is horrible :-(
|
||||||
|
* TODO: implement this without fp ops
|
||||||
|
*/
|
||||||
|
/* Parameters to be exported from the loop */
|
||||||
|
struct Params {
|
||||||
|
nrx: i32,
|
||||||
|
no: i32,
|
||||||
|
nb: i32,
|
||||||
|
nfx: i64,
|
||||||
|
fvco: f64,
|
||||||
|
};
|
||||||
|
let fin: f64 = freq_in.into();
|
||||||
|
let fout: f64 = freq.into();
|
||||||
|
let val: f64 = fout / fin;
|
||||||
|
let terr: f64 = 0.5 / ((NF_MAX / 2) as f64);
|
||||||
|
// NOTE: removed the handling that the Kendryte SDK has for terr<=0.0, as this is impossible
|
||||||
|
// given that NF_MAX is a positive integer constant
|
||||||
|
let mut merr: f64 = terr;
|
||||||
|
|
||||||
|
let mut found: Option<Params> = None;
|
||||||
|
for nfi in (val as i32)..NF_MAX {
|
||||||
|
let nr: i32 = ((nfi as f64) / val) as i32;
|
||||||
|
if nr == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if REF_RNG && (nr < NR_MIN) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if fin / (nr as f64) > REF_MAX {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut nrx: i32 = nr;
|
||||||
|
let mut nf: i32 = nfi;
|
||||||
|
let mut nfx: i64 = nfi.into();
|
||||||
|
let nval: f64 = (nfx as f64) / (nr as f64);
|
||||||
|
if nf == 0 {
|
||||||
|
nf = 1;
|
||||||
|
}
|
||||||
|
let err: f64 = 1.0 - nval / val;
|
||||||
|
|
||||||
|
if (err.abs() < merr * (1.0 + 1e-6)) || (err.abs() < 1e-16) {
|
||||||
|
let mut not: i32 = (VCO_MAX / fout).floor() as i32;
|
||||||
|
let mut no: i32 = if not > NO_MAX { NO_MAX } else { not };
|
||||||
|
while no > NO_MIN {
|
||||||
|
if (REF_RNG) && ((nr / no) < NR_MIN) {
|
||||||
|
no -= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (nr % no) == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
no -= 1;
|
||||||
|
}
|
||||||
|
if (nr % no) != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut nor: i32 = (if not > NO_MAX { NO_MAX } else { not } ) / no;
|
||||||
|
let mut nore: i32 = NF_MAX / nf;
|
||||||
|
if nor > nore {
|
||||||
|
nor = nore;
|
||||||
|
}
|
||||||
|
let noe: i32 = (VCO_MIN / fout).ceil() as i32;
|
||||||
|
if !MAX_VCO {
|
||||||
|
nore = (noe - 1) / no + 1;
|
||||||
|
nor = nore;
|
||||||
|
not = 0; /* force next if to fail */
|
||||||
|
}
|
||||||
|
if (((no * nor) < (not >> 1)) || ((no * nor) < noe)) && ((no * nor) < (NF_MAX / nf)) {
|
||||||
|
no = NF_MAX / nf;
|
||||||
|
if no > NO_MAX {
|
||||||
|
no = NO_MAX;
|
||||||
|
}
|
||||||
|
if no > not {
|
||||||
|
no = not;
|
||||||
|
}
|
||||||
|
nfx *= no as i64;
|
||||||
|
nf *= no;
|
||||||
|
if (no > 1) && !found.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* wait for larger nf in later iterations */
|
||||||
|
} else {
|
||||||
|
nrx /= no;
|
||||||
|
nfx *= nor as i64;
|
||||||
|
nf *= nor;
|
||||||
|
no *= nor;
|
||||||
|
if no > NO_MAX {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (nor > 1) && !found.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* wait for larger nf in later iterations */
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut nb: i32 = nfx as i32;
|
||||||
|
if nb < NB_MIN {
|
||||||
|
nb = NB_MIN;
|
||||||
|
}
|
||||||
|
if nb > NB_MAX {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fvco: f64 = fin / (nrx as f64) * (nfx as f64);
|
||||||
|
if fvco < VCO_MIN {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if fvco > VCO_MAX {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if nf < NF_MIN {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if REF_RNG && (fin / (nrx as f64) < REF_MIN) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if REF_RNG && (nrx > NR_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(found) = &found {
|
||||||
|
// check that this reduces error compared to minimum error value, or is an improvement
|
||||||
|
// in x_no
|
||||||
|
if !((err.abs() < merr * (1.0 - 1e-6))
|
||||||
|
|| (MAX_VCO && (no > found.no))
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if nrx > found.nrx {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
found = Some(Params {
|
||||||
|
nrx,
|
||||||
|
no,
|
||||||
|
nb,
|
||||||
|
nfx,
|
||||||
|
fvco,
|
||||||
|
});
|
||||||
|
merr = err.abs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(found) = found {
|
||||||
|
if merr >= terr * (1.0 - 1e-6) {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
unsafe {
|
||||||
|
let clkr: u8 = (found.nrx - 1).try_into().unwrap();
|
||||||
|
let clkf: u8 = (found.nfx - 1).try_into().unwrap();
|
||||||
|
let clkod: u8 = (found.no - 1).try_into().unwrap();
|
||||||
|
let bwadj: u8 = (found.nb - 1).try_into().unwrap();
|
||||||
|
match pll {
|
||||||
|
PLL0 => {
|
||||||
|
(*ptr).pll0.modify(|_,w|
|
||||||
|
w.clkr().bits(clkr)
|
||||||
|
.clkf().bits(clkf)
|
||||||
|
.clkod().bits(clkod)
|
||||||
|
.bwadj().bits(bwadj)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PLL1 => {
|
||||||
|
(*ptr).pll1.modify(|_,w|
|
||||||
|
w.clkr().bits(clkr)
|
||||||
|
.clkf().bits(clkf)
|
||||||
|
.clkod().bits(clkod)
|
||||||
|
.bwadj().bits(bwadj)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PLL2 => {
|
||||||
|
(*ptr).pll2.modify(|_,w|
|
||||||
|
w.ckin_sel().bits(pll2_source_to_cksel(source))
|
||||||
|
.clkr().bits(clkr)
|
||||||
|
.clkf().bits(clkf)
|
||||||
|
.clkod().bits(clkod)
|
||||||
|
.bwadj().bits(bwadj)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(pll_get_freq(pll))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Init PLL freqency
|
||||||
|
* @param[in] pll The PLL id
|
||||||
|
* @param[in] pll_freq The desired frequency in Hz
|
||||||
|
|
||||||
|
*/
|
||||||
|
pub fn pll_set_freq(pll: pll, freq: u32) -> Result<u32,()> {
|
||||||
|
assert!(freq != 0);
|
||||||
|
let ptr = pac::SYSCTL::ptr();
|
||||||
|
use pll::*;
|
||||||
|
|
||||||
|
/* 1. Change CPU CLK to XTAL */
|
||||||
|
if pll == PLL0 {
|
||||||
|
clock_set_clock_select(clock_select::ACLK, 0 /* clock_source::IN0 */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Disable PLL output */
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.out_en().clear_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.out_en().clear_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.out_en().clear_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Turn off PLL */
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.pwrd().clear_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.pwrd().clear_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.pwrd().clear_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. Set PLL to new value */
|
||||||
|
let result = if pll == PLL2 {
|
||||||
|
pll_source_set_freq(pll, pll2_cksel_to_source(clock_get_clock_select(clock_select::PLL2)), freq)
|
||||||
|
} else {
|
||||||
|
pll_source_set_freq(pll, clock_source::IN0, freq)
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 5. Power on PLL */
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.pwrd().set_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.pwrd().set_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.pwrd().set_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait >100ns */
|
||||||
|
usleep(1);
|
||||||
|
|
||||||
|
/* 6. Reset PLL then Release Reset*/
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
};
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().set_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().set_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().set_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/* wait >100ns */
|
||||||
|
usleep(1);
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.reset().clear_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 7. Get lock status, wait PLL stable */
|
||||||
|
while !pll_is_lock(pll) {
|
||||||
|
pll_clear_slip(pll);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8. Enable PLL output */
|
||||||
|
unsafe {
|
||||||
|
match pll {
|
||||||
|
PLL0 => (*ptr).pll0.modify(|_,w| w.out_en().set_bit()),
|
||||||
|
PLL1 => (*ptr).pll1.modify(|_,w| w.out_en().set_bit()),
|
||||||
|
PLL2 => (*ptr).pll2.modify(|_,w| w.out_en().set_bit()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 9. Change CPU CLK to PLL */
|
||||||
|
if pll == PLL0 {
|
||||||
|
clock_set_clock_select(clock_select::ACLK, 1 /*clock_source::PLL0*/);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
@ -57,6 +57,9 @@ fn main() -> ! {
|
|||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
|
||||||
// Configure clocks (TODO)
|
// Configure clocks (TODO)
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -69,6 +69,9 @@ fn color_from_xy(x: u16, y: u16, v: f32) -> (f32, f32, f32) {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -57,6 +57,9 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -58,6 +58,9 @@ fn hexdump<T: core::fmt::Write>(stdout: &mut T, buffer: &[u8], base: usize) {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -22,6 +22,9 @@ static mut SECP256K1_BUF: [u64; 70000/8] = [0u64; 70000/8];
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -67,6 +67,9 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
@ -21,6 +21,9 @@ const DEFAULT_BAUD: u32 = 115_200;
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
// Configure UARTHS (→host)
|
// Configure UARTHS (→host)
|
||||||
|
@ -67,6 +67,9 @@ fn io_init() {
|
|||||||
#[entry]
|
#[entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let p = Peripherals::take().unwrap();
|
let p = Peripherals::take().unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL0, 800_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL1, 300_000_000).unwrap();
|
||||||
|
sysctl::pll_set_freq(sysctl::pll::PLL2, 45_158_400).unwrap();
|
||||||
let clocks = k210_hal::clock::Clocks::new();
|
let clocks = k210_hal::clock::Clocks::new();
|
||||||
|
|
||||||
usleep(200000);
|
usleep(200000);
|
||||||
|
Loading…
Reference in New Issue
Block a user