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/
Revision 5:bb04c4a3b5ba, committed 2016-11-23
- Comitter:
- kenjiArai
- Date:
- Wed Nov 23 07:30:55 2016 +0000
- Parent:
- 4:9d3b3f0a3882
- Commit message:
- Frequency counter library using GPS 1PPS signal and temperature controlled 50MHz Base clock. Ported from F411 Frequency Counter.
Changed in this revision
diff -r 9d3b3f0a3882 -r bb04c4a3b5ba RingBuff.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RingBuff.lib Wed Nov 23 07:30:55 2016 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/kenjiArai/code/RingBuff/#e206b41f0032
diff -r 9d3b3f0a3882 -r bb04c4a3b5ba frq_cuntr_f746.cpp --- /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 + + + +
diff -r 9d3b3f0a3882 -r bb04c4a3b5ba frq_cuntr_f746.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frq_cuntr_f746.h Wed Nov 23 07:30:55 2016 +0000 @@ -0,0 +1,213 @@ +/* + * 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. + */ + +#ifndef MBED_FRQ_CUNTR +#define MBED_FRQ_CUNTR + +#include "mbed.h" + +#define DEBUG 0 // use Communication with PC(UART) + +typedef union +{ + struct { + uint64_t f_1sec_dt; + }; + struct { + uint32_t freq_dt; + uint16_t f_sw_dt; + uint16_t t_cnt; + }; +} freq_one; + +namespace Frequency_counter +{ + +/** Frequency Counter program + * Only for ST Nucleo-F746ZG Board + * + * @code + * #include "mbed.h" + * #include "frq_cuntr_f746.h" + * + * using namespace Frequency_counter; + * + * // frequency input -> PC_6 & PA_3 + * // 50MHz base clock -> PA_5, GPS 1PPS -> PA_1 + * // Connect -> three ports,PA_7,PB_10 and PC_7 connected together + * // CAUTION!!: SB13 & SB181 must remove from Nucleo-F746ZG board + * + * FRQ_CUNTR fc(49.999992f); // External base clock freq. + * + * int main() { + * double cntr_1pps = 0; + * double frequency = 0; + * while(true) { + * while (fc.status_1pps() == 0) {;} + * cntr_1pps = fc.read_avarage_1pps(); + * while (fc.status_freq_update() == 0) {;} + * frequency = fc.read_compensated_freq_data_w_gt(1); // 1sec gate + * printf("1PPS/ave = %%11.3f, FREQ. = %11.1f\r\n", cntr_1pps, frequency); + * } + * } + * @endcode + */ + +class FRQ_CUNTR +{ + +public: + + /** Configure counter + * @param Base clock Frequency [MHz] + */ + FRQ_CUNTR(double ex_clock); + + /** Read new frequency data (gate time = 1sec) + * @param none + * @return frequency data + */ + double read_freq_data(void); + + /** Read new frequency data with specific gate time + * @param gate time [sec] (1 sec to over 1 hour) + * @return frequency data + */ + double read_compensated_freq_data_w_gt(uint16_t gt); + // get raw data + double read_freq_w_gate_time(uint16_t gt); + + /** Read status (new frequency data is available or not) + * @param none + * @return !=0: new data is avairable, 0: not yet + */ + uint32_t status_freq_update(void); + + /** Read avarage measured data GPS 1PPS + * @param none + * @return Base clock frequency(average 1(not ave!), 10, 100 & 1000) + */ + double read_avarage_1pps(void); + + /** Read number of buffered data + * @param none + * @return number of data in the buffer + */ + uint32_t read_num_in_buffer(void); + + /** Read newest measured data GPS 1PPS + * @param none + * @return Base clock frequency (newest(no avaraging value)) + */ + uint32_t read_newest_1pps(void); + + /** Read status (new 1PPS data is available or not) + * @param none + * @return !=0: new data is avairable, 0: not yet + */ + uint32_t status_1pps(void); + + /** Read GPS status + * @param none + * @return 0: GPS is NOT ready + * not 0: 1PPS data is avairable & show gate_time for avarage + */ + uint32_t status_gps(void); + + /** Reciprocal measurement + * preparation for Reciprocal measurement -> recipro_start_measure + * check frequency input as IC trigger -> recipro_check_trigger + * read IC data -> recipro_read_data + */ + void recipro_start_measure(void); + uint32_t recipro_check_trigger(void); + uint32_t recipro_read_data(void); + + /** This is a "DEBUG PURPOSE" function + * Check Base clock frequency on TIM2 or/and TIM8+4 + * print internal data (need to define "DEBUG") + * @param gate time e.g. 1sec = 1.0f + * @return Frequency + * read_base_clock_frequency -> TIM2 data + * read_input_frequency -> TIM8+4 data + */ + uint32_t read_base_clock_frequency(double gatetime); + uint32_t read_input_frequency(double gatetime); + + /** This is a "DEBUG PURPOSE" function + * print internal data (No need to define "DEBUG") + * @param none + * @return none (just print tha data) + */ + void debug_printf_internal_data(void); + void debug_printf_all_buffer(void); + +protected: + void initialize_Freq_counter(void); // Initialize timers + void initialize_TIM2(void); // Initialize Timer2 (32bit) + void initialize_TIM8P4(void); // Initialize Timer8 + 4 (16+16bit) + void set_external_clock(double ex_clock); // Set OC data + uint32_t calc_1PPS_newest(void); // Calculate GPS 1PPS newest data + uint32_t read_ic2_counter_TIM2(void); // Read TIM2 captured counter data + uint32_t check_ic2_status_TIM2(void); // Check TIM2 IC2 status + uint32_t read_counter_TIM8P4(void); // Read TIM8+4 captured counter data + uint32_t check_ic1_status_TIM8P4(void); // Check TIM8 IC2 & TIM4 IC1 status + uint8_t read_oc_port_status(void); // Check TIM2 OC port + void set_1sec_gate_time(void); // Set one second gate time + uint64_t get_diff(uint64_t new_dt, uint64_t old_dt); + +private: + double newest_frequency; + double ex_clock_freq; + uint32_t gate_time; + uint32_t ex_clk_base; + uint32_t clk_hi_const; + uint32_t clk_upper_limit; + uint32_t clk_lower_limit; + uint32_t gps_ready; + // TIM2 + uint32_t counter_tim2; + uint32_t old_cntr_tim2; + // TIM8+4 + uint32_t counter_tim8p4; + uint32_t old_cntr_tim8p4; + uint16_t sw_ovrflw_tim8p4; + // 1PPS data + uint32_t onepps_newest; + uint8_t onepps_ready_flg; + +}; + +/* + Interrupt handler does NOT work following code + NVIC_SetVector(TIM2_IRQn, (uint32_t)FRQ_CUNTR::irq_ic2_TIM2); + From this reason, I wrote below code and set interrupt handler + out side "FRQ_CUNTR" class + NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic2_TIM2); + */ +void irq_ic2_TIM2(void); // TIM2 IC2 Interrupt control +void irq_ic1_TIM8P4(void); // TIM4 IC1 Interrupt control (also TIM8 IC2) + +} // Frequency_counter + +#endif // MBED_FRQ_CUNTR +
diff -r 9d3b3f0a3882 -r bb04c4a3b5ba frq_cuntr_full.cpp --- a/frq_cuntr_full.cpp Thu Jan 01 05:04:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,613 +0,0 @@ -/* - * mbed Library / Frequency Counter with GPS 1PPS Compensation - * Frequency Counter Hardware relataed program - * Only for ST Nucleo F411RE - * - * Copyright (c) 2014 Kenji Arai / JH1PJL - * http://www.page.sannet.ne.jp/kenjia/index.html - * http://mbed.org/users/kenjiArai/ - * Additional functions and modification - * started: October 18th, 2014 - * Revised: January 1st, 2015 - * - * 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_NUCLEO_F411RE) - -#include "frq_cuntr_full.h" - -#ifdef DEBUG -Serial pcm(USBTX, USBRX); -DigitalOut debug_led(LED1); -#endif - -#ifdef DEBUG -#define BAUD(x) pcm.baud(x) -#define PRINTF(...) pcm.printf(__VA_ARGS__) -#else -#define BAUD(x) {;} -#define PRINTF(...) {;} -#endif - -namespace Frequency_counter -{ -// TIM2 OC -static uint32_t oc_set_time0; -static uint32_t oc_set_time1; -static uint8_t new_gt_value; -static uint32_t oc_hi_time; -static uint32_t oc_lo_time; -// TIM2 IC -static uint8_t tim2_ready_flg; -static uint32_t tim2_cnt_data; -static uint32_t tim2_old_cnt_data; -// TIM3+4 IC -static uint8_t tim3p4_ready_flg; -static uint32_t tim3p4_cnt_data; - -//------------------------------------------------------------------------------------------------- -// Interrupt Handlers -//------------------------------------------------------------------------------------------------- -// TIM2 IC2 Interrupt control -void irq_ic2_TIM2(void) -{ - uint16_t reg; - reg = TIM2->SR; - if (reg & TIM_SR_CC2IF) { - TIM2->SR &= ~TIM_SR_CC2IF; // clear IC flag - tim2_old_cnt_data = tim2_cnt_data; - tim2_cnt_data = TIM2->CCR2; - tim2_ready_flg = 1; -#if defined(DEBUG) - debug_led = !debug_led; -#endif // defined(DEBUG) - } else if (reg & TIM_SR_CC3IF) { // Output Compare - TIM2->SR &= ~TIM_SR_CC3IF; // clear IC flag - if (GPIOB->IDR & 0x0400) { // Check PB10 status - TIM2->CCR3 = TIM2->CCR3 + oc_hi_time; - } else { - TIM2->CCR3 = TIM2->CCR3 + oc_lo_time; - if (new_gt_value) { - new_gt_value = 0; - oc_hi_time = oc_set_time0; - oc_lo_time = oc_set_time1; - } - } -#if defined(DEBUG) - debug_led = !debug_led; -#endif // defined(DEBUG) - } -} - -// TIM3 IC2 Interrupt control (same signal connected to TIM4 IC1) -void irq_ic2_TIM3P4(void) -{ - TIM3->SR &= ~TIM_SR_CC2IF; // clear IC flag - TIM4->SR &= ~TIM_SR_CC1IF; - tim3p4_cnt_data = (TIM4->CCR1 << 16) + TIM3->CCR2; - tim3p4_ready_flg = 1; -#if defined(DEBUG) - debug_led = !debug_led; -#endif // defined(DEBUG) -} - -//--------------------------------------------------------------------------------------- -// Frequency Counter -//--------------------------------------------------------------------------------------- -FRQ_CUNTR::FRQ_CUNTR(PinName f_in, double gt, double ex_clock): _pin(f_in) -{ - // Don't change calling sequence!! - set_external_clock(ex_clock); // 1st - set_gate_time(gt); // 2nd - initialize_Freq_counter(); // 3rd -} - -// Set gate time -double FRQ_CUNTR::set_gate_time(double gt) -{ - if (gt < 0.05) { - gate_time = 0.05; - } else if (gt > 60.0) { - gate_time = 60.0; - } else { - gate_time = gt; - } - oc_set_time0 = clk_hi_const; - double gt_tmp0 = ex_clk_base * gate_time; - uint32_t gt_tmp1 = (uint32_t)gt_tmp0; - if ((gt_tmp0 - (double)gt_tmp1) >= 0.5) { - ++gt_tmp1; - } - oc_set_time1 = gt_tmp1 - clk_hi_const; - new_gt_value = 1; - return gate_time; -} - -// Read gate time -double FRQ_CUNTR::read_gate_time(void) -{ - return gate_time; -} - -// Set External Clock Frequency -void FRQ_CUNTR::set_external_clock(double ex_clock) -{ -#if defined(BASE_EXTERNAL_CLOCK) - ex_clock_freq = ex_clock; - ex_clk_base = (uint32_t)(ex_clock_freq * 1000000); // MHz->Hz - clk_hi_const = (uint32_t)(ex_clock_freq * 1000000 * 0.04); // 40mS - uint32_t err = (uint32_t)(ex_clock_freq * 1000000 * 0.00001); // 10ppm error range - clk_upper_limit = ex_clk_base + err; - clk_lower_limit = ex_clk_base - err; - PRINTF("EXTERNAL Clock mode\r\n"); -#else // defined(BASE_EXTERNAL_CLOCK) - ex_clock_freq = 100; // Internal 100MHz - ex_clk_base = 100000000; // MHz->Hz - clk_hi_const = 4000000; // 40mS - uint32_t err = 10000; // error range - clk_upper_limit = ex_clk_base + err; - clk_lower_limit = ex_clk_base - err; - PRINTF("INTERNAL Clock mode\r\n"); -#endif // defined(BASE_EXTERNAL_CLOCK) -} - -// Read new frequency data -double FRQ_CUNTR::read_freq_data(void) -{ - old_cntr_tim3p4 = counter_tim3p4; - counter_tim3p4 = read_ic2_counter_TIM3P4(); - double freq0 = (double)(counter_tim3p4 - old_cntr_tim3p4); - newest_frequency = freq0 / gate_time; - return newest_frequency; -} - -// Read status (new frequency data is available or not) -uint32_t FRQ_CUNTR::status_freq_update(void) -{ - return check_ic2_status_TIM3P4(); -} - -// 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::set_1PPS_data(void) -{ - uint32_t diff = tim2_cnt_data - tim2_old_cnt_data; - if ((diff > clk_upper_limit) || (diff < clk_lower_limit)) { - PRINTF("IC0 %d %d %d \r\n", diff, clk_upper_limit, clk_lower_limit); - gps_ready = 0; - return 0; - } else { - gps_ready = 1; - onepps_cnt[onepps_num] = diff; - if (++onepps_num >= CNT_BF_SIZE) { - onepps_num = 0; - onepps_buf_full = 1; - } - onepps_newest = diff; - return diff; - } -} - -// Avarage measued data GPS 1PPS by 25MHz External Clock -uint32_t FRQ_CUNTR::read_avarage_1pps(void) -{ - uint64_t total = 0; - if (onepps_buf_full == 1) { - for (uint32_t i = 0; i < CNT_BF_SIZE; i++) { - total += (uint64_t)onepps_cnt[i]; - } - onepps_cnt_avarage = total / CNT_BF_SIZE; - PRINTF("buf"); - } else { - for (uint32_t i = 0; i < onepps_num; i++) { - total += (uint64_t)onepps_cnt[i]; - } - onepps_cnt_avarage = total / onepps_num; - PRINTF("not"); - } - PRINTF(" full, num= %3d , 1PPS/new= %9d\r\n", onepps_num, onepps_newest); - return onepps_cnt_avarage; -} - -// Newest measued data GPS 1PPS -uint32_t FRQ_CUNTR::read_newest_1pps(void) -{ - return onepps_newest; -} - -// Check GPS condition -uint8_t FRQ_CUNTR::status_gps(void) -{ - return gps_ready; -} - -//--------------------------------------------------------------------------------------- -// 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 { - tim2_ready_flg = 0; - set_1PPS_data(); - 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; - } else { - return 0; - } -} - -//--------------------------------------------------------------------------------------- -// TIM3+TIM4 (32bit Counter + IC) -//--------------------------------------------------------------------------------------- -// Read TIM3+4(as 32bit) captured counter value -uint32_t FRQ_CUNTR::read_ic2_counter_TIM3P4(void) -{ - return tim3p4_cnt_data; -} - -// Check TIM3 IC2 & TIM4 IC1 status -uint32_t FRQ_CUNTR::check_ic2_status_TIM3P4(void) -{ - if (tim3p4_ready_flg == 0) { - return 0; - } else { - tim3p4_ready_flg = 0; - return 1; - } -} - -//--------------------------------------------------------------------------------------- -// Frequency check for test purpose -//--------------------------------------------------------------------------------------- -// Read TIM2 Clock frequency -uint32_t FRQ_CUNTR::read_frequency_TIM2(float gate_time) -{ - uint32_t freq = 0; - TIM2->CNT = 0; - wait(gate_time); // Gate time for count - freq = TIM2->CNT; // read counter - PRINTF("Clock freq.=%10d [Hz], gate= %4.2f [Sec]\r\n", freq, gate_time); - return freq; // return counter data -} - -// Read TIM3(+TIM4) Input frequency -uint32_t FRQ_CUNTR::read_frequency_TIM3P4(float gate_time) -{ - uint32_t freq0 = 0; - uint32_t freq1 = 0; - TIM3->CNT = 0; - TIM4->CNT = 0; - TIM3->CNT = 0; - wait(gate_time); // Gate time for count - freq0 = TIM3->CNT; - freq1 = TIM4->CNT; - freq0 = (freq1 << 16) + freq0; - PRINTF("Input freq.=%10d [Hz], gate= %4.2f [Sec]\r\n", freq0, gate_time); - return freq0; // read counter -} - -//--------------------------------------------------------------------------------------- -// Clock output for test purpose -//--------------------------------------------------------------------------------------- -// Output internal clock -void FRQ_CUNTR::port_mco1_mco2_set(uint8_t select) -{ - // PA8 -> MCO_1 - GPIOA->AFR[1] &= 0xfffffff0; - GPIOA->AFR[1] |= GPIO_AF0_MCO << 0; - GPIOA->MODER &= ~(GPIO_MODER_MODER8); // AF - GPIOA->MODER |= GPIO_MODER_MODER8_1; - GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_8); // Output Push-Pull=0 - GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8;// Speed full=11 - GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR8); // Pull-up=01 - GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_0; - // PC9 -> MCO_2 - GPIOC->AFR[1] &= 0xffffff0f; - GPIOC->AFR[1] |= GPIO_AF0_MCO << 4; - GPIOC->MODER &= ~(GPIO_MODER_MODER9); // AF - GPIOC->MODER |= GPIO_MODER_MODER9_1; - GPIOC->OTYPER &= ~(GPIO_OTYPER_OT_9); // Output Push-Pull=0 - GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9;// Speed full=11 - GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR9); // Pull-up=01 - GPIOC->PUPDR |= GPIO_PUPDR_PUPDR9_0; - // Select output clock source - RCC->CFGR &= 0x009fffff; - if (select == 1) { - // MC01 output HSE 1/1, MCO2 output SYSCLK 1/1 - // MCO2 MCO2PRE MCO1PRE MCO1 - RCC->CFGR |= (0x0 << 30) + (0x0 << 27) + (0x0 << 24) + (0x2 << 21); - PRINTF("Set MCO1(PA8):HSE/1, MCO2(PC9):SYSCLK/1\r\n"); - } else if (select == 2) { - // MC01 output HSE 1/2, MCO2 output SYSCLK 1/2 - // MCO2 MCO2PRE MCO1PRE MCO1 - RCC->CFGR |= (0x0 << 30) + (0x4 << 27) + (0x4 << 24) + (0x2 << 21); - PRINTF("Set MCO1(PA8):HSE/2, MCO2(PC9):SYSCLK/2\r\n"); - } else { // select = 4 and other wrong order - // MC01 output HSE 1/4, MCO2 output SYSCLK 1/4 - // MCO2 MCO2PRE MCO1PRE MCO1 - RCC->CFGR |= (0x0 << 30) + (0x6 << 27) + (0x6 << 24) + (0x2 << 21); - PRINTF("Set MCO1(PA8):HSE/4, MCO2(PC9):SYSCLK/4\r\n"); - } -} - -//--------------------------------------------------------------------------------------- -// Initialize TIM2 and TIM3+4 -//--------------------------------------------------------------------------------------- -void FRQ_CUNTR::initialize_Freq_counter(void) -{ - initialize_TIM2(); - initialize_TIM3P4(); -} - -// Initialize TIM2 -// Internal clock (100MHz) or External clock(?MHz) and IC2 for GPS 1pps signal measurement -void FRQ_CUNTR::initialize_TIM2(void) -{ -#if defined(BASE_EXTERNAL_CLOCK) - // PA0 -> Counter frequency input pin as Timer2 CH1/ETR - RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN); - GPIOA->AFR[0] &= 0xfffffff0; - GPIOA->AFR[0] |= GPIO_AF1_TIM2; - GPIOA->MODER &= ~(GPIO_MODER_MODER0); // AF - GPIOA->MODER |= GPIO_MODER_MODER0_1; - GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR0); // PU - GPIOA->PUPDR |= GPIO_PUPDR_PUPDR0_0; - // Initialize Timer2(32bit) for an external up counter mode - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; - TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));// count_up + div by 1 - TIM2->CR1 |= TIM_CR1_URS; - TIM2->ARR = 0xffffffff; - TIM2->PSC = 0x0000; - TIM2->CCER &= (uint16_t)~TIM_CCER_CC1E; // Disable the CC1 - TIM2->CCMR1 &= (uint16_t)~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S); // input filter + input select - TIM2->CCMR1 |= (uint16_t)TIM_CCMR1_CC1S_0; - TIM2->CCER &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP); // positive edge - TIM2->SMCR = (uint16_t)(TIM_SMCR_ECE| TIM_SMCR_ETPS_0 | TIM_SMCR_TS); // clock/2 !! - TIM2->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter -#else // defined(BASE_EXTERNAL_CLOCK) - // Initialize Timer2(32bit) for an internal up counter mode - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; - TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD)); // count_up + div by 1 - TIM2->CR1 |= TIM_CR1_URS; - TIM2->ARR = 0xffffffff; - TIM2->PSC = 0x0000; - TIM2->CCER &= (uint16_t)~TIM_CCER_CC1E; // Disable the CC1 - TIM2->SMCR &= (uint16_t)~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS); - TIM2->SMCR |= (uint16_t)0; // Internal clock = 100MHz - TIM2->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter -#endif // defined(BASE_EXTERNAL_CLOCK) - // PA1 -> Input Capture pin as Timer2 IC2 - GPIOA->AFR[0] &= 0xffffff0f; - GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 4; - GPIOA->MODER &= ~(GPIO_MODER_MODER1); // AF - GPIOA->MODER |= GPIO_MODER_MODER1_1; - GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR1); - GPIOA->PUPDR |= GPIO_PUPDR_PUPDR1_0; // PU - // Initialize Timer2 I.C.2 - TIM2->CCER &= (uint16_t)~TIM_CCER_CC2E; // Disable the CC2 - TIM2->CCMR1 &= (uint16_t)~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S);// input filter + input select - TIM2->CCMR1 |= (uint16_t)TIM_CCMR1_CC2S_0; - TIM2->CCER &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); // positive edge - TIM2->CCER |= (uint16_t)TIM_CCER_CC2E; // enable capture - // PB10 -> Output Compare pin as Timer2 CH3/OC3 - GPIOB->AFR[1] &= 0xfffff0ff; - GPIOB->AFR[1] |= GPIO_AF1_TIM2 << 8; - GPIOB->MODER &= ~(GPIO_MODER_MODER10); // AF - GPIOB->MODER |= GPIO_MODER_MODER10_1; - GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_10);// Output Push-Pull=0 - GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10;// Speed full=11 - GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR10); // Pull-up=01 - GPIOB->PUPDR |= GPIO_PUPDR_PUPDR10_0; - // Initialize Timer2 O.C.3 - TIM2->CCER &= (uint16_t)~TIM_CCER_CC3E; // Reset the CC3E Bit - TIM2->CCMR2 &= (uint16_t)~(TIM_CCMR2_OC3M | TIM_CCMR2_CC3S | - TIM_CCMR2_OC3PE | TIM_CCMR2_OC3CE | TIM_CCMR2_OC3FE); - TIM2->CCMR2 |= (TIM_CCMR2_OC3M_0 | TIM_CCMR2_OC3M_1); - TIM2->CCER &= (uint16_t)~TIM_CCER_CC3P;// Reset the Output Polarity level - TIM2->CCER |= (uint16_t)TIM_CCER_CC3E; // Set the CC3E Bit - new_gt_value = 0; - oc_hi_time = oc_set_time0; - oc_lo_time = oc_set_time1; - TIM2->CCR3 = TIM2->CNT + oc_hi_time;// Set the Capture Compare Register value - // Only for Debug purpose - BAUD(9600); - // PA - PRINTF("\r\n// Timer2(32bit) for an internal up counter mode\r\n"); - PRINTF("// PA1 -> Input Capture pin as Timer2 CH2/TI2\r\n"); - PRINTF("GPIOA->AFR[0]0x%08x:0x%08x\r\n",&GPIOA->AFR[0], GPIOA->AFR[0]); - PRINTF("GPIOA->AFR[1]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->AFR[0]0x%08x:0x%08x\r\n",&GPIOB->AFR[0], GPIOB->AFR[0]); - PRINTF("GPIOB->AFR[1]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("// 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\r\n",&TIM2->CCR3, TIM2->CCR3); - // Interrupt Timer2 IC2 - for (uint32_t i = 0; i < CNT_BF_SIZE; i++) { - onepps_cnt[i] = 0; - } - onepps_num = 0; - onepps_ready_flg = 0; - onepps_buf_full = 0; - onepps_cnt_avarage = 0; - tim2_ready_flg = 0; - tim2_cnt_data = 0; - tim2_old_cnt_data = 0; - TIM2->SR &= ~(TIM_SR_CC2IF + TIM_SR_CC3IF); // clear IC flag - TIM2->DIER |= TIM_DIER_CC2IE + TIM_DIER_CC3IE; - NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic2_TIM2); - NVIC_ClearPendingIRQ(TIM2_IRQn); - NVIC_EnableIRQ(TIM2_IRQn); -} - -// Initialize TIM3 and TIM4 as 32bit counter (TIM3(16bit) + TIM4(16bit)) -// TIM3 clock input is unkown freq.(measuring freq.) and TIM4 is slave counter -// 1sec gate signal connected both TIM3 IC2 and TIM4 IC1 -void FRQ_CUNTR::initialize_TIM3P4(void) -{ - // PC6 -> Unkown frequency input pin as Timer3 CH1/TI1 - RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOCEN); - GPIOC->AFR[0] &= 0xf0ffffff; - GPIOC->AFR[0] |= GPIO_AF2_TIM3 << 24; - GPIOC->MODER &= ~(GPIO_MODER_MODER6); // AF - GPIOC->MODER |= GPIO_MODER_MODER6_1; - GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR6); - GPIOC->PUPDR |= GPIO_PUPDR_PUPDR6_0; // PU - // Initialize Timer3(16bit) for an external up counter mode - RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; - TIM3->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));// count_up + div by 1 - TIM3->CR1 |= (uint16_t)TIM_CR1_URS; - TIM3->ARR = 0xffff; - TIM3->CCER &= (uint16_t)~TIM_CCER_CC1E; // Disable the CC1 - TIM3->CCMR1 &= (uint16_t)~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S); // input filter + input select - TIM3->CCMR1 |= (uint16_t)TIM_CCMR1_CC1S_0; - TIM3->CCER &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NE | TIM_CCER_CC1NP);// positive edge - TIM3->SMCR &= (uint16_t)~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS);// external mode 1 - TIM3->SMCR |= (uint16_t)( TIM_TS_TI1FP1 | TIM_SLAVEMODE_EXTERNAL1); // ECE must be ZERO!!!! - TIM3->CR2 &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS); - TIM3->CR2 |= (uint16_t)TIM_CR2_MMS_1; // TRGO update - TIM3->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter - // Initialize Timer4(16bit) for an slave up counter of TIM3 - RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; - TIM4->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));// count_up + div by 1 - TIM4->CR1 |= (uint16_t)TIM_CR1_URS; - TIM4->ARR = 0xffff; - TIM4->CCER &= (uint16_t)TIM_CCER_CC1E; // Capture enable - TIM4->SMCR &= (uint16_t)~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS);// external mode 1 - TIM4->SMCR |= (uint16_t)( TIM_TS_ITR2 | TIM_SLAVEMODE_EXTERNAL1);// ECE must be ZERO!!!! - TIM4->CR2 &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS); - TIM4->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter - // PC7 -> Input Capture pin as Timer3 IC2 - GPIOC->AFR[0] &= 0x0fffffff; - GPIOC->AFR[0] |= GPIO_AF2_TIM3 << 28; - GPIOC->MODER &= ~(GPIO_MODER_MODER7); // AF - GPIOC->MODER |= GPIO_MODER_MODER7_1; - GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR7); - GPIOC->PUPDR |= GPIO_PUPDR_PUPDR7_0; // PU - // Initialize Timer3 IC2 - TIM3->CCER &= (uint16_t)~TIM_CCER_CC2E; // Disable the CC2 - TIM3->CCMR1 &= (uint16_t)~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S);// input filter + input select - TIM3->CCMR1 |= (uint16_t)TIM_CCMR1_CC2S_0; - TIM3->CCER &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); // positive edge - TIM3->CCER |= (uint16_t)TIM_CCER_CC2E; // enable capture - // PB6 -> Input Capture pin as Timer4 IC1 - GPIOB->AFR[0] &= 0xf0ffffff; - GPIOB->AFR[0] |= GPIO_AF2_TIM4 << 24; - GPIOB->MODER &= ~(GPIO_MODER_MODER6); // AF - GPIOB->MODER |= GPIO_MODER_MODER6_1; - GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR6); - GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0; // Pull-up=01 - // Initialize Timer4 IC1 - TIM4->CCER &= (uint16_t)~TIM_CCER_CC1E; - TIM4->CCMR1 &= ((uint16_t)~TIM_CCMR1_CC1S) & ((uint16_t)~TIM_CCMR1_IC1F); - TIM4->CCMR1 |= (uint16_t)TIM_CCMR1_CC1S_0; - TIM4->CCER &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP); // positive edge - TIM4->CCER |= (uint16_t)TIM_CCER_CC1E; // enable capture - // Only for Debug purpose - // PB - PRINTF("// PB6 -> Input Capture pin as Timer4 CH1/TI1\r\n"); - PRINTF("GPIOB->AFR[0]0x%08x:0x%08x\r\n",&GPIOB->AFR[0], GPIOB->AFR[0]); - PRINTF("GPIOB->AFR[1]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 Timer3 CH1/TI1\r\n"); - PRINTF("// PC7 -> Input Capture pin as Timer3 CH2/TI2\r\n"); - PRINTF("GPIOC->AFR[0]0x%08x:0x%08x\r\n",&GPIOC->AFR[0], GPIOC->AFR[0]); - PRINTF("GPIOC->AFR[1]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); - // TIM3 - PRINTF("// PC6 -> Timer3(16bit) for an external up counter mode\r\n"); - PRINTF("// PC7 -> Timer3 IC2\r\n"); - PRINTF("TIM3->CR1 0x%08x:0x%08x\r\n",&TIM3->CR1, TIM3->CR1); - PRINTF("TIM3->ARR 0x%08x:0x%08x\r\n",&TIM3->ARR, TIM3->ARR); - PRINTF("TIM3->PSC 0x%08x:0x%08x\r\n",&TIM3->PSC, TIM3->PSC); - PRINTF("TIM3->CCMR1 0x%08x:0x%08x\r\n",&TIM3->CCMR1, TIM3->CCMR1); - PRINTF("TIM3->CCMR2 0x%08x:0x%08x\r\n",&TIM3->CCMR2, TIM3->CCMR2); - PRINTF("TIM3->CCER 0x%08x:0x%08x\r\n",&TIM3->CCER, TIM3->CCER); - PRINTF("TIM3->SMCR 0x%08x:0x%08x\r\n",&TIM3->SMCR, TIM3->SMCR); - // TIM4 - PRINTF("// none-> Timer4(16bit) for an slave counter\r\n"); - 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\r\n",&TIM4->SMCR, TIM4->SMCR); - PRINTF("RCC->APB1ENR 0x%08x:0x%08x\r\n\r\n",&RCC->APB1ENR, RCC->APB1ENR); - // Interrupt Timer3 IC2 - tim3p4_ready_flg = 0; - tim3p4_cnt_data = 0; - TIM3->SR &= ~TIM_SR_CC2IF; // clear IC flag - TIM4->SR &= ~TIM_SR_CC1IF; - TIM3->DIER |= TIM_DIER_CC2IE; - NVIC_SetVector(TIM3_IRQn, (uint32_t)irq_ic2_TIM3P4); - NVIC_ClearPendingIRQ(TIM3_IRQn); - NVIC_EnableIRQ(TIM3_IRQn); -} - -//--------------------------------------------------------------------------------------- -// Only for Debug purpose -//--------------------------------------------------------------------------------------- -void FRQ_CUNTR::debug_printf_internal_data(void) -{ - PRINTF("Debug information\r\n"); - PRINTF("gate_time %f\r\n", gate_time); - 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("\r\n"); -} - -} // Frequency_counter - -#endif // #if defined(TARGET_NUCLEO_F411RE)
diff -r 9d3b3f0a3882 -r bb04c4a3b5ba frq_cuntr_full.h --- a/frq_cuntr_full.h Thu Jan 01 05:04:20 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,219 +0,0 @@ -/* - * mbed Library / Frequency Counter with GPS 1PPS Compensation - * Frequency Counter Hardware relataed program - * Only for ST Nucleo F411RE - * - * Copyright (c) 2014 Kenji Arai / JH1PJL - * http://www.page.sannet.ne.jp/kenjia/index.html - * http://mbed.org/users/kenjiArai/ - * Additional functions and modification - * started: October 18th, 2014 - * Revised: January 1st, 2015 - * - * 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. - */ - -#ifndef MBED_FRQ_CUNTR -#define MBED_FRQ_CUNTR - -#include "mbed.h" - -// please comment out when normal run mode -//#define DEBUG // use Communication with PC(UART) - -/* - CAUTION: - If you select internal clock (100MHz), you need consider PLL clock behavior. - PLL clock drifts over 70Hz (increase frequency) within 30 to 40 second - then suddenly back to low frequency and increase again. - Even you prepare precision external clock, this frequency drift cannot avoid. - Comment out "BASE_EXTERNAL_CLOCK" is only for checking!! - */ -#define BASE_EXTERNAL_CLOCK - -// use avaraged 1pps data -#define ONEPPS_AVE - -namespace Frequency_counter -{ - -#define CNT_BF_SIZE 120 // 1PPS data save size - -/** Frequency Counter program - * Only for ST Nucleo F411RE Board - * - * @code - * #include "mbed.h" - * - * using namespace Frequency_counter; - * - * // PC_6,PC_7 & PB_6 use for Timer3 & 4(16+16bit) - * // PA_0,PA_1 & PB_10 use for Timer2(32bit) - * // PA_8 & PC_7 use for MCO (Test purpose) - * FRQ_CUNTR fc(PC_6, 1.0, 24.999982f); //Input port, gate time[sec] & External clock freq. - * - * int main() { - * uint32_t counter_1pps = 0; - * double new_frequency = 0; - * // This is for test purpose - * fc.port_mco1_mco2_set(4); // Clk/4 ->1/1(100MHz) cannot measure!! - * fc.read_frequency_TIM2(1.0); // read TIM2 source frequency (test) - * fc.read_frequency_TIM3P4(1.0); // read TIM3 source frequency (test) - * while(true) { - * while (fc.status_1pps() == 0) {;} - * counter_1pps = fc.read_avarage_1pps(); - * while (fc.status_freq_update() == 0) {;} - * new_frequency = fc.read_freq_data(); - * printf("1PPS/ave = %9d , FREQUENCY = %11.3f\r\n", counter_1pps, new_frequency); - * } - * } - * @endcode - */ - -class FRQ_CUNTR -{ -public: - - /** Configure data pin (Not changeable) - * @param Freq. input pin + Gate time[sec] + External clock[MHz] - */ - FRQ_CUNTR(PinName f_in, double gt, double ex_clock); - - /** Set gate time - * @param gate time [sec] - * @return gate time (range 50mS to 1 minute) - */ - double set_gate_time(double gt); - - /** Set external clock frequency - * @param frequency e.g. 25.000000 [MHz] - * @return none - */ - void set_external_clock(double ex_clock); - - /** Read gate time - * @param none - * @return gate time (range 50mS to 1 minute) - */ - double read_gate_time(void); - - /** Read status (new frequency data is available or not) - * @param none - * @return !=0: new data is avairable, 0: not yet - */ - uint32_t status_freq_update(void); - - /** Read new frequency data - * @param none - * @return frequency data - */ - double read_freq_data(void); - - /** Read avarage measued data GPS 1PPS - * @param none - * @return Frequency - */ - uint32_t read_avarage_1pps(void); - - /** Read newest measued data GPS 1PPS - * @param none - * @return Frequency - */ - uint32_t read_newest_1pps(void); - - /** Read status (new 1PPS data is available or not) - * @param none - * @return !=0: new data is avairable, 0: not yet - */ - uint32_t status_1pps(void); - - /** Read GPS status - * @param none - * @return 1: GPS is ready - */ - uint8_t status_gps(void); - - /** This is a "TEST PURPOSE" function - * Check PA0 pin input or internal clock frequency - * @param none - * @return Frequency - */ - uint32_t read_frequency_TIM2(float gate_time); - - /** This is a "TEST PURPOSE" function - * Check PC6 pin input frequency - * @param none - * @return Frequency - */ - uint32_t read_frequency_TIM3P4(float gate_time); - - /** This is a "TEST PURPOSE" function - * Output clock from pin PA8 & PC9 uses for MCO_1 & MCO_2 - * @param none - * @return none - */ - void port_mco1_mco2_set(uint8_t select); - - /** This is a "DEBUG PURPOSE" function - * print internal data (need to define "DEBUG" - * @param none - * @return none - */ - void debug_printf_internal_data(void); - -protected: - DigitalIn _pin; - - void initialize_Freq_counter(void); // Initialize timers - // Internal clock (100MHz) or External clock(?MHz) and IC2 for GPS 1pps signal measurement - void initialize_TIM2(void); - // Initialize TIM3 and TIM4 as 32bit counter (TIM3(16bit) + TIM4(16bit)) - void initialize_TIM3P4(void); - uint32_t set_1PPS_data(void); // Set GPS 1PPS counter value - uint32_t read_ic2_counter_TIM2(void); // Read TIM2 captured counter value - uint32_t check_ic2_status_TIM2(void); // Check TIM2 IC2 status - uint32_t read_ic2_counter_TIM3P4(void); // Read TIM3+4(as 32bit) captured counter value - uint32_t check_ic2_status_TIM3P4(void); // Check TIM3 IC2 & TIM4 IC1 status - uint8_t read_oc_port_status(void); // Check TIM2 OC port - -private: - double newest_frequency; - double gate_time; - double ex_clock_freq; - uint32_t ex_clk_base; - uint32_t clk_hi_const; - uint32_t clk_upper_limit; - uint32_t clk_lower_limit; - uint8_t gps_ready; - // TIM2 - uint32_t counter_tim2; - uint32_t old_cntr_tim2; - // TIM3+4 - uint32_t counter_tim3p4; - uint32_t old_cntr_tim3p4; - // 1PPS data - uint32_t onepps_newest; - uint32_t onepps_cnt[CNT_BF_SIZE]; - uint32_t onepps_num; - uint64_t onepps_cnt_avarage; - uint8_t onepps_buf_full; - uint8_t onepps_ready_flg; - -}; - -/* - Interrupt handler does NOT work following code - NVIC_SetVector(TIM2_IRQn, (uint32_t)FRQ_CUNTR::irq_ic2_TIM2); - From this reason, I wrote below code and set interrupt handler out side "FRQ_CUNTR" class - NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic2_TIM2); - */ -void irq_ic2_TIM2(void); // TIM2 IC2 Interrupt control -void irq_ic2_TIM3P4(void); // TIM3 IC2 Interrupt control (same signal connected to TIM4 IC1) - -} // Frequency_counter - -#endif // MBED_FRQ_CUNTR