Clock Manager: Detect Si5351 CLKIN present, measure frequency, and use if approximately 10MHz.

This commit is contained in:
Jared Boone 2018-08-05 12:21:25 -07:00
parent 30f2bc4149
commit 88afee26d7
3 changed files with 35 additions and 4 deletions

View File

@ -269,11 +269,23 @@ void ClockManager::init() {
clock_generator.enable_fanout();
clock_generator.set_pll_input_sources(si5351_pll_input_sources);
const bool use_clkin = false;
const auto clkin_present = !clock_generator.clkin_loss_of_signal();
auto clkin_valid = false;
if( clkin_present ) {
// Measure Si5351B CLKIN frequency against LPC43xx IRC oscillator
set_gp_clkin_to_clkin_direct();
start_frequency_monitor_measurement(cgu::CLK_SEL::GP_CLKIN);
wait_For_frequency_monitor_measurement_done();
const auto clkin_frequency = get_frequency_monitor_measurement_in_hertz();
// CLKIN is required to be 10MHz. FREQ_MON measurement is accurate to 1.5%
// due to LPC43xx IRC oscillator precision.
clkin_valid = (clkin_frequency >= 9850000) && (clkin_frequency <= 10150000);
}
clock_generator.set_clock_control(
use_clkin ?
si5351_clock_control_clkin
: si5351_clock_control_xtal
clkin_valid ? si5351_clock_control_clkin : si5351_clock_control_xtal
);
clock_generator.write(si5351_pll_a_xtal_reg);
@ -422,6 +434,14 @@ void ClockManager::disable_gp_clkin_source() {
clock_generator.disable_output(clock_generator_output_mcu_clkin);
}
void ClockManager::set_gp_clkin_to_clkin_direct() {
clock_generator.set_clock_control(
clock_generator_output_mcu_clkin,
{ ClockControl::CLK_IDRV_2mA | ClockControl::CLK_SRC_CLKIN | ClockControl::CLK_INV_Normal | ClockControl::MS_INT_Integer | ClockControl::CLK_PDN_Power_On }
);
enable_gp_clkin_source();
}
void ClockManager::start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel) {
// Measure a clock input for 480 cycles of the LPC43xx IRC.
LPC_CGU->FREQ_MON = LPC_CGU_FREQ_MON_Type {

View File

@ -77,6 +77,8 @@ private:
void enable_gp_clkin_source();
void disable_gp_clkin_source();
void set_gp_clkin_to_clkin_direct();
void start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel);
void wait_For_frequency_monitor_measurement_done();

View File

@ -310,6 +310,10 @@ public:
while(device_status() & 0x80);
}
bool clkin_loss_of_signal() {
return (device_status() >> 4) & 1;
}
void enable_fanout() {
write_register(Register::FanoutEnable, 0b11010000);
}
@ -373,6 +377,11 @@ public:
update_all_clock_control();
}
void set_clock_control(const size_t n, const ClockControl::Type clock_control) {
_clock_control[n] = clock_control;
write_register(Register::CLKControl_Base + n, _clock_control[n]);
}
void enable_clock(const size_t n) {
_clock_control[n] &= ~ClockControl::CLK_PDN_Mask;
write_register(Register::CLKControl_Base + n, _clock_control[n]);