Very simple but enough accuracy "Frequency Counter". Using GPS 1PPS signal for 1sec gate. CPU is F746, F446 and F411.

Dependencies:   fc_GPS1PPS_f746_f4xx iSerial mbed

Please refer following.
/users/kenjiArai/notebook/frequency-counters/

Concept block are follows.
F746
/media/uploads/kenjiArai/block_diagram_fc_f746_wo_oven.pdf
F411&F446
/media/uploads/kenjiArai/block_diagram_fc_f411_wo_oven.pdf
Hardware Circuit(common F746,F446 and F411)
/media/uploads/kenjiArai/fc_f746ng_circuit.pdf
/media/uploads/kenjiArai/f746_fc_1.jpg

main.cpp

Committer:
kenjiArai
Date:
2016-11-16
Revision:
0:da29cdc50643

File content as of revision 0:da29cdc50643:

/*
 * mbed Application program / Frequency Counter using GPS 1PPS gate puls
 *      Only for ST DISCO-F746NG and Nucleo-F411RE + F446RE
 *
 * Copyright (c) 2014,'15,'16 Kenji Arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  http://mbed.org/users/kenjiArai/
 *      Created:    October   18th, 2014
 *      Revised:    January    2nd, 2015
 *      Re-started: June      25th, 2016    ported from F411 to F746
 *      Re-started: October    5th, 2016    Change board -> DISCO-F746NG
 *      Re-started: October   10th, 2016    back to F411
 *      Revised:    Nobember  15th, 2016
 *
 * Base program: Frequency_counter_w_GPS_1PPS (only for Nucleo-F411RE board)
 * https://developer.mbed.org/users/kenjiArai/code/Frequency_Counter_w_GPS_1PPS/
 *
 * 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.
 */

#define     USE_COM         // use Communication with PC(UART)
#define     USE_DEBUG

//  Include --------------------------------------------------------------------
#include    "mbed.h"
#include    "GPSrcvr.h"
#include    "fc_GPS1PPS.h"

//  Definition -----------------------------------------------------------------
#ifdef  USE_COM
#define BAUD(x)             pc.baud(x)
#define GETC(x)             pc.getc(x)
#define PUTC(x)             pc.putc(x)
#define PRINTF(...)         pc.printf(__VA_ARGS__)
#define READABLE(x)         pc.readable(x)
#else
#define BAUD(x)             {;}
#define GETC(x)             {;}
#define PUTC(x)             {;}
#define PRINTF(...)         {;}
#define READABLE(x)         {;}
#endif

#ifdef  USE_DEBUG
#define U_DEBUGBAUD(x)      pc.baud(x)
#define U_DEBUG(...)        pc.printf(__VA_ARGS__)
#define DBG(c)              pc.putc(c)
#else
#define U_DEBUGBAUD(x)      {;}
#define U_DEBUG(...)        {;}
#define DBG(c)              {;}
#endif

#if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
#define RECIPRO_LMT         4500
#define RECIPRO_10KHZ       5000
#elif defined(TARGET_STM32F746NG)
#define RECIPRO_LMT         9000
#define RECIPRO_10KHZ       10000
#else
#error "Target is only Nucleo-F411RE + F446RE or DISCO-F746NG!!!"
#endif
#define GSP_BUF_B           (128 * 3)
#define GPS_BUF_S           (128 * 2)

enum input_select {
         BNC_NORMAL = 1,
         RECIPRO_AC,
         RECIPRO_DC,
         SMA_10,
         SMA_20
};

using namespace Frequency_counter;

//  Object ---------------------------------------------------------------------
#if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
DigitalOut  input_frq_select(PA_4);
DigitalInOut  prescaler10or20(PA_7);
DigitalOut  recipro_select(PB_6);
#elif defined(TARGET_STM32F746NG)
DigitalOut  input_frq_select(PF_9);
DigitalInOut  prescaler10or20(PB_15);
DigitalOut  recipro_select(PA_8);
#endif
DigitalOut  led1(LED1);
Serial      pc(USBTX, USBRX);
Timer       tmr;

//**** Req. Counter
FRQ_CUNTR   fc;

//  RAM ------------------------------------------------------------------------
// Freq.
double      new_frequency;
double      f_10sec;
double      f_100sec;
double      f_1000sec;
double      freq_recipro;
// Operation mode
uint8_t     input_mode;

//  ROM / Constant data --------------------------------------------------------
//                               12345678901234567890
static char *const msg_msg0   = "Frequency Counter by JH1PJL K.Arai";
#if   defined(TARGET_NUCLEO_F411RE)
static char *const msg_msg1   = "on Nucleo-F411RE System";
#elif defined(TARGET_NUCLEO_F446RE)
static char *const msg_msg1   = "on Nucleo-F446RE System";
#elif defined(TARGET_STM32F746NG)
static char *const msg_msg1   = "on DISCO-F746NG System";
#endif
static char *const msg_msg2   = "    "__DATE__" ";
static char *const msg_mode1  = "  BNC none-prescaler              ";
static char *const msg_mode2  = "  BNC recipro(BNC none-prescaler) ";
static char *const msg_mode3  = "  BNC recipro(dedicated BNC input)";
static char *const msg_mode4  = "  SMA prescaler 1/10              ";
static char *const msg_mode5  = "  SMA prescaler 1/20              ";

