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

GPS_rcvr/GPSrcvr.cpp

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

File content as of revision 0:da29cdc50643:

/*
 * 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   14th, 2016
 */

//  Include --------------------------------------------------------------------
#include    <string.h>
#include    "mbed.h"
#include    "GPSrcvr.h"
#if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
#include    "iSerial.h"
#elif defined(TARGET_STM32F746NG)
#include    "RingBuffer.h"
#endif

//  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 ---------------------------------------------------------------------
#if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
DigitalIn   gps_rx(PC_7);       // for checking GPS RX line
iSerial     gps(NC, PC_7, 0, 1024); // GPS Data receive
#elif defined(TARGET_STM32F746NG)
RingBuffer  rxbuf(1024);        // can receive all information every one sec
DigitalIn   gps_rx(PF_6);       // for checking GPS RX line
Serial      gps(NC, PF_6);      // GPS Data receive
#else
#error "Target is only Nucleo-F411RE(F446RE) or DISCO-F746NG!!!"
#endif

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);
#if defined(TARGET_STM32F746NG)
void        iGPSrcv_initialize(void);
int         iGPS_readable(void);
int         iGPS_getc(void);
#endif

////////////////////////////////////////////////////////////////////////////////
// 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
////////////////////////////////////////////////////////////////////////////////
#if defined(TARGET_STM32F746NG)

// ------ Interrupt Function ------
void rx_handler(void)
{
    uint32_t reg = UART7->ISR;
    if (reg && USART_ISR_RXNE){ // data is ready to read
        UART7->ISR &= ~(USART_ISR_RXNE + USART_ISR_PE + USART_ISR_FE
                        + USART_ISR_NE + USART_ISR_ORE);
        rxbuf.save((unsigned char)UART7->RDR);   
    }
}

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

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

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

#endif

////////////////////////////////////////////////////////////////////////////////
//  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");
#if defined(TARGET_STM32F746NG)
    //  Clear GPS RX line errors(over run)
    UART7->ICR = 0;
    UART7->CR1 = 0;
    UART7->CR1 = 5;
    iGPSrcv_initialize();
#endif
    U_DEBUG("Start GPS!!");
    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;
            DBG('2');
            if (gps_ready == 3) {
                DBG('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);
                        DBG('4');
                        return;
                    }
                }
            }
        } 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();
            DBG('x');
        } 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();
            DBG('1');
        }
    }
}

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 defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
    while (gps.getc()  != '$'){;} 
#elif defined(TARGET_STM32F746NG)
    while (iGPS_getc() != '$'){;}
#endif
    *p++ = '$';
#if 0
    U_DEBUG("\r\n");
#else
    pc.printf("\r\n");
#endif
    for (char i= 0;i < 150;i++){
#if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)
        *p = gps.getc(); 
#elif defined(TARGET_STM32F746NG)
        *p = iGPS_getc();
#endif
#if 0
        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;
}