diff --git a/firmware/application/clock_manager.cpp b/firmware/application/clock_manager.cpp index c8b75cce..0cbf462f 100644 --- a/firmware/application/clock_manager.cpp +++ b/firmware/application/clock_manager.cpp @@ -422,6 +422,30 @@ void ClockManager::disable_gp_clkin_source() { clock_generator.disable_output(clock_generator_output_mcu_clkin); } +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 { + .RCNT = 480, + .FCNT = 0, + .MEAS = 0, + .CLK_SEL = toUType(clk_sel), + .RESERVED0 = 0 + }; + LPC_CGU->FREQ_MON.MEAS = 1; +} + +void ClockManager::wait_For_frequency_monitor_measurement_done() { + // FREQ_MON mechanism fails to finish if there's no clock present on selected input?! + while(LPC_CGU->FREQ_MON.MEAS == 1); +} + +uint32_t ClockManager::get_frequency_monitor_measurement_in_hertz() { + // Measurement is only as accurate as the LPC43xx IRC oscillator, + // which is +/- 1.5%. Measurement is for 480 IRC clcocks. Scale + // the cycle count to get a value in Hertz. + return LPC_CGU->FREQ_MON.FCNT * 25000; +} + void ClockManager::enable_xtal_oscillator() { LPC_CGU->XTAL_OSC_CTRL.BYPASS = 0; LPC_CGU->XTAL_OSC_CTRL.ENABLE = 1; diff --git a/firmware/application/clock_manager.hpp b/firmware/application/clock_manager.hpp index f1398529..de36d374 100644 --- a/firmware/application/clock_manager.hpp +++ b/firmware/application/clock_manager.hpp @@ -66,6 +66,8 @@ public: void set_reference_ppb(const int32_t ppb); + uint32_t get_frequency_monitor_measurement_in_hertz(); + private: I2C& i2c0; si5351::Si5351& clock_generator; @@ -75,6 +77,8 @@ private: void enable_gp_clkin_source(); void disable_gp_clkin_source(); + void start_frequency_monitor_measurement(const cgu::CLK_SEL clk_sel); + void wait_For_frequency_monitor_measurement_done(); void enable_xtal_oscillator(); void disable_xtal_oscillator();