Frequency counter using GPS 1PPS signal and temperature controlled 50MHz Base clock. Ported from F411 Frequency Counter.

Dependencies:   QEI DRV8830 PID ADT7410 TextLCD Frq_cuntr_Nucleo-F746ZG RingBuffer

Fork of Frequency_Counter_w_GPS_1PPS by Kenji Arai

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

main.cpp

Committer:
kenjiArai
Date:
2019-12-22
Revision:
15:ae0413277bc6
Parent:
14:ba6ea409ab05

File content as of revision 15:ae0413277bc6:

/*
 * mbed Application program / Frequency Counter with GPS 1PPS Compensation
 *      Only for ST Nucleo-F746ZG on mbed-OS5
 *
 * Copyright (c) 2014,'15,'16,'19 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
 *      Revised:    December  22nd, 2019
 *
 * Base program: Frequency_counter_w_GPS_1PPS (only for Nucleo-F411RE board)
 * https://developer.mbed.org/users/kenjiArai/code/Frequency_Counter_w_GPS_1PPS/
 */

/*
--------------------------------------------------------------------------------
  Frequency Counter Functions
    Mesurement frequency range:
         10Hz to 100MHz (BNC Connector)
    Extended range:
         Up to 1GHz (1/10 prescaler) or more over (1/20) (SMA)
    Gate time:
         1 sec to 4095sec (extend to more if RAM is avairable)
    Reciprocal measurement:
         0.01Hz to 5KHz (extend more lower frequency change input I/F)
    Base Internal Clock:
         50MHz VCTCXO (Connor-Winfield TB514-050.0M)
    1 PPS:
         GPS receiver(u-blux7/NEO-7) with an external antenna (SMA)
    Temperature controlled Oven:
         32 degree Celsius +/-0.2 for 50MHz VCTCXO & 3.3V regulater
  Hardware Configration
    frequency input:                PC_6 & PA_3
    50MHz base clock input:         PA_5
    GPS 1PPS input:                 PA_1
    Connect (for 1sec gate):        PA_7, PB_10 and PC_7 connected together
  IMPORTANT!!!!
    SB13 & SB181 must REMOVE from Nucleo-F746ZG board
--------------------------------------------------------------------------------
*/

#define     USE_COM         // use Communication with PC(UART)
#define     USE_DEBUG
//#define     HW_TEST_GO    // activate Hardware test mode

//  Include --------------------------------------------------------------------
#include    "mbed.h"
#include    "GPSrcvr.h"
#include    "DRV8830.h"
#include    "ADT7410.h"
#include    "PID.h"
#include    "frq_cuntr_f746.h"
#include    "TextLCD.h"
#include    "QEI.h"
#include    "uif.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

#define CLEAR_PD_2_RX_LINE() {UART5->ICR = 0; UART5->CR1 = 0; UART5->CR1 = 5;}

#define CLOCK_BASE      (50.000000f)    // MHz
#define TRGT_TEMP       (32.0f)         // degC

#define RECIPRO_OVRFLW  10000           // = 5KHz
#define RECIPRO_TIMEOUT 1000000         // = 0.001Hz

#define GSP_BUF_B       (128 * 3)
#define GPS_BUF_S       (128 * 2)

using namespace Frequency_counter;

//  Object ---------------------------------------------------------------------
//DigitalOut      led_gate(LED1);
DigitalIn       pa1(PA_1);      // GPS 1PPS input
//**** UART
Serial          pc(USBTX, USBRX);
//**** Req. Counter
FRQ_CUNTR       fc(CLOCK_BASE); // External clock freq.

//  RAM ------------------------------------------------------------------------
// all display data
dispDef     disp_data;
// Freq.
double      new_frequency;
double      freq_recipro;
uint32_t    interval_recipro;
uint8_t     recipro_new_data_ready;
uint8_t     recipro_overflow;

//  ROM / Constant data --------------------------------------------------------


