Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Frequency_Cntr_1PPS_F746ZG
Fork of Frq_cuntr_full by
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
--- /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
--- /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
+
+
+
+
--- /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
+
--- 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)
--- 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
