Frequency counter library using GPS 1PPS signal and temperature controlled 50MHz Base clock. Ported from F411 Frequency Counter.
Dependents: Frequency_Cntr_1PPS_F746ZG
Fork of Frq_cuntr_full by
Please refer following.
/users/kenjiArai/notebook/frequency-counters/
frq_cuntr_f746.cpp
- Committer:
- kenjiArai
- Date:
- 2016-11-23
- Revision:
- 5:bb04c4a3b5ba
File content as of revision 5:bb04c4a3b5ba:
/* * 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