//  Function prototypes --------------------------------------------------------
extern void dispay_LCD_and_UART(dispDef *dt);
extern void select_input_div_1or10or20(uint8_t mode);

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
// Frequency measurement
void measure_freq(void const *args)
{
    while(true) {
        if (fc.status_freq_update() != 0) {
            new_frequency = fc.read_freq_data();
            disp_data.m_frq      = new_frequency;
            disp_data.m_frq_comp = fc.read_compensated_freq_data_w_gt(1);
            disp_data.m_frq_10   = fc.read_compensated_freq_data_w_gt(10);
            disp_data.m_frq_100  = fc.read_compensated_freq_data_w_gt(100);
            disp_data.m_frq_1000 = fc.read_compensated_freq_data_w_gt(1000);
        }
        if (fc.status_1pps() != 0) {
            disp_data.b_1pps_new = fc.read_newest_1pps();
            disp_data.b_1pps_lng = fc.read_avarage_1pps();
        }
        ThisThread::sleep_for(100);  // 0.1sec
    }
}

// Frequency measurement / Reciprocal measurement
void measure_freq_recipro(void const *args)
{
    int32_t  run2stop;
    Timer    tmr0;

    while(true) {
        tmr0.reset();
        tmr0.start();
        fc.recipro_start_measure();
        while (fc.recipro_check_trigger() == 0){
            ThisThread::sleep_for(1);  // 1mS
            run2stop = tmr0.read_ms();
            if (run2stop >= RECIPRO_TIMEOUT){
                break;
            }
        }
        if (run2stop >= RECIPRO_TIMEOUT){
            freq_recipro = 0;
        } else {
            interval_recipro = fc.recipro_read_data();
            if (interval_recipro >= RECIPRO_OVRFLW){
                // Measure less than 5KHz frequency
                freq_recipro = CLOCK_BASE/(double)interval_recipro * 1000000;
                recipro_overflow = 0;
            } else {
                freq_recipro = 0;
                recipro_overflow = 1;
            }
        }
        recipro_new_data_ready = 1;
        disp_data.m_frq_recipro = freq_recipro; 
        disp_data.recipro_of = recipro_overflow;
        run2stop = tmr0.read_ms();
        if (run2stop > 1000){
            ThisThread::sleep_for(run2stop % 1000);  // next interval          
        } else {
            run2stop = 1000 - run2stop;
            /* Wait until it is time to check again. */
            ThisThread::sleep_for(run2stop);         // 1sec interval
        }
    }
}

// Constant temperature oven control
void temp_control(void const *args)
{
    static double   volt = 0.0;
    static double   tmp = 0;
    static double   pid_val = 0;
    static uint32_t error_count = 3600;
    static int32_t  keep_1sec;

    //**** Peltier temperature control 
    I2C      i2cBus(PB_9,PB_8);  // SDA, SCL
    DRV8830  heater(i2cBus, (uint8_t)DRV8830ADDR_00); // H brige
    PID      pid(8.0f, 85.0f, 4.0f, 0.7f);            // PID for oven
    ADT7410  t(i2cBus, ADT7410ADDR_NN);               // inside oven temp.
    Timer    tmr2;

    t.set_config(OPERATION_MODE_CONT + RESOLUTION_16BIT);
    pid.setInputLimits(0.0f, 5.0f);
    pid.setOutputLimits(0.0f, 5.0f);
    pid.setSetPoint(TRGT_TEMP/10.0f);
    while(true) {
        tmr2.reset();
        tmr2.start();
        tmp = t.read_temp();
        disp_data.box_tmp = tmp;
        //PRINTF("Temp=%f degC\r\n", tmp);
        pid.setProcessValue(tmp / 10.0f);
        pid_val = pid.compute();
        volt = pid_val - (TRGT_TEMP/10.0f);
        if (volt < -5.0f) {
            volt = -5.0f;
        } else if (volt > 5.0f) {
            volt = 5.0f;
        }
        if ((volt == -5.0f) || (volt == 5.0f)){
            if (--error_count == 0){
                pid.reset();
                error_count = 3600;
                pid.setInputLimits(0.0f, 5.0f);
                pid.setOutputLimits(0.0f, 5.0f);
                pid.setSetPoint(TRGT_TEMP/10.0f);
            }
        } else {
            error_count = 3600;
        }
        heater.set_voltage(-volt);
        //PRINTF("Volt=%f V\r\n", volt);
        if (heater.status()) {
            heater.reset();
        }
        if ((tmp > (TRGT_TEMP + 0.2f)) || (tmp < (TRGT_TEMP - 0.4f))){
            disp_data.temp_is_okay = 0;
        } else {
            disp_data.temp_is_okay = 1;
        }
#if defined(HW_TEST_GO)
        pc.printf("Volt=%+4.3f [V] , Oven Temp. %+6.3f [degC]", volt, tmp);
        pc.printf(", Diff=%3.1f-x= %+6.3f \r\n", TRGT_TEMP, TRGT_TEMP - tmp);
#endif
        keep_1sec = 1000 - keep_1sec;
        ThisThread::sleep_for(keep_1sec);         // 1sec interval
    }
}