//  Function prototypes --------------------------------------------------------
void gps_data_rcv(void);

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
void freq_measurement(uint8_t mode)
{
    uint16_t    n = 0;
    char        buf[48];
    time_t      seconds;
    double      scale;

    if (mode == SMA_20){
        scale = 20.0f;
    } else if(mode == SMA_10){
        scale = 10.0f;
    } else {
        scale = 1.0f;
    }
    while(true){
        tmr.reset();
        tmr.start();
        if (fc.status_freq_update() != 0) {
            new_frequency = fc.read_freq_data() * scale;
            f_10sec   = fc.read_freq_w_gate_time(10) * scale;
            f_100sec  = fc.read_freq_w_gate_time(100) * scale;
            f_1000sec = fc.read_freq_w_gate_time(1000) * scale;
            PRINTF("%8d, Freq: %9.0f,", ++n, new_frequency);
            PRINTF(" F10s: %10.1f, F100s: %11.2f,", f_10sec, f_100sec);
            PRINTF(" F1000s: %12.3f,", f_1000sec);
        } else {
            PRINTF("%8d, No data,,,,", ++n);
        }
        if (mode == SMA_20){
            PRINTF(" Div: 1/20,");
        } else if(mode == SMA_10){
            PRINTF(" Div: 1/10,");
        } else {
            PRINTF(" Div: 1/1 ,");
        }             
        seconds = time(NULL) + 32400; // Adjust UTC to JST
        strftime(buf, 40, " %I:%M:%S %p JST (%m/%d)", localtime(&seconds));
        PRINTF("%s\r\n", buf);
        wait_ms(1000 - tmr.read_ms());      // 1sec interval
    }
}

void recipro()
{
    uint16_t    n = 0;
    char        buf[48];
    time_t      seconds;
    double      freq_recipro;
    uint32_t    interval_recipro;
    uint32_t    base_clk;
    int32_t     run2stop;

    while(true){
        fc.recipro_start_measure();
        PRINTF("Start measurement\r");
        while (fc.recipro_check_trigger() == 0){
            run2stop = tmr.read_ms();
            if (run2stop >= 100000){ // 100sec 0.001Hz
                break;
            }
        }
        if (run2stop >= 1000000){ // 100sec 0.001Hz
            freq_recipro = 0;
        } else {
            interval_recipro = fc.recipro_read_data();
            base_clk = fc.recipro_base_clk_data(1);
            if (interval_recipro >= 9000){// Measure less than 10KHz frequency
                freq_recipro = (double)base_clk / (double)interval_recipro;
                PRINTF("%8d, Freq: %11.5f [Hz] , ", n++, freq_recipro);
                PRINTF("Raw:  %11u [cnt] , ", interval_recipro);
                PRINTF("Base: %11u [Hz], ", base_clk);
                seconds = time(NULL) + 32400;   // Adjust UTC to JST
                strftime(buf, 40,
                            " %I:%M:%S %p JST (%m/%d)", localtime(&seconds));
                PRINTF("%s\r\n", buf);
                run2stop = tmr.read_ms();
                if (run2stop < 1000){ 
                    run2stop = 1000 - run2stop;
                    wait_ms(run2stop);          // 1sec interval
                }
            } else {
                freq_recipro = 0;
            }
        }
    }
}

int main()
{
    PRINTF("\r\n%s%s\r\n", msg_msg0, msg_msg2);
    PRINTF("%s\r\n", msg_msg1);
    PRINTF("Wait GPS 1PPS signal\r\n");
    gps_data_rcv();
    PRINTF("\r\nPlease select measurement mode.\r\n");
    PRINTF("%s-> 1\r\n", msg_mode1);
    PRINTF("%s-> 2\r\n", msg_mode2);
    PRINTF("%s-> 3\r\n", msg_mode3);
    PRINTF("%s-> 4\r\n", msg_mode4);
    PRINTF("%s-> 5\r\n", msg_mode5);
    PRINTF("Enter 1 to 5 (other input then 1)\r\n");
    // Select operation mode
    char c = GETC() - '0';
    if ((c > 5) || (c <= 0)){   c = 1;}
    input_mode = c;
    PRINTF("If you want to change the input signal,");
    PRINTF(" please restart the system (Enter Alt+B from your PC)\r\n");
    PRINTF("\r\nStart measuring\r\nMeasureing mode = ");
    switch(input_mode){
        case RECIPRO_AC:
            PRINTF("%s\r\n", msg_mode2);
            input_frq_select = 1;
            prescaler10or20.output();
            prescaler10or20 = 0;
            recipro_select = 0;
            recipro();
            break;
        case RECIPRO_DC:
            PRINTF("%s\r\n", msg_mode3);
            input_frq_select = 1;
            prescaler10or20.output();
            prescaler10or20 = 0;
            recipro_select = 1;
            recipro();
            break;
        case SMA_10:
            PRINTF("%s\r\n", msg_mode4);
            input_frq_select = 0;
            prescaler10or20.output();
            prescaler10or20 = 0;
            recipro_select = 0;
            freq_measurement(input_mode);
            break;
        case SMA_20:
            PRINTF("%s\r\n", msg_mode5);
            input_frq_select = 0;
            prescaler10or20.input();
            recipro_select = 0;
            freq_measurement(input_mode);
            break;
        case BNC_NORMAL:
        default:
            input_mode = BNC_NORMAL;
            PRINTF("%s\r\n", msg_mode1);
            input_frq_select = 1;
            prescaler10or20.output();
            prescaler10or20 = 0;
            recipro_select = 0;
            freq_measurement(input_mode);
            break;
    }
    while(true){;}  // Just in case
}