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/

GPS_rcvr/GPSrcvr.cpp

Committer:
kenjiArai
Date:
2016-11-23
Revision:
13:1041596c416c
Child:
15:ae0413277bc6

File content as of revision 13:1041596c416c:

/*
 * mbed Application program / GPS receiver control and 1PPS output
 *
 * Copyright (c) 2004,'09,'10,'16 Kenji Arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  http://mbed.org/users/kenjiArai/
 *      Created: March     28th, 2004   Kenji Arai
 *      updated: July      25th, 2009   for PIC24USB
 *      updated: January   16th, 2010   change to GPS-GM318
 *      updated: April     24th, 2010   for mbed / NXP LPC1768
 *      Revised: Nomeber   20th, 2016
 */

//  Include --------------------------------------------------------------------
#include    <string.h>
#include    "mbed.h"
#include    "RingBuffer.h"
#include    "GPSrcvr.h"

//  Definition -----------------------------------------------------------------
//#define     USE_DEBUG

#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     GSP_BUF_B       (128 * 3)
#define     GPS_BUF_S       (128 * 2)

//  Object ---------------------------------------------------------------------
DigitalIn   gps_rx(PD_2);       // for checking GPS RX line
Serial      gps(NC, PD_2);      // GPS Data receive
RingBuffer  rxbuf(1024);        // can receive all information every one sec

extern Serial pc;

//  RAM ------------------------------------------------------------------------
bool        gps_is_okay_flag;
uint8_t     gps_ready;
uint8_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_GSA[GPS_BUF_S];
char        MsgBuf_GGA[GPS_BUF_S];

//  Function prototypes --------------------------------------------------------
uint8_t     check_gps_3d(void);
uint8_t     check_gps_ready(void);
void        get_time_and_date(struct tm *pt);
void        getline_gps(void);
void        gps_data_rcv(void);
void        iGPSrcv_initialize(void);
int         iGPS_readable(void);
int         iGPS_getc(void);

////////////////////////////////////////////////////////////////////////////////
// Receive GPS data using Interrupt handler
//
// !!! Takes urgent and dirty solution by due to IRQ restriction
//      on mbed library (reason is unknown as of today)
// reference source file:stm32f746xx.h
//     under /mbed-dev/targets/cmsis/TARGET_STM/TARGET_NUCLEO_F746ZG
////////////////////////////////////////////////////////////////////////////////
// ------ Interrupt Function ------
void rx_handler(void)
{
    uint32_t reg = UART5->ISR;
    if (reg && USART_ISR_RXNE){ // data is ready to read
        UART5->ISR &= ~(USART_ISR_RXNE + USART_ISR_PE + USART_ISR_FE
                        + USART_ISR_NE + USART_ISR_ORE);
        rxbuf.save((unsigned char)UART5->RDR);   
    }
}

void iGPSrcv_initialize(void)
{
    __disable_irq();
    UART5->CR1 &= ~(USART_CR1_TE + USART_CR1_TCIE + USART_CR1_TXEIE
                     + USART_CR1_PEIE + USART_CR1_IDLEIE);
    UART5->CR1 |= (USART_CR1_RXNEIE + USART_CR1_RE + USART_CR1_UE);    
    NVIC_SetVector(UART5_IRQn, (uint32_t)rx_handler);
    NVIC_ClearPendingIRQ(UART5_IRQn);
    NVIC_EnableIRQ(UART5_IRQn);
    __enable_irq();
#if 0
    printf("UART5->CR1  0x%08x:0x%08x\r\n", &UART5->CR1, UART5->CR1);
    printf("UART5->CR2  0x%08x:0x%08x\r\n", &UART5->CR2, UART5->CR2);
    printf("UART5->CR3  0x%08x:0x%08x\r\n", &UART5->CR3, UART5->CR3);
    printf("UART5->BRR  0x%08x:0x%08x\r\n", &UART5->BRR, UART5->BRR);
    printf("UART5->GTPR 0x%08x:0x%08x\r\n", &UART5->GTPR, UART5->GTPR);
    printf("UART5->RTOR 0x%08x:0x%08x\r\n", &UART5->RTOR, UART5->RTOR);
    printf("UART5->RQR  0x%08x:0x%08x\r\n", &UART5->RQR, UART5->RQR);
    printf("UART5->ISR  0x%08x:0x%08x\r\n", &UART5->ISR, UART5->ISR);
    printf("UART5->ICR  0x%08x:0x%08x\r\n", &UART5->ICR, UART5->ICR);
#endif
}

