Frequency counter library only for NucleoF411RE

Dependents:   Frequency_Counter_w_GPS_1PPS

frq_cuntr_full.h

Committer:
kenjiArai
Date:
2015-01-01
Revision:
4:9d3b3f0a3882
Parent:
3:339307e1dc0d

File content as of revision 4:9d3b3f0a3882:

/*
 * 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