Frequency counter library only for DISCO-F746NG & NucleoF411RE +F446RE

Dependencies:   RingBuff

Dependents:   FreqCntr_GPS1PPS_F746F4xx_w_recipro Freq_Cntr_GPS1PPS_F746NG_GUI

Fork of Frq_cuntr_full by Kenji Arai

Revision:
5:783b039f9119
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fc_hw_f746.h	Wed Nov 16 13:13:09 2016 +0000
@@ -0,0 +1,359 @@
+/*
+ * mbed Library / Frequency Counter using GPS 1PPS gate pulse
+ *      Frequency Counter Hardware relataed program
+ *      Only for ST DISCO-F746NG
+ *
+ *      Re-started: October    5th, 2016    Change board -> DISCO-F746NG
+ *      Re-started: October   17th, 2016    Separate common & HW related part
+ *      Revised:    November  13th, 2016
+ *
+ */
+
+#if defined(TARGET_STM32F746NG)
+
+// Following ring buffers are very big!! 4096 x 8(bytes) x 2(buff) = 64KB
+RingBuff<uint64_t> fdt_buffer;      // RinBuffer for TIM8+4
+freq_one fdt;                       // frequency data in pack (interrupt)
+RingBuff<uint64_t> onepps_buf;      // RinBuffer for TIM2
+freq_one onepps_dt;                 // frequency data in pack (interrupt)
+
+//------------------------------------------------------------------------------
+//  Initialize TIM2 and TIM8+4
+//------------------------------------------------------------------------------
+// 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
+//   1PPS gate signal connected both TIM8 IC2, TIM4 IC3 (& TIM2 IC3)
+void FRQ_CUNTR::initialize_TIMxPy(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     = 0;                         // Reset all
+                                // input filter + input select
+    TIM8->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM8->CCMR1   |= TIM_CCMR1_CC1S_0;          // CC1 channel = TI1
+                                // 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     = 0;                         // Reset all
+                                // 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
+    // PB8 -> Input Capture pin as Timer4 IC3
+    GPIOB->AFR[1] &= 0xfffffff0;
+    GPIOB->AFR[1] |= GPIO_AF2_TIM4 << 0;        // (8-8)bit x 4
+    GPIOB->MODER  &= ~(GPIO_MODER_MODER8);      // AF
+    GPIOB->MODER  |= GPIO_MODER_MODER8_1;       //  alternate function mode
+    GPIOB->PUPDR  &= ~(GPIO_PUPDR_PUPDR8);      // PU
+    GPIOB->PUPDR  |= GPIO_PUPDR_PUPDR8_0;       //  Pull-up mode
+    // Initialize Timer4 IC3
+    TIM4->CCER    &= (uint16_t)~TIM_CCER_CC3E;
+    TIM4->CCMR2   &= ~(TIM_CCMR2_CC3S | TIM_CCMR2_IC3F);
+    TIM4->CCMR2   |= TIM_CCMR2_CC3S_0;
+                                // positive edge
+    TIM4->CCER    &= (uint16_t)~(TIM_CCER_CC3P | TIM_CCER_CC3NP);
+    TIM4->CCER    |= (uint16_t)TIM_CCER_CC3E;   // 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("// PB8 -> Input Capture pin as Timer4 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);
+    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);
+    PRINTF("TIM8->DIER     0x%08x:0x%08x\r\n",&TIM8->DIER, TIM8->DIER);
+    //  TIM4
+    PRINTF("// PB8 -> Timer4 IC3\r\n");
+    PRINTF("TIM4->CR1      0x%08x:0x%08x\r\n",&TIM4->CR1, TIM4->CR1);
+    PRINTF("TIM4->CR2      0x%08x:0x%08x\r\n",&TIM4->CR2, TIM4->CR2);
+    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 IC3 (NOT Timer8 IC2) & Overflow
+    timxpy_ready_flg = 0;
+    timxpy_cnt_data = 0;
+    sw_ovrflw_timxpy = 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_CC3IE + TIM_DIER_UIE;
+    NVIC_SetVector(TIM4_IRQn, (uint32_t)irq_ic_TIMxPy);
+    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);
+}
+
+// Initialize TIM2
+// IC3->PB10 for GPS 1pps signal
+// IC1->PA15 for Reciprocal frequency counting mode (Interrupt)
+void FRQ_CUNTR::initialize_TIMz(void)
+{
+    // Initialize Timer2(32bit) for an internal(108MHz) 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     = 0;                         // Reset all
+                                // input filter + input select
+    TIM2->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM2->CCMR1   |= TIM_CCMR1_CC1S_0;
+    TIM2->SMCR     = 0;                         // Internal clock
+    TIM2->CR1     |= (uint16_t)TIM_CR1_CEN;     // Enable the TIM Counter
+    // PA15 -> Input Capture pin as Timer2 IC1
+    GPIOA->AFR[1] &= 0x0fffffff;
+    GPIOA->AFR[1] |= GPIO_AF1_TIM2 << 28;       // 15-8 = 7bit x 4
+    GPIOA->MODER  &= ~(GPIO_MODER_MODER15);     // AF
+    GPIOA->MODER  |= GPIO_MODER_MODER15_1;      //  alternate function mode  
+    GPIOA->PUPDR  &= ~(GPIO_PUPDR_PUPDR15);     // PU
+    GPIOA->PUPDR  |= GPIO_PUPDR_PUPDR15_0;      //  Pull-up mode
+    // Initialize Timer2 IC1
+                                // input filter + input select
+    TIM2->CCMR1   &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S);
+    TIM2->CCMR1   |= (TIM_CCMR1_CC1S_0 + TIM_CCMR1_IC1F_1); // filter = fCLK/4
+                                // positive edge
+    TIM2->CCER    &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP);
+    TIM2->CCER    |= (uint16_t)TIM_CCER_CC1E;   // enable capture
+    // PB10 -> Input Capture pin as Timer2 IC3 for Reciprocal
+    GPIOB->AFR[1] &= 0xfffff0ff;
+    GPIOB->AFR[1] |= GPIO_AF1_TIM2 << 8;       // 10-8 = 2bit x 4
+    GPIOB->MODER  &= ~(GPIO_MODER_MODER10);    // AF
+    GPIOB->MODER  |= GPIO_MODER_MODER10_1;     //  alternate function mode
+    GPIOB->PUPDR  &= ~(GPIO_PUPDR_PUPDR10);    // PU
+    GPIOB->PUPDR  |= GPIO_PUPDR_PUPDR10_0;     //  Pull-up mode
+    // Initialize Timer2 IC3
+    TIM2->CCER    &= (uint16_t)~TIM_CCER_CC3E;  // Disable the CC
+    TIM2->CCMR2   &= ~(TIM_CCMR2_IC3F | TIM_CCMR2_CC3S);
+    //TIM2->CCMR2   |= TIM_CCMR2_CC3S_0; // filter none
+    TIM2->CCMR2   |= (TIM_CCMR2_CC3S_0 + TIM_CCMR2_IC3F_1); // filter = fCLK/4
+                                // positive edge
+    TIM2->CCER    &= (uint16_t)~(TIM_CCER_CC3P | TIM_CCER_CC3NP);
+    TIM2->CCER    |= (uint16_t)TIM_CCER_CC3E;   // enable capture
+    // 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("// PA15  -> Input Capture pin as Timer2 CH1/TI1\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  -> Input Capture 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("// PA15 -> Timer2 IC1\r\n");
+    PRINTF("// PB10 -> Timer2 IC3\r\n");
+    PRINTF("TIM2->CR1    0x%08x:0x%08x\r\n",&TIM2->CR1, TIM2->CR1);
+    PRINTF("TIM2->CR2    0x%08x:0x%08x\r\n",&TIM2->CR2, TIM2->CR2);
+    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);
+    // Interrupt Timer2 IC4(disable at this moment) & Overflow
+    timz_cnt_data = 0;
+    sw_ovrflw_timz = 0;
+    TIM2->SR = 0;           // clear all IC/OC flag
+    TIM2->DIER = 0;         // Disable all interrupt
+    TIM2->DIER = TIM_DIER_UIE;  // set only overflow
+    NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic_TIMz);
+    NVIC_ClearPendingIRQ(TIM2_IRQn);
+    NVIC_EnableIRQ(TIM2_IRQn);
+    PRINTF("TIM2->DIER   0x%08x:0x%08x\r\n\r\n",&TIM2->DIER, TIM2->DIER);
+}
+
+//------------------------------------------------------------------------------
+//  Reciprocal measuremt
+//------------------------------------------------------------------------------
+void FRQ_CUNTR::start_action(void)
+{
+    __disable_irq();
+    TIM2->SR &= ~TIM_SR_CC1IF;      // clear IC flag
+    TIM2->DIER |= TIM_DIER_CC1IE;   // Enable IC1
+    __enable_irq();
+}
+
+//------------------------------------------------------------------------------
+//  Frequency check for test & debug purpose
+//------------------------------------------------------------------------------
+// Read TIM8(+TIM4) Input frequency
+uint32_t FRQ_CUNTR::debug_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
+}
+
+// Read TIM2 Clock frequency
+uint32_t FRQ_CUNTR::debug_read_base_clock_frequency(double gatetime)
+{
+    TIM2->CNT = 0;
+    wait(gatetime);                         // Gate time for count
+    uint32_t freq = TIM2->CNT;              // read counter
+    PRINTF("Clock Counter=%10d, gate= %4.2f [Sec]\r\n", freq, gatetime);
+    return freq;                            // return counter data
+}
+
+// Dump all buffered data
+void FRQ_CUNTR::debug_printf_all_buffer(void)
+{
+    fdt_buffer.debug_print_all_buffer();
+}
+
+//------------------------------------------------------------------------------
+//  Interrupt Handlers
+//------------------------------------------------------------------------------
+// GPS 1PPS signal interrupt (connected to TIM4 IC3, TIM8 IC2 and TIM2 IC3)
+// TIM4 IC3 Interrupt control
+void irq_ic_TIMxPy(void)
+{
+    // IC3 (GPS 1PPS)
+    if (TIM4->SR & TIM_SR_CC3IF){
+        TIM8->SR &= ~TIM_SR_CC2IF;      // clear IC flag
+        TIM4->SR &= ~TIM_SR_CC3IF;      // clear IC flag
+        TIM2->SR &= ~TIM_SR_CC3IF;      // clear IC flag
+        timxpy_cnt_data = (TIM4->CCR3 << 16) + TIM8->CCR2;  // 16+16 bit
+        timxpy_ready_flg = 1;
+        timz_cnt_data = TIM2->CCR3;                         // 32 bit
+        // data saves into the ring buffer / Unknown Freq.
+        fdt.freq_dt = timxpy_cnt_data;
+        fdt.f_sw_dt = sw_ovrflw_timxpy;
+        fdt.t_cnt   = ++time_count;
+        fdt_buffer.ring_put_dt(fdt.f_1sec_dt);
+        // data saves into the ring buffer / F746 internal clock
+        onepps_dt.freq_dt = timz_cnt_data;
+        onepps_dt.f_sw_dt = sw_ovrflw_timz;
+        onepps_dt.t_cnt   = ++time_count_onepps;
+        onepps_buf.ring_put_dt(onepps_dt.f_1sec_dt);
+        #if ACTIVE_LED_TIMX
+        irq_led1 = !irq_led1;
+        #endif // ACTIVE_LED
+    }
+    // TIM4 overflow
+    if (TIM4->SR & TIM_SR_UIF){
+        TIM4->SR &= ~TIM_SR_UIF;
+        ++sw_ovrflw_timxpy;
+    }
+}
+
+// Reciprocal data (TIM2 IC1)
+void irq_ic_TIMz(void)
+{
+    // IC1 (for reciprocal measurement)
+    if (TIM2->SR & TIM_SR_CC1IF){
+        TIM2->SR &= ~TIM_SR_CC1IF;  // clear IC flag
+        uint32_t data = TIM2->CCR1;
+        if (recipro_step == 0){             // start measuring
+            recipro_start = data;
+            recipro_step = 1;
+        } else if (recipro_step == 1){      // stop
+            TIM2->DIER &= ~TIM_DIER_CC1IE;  // disable IC4 interrupt
+            recipro_stop = data;
+            recipro_step = 2;
+        } else {                            // jsut in case
+            TIM2->DIER &= ~TIM_DIER_CC1IE;  // disable IC4 interrupt
+            recipro_step = 0;
+        }
+        #if ACTIVE_LED_TIMZ
+        irq_led1 = !irq_led1;
+        #endif // ACTIVE_LED
+    }
+    // TIM2 overflow
+    if (TIM2->SR & TIM_SR_UIF){             // 32bit counter overflow
+        TIM2->SR &= ~TIM_SR_UIF;
+        ++sw_ovrflw_timz;
+    }
+}
+
+#endif  // defined(TARGET_STM32F746NG)