Frequency counter library only for DISCO-F746NG & NucleoF411RE +F446RE
Dependents: FreqCntr_GPS1PPS_F746F4xx_w_recipro Freq_Cntr_GPS1PPS_F746NG_GUI
Fork of Frq_cuntr_full by
fc_common.cpp@6:be7123d400ae, 2016-11-16 (annotated)
- Committer:
- kenjiArai
- Date:
- Wed Nov 16 13:15:35 2016 +0000
- Revision:
- 6:be7123d400ae
- Parent:
- 5:783b039f9119
Frequency counter library using GPS 1PPS signal
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kenjiArai | 5:783b039f9119 | 1 | /* |
kenjiArai | 5:783b039f9119 | 2 | * mbed Library / Frequency Counter using GPS 1PPS gate pulse |
kenjiArai | 5:783b039f9119 | 3 | * Frequency Counter program (Common part) |
kenjiArai | 5:783b039f9119 | 4 | * Only for ST DISCO-F746NG and Nucleo-F411RE+F446RE |
kenjiArai | 5:783b039f9119 | 5 | * |
kenjiArai | 5:783b039f9119 | 6 | * Copyright (c) 2014,'15,'16 Kenji Arai / JH1PJL |
kenjiArai | 5:783b039f9119 | 7 | * http://www.page.sannet.ne.jp/kenjia/index.html |
kenjiArai | 5:783b039f9119 | 8 | * http://mbed.org/users/kenjiArai/ |
kenjiArai | 5:783b039f9119 | 9 | * Started: October 18th, 2014 |
kenjiArai | 5:783b039f9119 | 10 | * Revised: January 1st, 2015 |
kenjiArai | 5:783b039f9119 | 11 | * Re-started: June 25th, 2016 ported from F411 board |
kenjiArai | 5:783b039f9119 | 12 | * Re-started: October 5th, 2016 Change board -> DISCO-F746NG |
kenjiArai | 5:783b039f9119 | 13 | * Re-started: October 17th, 2016 Continue F746 and back to F411 |
kenjiArai | 5:783b039f9119 | 14 | * Revised: November 13th, 2016 |
kenjiArai | 5:783b039f9119 | 15 | * |
kenjiArai | 5:783b039f9119 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
kenjiArai | 5:783b039f9119 | 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
kenjiArai | 5:783b039f9119 | 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
kenjiArai | 5:783b039f9119 | 19 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
kenjiArai | 5:783b039f9119 | 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
kenjiArai | 5:783b039f9119 | 21 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR |
kenjiArai | 5:783b039f9119 | 22 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
kenjiArai | 5:783b039f9119 | 23 | */ |
kenjiArai | 5:783b039f9119 | 24 | |
kenjiArai | 5:783b039f9119 | 25 | #include "fc_GPS1PPS.h" |
kenjiArai | 5:783b039f9119 | 26 | #include "RingBuff.h" |
kenjiArai | 5:783b039f9119 | 27 | |
kenjiArai | 5:783b039f9119 | 28 | #define ACTIVE_LED_TIMX 0 |
kenjiArai | 5:783b039f9119 | 29 | #define ACTIVE_LED_TIMZ 0 |
kenjiArai | 5:783b039f9119 | 30 | |
kenjiArai | 5:783b039f9119 | 31 | #if ACTIVE_LED_TIMX || ACTIVE_LED_TIMZ |
kenjiArai | 5:783b039f9119 | 32 | DigitalOut irq_led1(LED1); |
kenjiArai | 5:783b039f9119 | 33 | #endif |
kenjiArai | 5:783b039f9119 | 34 | |
kenjiArai | 5:783b039f9119 | 35 | #if DEBUG |
kenjiArai | 5:783b039f9119 | 36 | #define PRINTF(...) printf(__VA_ARGS__) |
kenjiArai | 5:783b039f9119 | 37 | #else |
kenjiArai | 5:783b039f9119 | 38 | #define PRINTF(...) {;} |
kenjiArai | 5:783b039f9119 | 39 | #endif |
kenjiArai | 5:783b039f9119 | 40 | |
kenjiArai | 5:783b039f9119 | 41 | namespace Frequency_counter |
kenjiArai | 5:783b039f9119 | 42 | { |
kenjiArai | 5:783b039f9119 | 43 | |
kenjiArai | 5:783b039f9119 | 44 | // TIMxPy IC + OverFlow & TIMz IC |
kenjiArai | 5:783b039f9119 | 45 | static uint8_t timxpy_ready_flg; |
kenjiArai | 5:783b039f9119 | 46 | static uint32_t timxpy_cnt_data; |
kenjiArai | 5:783b039f9119 | 47 | static uint16_t time_count; |
kenjiArai | 5:783b039f9119 | 48 | static uint16_t sw_ovrflw_timxpy; |
kenjiArai | 5:783b039f9119 | 49 | static uint32_t timz_cnt_data; |
kenjiArai | 5:783b039f9119 | 50 | static uint16_t time_count_onepps; |
kenjiArai | 5:783b039f9119 | 51 | // TIMz IC (Reciprocal) + OverFlow |
kenjiArai | 5:783b039f9119 | 52 | static uint16_t sw_ovrflw_timz; |
kenjiArai | 5:783b039f9119 | 53 | static uint8_t recipro_step; |
kenjiArai | 5:783b039f9119 | 54 | static uint32_t recipro_start; |
kenjiArai | 5:783b039f9119 | 55 | static uint32_t recipro_stop; |
kenjiArai | 5:783b039f9119 | 56 | |
kenjiArai | 5:783b039f9119 | 57 | #include "fc_hw_f411.h" |
kenjiArai | 5:783b039f9119 | 58 | #include "fc_hw_f746.h" |
kenjiArai | 5:783b039f9119 | 59 | |
kenjiArai | 5:783b039f9119 | 60 | //------------------------------------------------------------------------------ |
kenjiArai | 5:783b039f9119 | 61 | // Frequency Counter Library |
kenjiArai | 5:783b039f9119 | 62 | //------------------------------------------------------------------------------ |
kenjiArai | 5:783b039f9119 | 63 | FRQ_CUNTR::FRQ_CUNTR(void) |
kenjiArai | 5:783b039f9119 | 64 | { |
kenjiArai | 5:783b039f9119 | 65 | initialize_TIMxPy(); // Use for base functuion (FC based on 1PPS) |
kenjiArai | 5:783b039f9119 | 66 | initialize_TIMz(); // Use for reciprocal |
kenjiArai | 5:783b039f9119 | 67 | } |
kenjiArai | 5:783b039f9119 | 68 | |
kenjiArai | 5:783b039f9119 | 69 | // Read new frequency data |
kenjiArai | 5:783b039f9119 | 70 | double FRQ_CUNTR::read_freq_data(void) |
kenjiArai | 5:783b039f9119 | 71 | { |
kenjiArai | 5:783b039f9119 | 72 | return read_freq_w_gate_time(1); // gate time is 1 second |
kenjiArai | 5:783b039f9119 | 73 | } |
kenjiArai | 5:783b039f9119 | 74 | |
kenjiArai | 5:783b039f9119 | 75 | // Read new frequency data with specific gate time |
kenjiArai | 5:783b039f9119 | 76 | double FRQ_CUNTR::read_freq_w_gate_time(uint16_t gt) |
kenjiArai | 5:783b039f9119 | 77 | { |
kenjiArai | 5:783b039f9119 | 78 | freq_one f_new, f_old; |
kenjiArai | 5:783b039f9119 | 79 | |
kenjiArai | 5:783b039f9119 | 80 | if (gt == 0){ return 0.0f;} |
kenjiArai | 5:783b039f9119 | 81 | f_new.f_1sec_dt = fdt_buffer.ring_get_newest_dt(); // newest data |
kenjiArai | 5:783b039f9119 | 82 | f_old.f_1sec_dt = fdt_buffer.ring_get_pointed_dt(gt);// gt[sec] before data |
kenjiArai | 5:783b039f9119 | 83 | uint32_t new_cnt = (uint32_t)f_new.t_cnt; |
kenjiArai | 5:783b039f9119 | 84 | uint32_t old_cnt = (uint32_t)f_old.t_cnt; |
kenjiArai | 5:783b039f9119 | 85 | if (old_cnt > new_cnt){ |
kenjiArai | 5:783b039f9119 | 86 | new_cnt += 0x10000; |
kenjiArai | 5:783b039f9119 | 87 | } |
kenjiArai | 5:783b039f9119 | 88 | if ((new_cnt - old_cnt) == gt){ // make sure gt[sec] |
kenjiArai | 5:783b039f9119 | 89 | uint64_t dt = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt); |
kenjiArai | 5:783b039f9119 | 90 | return (double)dt / (double)gt; // Calculate a frequency value |
kenjiArai | 5:783b039f9119 | 91 | } else { |
kenjiArai | 5:783b039f9119 | 92 | return 0.0f; // if gt isn't same as buffered number, cancel calculation |
kenjiArai | 5:783b039f9119 | 93 | } |
kenjiArai | 5:783b039f9119 | 94 | } |
kenjiArai | 5:783b039f9119 | 95 | |
kenjiArai | 5:783b039f9119 | 96 | // Read status (new frequency data is available or not) |
kenjiArai | 5:783b039f9119 | 97 | uint32_t FRQ_CUNTR::status_freq_update(void) |
kenjiArai | 5:783b039f9119 | 98 | { |
kenjiArai | 5:783b039f9119 | 99 | if (timxpy_ready_flg == 0){ // 1PPS is not comming yet |
kenjiArai | 5:783b039f9119 | 100 | return 0; |
kenjiArai | 5:783b039f9119 | 101 | } else { // Gate signal is comming |
kenjiArai | 5:783b039f9119 | 102 | timxpy_ready_flg = 0; |
kenjiArai | 5:783b039f9119 | 103 | return 1; |
kenjiArai | 5:783b039f9119 | 104 | } |
kenjiArai | 5:783b039f9119 | 105 | } |
kenjiArai | 5:783b039f9119 | 106 | |
kenjiArai | 5:783b039f9119 | 107 | // Calculate diff between new & old 48bit data |
kenjiArai | 5:783b039f9119 | 108 | uint64_t FRQ_CUNTR::get_diff(uint64_t new_dt, uint64_t old_dt){ |
kenjiArai | 5:783b039f9119 | 109 | uint64_t nw,od; |
kenjiArai | 5:783b039f9119 | 110 | |
kenjiArai | 5:783b039f9119 | 111 | nw = new_dt & 0x0000ffffffffffff; // select 48bit data |
kenjiArai | 5:783b039f9119 | 112 | od = old_dt & 0x0000ffffffffffff; |
kenjiArai | 5:783b039f9119 | 113 | if (nw < od){ // 48bits counter overflow! |
kenjiArai | 5:783b039f9119 | 114 | nw += 0x0001000000000000; |
kenjiArai | 5:783b039f9119 | 115 | } |
kenjiArai | 5:783b039f9119 | 116 | return (nw - od); |
kenjiArai | 5:783b039f9119 | 117 | } |
kenjiArai | 5:783b039f9119 | 118 | |
kenjiArai | 5:783b039f9119 | 119 | //------------------------------------------------------------------------------ |
kenjiArai | 5:783b039f9119 | 120 | // Frequency Counter / Reciprocal measurement |
kenjiArai | 5:783b039f9119 | 121 | //------------------------------------------------------------------------------ |
kenjiArai | 5:783b039f9119 | 122 | /* // Example |
kenjiArai | 5:783b039f9119 | 123 | int main(){ |
kenjiArai | 5:783b039f9119 | 124 | static double freq_recipro; |
kenjiArai | 5:783b039f9119 | 125 | static uint32_t interval_recipro, base_clk,run2stop; |
kenjiArai | 5:783b039f9119 | 126 | |
kenjiArai | 5:783b039f9119 | 127 | while(1){ |
kenjiArai | 5:783b039f9119 | 128 | fc.recipro_start_measure(); // step1 |
kenjiArai | 5:783b039f9119 | 129 | while (fc.recipro_check_trigger() == 0){ // step2 |
kenjiArai | 5:783b039f9119 | 130 | run2stop = tmr.read_ms(); |
kenjiArai | 5:783b039f9119 | 131 | if (run2stop >= 10000){ break;} |
kenjiArai | 5:783b039f9119 | 132 | } |
kenjiArai | 5:783b039f9119 | 133 | if (run2stop >= 100000){ // 10sec 0.01Hz |
kenjiArai | 5:783b039f9119 | 134 | freq_recipro = 0; |
kenjiArai | 5:783b039f9119 | 135 | } else { |
kenjiArai | 5:783b039f9119 | 136 | interval_recipro = fc.recipro_read_data(); // step3 |
kenjiArai | 5:783b039f9119 | 137 | base_clk = fc.recipro_base_clk_data(1); // step4 |
kenjiArai | 5:783b039f9119 | 138 | if (interval_recipro >= 9000){// Measure less than 10KHz frequency |
kenjiArai | 5:783b039f9119 | 139 | // step final |
kenjiArai | 5:783b039f9119 | 140 | freq_recipro = (double)base_clk / (double)interval_recipro; |
kenjiArai | 5:783b039f9119 | 141 | } else { |
kenjiArai | 5:783b039f9119 | 142 | freq_recipro = 0; |
kenjiArai | 5:783b039f9119 | 143 | } |
kenjiArai | 5:783b039f9119 | 144 | } |
kenjiArai | 5:783b039f9119 | 145 | printf("Freq: %11.5f [Hz]", freq_recipro); |
kenjiArai | 5:783b039f9119 | 146 | printf("Raw: %11u", interval_recipro); |
kenjiArai | 5:783b039f9119 | 147 | wait(1.0f); // next interval |
kenjiArai | 5:783b039f9119 | 148 | } |
kenjiArai | 5:783b039f9119 | 149 | } |
kenjiArai | 5:783b039f9119 | 150 | */ |
kenjiArai | 5:783b039f9119 | 151 | // step1 |
kenjiArai | 5:783b039f9119 | 152 | void FRQ_CUNTR::recipro_start_measure(void) |
kenjiArai | 5:783b039f9119 | 153 | { |
kenjiArai | 5:783b039f9119 | 154 | recipro_step = 0; // initialize step |
kenjiArai | 5:783b039f9119 | 155 | start_action(); |
kenjiArai | 5:783b039f9119 | 156 | } |
kenjiArai | 5:783b039f9119 | 157 | |
kenjiArai | 5:783b039f9119 | 158 | // step2 |
kenjiArai | 5:783b039f9119 | 159 | uint32_t FRQ_CUNTR::recipro_check_trigger(void) |
kenjiArai | 5:783b039f9119 | 160 | { |
kenjiArai | 5:783b039f9119 | 161 | if (recipro_step == 2){ // check IC event happen or not |
kenjiArai | 5:783b039f9119 | 162 | return 1; // happen |
kenjiArai | 5:783b039f9119 | 163 | } else { |
kenjiArai | 5:783b039f9119 | 164 | return 0; // not yet |
kenjiArai | 5:783b039f9119 | 165 | } |
kenjiArai | 5:783b039f9119 | 166 | } |
kenjiArai | 5:783b039f9119 | 167 | |
kenjiArai | 5:783b039f9119 | 168 | // step3 |
kenjiArai | 5:783b039f9119 | 169 | uint32_t FRQ_CUNTR::recipro_read_data(void) |
kenjiArai | 5:783b039f9119 | 170 | { |
kenjiArai | 5:783b039f9119 | 171 | uint64_t dt; |
kenjiArai | 5:783b039f9119 | 172 | if (recipro_stop < recipro_start){ // 32bit counter overflow |
kenjiArai | 5:783b039f9119 | 173 | dt = 0x100000000 + recipro_stop; |
kenjiArai | 5:783b039f9119 | 174 | dt -= recipro_stop; |
kenjiArai | 5:783b039f9119 | 175 | } else { |
kenjiArai | 5:783b039f9119 | 176 | dt = recipro_stop - recipro_start; |
kenjiArai | 5:783b039f9119 | 177 | } |
kenjiArai | 5:783b039f9119 | 178 | return (uint32_t)dt; |
kenjiArai | 5:783b039f9119 | 179 | } |
kenjiArai | 5:783b039f9119 | 180 | |
kenjiArai | 5:783b039f9119 | 181 | // step4 |
kenjiArai | 5:783b039f9119 | 182 | uint32_t FRQ_CUNTR::recipro_base_clk_data(uint16_t gt) |
kenjiArai | 5:783b039f9119 | 183 | { |
kenjiArai | 5:783b039f9119 | 184 | freq_one f_new, f_old; |
kenjiArai | 5:783b039f9119 | 185 | |
kenjiArai | 5:783b039f9119 | 186 | if (gt == 0){ return 0.0f;} |
kenjiArai | 5:783b039f9119 | 187 | f_new.f_1sec_dt = onepps_buf.ring_get_newest_dt(); // newest data |
kenjiArai | 5:783b039f9119 | 188 | f_old.f_1sec_dt = onepps_buf.ring_get_pointed_dt(gt);// gt[sec] before data |
kenjiArai | 5:783b039f9119 | 189 | uint32_t new_cnt = (uint32_t)f_new.t_cnt; |
kenjiArai | 5:783b039f9119 | 190 | uint32_t old_cnt = (uint32_t)f_old.t_cnt; |
kenjiArai | 5:783b039f9119 | 191 | if (old_cnt > new_cnt){ |
kenjiArai | 5:783b039f9119 | 192 | new_cnt += 0x10000; |
kenjiArai | 5:783b039f9119 | 193 | } |
kenjiArai | 5:783b039f9119 | 194 | if ((new_cnt - old_cnt) == gt){ // make sure gt |
kenjiArai | 5:783b039f9119 | 195 | uint64_t dt = get_diff(f_new.f_1sec_dt, f_old.f_1sec_dt); |
kenjiArai | 5:783b039f9119 | 196 | return (double)dt / (double)gt; |
kenjiArai | 5:783b039f9119 | 197 | } else { |
kenjiArai | 5:783b039f9119 | 198 | return 0.0f; |
kenjiArai | 5:783b039f9119 | 199 | } |
kenjiArai | 5:783b039f9119 | 200 | } |
kenjiArai | 5:783b039f9119 | 201 | |
kenjiArai | 5:783b039f9119 | 202 | } // Frequency_counter |