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/

Revision:
9:e98e94ba17f9
Parent:
8:7b033903c8fb
Child:
11:20e7a45f1448
--- a/main.cpp	Sat Nov 22 23:09:17 2014 +0000
+++ b/main.cpp	Thu Jan 01 05:08:31 2015 +0000
@@ -5,7 +5,7 @@
  *  http://www.page.sannet.ne.jp/kenjia/index.html
  *  http://mbed.org/users/kenjiArai/
  *      Created: October   18th, 2014
- *      Revised: Nobember  23rd, 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
@@ -15,10 +15,19 @@
  */
 
 #define USE_COM         // use Communication with PC(UART)
+#define SET_RTC
+//#define USE_DEBUG
 
 //  Include ---------------------------------------------------------------------------------------
 #include "mbed.h"
+#include "rtos.h"
+#include "TextLCD.h"
+#include "DRV8830.h"
+#include "ADT7410.h"
+#include "PID.h"
 #include "frq_cuntr_full.h"
+#include "CheckRTC.h"
+#include "gps.h"
 
 using namespace Frequency_counter;
 
@@ -37,48 +46,404 @@
 #define READABLE(x)     {;}
 #endif
 
+#ifdef USE_DEBUG
+#define DEBUGBAUD(x)    pc.baud(x)
+#define DEBUG(...)      pc.printf(__VA_ARGS__)
+#else
+#define DEBUGBAUD(x)    {;}
+#define DEBUG(...)      {;}
+#endif
+
+#define CLOCK_BASE      (24.999982f)
+
+#define GSP_BUF_B       (128 * 3)
+#define GPS_BUF_S       (128 * 2)
+
 //  Object ----------------------------------------------------------------------------------------
-//DigitalOut led_gate(LED1);
-DigitalIn   sw_01(PC_0);
-DigitalIn   sw_10(PC_1);
+DigitalOut  led_gate(LED1);
 Serial      pc(USBTX, USBRX);
+Serial      gps(NC, PA_10);             // GPS RX
 I2C         i2cBus(PB_9,PB_8);  // SDA, SCL
-// PC_6,PC_7 & PB6 use for Timer3 & 4
-// PA_0,PA_1 & PB_10 use for Timer2
-FRQ_CUNTR   fc(PC_6, 1.0);      // Input port & gate time[sec]
+DRV8830     heater(i2cBus, (uint8_t)DRV8830ADDR_00);
+ADT7410     t(i2cBus, ADT7410ADDR_NN);
+TextLCD     lcd(PB_0, PA_4, PC_0, PC_1, PC_2, PC_3, TextLCD::LCD20x4); // rs, e, d4-d7
+PID         pid(14.0f, 50.0f, 1.5f, 1.0f);
+// 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, CLOCK_BASE); // Input port, gate time[sec] and External clock freq.
 
 //  RAM -------------------------------------------------------------------------------------------
+// Freq.
+uint32_t    counter_1pps;
+double      new_frequency;
+double      base_clock_1pps;
+// Temp Control
+float       volt = 0.0;
+float       tmp = 0;
+float       pid_val = 0;
+uint32_t    n = 0;
+// GPS
+uint32_t    gps_status;
+uint8_t     gps_rmc_ready;
+char        GPS_Buffer[GSP_BUF_B];       //GPS data buffer
+char        MsgBuf_RMC[GPS_BUF_S];
+char        MsgBuf_GGA[GPS_BUF_S];
+// Time
+time_t      seconds;
+time_t      seconds_jst;
+struct tm   t_gps;
+// rtos
+Queue<uint32_t, 2> queue0;
 
 //  ROM / Constant data ---------------------------------------------------------------------------
+//                              12345678901234567890
+static char *const msg_clear = "                    ";
+static char *const msg_msg0  = "Frequency Counter   ";
+static char *const msg_msg1  = "  mbed Nucleo F411RE";
+static char *const msg_msg2  = "    by JH1PJL K.Arai";
+static char *const msg_msg3  = "    "__DATE__" ";
 
 //  Function prototypes ---------------------------------------------------------------------------