int iGPS_readable(void)
{
    return rxbuf.check();
}

int iGPS_getc(void)
{
    while(!rxbuf.check()){;}    // wait receiving a character
    return rxbuf.read();
}

////////////////////////////////////////////////////////////////////////////////
//  Parse GPS data
//      Module Type: u-blux7 NEO-7M
////////////////////////////////////////////////////////////////////////////////
// Get RMC & GAA data
void gps_data_rcv(void)
{
    int8_t i;
    time_t old_ave_sec[2];
    uint32_t diff = 0;
    time_t seconds;
    struct tm   t_gps;

    seconds = time(NULL);
    U_DEBUG("\r\nCurrent Time: %s\r\n", ctime(&seconds));
    old_ave_sec[0] = 0;
    old_ave_sec[1] = 0;
    // Wait long interval (every 1sec)
    for (uint32_t i = 0; i < 100000; i++){
        if (gps_rx == 0){
            i = 0;
        }
    }
    U_DEBUG("GPS line is Hi\r\n");
    //  Clear GPS RX line errors(over run)
    UART5->ICR = 0;
    UART5->CR1 = 0;
    UART5->CR1 = 5;
    iGPSrcv_initialize();
    U_DEBUG("Start GPS!!");
    gps_is_okay_flag = false;
    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;
#if 0
            U_DEBUG("Get GPRMC\r\n");
#else
            if (gps_is_okay_flag == false){
                pc.printf("GPRMC,");
            }
#endif
            if (gps_ready == 3) {
                U_DEBUG("3D condition\r\n");
                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);
                        U_DEBUG("Set time and GPS is okay!\r\n");
                        gps_is_okay_flag = true;
                    }
                }
            }
        } else if (strncmp(GPS_Buffer, "$GPGSA",6) == 0) {
            for (i=0; GPS_Buffer[i] != 0; i++) {// Copy msg to GSA buffer
                MsgBuf_GSA[i] = GPS_Buffer[i];
            }
            MsgBuf_GSA[i+1] = 0;
            gps_ready = check_gps_3d();
#if 0
            U_DEBUG("Get GPGSA\r\n");
#else
            if (gps_is_okay_flag == false){
                pc.printf("GPGSA,");
            }
#endif
        } 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;
            gps_status = check_gps_ready();
#if 0
            U_DEBUG("Get GPGGA\r\n");
#else
            if (gps_is_okay_flag == false){
                pc.printf("GPGGA,");
            }
#endif
        }
    }
}

bool check_gps_is_okay()
{
    return gps_is_okay_flag;
}

// Get line of data from GPS
void getline_gps(void)
{
    char *p = GPS_Buffer;

#if 1
    while (iGPS_getc() != '$'){;}
#else
    while (iGPS_getc() != '$') {
        Thread::yield();
    }
#endif
    *p++ = '$';
#if 1
    U_DEBUG("\r\n");
#else
    pc.printf("\r\n");
#endif
    for (char i= 0;i < 150;i++){
        *p = iGPS_getc();
#if 1
        DBG(*p);
#else
        pc.putc(*p);
#endif
        if (*p == '\r'){
            *++p = '\n';
            *++p = 0;
            *++p = 0;
            U_DEBUG("Get one GPS data\r\n");
            return;
        } else {
            p++;
        }
    }
    *++p = 0;
    *++p = 0;
}

// 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 (1=Not fix, 2=2D, 3=3D)
uint8_t check_gps_3d(void){
    char *p;
    uint8_t x;
    uint8_t d;

    // pick-up time
    p = MsgBuf_GSA;
    p = num_of_comma(p,1);  // skip ','
    // reach to "Position Fix Indicator"
    if (*p == 'A') {
        ++p; //','
        ++p; // 1 or 2 or 3
        d = hex(*p++);
        if (d != ERR) {
            x = d;
        } else {
            x = 1;
        }
    } else {
        x = 1;
    }
    return x;
}

// Get GPS status and number of satelites
uint8_t check_gps_ready(void){
    char *p;
    uint8_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 == '1' || *p == '2') {
        ++p; //','
        ++p; // Number
        d = hex(*p++);
        if (d != ERR) {
            x = d * 10;
            x += (uint32_t)hex(*p++);
            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;
}