void display_data(void const *args)
{
    int32_t tim_remain;
    Timer   tmr1;

    while(true){
        tmr1.reset();
        tmr1.start();
        disp_data.gps_1pps_ave = fc.read_num_in_buffer();
        disp_data.ready_1pps = check_gps_3d();
        // User_IF    
        dispay_LCD_and_UART(&disp_data); // separate files uif.cpp & uif.h
        /* Wait */
        tim_remain = 1000 - tmr1.read_ms();
        ThisThread::sleep_for(tim_remain);
    }
}

void receive_gps(void const *args)
{
    gps_data_rcv(); // infinit loop -> never return
    // separate files GPSrcvr.cpp & GPSrcvr.h
}

#if !defined(HW_TEST_GO)    // Normal control mode

// Thread definition
osThreadDef(measure_freq, osPriorityNormal,1024);
osThreadDef(measure_freq_recipro, osPriorityNormal,1024);
osThreadDef(temp_control, osPriorityNormal,2048);
osThreadDef(receive_gps, osPriorityNormal,1024);
osThreadDef(display_data, osPriorityNormal,2048);

int main(){
    disp_first_msg();
    ThisThread::sleep_for(1000); // 1sec
    disp_wait_gps();
    osThreadCreate(osThread(receive_gps), NULL);
    PRINTF("\r\nStart GPS receiving!\r\n");
    while (check_gps_is_okay() == false){;}  // wait till "true"
    PRINTF("GPS data is valid!\r\n");
    fc.debug_printf_internal_data();
    osThreadCreate(osThread(measure_freq), NULL);
    ThisThread::sleep_for(5);    //wait
    osThreadCreate(osThread(temp_control), NULL);
    ThisThread::sleep_for(8);    //wait
    osThreadCreate(osThread(measure_freq_recipro), NULL);
    ThisThread::sleep_for(3);    //wait
    osThreadCreate(osThread(display_data), NULL);
    ThisThread::sleep_for(10);   //wait
    select_input_div_1or10or20(0);  // BNC (none presclaer)
    while(true) {
        /* Wait until it is time to check again. */
        ThisThread::sleep_for(60000);        // 1min.
    }
}

#else               // Hardware Test mode

#include "hw_tst.h"
extern void hardware_test(void);

int main(){
    hardware_test();
}

double read_temperature(uint8_t n)
{
    if (n == 0){
        t.set_config(OPERATION_MODE_CONT + RESOLUTION_16BIT);
        return 0;
    } else if (n == 1){
        return t.read_temp();
    }
    return 0;
}

#endif // !defined(HW_TEST_GO)