Frequency counter library using GPS 1PPS signal and temperature controlled 50MHz Base clock. Ported from F411 Frequency Counter.

Dependencies:   RingBuff

Dependents:   Frequency_Cntr_1PPS_F746ZG

Fork of Frq_cuntr_full by Kenji Arai

Please refer following.
/users/kenjiArai/notebook/frequency-counters/

Revision:
5:bb04c4a3b5ba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/frq_cuntr_f746.cpp	Wed Nov 23 07:30:55 2016 +0000
@@ -0,0 +1,795 @@
+/*
+ * mbed Library / Frequency Counter with GPS 1PPS Compensation
+ *      Frequency Counter Hardware relataed program
+ *      Only for ST Nucleo-F746ZG
+ *
+ * Copyright (c) 2014,'15,'16 Kenji Arai / JH1PJL
+ *  http://www.page.sannet.ne.jp/kenjia/index.html
+ *  http://mbed.org/users/kenjiArai/
+ *      Started:    October   18th, 2014
+ *      Revised:    January    1st, 2015
+ *      Re-started: June      25th, 2016    ported from F411 board
+ *      Revised:    Novemeber 23rd, 2016
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if !defined(TARGET_STM32F746ZG)
+#error "This function works only on F746ZG!!"
+#endif  // !defined(TARGET_STM32F746ZG)
+
+#include    "frq_cuntr_f746.h"
+#include    "RingBuff.h"
+
+#define     ACTIVE_LED      1
+
+#if ACTIVE_LED
+DigitalOut irq_led1(LED1);
+DigitalOut irq_led2(LED2);
+DigitalOut irq_led3(LED3);
+#endif
+
+#if DEBUG
+#define PRINTF(...)     printf(__VA_ARGS__)
+#else
+#define PRINTF(...)     {;}
+#endif
+
+namespace Frequency_counter
+{
+
+// Following ring buffers are very big!! 4096 x 8(bytes) x 2(buff) = 64KB
+RingBuff<uint64_t> onepps_buf;    // RinBuffer for 1PPS (TIM2)
+freq_one onepps_dt;                 // frequency data in pack (interrupt)
+RingBuff<uint64_t> fdt_buffer;    // RinBuffer for TIM8+4
+freq_one fdt;                       // frequency data in pack (interrupt)
+
+// TIM2 IC2 + OverFlow
+static uint8_t  tim2_ready_flg;
+static uint32_t tim2_cnt_data;
+static uint16_t time_count_onepps;
+static uint16_t sw_ovrflw_tim2;
+// TIM2 IC4 (Reciprocal)
+static uint8_t  recipro_step;
+static uint32_t recipro_start;
+static uint32_t recipro_stop;
+// TIM2 OC
+static uint32_t oc_hi_time;
+static uint32_t oc_lo_time;
+// TIM4(TIM8) IC + OverFlow
+static uint8_t  tim8p4_ready_flg;
+static uint32_t tim8p4_cnt_data;
+static uint16_t time_count;
+static uint16_t sw_ovrflw_tim8p4;
+
+//------------------------------------------------------------------------------
+//  Frequency Counter
+//------------------------------------------------------------------------------
+FRQ_CUNTR::FRQ_CUNTR(double ex_clock)
+{
+    // Don't change calling sequence!!
+    set_external_clock(ex_clock);       // 1st
+    set_1sec_gate_time();               // 2nd
+    initialize_Freq_counter();          // 3rd
+}
+
+// Set External Clock Frequency
+void FRQ_CUNTR::set_external_clock(double ex_clock)
+{
+    ex_clock_freq = ex_clock;
+    ex_clk_base  = (uint32_t)(ex_clock_freq * 1000000.0f);       // MHz->Hz
+    clk_hi_const = (uint32_t)(ex_clock_freq * 1000000.0f * 0.2f);// Count=200mS
+    // 100ppm error range
+    uint32_t err = (uint32_t)(ex_clock_freq * 1000000.0f * 0.0001f);
+    clk_upper_limit = ex_clk_base + err;
+    clk_lower_limit = ex_clk_base - err;
+    PRINTF("\r\nSet EXTERNAL Clock mode\r\n");
+}
+
+// Set real gate time
+void FRQ_CUNTR::set_1sec_gate_time(void)
+{
+    oc_hi_time = clk_hi_const;              // 200mS
+    double gt_tmp0 = ex_clk_base * 1.0f;    // one sec
+    uint32_t gt_tmp1 = (uint32_t)gt_tmp0;
+    if ((gt_tmp0 - (double)gt_tmp1) >= 0.5f){
+        ++gt_tmp1;
+        if ((gt_tmp0 - (double)gt_tmp1) >= 0.5f){
+            ++gt_tmp1;
+        }         
+    }
+    oc_lo_time = gt_tmp1 - clk_hi_const;
+}
+
+void FRQ_CUNTR::initialize_Freq_counter(void)
+{
+    initialize_TIM2();
+    initialize_TIM8P4();
+}
+
+// Read new frequency data
+double FRQ_CUNTR::read_freq_data(void)
+{
+    return read_freq_w_gate_time(1);
+}
+
+// Read compensated frequency data with suitable gate time
+/*
+    yr: Measured 1PPS
+    yi: Ideal 1PPS (expected value)
+    xr: Measued unkown frequency data
+    --->  xi: Compesated data
+    comp = (yr-yi)/yi
+    -> delta = comp * xr
+    -> xi = xr + delta = compensated data
+*/
+double FRQ_CUNTR::read_compensated_freq_data_w_gt(uint16_t gt)
+{
+    freq_one f_new, f_old;
+    freq_one one_new, one_old;
+    uint32_t new_cnt, old_cnt;
+    uint64_t temp0;
+    double   temp1,   temp2;
+
+    f_new.f_1sec_dt = fdt_buffer.ring_get_newest_dt();   // newest data
+    f_old.f_1sec_dt = fdt_buffer.ring_get_pointed_dt(gt);// gt[sec] before data
+    one_new.f_1sec_dt = onepps_buf.ring_get_newest_dt();
+    one_old.f_1sec_dt = onepps_buf.ring_get_pointed_dt(gt);
+    new_cnt = (uint32_t)f_new.t_cnt;
+    old_cnt = (uint32_t)f_old.t_cnt;    
+    if (old_cnt > new_cnt){
+        new_cnt += 0x10000;
+    }
+    if ((new_cnt - old_cnt) != gt){
+        return 0.0f;
+    }
+    new_cnt = (uint32_t)one_new.t_cnt;
+    old_cnt = (uint32_t)one_old.t_cnt;
+    if (old_cnt > new_cnt){
+        new_cnt += 0x10000;
+    }
+    if ((new_cnt - old_cnt) != gt){
+        return 0.0f;
+    }
+    // comp = (yr-yi)/yi
+    temp0 = get_diff(one_new.f_1sec_dt, one_old.f_1sec_dt);
+    temp1 = (double)temp0 - ex_clock_freq * 1000000.0f * (double)gt;   
+    temp2 = temp1 / (ex_clock_freq * 1000000.0f * (double)gt);
+    // delta = comp * xr
+    temp0 = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt);
+    temp1 = temp2 * (double)temp0;
+    // xi = xr + delta
+    temp2 = (double)temp0 + temp1;
+    return temp2 / (double)gt;
+}
+
+// Read new frequency data with specific gate time
+double FRQ_CUNTR::read_freq_w_gate_time(uint16_t gt)
+{
+    freq_one f_new, f_old;
+
+    if (gt == 0){ return 0.0f;}
+    f_new.f_1sec_dt = fdt_buffer.ring_get_newest_dt();   // newest data
+    f_old.f_1sec_dt = fdt_buffer.ring_get_pointed_dt(gt);// gt[sec] before data
+    uint32_t new_cnt = (uint32_t)f_new.t_cnt;
+    uint32_t old_cnt = (uint32_t)f_old.t_cnt;
+    if (old_cnt > new_cnt){
+        new_cnt += 0x10000;
+    }
+    if ((new_cnt - old_cnt) == gt){  // make sure gt[sec]
+        uint64_t dt = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt);
+        return (double)dt / (double)gt;
+    } else {
+        return 0.0f;
+    }
+}
+
+// Read status (new frequency data is available or not)
+uint32_t FRQ_CUNTR::status_freq_update(void)
+{
+    return check_ic1_status_TIM8P4();
+}
+
+// Read status (new 1PPS data is available or not)
+uint32_t FRQ_CUNTR::status_1pps(void)
+{
+    return check_ic2_status_TIM2();
+}
+
+// Read GPS 1PPS counter value
+uint32_t FRQ_CUNTR::calc_1PPS_newest(void)
+{
+    freq_one f_new, f_old;
+    uint64_t diff = 0;
+
+    f_new.f_1sec_dt = onepps_buf.ring_get_newest_dt();  // newest data
+    f_old.f_1sec_dt = onepps_buf.ring_get_pointed_dt(1);
+    uint32_t new_cnt = (uint32_t)f_new.t_cnt;
+    uint32_t old_cnt = (uint32_t)f_old.t_cnt;
+    if (old_cnt > new_cnt){
+        new_cnt += 0x10000;
+    }
+    if ((new_cnt - old_cnt) == 1){  // make sure gt[sec]
+        diff = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt);
+    }
+    if ((diff > clk_upper_limit) || (diff < clk_lower_limit)){
+        // Missing 1PPS signal or Base clock is out of range
+        gps_ready = 0;
+        onepps_buf.ring_clear_buf();    // Clear ring buffer
+        return 0;
+    } else {    // GPS 1pps is in good range
+        gps_ready = 1;
+        onepps_ready_flg = 0;
+        onepps_newest = diff;
+        return diff;
+    }
+}
+
+// Avarage measured data GPS 1PPS by External Base Clock
+double FRQ_CUNTR::read_avarage_1pps(void)
+{
+    freq_one f_new, f_old;
+    int16_t size = 0;
+
+    f_new.f_1sec_dt = onepps_buf.ring_get_newest_dt();  // newest data
+    size = onepps_buf.ring_get_buf_size();
+    if (size >= 1500){      // Not use old 500 data
+        gate_time = 1000;       // Gate Time = 16min40sec
+    } else if (size >= 200){// Not use old 100 data
+        gate_time = 100;        // Gate Time = 1min40sec
+    } else if (size >= 20){ // Not use old 10 data
+        gate_time = 10;         // Gate Time = 10sec
+    } else if (size >= 10){ // Not use old 9 data
+        gate_time = 1;          // Gate Time = 1sec
+    } else {
+        gate_time = 1;
+        return 0.0f;            // data is not avairable
+    }
+    f_old.f_1sec_dt = onepps_buf.ring_get_pointed_dt(gate_time);
+    uint32_t new_cnt = (uint32_t)f_new.t_cnt;
+    uint32_t old_cnt = (uint32_t)f_old.t_cnt;
+    if (old_cnt > new_cnt){
+        new_cnt += 0x10000;
+    }
+    if ((new_cnt - old_cnt) == gate_time){  // make sure gt[sec]
+        uint64_t dt = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt);
+        return (double)dt / (double)gate_time;
+    } else {
+        return 0.0f;
+    }
+}
+
+// Read number of buffered data
+uint32_t FRQ_CUNTR::read_num_in_buffer(void)
+{
+    return onepps_buf.ring_get_buf_size();
+}
+
+// Newest measued data GPS 1PPS
+uint32_t FRQ_CUNTR::read_newest_1pps(void)
+{
+    calc_1PPS_newest();
+    return onepps_newest;
+}
+
+// Check GPS condition
+uint32_t FRQ_CUNTR::status_gps(void)
+{
+    if (gps_ready){
+        return gate_time;
+    } else {
+        return 0;   // 1PPS signal is not avarable
+    }
+}
+
+uint64_t FRQ_CUNTR::get_diff(uint64_t new_dt, uint64_t old_dt){
+    uint64_t nw,od;
+
+    nw = new_dt & 0x0000ffffffffffff;   // select 48bit data
+    od = old_dt & 0x0000ffffffffffff;
+    if (nw < od){ // 48bits counter overflow!
+        nw += 0x0001000000000000;
+    }
+    return (nw - od);
+}
+
+//------------------------------------------------------------------------------
+//  Frequency Counter / Reciprocal measurement
+//------------------------------------------------------------------------------
+void FRQ_CUNTR::recipro_start_measure(void)
+{
+    recipro_step = 0;               // initialize step
+    __disable_irq();
+    TIM2->SR &= ~TIM_SR_CC4IF;      // clear IC flag
+    TIM2->DIER |= TIM_DIER_CC4IE;   // Enable IC4
+    __enable_irq();
+}
+
+uint32_t FRQ_CUNTR::recipro_check_trigger(void)
+{
+    if (recipro_step == 2){         // check IC event happan or not
+        return 1;                   // happen
+    } else {
+        return 0;                   // not yet
+    }
+}
+
+uint32_t FRQ_CUNTR::recipro_read_data(void)
+{
+    uint64_t dt;
+    if (recipro_stop < recipro_start){  // 32bit counter overflow
+        dt =  0x100000000 +  recipro_stop;
+        dt -=  recipro_stop;
+    } else {
+        dt = recipro_stop - recipro_start;
+    }
+    return (uint32_t)dt;
+}
+
+//------------------------------------------------------------------------------
+//  TIM2 (32bit Counter + IC + OC)
+//------------------------------------------------------------------------------
+// Read TIM2 captured counter value
+uint32_t FRQ_CUNTR::read_ic2_counter_TIM2(void)
+{
+    return tim2_cnt_data;   // return TIM2->CCR2;
+}
+
+// Check TIM2 IC2 status
+uint32_t FRQ_CUNTR::check_ic2_status_TIM2(void)
+{
+    if (tim2_ready_flg == 0){
+        return 0;
+    } else {                // GPS 1PPS is comming
+        tim2_ready_flg = 0;
+        return 1;
+    }
+}
+
+// Check OC port status
+uint8_t FRQ_CUNTR::read_oc_port_status(void)
+{
+    uint32_t p = GPIOB->IDR;
+    if (p & 0x0400){        // Check PB10 status
+        return 1;           // H level
+    } else {
+        return 0;           // L level
+    }
+}
+
+//------------------------------------------------------------------------------
+//  TIM8+TIM4 (32bit Counter + IC)
+//------------------------------------------------------------------------------
+// Read TIM8+4(as 32bit) captured counter value
+uint32_t FRQ_CUNTR::read_counter_TIM8P4(void)
+{
+    return tim8p4_cnt_data;
+}
+
+// Check TIM8 IC2 & TIM4 IC1 status
+uint32_t FRQ_CUNTR::check_ic1_status_TIM8P4(void)
+{
+    if (tim8p4_ready_flg == 0){
+        return 0;
+    } else {                // Gate signal is comming
+        tim8p4_ready_flg = 0;
+        return 1;
+    }
+}
+
+//------------------------------------------------------------------------------
+//  Initialize TIM2 and TIM8+4
+//------------------------------------------------------------------------------
+// Initialize TIM2
+// External clock(50MHz)->PA_5 and
+// IC2->PA_1 for GPS 1pps signal measurement
+// IC4->PA_3 for Reciprocal frequency counting mode
+// OC3->PB_10 for Base gate time output(1 Second and other gate time)
+/*
+    ????? Strange behavior :
+            TIM2_ETR is assigned AF2 but following is assigned AF1! 
+ */
+void FRQ_CUNTR::initialize_TIM2(void)
+{
+    // PA5 -> Counter frequency input pin as Timer2 ETR(CH1?)
+    RCC->AHB1ENR  |= (RCC_AHB1ENR_GPIOAEN);
+    GPIOA->AFR[0] &= 0xff0fffff;
+    GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 20;       // 5(PA5) x 4bits = AFSEL5
+    // ??? AF3(TIM2_ETR) does NOT works!!
+    //GPIOA->AFR[0] |= ((uint8_t)0x02) << 20;
+    GPIOA->MODER  &= ~(GPIO_MODER_MODER5);      // AF
+    GPIOA->MODER  |= GPIO_MODER_MODER5_1;       //  alternate function mode
+    GPIOA->PUPDR  &= ~(GPIO_PUPDR_PUPDR5);      // PU
+    GPIOA->PUPDR  |= GPIO_PUPDR_PUPDR5_0;       //  Pull-up mode
+    // Initialize Timer2(32bit) for an external(ECE bit = 1) up counter mode
+    RCC->APB1ENR  |= RCC_APB1ENR_TIM2EN;
+                                // count_up + div by 1
+    TIM2->CR1     &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));
+                                // only counter overflow for interrupt
+    TIM2->CR1     |= (uint16_t)TIM_CR1_URS;
+                                // Up counter uses from 0 to max(32bit)
+    TIM2->ARR      = 0xffffffff;
+    TIM2->PSC      = 0x0000;                    // 1/1
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC1E;  // Disable the CC1
+                                // input filter + input select
+    TIM2->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM2->CCMR1   |= TIM_CCMR1_CC1S_0;
+    TIM2->SMCR     =
+             (TIM_SMCR_ECE| TIM_ETRPRESCALER_DIV1 | TIM_CLOCKSOURCE_ETRMODE1);
+    TIM2->CR1     |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM Counter
+    // PA1 -> Input Capture pin as Timer2 IC2
+    GPIOA->AFR[0] &= 0xffffff0f;
+    GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 4;        // 1bit x 4
+    GPIOA->MODER  &= ~(GPIO_MODER_MODER1);      // AF
+    GPIOA->MODER  |= GPIO_MODER_MODER1_1;       //  alternate function mode  
+    GPIOA->PUPDR  &= ~(GPIO_PUPDR_PUPDR1);      // PU
+    GPIOA->PUPDR  |= GPIO_PUPDR_PUPDR1_0;       //  Pull-up mode
+    // Initialize Timer2 IC2
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC2E;  // Disable the CC2
+                                // input filter + input select
+    TIM2->CCMR1   &= ~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S);
+    TIM2->CCMR1   |= TIM_CCMR1_CC2S_0;
+                                // positive edge
+    TIM2->CCER    &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP);
+    TIM2->CCER    |= (uint16_t)TIM_CCER_CC2E;   // enable capture
+    // PA3 -> Input Capture pin as Timer2 IC4 for Reciprocal
+    GPIOA->AFR[0] &= 0xffff0fff;
+    GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 12;       // 3bit x 4
+    GPIOA->MODER  &= ~(GPIO_MODER_MODER3);      // AF
+    GPIOA->MODER  |= GPIO_MODER_MODER3_1;       //  alternate function mode
+    GPIOA->PUPDR  &= ~(GPIO_PUPDR_PUPDR3);      // PU
+    GPIOA->PUPDR  |= GPIO_PUPDR_PUPDR3_0;       //  Pull-up mode
+    // Initialize Timer2 IC4
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC4E;  // Disable the CC
+    TIM2->CCMR2   &= ~(TIM_CCMR2_IC4F | TIM_CCMR2_CC4S);
+    TIM2->CCMR2   |= (TIM_CCMR2_CC4S_0 + TIM_CCMR2_IC4F_1); // filter = fCLK/4
+                                // positive edge
+    TIM2->CCER    &= (uint16_t)~(TIM_CCER_CC4P | TIM_CCER_CC4NP);
+    TIM2->CCER    |= (uint16_t)TIM_CCER_CC4E;   // enable capture
+    // PB10 -> Output Compare pin as Timer2 OC3
+    GPIOB->AFR[1] &= 0xfffff0ff;
+    GPIOB->AFR[1] |= GPIO_AF1_TIM2 << 8;        // 10bit x 4 -> 2bit x 4(AFR[1])
+    GPIOB->MODER  &= ~(GPIO_MODER_MODER10);     // AF
+    GPIOB->MODER  |= GPIO_MODER_MODER10_1;      //  alternate function mode
+    GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_10);      // Output Push-Pull=0
+    GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10;  //  Speed full=11
+    GPIOB->PUPDR  &= ~(GPIO_PUPDR_PUPDR10);     // No Pull-up&down = 0
+    // Initialize Timer2 OC3
+                                // Reset the CC3E Bit (Disable output)
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC3E;
+    TIM2->CCMR2   &= ~(TIM_CCMR2_OC3M | TIM_CCMR2_CC3S |
+                        TIM_CCMR2_OC3PE | TIM_CCMR2_OC3CE | TIM_CCMR2_OC3FE);
+    TIM2->CCMR2   |= TIM_CCMR2_OC3M_2;          // force to low level
+                                // Reset the Output Polarity level (active H)
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC3P;
+                                // Set the CC3E Bit (Enable output)
+    TIM2->CCER    |= (uint16_t)TIM_CCER_CC3E;
+                                // Set the Capture Compare Register value
+    TIM2->CCR3     = TIM2->CNT + oc_lo_time;
+    // Up counter based on gate time period
+    time_count_onepps = 0;
+    // Only for Debug purpose
+    //  PA
+    PRINTF("\r\n// Timer2(32bit) for an internal up counter mode\r\n");
+    PRINTF("// Set GPIO for Timer2\r\n");
+    PRINTF("// PA1  -> Input Capture pin as Timer2 CH2/TI2\r\n");
+    PRINTF("// PA3  -> Input Capture pin as Timer2 CH4/TI4\r\n");
+    PRINTF("GPIOA->AFRL  0x%08x:0x%08x\r\n",&GPIOA->AFR[0], GPIOA->AFR[0]);
+    PRINTF("GPIOA->AFRH  0x%08x:0x%08x\r\n",&GPIOA->AFR[1], GPIOA->AFR[1]);
+    PRINTF("GPIOA->MODER 0x%08x:0x%08x\r\n",&GPIOA->MODER, GPIOA->MODER);
+    PRINTF("GPIOA->PUPDR 0x%08x:0x%08x\r\n",&GPIOA->PUPDR, GPIOA->PUPDR);
+    //  PB
+    PRINTF("// PB10 -> Output Compare pin as Timer2 CH3/TI3\r\n");
+    PRINTF("GPIOB->AFRL  0x%08x:0x%08x\r\n",&GPIOB->AFR[0], GPIOB->AFR[0]);
+    PRINTF("GPIOB->AFRH  0x%08x:0x%08x\r\n",&GPIOB->AFR[1], GPIOB->AFR[1]);
+    PRINTF("GPIOB->MODER 0x%08x:0x%08x\r\n",&GPIOB->MODER, GPIOB->MODER);
+    PRINTF("GPIOB->PUPDR 0x%08x:0x%08x\r\n",&GPIOB->PUPDR, GPIOB->PUPDR);
+    //  TIM2
+    PRINTF("// PA1 -> Timer2 IC2\r\n");
+    PRINTF("// PA3 -> Timer2 IC4\r\n");
+    PRINTF("// PB10-> Timer2 OC3\r\n");
+    PRINTF("TIM2->CR1    0x%08x:0x%08x\r\n",&TIM2->CR1, TIM2->CR1);
+    PRINTF("TIM2->ARR    0x%08x:0x%08x\r\n",&TIM2->ARR, TIM2->ARR);
+    PRINTF("TIM2->PSC    0x%08x:0x%08x\r\n",&TIM2->PSC, TIM2->PSC);
+    PRINTF("TIM2->CCMR1  0x%08x:0x%08x\r\n",&TIM2->CCMR1, TIM2->CCMR1);
+    PRINTF("TIM2->CCMR2  0x%08x:0x%08x\r\n",&TIM2->CCMR2, TIM2->CCMR2);
+    PRINTF("TIM2->CCER   0x%08x:0x%08x\r\n",&TIM2->CCER, TIM2->CCER);
+    PRINTF("TIM2->SMCR   0x%08x:0x%08x\r\n",&TIM2->SMCR, TIM2->SMCR);
+    PRINTF("TIM2->CCR3   0x%08x:0x%08x\r\n",&TIM2->CCR3, TIM2->CCR3);
+    // Interrupt Timer2 IC2,OC3 & Overflow
+    tim2_ready_flg = 0;
+    tim2_cnt_data = 0;
+    sw_ovrflw_tim2 = 0;
+    TIM2->SR = 0;           // clear all IC/OC flag
+    TIM2->DIER = 0;         // Reset all interrupt flag
+    TIM2->DIER = TIM_DIER_CC2IE + TIM_DIER_CC3IE + TIM_DIER_UIE;
+    NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic2_TIM2);
+    NVIC_ClearPendingIRQ(TIM2_IRQn);
+    NVIC_EnableIRQ(TIM2_IRQn);
+    PRINTF("TIM2->DIER   0x%08x:0x%08x\r\n\r\n",&TIM2->DIER, TIM2->DIER);
+}
+
+// Initialize TIM8 & TIM4 as 32bit counter (TIM8(Low 16bit) + TIM4(High 16bit))
+//   TIM8 clock input is unkown freq.(measuring freq.) and TIM4 is slave counter
+//   1sec gate signal connected both TIM8 IC2, TIM4 IC1 with TIM2 OC3
+void FRQ_CUNTR::initialize_TIM8P4(void)
+{
+    // Timer8 input max freq.= 108MHz (@SystemCoreClock = 216MHz)
+    // PC6 -> Unkown frequency input pin as Timer8 CH1/TI1
+    RCC->AHB1ENR  |= (RCC_AHB1ENR_GPIOCEN);
+    GPIOC->AFR[0] &= 0xf0ffffff;
+    GPIOC->AFR[0] |= GPIO_AF3_TIM8 << 24;       // 6bit x 4
+    GPIOC->MODER  &= ~(GPIO_MODER_MODER6);      // AF
+    GPIOC->MODER  |= GPIO_MODER_MODER6_1;       //  alternate function mode
+    GPIOC->PUPDR  &= ~(GPIO_PUPDR_PUPDR6);      // PU
+    GPIOC->PUPDR  |= GPIO_PUPDR_PUPDR6_0;       //  Pull-up mode
+    // Initialize Timer8(16bit) for an external up counter mode
+    RCC->APB2ENR  |= RCC_APB2ENR_TIM8EN;
+                                // count_up + div by 1
+    TIM8->CR1     &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));
+                                // update request only by overflow
+    TIM8->CR1     |= (uint16_t)TIM_CR1_URS;
+    TIM8->ARR      = 0xffff;                    // Use 16bit full
+    TIM8->CCER    &= (uint16_t)~TIM_CCER_CC1E;  // Disable the CC1
+                                // input filter + input select
+    TIM8->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM8->CCMR1   |= TIM_CCMR1_CC1S_0;// CC1 channel = TI1
+                                // Not use IC1
+    TIM8->CCER    &= 
+                   (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP);
+                                // external mode 1
+    TIM8->SMCR    &= ~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS);
+                                // ECE must be ZERO!!!!
+    TIM8->SMCR    |= ( TIM_TS_TI1FP1 | TIM_SLAVEMODE_EXTERNAL1);
+    TIM8->CR2     &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS);
+    TIM8->CR2     |= (uint16_t)TIM_CR2_MMS_1;   // TRGO update
+    TIM8->CR1     |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM Counter
+    // PC7 -> Input Capture pin as Timer8 IC2
+    GPIOC->AFR[0] &= 0x0fffffff;
+    GPIOC->AFR[0] |= GPIO_AF3_TIM8 << 28;       // 7bit x 4
+    GPIOC->MODER  &= ~(GPIO_MODER_MODER7);      // AF
+    GPIOC->MODER  |= GPIO_MODER_MODER7_1;       //  alternate function mode
+    GPIOC->PUPDR  &= ~(GPIO_PUPDR_PUPDR7);      // PU
+    GPIOC->PUPDR  |= GPIO_PUPDR_PUPDR7_0;       //  Pull-up mode
+    // Initialize Timer8 IC2
+    TIM8->CCER    &= (uint16_t)~TIM_CCER_CC2E;    // Disable the CC2
+                                // input filter + input select
+    TIM8->CCMR1   &= ~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S);
+    TIM8->CCMR1   |= TIM_CCMR1_CC2S_0;
+                                // positive edge
+    TIM8->CCER    &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP);
+    TIM8->CCER    |= (uint16_t)TIM_CCER_CC2E;     // enable capture
+    // Initialize Timer4(16bit) as slave counter of TIM8
+    // TIM8 overflow event -> ITR3 as Timer4 clock
+    RCC->APB1ENR  |= RCC_APB1ENR_TIM4EN;
+    TIM4->CR1     &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));
+                                // only counter overflow for interrupt
+    TIM4->CR1     |= (uint16_t)TIM_CR1_URS;
+                                // Up counter uses from 0 to max(32bit)
+    TIM4->ARR      = 0xffff;                    // Use 16bit full
+    TIM4->CCER    &= (uint16_t)~TIM_CCER_CC1E;  // Disable the CC1
+                                // input filter + input select
+    TIM4->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM4->CCMR1   |= TIM_CCMR1_CC1S_0;          // CC1 channel = TI1
+                                // Not use IC1
+    TIM4->CCER    &= 
+                   (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP);
+                                // external mode 1
+    TIM4->SMCR    &= ~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS);
+    TIM4->SMCR    |= (TIM_TS_ITR3);             // Set Internal Triger 3 (ITR3)
+    TIM4->SMCR    |= (TIM_SLAVEMODE_EXTERNAL1); // ECE must be ZERO!!!!
+    TIM4->CR2     &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS);
+    TIM4->CR2     |= (uint16_t)TIM_CR2_MMS_1;   // TRGO update
+    TIM4->CR1     |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM Counter
+    // PB6 -> Input Capture pin as Timer4 IC1
+    GPIOB->AFR[0] &= 0xf0ffffff;
+    GPIOB->AFR[0] |= GPIO_AF2_TIM4 << 24;       // 6bit x 4
+    GPIOB->MODER  &= ~(GPIO_MODER_MODER6);      // AF
+    GPIOB->MODER  |= GPIO_MODER_MODER6_1;       //  alternate function mode
+    GPIOB->PUPDR  &= ~(GPIO_PUPDR_PUPDR6);      // PU
+    GPIOB->PUPDR  |= GPIO_PUPDR_PUPDR6_0;       //  Pull-up mode
+    // Initialize Timer4 IC1
+    TIM4->CCER    &= (uint16_t)~TIM_CCER_CC1E;
+    TIM4->CCMR1   &= ~(TIM_CCMR1_CC1S | TIM_CCMR1_IC1F);
+    TIM4->CCMR1   |= TIM_CCMR1_CC1S_0;
+                                // positive edge
+    TIM4->CCER    &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP);
+    TIM4->CCER    |= (uint16_t)TIM_CCER_CC1E;   // enable capture
+    // Up counter based on gate time period
+    time_count = 0;
+    // Only for Debug purpose
+    PRINTF("\r\n// Timer8(16bit high(max106MHz) clock)\r\n");
+    PRINTF("//  and Timer4(16bit low clock) combined up counter\r\n");
+    PRINTF("// Set GPIO for Timer8&4\r\n");
+    //  PB
+    PRINTF("// PB6 -> Input Capture pin as Timer4 CH1/TI1\r\n");
+    PRINTF("GPIOB->AFRL    0x%08x:0x%08x\r\n",&GPIOB->AFR[0], GPIOB->AFR[0]);
+    PRINTF("GPIOB->AFRH    0x%08x:0x%08x\r\n",&GPIOB->AFR[1], GPIOB->AFR[1]);
+    PRINTF("GPIOB->MODER   0x%08x:0x%08x\r\n",&GPIOB->MODER, GPIOB->MODER);
+    PRINTF("GPIOB->PUPDR   0x%08x:0x%08x\r\n",&GPIOB->PUPDR, GPIOB->PUPDR);
+    PRINTF("GPIOB->OTYPER  0x%08x:0x%08x\r\n",&GPIOB->OTYPER, GPIOB->OTYPER);
+    PRINTF("GPIOB->OSPEEDR 0x%08x:0x%08x\r\n",&GPIOB->OSPEEDR, GPIOB->OSPEEDR);
+    //  PC
+    PRINTF("// PC6 -> unkown frequency input pin as Timer8 CH1/TI1\r\n");
+    PRINTF("// PC7 -> Input Capture pin as Timer8 CH2/TI2\r\n");
+    PRINTF("GPIOC->AFRL    0x%08x:0x%08x\r\n",&GPIOC->AFR[0], GPIOC->AFR[0]);
+    PRINTF("GPIOC->AFRH    0x%08x:0x%08x\r\n",&GPIOC->AFR[1], GPIOC->AFR[1]);
+    PRINTF("GPIOC->MODER   0x%08x:0x%08x\r\n",&GPIOC->MODER, GPIOC->MODER);
+    PRINTF("GPIOC->PUPDR   0x%08x:0x%08x\r\n",&GPIOC->PUPDR, GPIOC->PUPDR);
+    PRINTF("GPIOC->OTYPER  0x%08x:0x%08x\r\n",&GPIOC->OTYPER, GPIOC->OTYPER);
+    PRINTF("GPIOC->OSPEEDR 0x%08x:0x%08x\r\n",&GPIOC->OSPEEDR, GPIOC->OSPEEDR);
+    //  TIM8
+    PRINTF("// PC6 -> Timer8(16bit) for an external up counter mode\r\n");
+    PRINTF("// PC7 -> Timer8 IC2\r\n");
+    PRINTF("TIM8->CR1      0x%08x:0x%08x\r\n",&TIM8->CR1, TIM8->CR1);
+    PRINTF("TIM8->CR2      0x%08x:0x%08x\r\n",&TIM8->CR2, TIM8->CR2);
+    PRINTF("TIM8->ARR      0x%08x:0x%08x\r\n",&TIM8->ARR, TIM8->ARR);
+    PRINTF("TIM8->PSC      0x%08x:0x%08x\r\n",&TIM8->PSC, TIM8->PSC);
+    PRINTF("TIM8->CCMR1    0x%08x:0x%08x\r\n",&TIM8->CCMR1, TIM8->CCMR1);
+    PRINTF("TIM8->CCMR2    0x%08x:0x%08x\r\n",&TIM8->CCMR2, TIM8->CCMR2);
+    PRINTF("TIM8->CCER     0x%08x:0x%08x\r\n",&TIM8->CCER, TIM8->CCER);
+    PRINTF("TIM8->SMCR     0x%08x:0x%08x\r\n",&TIM8->SMCR, TIM8->SMCR);
+    //  TIM4
+    PRINTF("// PB6 -> Timer4 IC1\r\n");
+    PRINTF("TIM4->CR1      0x%08x:0x%08x\r\n",&TIM4->CR1, TIM4->CR1);
+    PRINTF("TIM4->ARR      0x%08x:0x%08x\r\n",&TIM4->ARR, TIM4->ARR);
+    PRINTF("TIM4->PSC      0x%08x:0x%08x\r\n",&TIM4->PSC, TIM4->PSC);
+    PRINTF("TIM4->CCMR1    0x%08x:0x%08x\r\n",&TIM4->CCMR1, TIM4->CCMR1);
+    PRINTF("TIM4->CCMR2    0x%08x:0x%08x\r\n",&TIM4->CCMR2, TIM4->CCMR2);
+    PRINTF("TIM4->CCER     0x%08x:0x%08x\r\n",&TIM4->CCER, TIM4->CCER);
+    PRINTF("TIM4->SMCR     0x%08x:0x%08x\r\n",&TIM4->SMCR, TIM4->SMCR);
+    // Interrupt Timer4 IC1 (NOT Timer8 IC2) & Overflow
+    tim8p4_ready_flg = 0;
+    tim8p4_cnt_data = 0;
+    sw_ovrflw_tim8p4 = 0;
+    TIM8->SR = 0;           // clear all IC/OC flag
+    TIM4->SR = 0;           // clear all IC/OC flag
+    TIM4->DIER = 0;         // Reset all interrupt flag
+    TIM4->DIER = TIM_DIER_CC1IE + TIM_DIER_UIE;
+    NVIC_SetVector(TIM4_IRQn, (uint32_t)irq_ic1_TIM8P4);
+    NVIC_ClearPendingIRQ(TIM4_IRQn);
+    NVIC_EnableIRQ(TIM4_IRQn);
+    PRINTF("TIM4->DIER     0x%08x:0x%08x\r\n\r\n",&TIM4->DIER, TIM4->DIER);
+    PRINTF("RCC->APB1ENR   0x%08x:0x%08x\r\n\r\n",&RCC->APB1ENR, RCC->APB1ENR);
+}
+
+//------------------------------------------------------------------------------
+//  Frequency check for test & debug purpose
+//------------------------------------------------------------------------------
+// Read TIM2 Clock frequency
+uint32_t FRQ_CUNTR::read_base_clock_frequency(double gatetime)
+{
+    TIM2->CNT = 0;
+    wait(gatetime);                         // Gate time for count
+    uint32_t freq = TIM2->CNT;              // read counter
+    PRINTF("Clock freq.=%10d [Hz], gate= %4.2f [Sec]\r\n", freq, gatetime);
+    return freq;                            // return counter data
+}
+
+// Read TIM8(+TIM4) Input frequency
+uint32_t FRQ_CUNTR::read_input_frequency(double gatetime)
+{
+    TIM8->CR1 &= ~(uint16_t)TIM_CR1_CEN;    // disable the TIM8 Counter
+    TIM4->CNT  = 0;
+    TIM8->CNT  = 0;
+    TIM8->CR1 |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM8 Counter
+    wait(gatetime);                // Gate time for count
+    TIM8->CR1 &= ~(uint16_t)TIM_CR1_CEN;    // disable the TIM8 Counter
+    uint32_t freq = (TIM4->CNT << 16) + TIM8->CNT;
+    TIM8->CR1 |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM8 Counter
+    PRINTF("Input freq.=%10d [Hz], gate= %4.2f [Sec]\r\n", freq, gatetime);
+    return freq;                            // read counter
+}
+
+void FRQ_CUNTR::debug_printf_all_buffer(void)
+{
+    fdt_buffer.debug_print_all_buffer();
+}
+
+void FRQ_CUNTR::debug_printf_internal_data(void)
+{
+    printf("Debug information\r\n");
+    printf("ex_clock_freq    %f\r\n", ex_clock_freq);
+    printf("ex_clk_base     %9d\r\n", ex_clk_base);
+    printf("clk_hi_const    %9d\r\n", clk_hi_const);
+    printf("clk_upper_limit %9d\r\n", clk_upper_limit);
+    printf("clk_lower_limit %9d\r\n", clk_lower_limit);
+    printf("oc_hi_time      %9d\r\n", oc_hi_time);
+    printf("oc_lo_time      %9d\r\n", oc_lo_time);
+    printf("\r\n");
+}
+
+//------------------------------------------------------------------------------
+//  Interrupt Handlers
+//------------------------------------------------------------------------------
+void irq_ic2_TIM2(void)
+{
+    // IC2 (By GPS 1PPS)
+    if (TIM2->SR & TIM_SR_CC2IF){
+        TIM2->SR &= ~TIM_SR_CC2IF;  // clear IC flag
+        tim2_cnt_data = TIM2->CCR2;
+        tim2_ready_flg = 1;
+        // data saves intto the ring buffer
+        onepps_dt.freq_dt = tim2_cnt_data;
+        onepps_dt.f_sw_dt = sw_ovrflw_tim2;
+        onepps_dt.t_cnt   = ++time_count_onepps;
+        onepps_buf.ring_put_dt(onepps_dt.f_1sec_dt);
+        #if ACTIVE_LED
+        irq_led3 = !irq_led3;
+        #endif // ACTIVE_LED
+    }
+    // Gate signal (every 1Sec)
+    if (TIM2->SR & TIM_SR_CC3IF){   // Output Compare
+        TIM2->SR &= ~TIM_SR_CC3IF;  // clear OC flag
+        TIM2->CCMR2   &= ~(TIM_CCMR2_OC3M);     // Clear OC mode
+        // Check PB10 status
+        if (GPIOB->IDR & 0x0400){   // High level
+            TIM2->CCR3 = TIM2->CCR3 + oc_hi_time;
+            TIM2->CCMR2   |= TIM_CCMR2_OC3M_1;  // to be low
+            #if ACTIVE_LED
+            irq_led2 = 1;
+            #endif // ACTIVE_LED
+        } else {                    // Low level
+            TIM2->CCR3 = TIM2->CCR3 + oc_lo_time;
+            TIM2->CCMR2   |= TIM_CCMR2_OC3M_0;  // to be high
+            #if ACTIVE_LED
+            irq_led2 = 0;
+            #endif // ACTIVE_LED
+        }
+    }
+    // IC4 (for reciprocal measurement)
+    if (TIM2->SR & TIM_SR_CC4IF){
+        TIM2->SR &= ~TIM_SR_CC4IF;  // clear IC flag
+        uint32_t data = TIM2->CCR4;
+        if (recipro_step == 0){
+            recipro_start = data;
+            recipro_step = 1;
+        } else if (recipro_step == 1){
+            TIM2->DIER &= ~TIM_DIER_CC4IE;  // disable IC4 interrupt
+            recipro_stop = data;
+            recipro_step = 2;
+        }
+    }
+    // TIM2 overflow
+    if (TIM2->SR & TIM_SR_UIF){
+        TIM2->SR &= ~TIM_SR_UIF;
+        ++sw_ovrflw_tim2;
+    }
+}
+
+// TIM4 IC1 Interrupt control (same signal connected to TIM8 IC2)
+void irq_ic1_TIM8P4(void)
+{
+    // IC1 (TIM2 Gate signal)
+    if (TIM4->SR & TIM_SR_CC1IF){
+        TIM8->SR &= ~TIM_SR_CC2IF;      // clear IC flag
+        TIM4->SR &= ~TIM_SR_CC1IF;
+        tim8p4_cnt_data = (TIM4->CCR1 << 16) + TIM8->CCR2;
+        tim8p4_ready_flg = 1;
+        // data saves intto the ring buffer
+        fdt.freq_dt = tim8p4_cnt_data;
+        fdt.f_sw_dt = sw_ovrflw_tim8p4;
+        fdt.t_cnt   = ++time_count;
+        fdt_buffer.ring_put_dt(fdt.f_1sec_dt);
+        #if ACTIVE_LED
+        irq_led1 = !irq_led1;
+        #endif // ACTIVE_LED
+    }
+    // TIM4 overflow
+    if (TIM4->SR & TIM_SR_UIF){
+        TIM4->SR &= ~TIM_SR_UIF;
+        ++sw_ovrflw_tim8p4;
+    }
+}
+
+}   // Frequency_counter
+
+
+
+