-
-//  Function prototypes ---------------------------------------------------------------------------
+void gps_rcv(void);
+uint32_t check_gps_ready(void);
+uint8_t check_gps_rmc_ready(void);
+void get_time_and_date(struct tm *pt);
+void getline_gps(void);
 
 //-------------------------------------------------------------------------------------------------
 //  Control Program
 //-------------------------------------------------------------------------------------------------
-int main()
+void measure_freq(void const *args)
+{
+    while(true) {
+        if (fc.status_freq_update() != 0) {
+            new_frequency = fc.read_freq_data();
+            queue0.put((uint32_t*)1);
+        }
+        if (fc.status_1pps() != 0) {
+            counter_1pps = fc.read_avarage_1pps();
+        }
+        Thread::wait(100);
+    }
+}
+
+void temp_control(void const *args)
+{
+    t.set_config(OPERATION_MODE_CONT + RESOLUTION_16BIT);
+    pid.setInputLimits(0.0, 4.5);
+    pid.setOutputLimits(0.0, 5.0);
+    pid.setSetPoint(2.5);
+    while(true) {
+        tmp = t.read_temp();
+        pid.setProcessValue(tmp / 10);
+        pid_val = pid.compute();
+        volt = pid_val - 2.5f;
+        if (volt < -0.8f) {
+            volt = -0.8f;
+        } else if (volt > 0.8f) {
+            volt = 0.8f;
+        }
+        heater.set_voltage(volt);
+        if (heater.status()) {
+            heater.reset();
+        }
+        /* Wait until it is time to check again. */
+        Thread::wait(1000);
+    }
+}
+
+// Get GAA data
+void gps_data_rcv(void const *args)
 {
-    uint32_t counter_1pps = 0;
-    uint32_t new_frequency = 0;
+    int8_t i;
+    time_t old_ave_sec[2];
+    uint32_t diff;
+
+    gps.baud(9600);
+    seconds = time(NULL);
+    DEBUG("\r\nCurrent Time: %s\r\n", ctime(&seconds));
+    old_ave_sec[0] = 0;
+    old_ave_sec[1] = 0;
+    while(true) {
+        getline_gps();          // Get GPS data from UART
+        if (strncmp(GPS_Buffer, "$GPRMC",6) == 0) {
+            for (i=0; GPS_Buffer[i] != 0; i++) {// Copy msg to RMC buffer
+                MsgBuf_RMC[i] = GPS_Buffer[i];
+            }
+            MsgBuf_RMC[i+1] = 0;
+            DEBUG("GET RMC\r\n");
+            if (gps_status > 3) {
+                get_time_and_date(&t_gps);
+                seconds = mktime(&t_gps);
+                if (old_ave_sec[0] == 0){
+                    old_ave_sec[0] = seconds;
+                } else if (old_ave_sec[1] == 0){
+                    old_ave_sec[1] = seconds;
+                } else {
+                    if (old_ave_sec[0] >= old_ave_sec[1]){
+                        diff = old_ave_sec[0] - old_ave_sec[1];
+                    } else {
+                        diff = old_ave_sec[1] - old_ave_sec[0];
+                    }
+                    if (diff > 100 ){
+                        old_ave_sec[0] = seconds;
+                        old_ave_sec[1] = 0;
+                    } else {
+                        if (old_ave_sec[0] > old_ave_sec[1]){
+                            diff = seconds - old_ave_sec[0];
+                            if (diff < 100){
+                                old_ave_sec[1] = seconds;
+                            }
+                        } else {
+                            diff = seconds - old_ave_sec[1];
+                            if (diff < 100){
+                                old_ave_sec[0] = seconds;
+                            }
+                        }
+                        set_time(seconds);
+                        DEBUG("SET RTC\r\n");
+                    }
+                }
+            }
+        } else if (strncmp(GPS_Buffer, "$GPGGA",6) == 0) {
+            for (i=0; GPS_Buffer[i] != 0; i++) {// Copy msg to GGA buffer
+                MsgBuf_GGA[i] = GPS_Buffer[i];
+            }
+            MsgBuf_GGA[i+1] = 0;
+            DEBUG("GET GGA\r\n");
+            gps_status = check_gps_ready();
+        }
+    }
+}
+
+void display_data(void const *args)
+{
+    char buf[40];
 
     BAUD(9600);
-    // PA8 & PC9 uses for MCO_1 & MCO_2 -> Clock output for checking
-    fc.port_mco1_mco2_set(2);      // Clk/2 ->1/1(100MHz) cannot measure!!
-    wait(1.0);
-    fc.read_frequency_TIM2(1.0);
-    fc.read_frequency_TIM3P4(1.0);
+    DEBUGBAUD(9600);
     PRINTF("\r\nFrequency Counter by JH1PJL created on "__DATE__"\r\n");
+    // Initial screen
+    lcd.locate(0, 0);
+    lcd.printf(msg_msg0);
+    lcd.printf(msg_msg1);
+    lcd.printf(msg_msg2);
+    lcd.printf(msg_msg3);
+    Thread::wait(3000);
+    lcd.locate(0, 0);
+    lcd.printf(msg_clear);
+    lcd.printf(msg_clear);
+    lcd.printf(msg_clear);
+    lcd.printf(msg_clear);
     while(true) {
-        while (fc.status_1pps() == 0) {
-            ;
+        osEvent evt = queue0.get();
+        PRINTF("FRQ= %11.1f Hz, ", new_frequency);
+        PRINTF("1PPS= %9d , %9d (new), ",counter_1pps, fc.read_newest_1pps());
+        PRINTF("%+6.3f dC, ", tmp);
+        PRINTF("PID= %+6.3f , ", volt);
+//        PRINTF("t= %5d S, ", n++);
+        seconds = time(NULL);
+        seconds_jst = seconds + 32400;   // +9 hours ->JST
+        //                 December 31,'14, 13:12:11
+//        strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
+        //                 31 Dec 2014 13:12:11
+//        strftime(buf,40, "%x %X ", localtime(&seconds));
+        //                 1:12:11 PM (2014/12/31)
+        strftime(buf,40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds_jst));
+        PRINTF("%s, ", buf);
+        if (fc.status_gps()) {
+            PRINTF("RDY");
+        } else {
+            PRINTF("NO ");
+        }
+        PRINTF("\r\n");
+        lcd.locate(0, 0);
+        lcd.printf("Freq= %11.2f Hz", new_frequency);
+        lcd.locate(0, 1);
+        lcd.printf("1PPS=%9d Hz", counter_1pps);
+        lcd.locate(0, 2);
+        strftime(buf,40, " %I:%M:%S %p (%m/%d)", localtime(&seconds_jst));
+        lcd.printf("%s, ", buf);
+        lcd.locate(0, 3);
+        lcd.printf("t= %+4.1f%cC", tmp, 0xdf);
+        if (fc.status_gps()) {
+            lcd.printf("   GPS RDY");
+        } else {
+            lcd.printf("   NO GPS ");
         }
-        counter_1pps = fc.read_avarage_1pps();
-        while (fc.status_freq_update() == 0) {
-            ;
+        base_clock_1pps = (double)counter_1pps / 1000000;
+        double diff = base_clock_1pps - CLOCK_BASE;
+        if (diff < 0) {
+            diff *= -1;
+        }
+        if (diff < 0.00001) {   // less than 10Hz
+            fc.set_external_clock(base_clock_1pps);
         }
-        new_frequency = fc.read_freq_data();
-        PRINTF("1PPS/ave = %9d , FREQUENCY = %9d\r\n", counter_1pps, new_frequency);
+        /* Wait until it is time to check again. */
+        Thread::wait(100);
+    }
+}
+
+// Thread definition
+osThreadDef(measure_freq, osPriorityNormal,1024);
+osThreadDef(temp_control, osPriorityNormal,1024);
+osThreadDef(display_data, osPriorityNormal,3072);
+osThreadDef(gps_data_rcv, osPriorityNormal,3072);
+
+int main()
+{
+//    PA8 & PC9 uses for MCO_1 & MCO_2 -> Clock output for checking
+    fc.port_mco1_mco2_set(4);      // Clk/4 ->1/1(100MHz) cannot measure!!
+    osThreadCreate(osThread(measure_freq), NULL);
+    Thread::wait(5);   //wait
+    osThreadCreate(osThread(temp_control), NULL);
+    Thread::wait(8);   //wait
+    osThreadCreate(osThread(display_data), NULL);
+    Thread::wait(10);   //wait
+    if (CheckRTC() == OK) { // If RTC is NG, no need to start GPS RX function
+        DEBUG("\r\nGPS task starts\r\n");
+        osThreadCreate(osThread(gps_data_rcv), NULL);
+    }
+    while(true) {
+        /* Wait until it is time to check again. */
+        Thread::wait(5000);
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////
+// GPS data Analysis
+//
+//  PA6C GPS Module
+//      http://www.gtop-tech.com/en/product/MT3339_GPS_Module_03.html
+//      Update time: 1 second (1PPS: ±10ns RMS)
+//      MediaTek MT3339 Chipset, L1 Frequency, C/A code, 66 Channels
+//      NMEA 0183
+//
+//      current setting: GGA, VTG, GGA, RMC
+//
+///////////////////////////////////////////////////////////////////////////////
+// Get line of data from GPS
+void getline_gps(void)
+{
+    while (gps.getc() != '$') {
+        //DEBUG("GETC but not $\r\n");
+        Thread::yield();
+    }
+    GPS_Buffer[0] = '$';
+    for (int8_t i = 1; i < GSP_BUF_B; i++) {
+        GPS_Buffer[i] = gps.getc();
+        if (GPS_Buffer[i] == '\r' || GPS_Buffer[i] == '\n') {
+            GPS_Buffer[i] = '\r';
+            GPS_Buffer[i+1] = '\n';
+            GPS_Buffer[i+2] = 0;
+            GPS_Buffer[i+3] = 0;
+            //DEBUG("Get one GPS data\r\n");
+            return;
+        }
+    }
+}
+
+// ASCII to hex
+uint8_t hex(char c)
+{
+    if(c<= '/') return( ERR );
+    if(((c -= '0')<= 9 || 10 <= ( c -= 'A' - '0' - 10)) && c <= 15) {
+        return((uint8_t)c);
+    }
+    return(ERR);
+}
+
+// Search next ',' (comma)
+char *next_comma( char *p )
+{
+    while (1) {
+        if ( *p== ',' ) {
+            return ++p;
+        } else if ( *p == 0 ) {
+            return (char*)-1;
+        } else {
+            p++;
+        }
+    }
+}
+
+// 2 digits ASCII char to one byte hex
+unsigned char   change_acii_hex( char*p )
+{
+    unsigned char c;
+
+    c = hex(*p++);              /* No concern ERR condition! */
+    c = (c * 10) + hex(*p++);
+    return c;
+}
+
+// Skip number of comma
+char *num_of_comma( char *p, int8_t n )
+{
+    for (; n> 0; n--) {
+        if ( (p = next_comma(p)) == (char*) -1 ) {
+            return (char*)-1;
+        }
+    }
+    return p;
+}
+
+// Get GPS status and number of satelites
+uint32_t check_gps_ready(void)
+{
+    char *p;
+    uint32_t x;
+    uint8_t d;
+
+    // pick-up time
+    p = MsgBuf_GGA;
+    p = num_of_comma(p,6);  // skip ','
+    // reach to "Position Fix Indicator"
+    if (*p == '0') {
+        x = 0;
+    } else if (*p == '1') {
+        x = 0x10;
+    } else if (*p == '2') {
+        x = 0x20;
+    } else {
+        x= 0;
+    }
+    ++p;
+    if (*p == ',') {
+        ++p;
+        d = hex(*p++);
+        if (d != ERR) {
+            x += (uint32_t)d;
+            if (*p != ',') {
+                x = 0;
+            }
+        } else {
+            x = 0;
+        }
+    } else {
+        x = 0;
+    }
+    return x;
+}
+
+//  Get time(UTC) from GPS data
+void get_time_and_date(struct tm *pt)
+{
+    char *p;
+
+    p = MsgBuf_RMC;
+    p = num_of_comma(p,1);  /* skip one ',' */
+    pt->tm_hour   = change_acii_hex(p);
+    p += 2;
+    pt->tm_min = change_acii_hex(p);
+    p += 2;
+    pt->tm_sec = change_acii_hex(p);
+    p = MsgBuf_RMC;
+    p = num_of_comma(p,9);  /* skip one ',' */
+    pt->tm_mday  = change_acii_hex(p);
+    p += 2;
+    pt->tm_mon = change_acii_hex(p) - 1;
+    p += 2;
+    pt->tm_year  = change_acii_hex(p) + 100;
+}