From 9b9c5214598eb30af600926a63b95bb105531960 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Thu, 4 Feb 2021 09:57:43 +0100 Subject: [PATCH] GPS driver for MD-3x0 targets --- meson.build | 2 + platform/drivers/GPS/GPS.h | 69 ++++++++++ platform/drivers/GPS/GPS_MDx.c | 173 +++++++++++++++++++++++++ platform/targets/MD-3x0/hwconfig.h | 4 + tests/platform/gps_test_MDx.c | 200 ++++++++++++++--------------- 5 files changed, 341 insertions(+), 107 deletions(-) create mode 100644 platform/drivers/GPS/GPS.h create mode 100644 platform/drivers/GPS/GPS_MDx.c diff --git a/meson.build b/meson.build index 34c518c5..c2a74837 100644 --- a/meson.build +++ b/meson.build @@ -35,6 +35,7 @@ openrtx_inc = ['openrtx/include', 'openrtx/include/calibration', 'platform/drivers/ADC', 'platform/drivers/NVM', + 'platform/drivers/GPS', 'platform/drivers/tones', 'openrtx/include/fonts/adafruit', 'platform/drivers/tones', @@ -199,6 +200,7 @@ md3x0_src = src + stm32f405_src + ['platform/drivers/display/HX8353_MDx.c', 'platform/drivers/baseband/SKY72310.c', 'platform/drivers/baseband/radio_MD3x0.c', 'platform/drivers/baseband/HR_C5000.c', + 'platform/drivers/GPS/GPS_MDx.c', 'platform/targets/MD-3x0/platform.c'] md3x0_inc = inc + stm32f405_inc + ['platform/targets/MD-3x0'] diff --git a/platform/drivers/GPS/GPS.h b/platform/drivers/GPS/GPS.h new file mode 100644 index 00000000..3b7eba98 --- /dev/null +++ b/platform/drivers/GPS/GPS.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef GPS_H +#define GPS_H + +#include +#include + +/** + * Low-level driver for interfacing with radio's on-board GPS module. + */ + +/** + * Initialise the GPS driver. + * This function does not turn on the GPS module. + * @param baud: baud rate of GPS serial interface. + */ +void gps_init(const uint16_t baud); + +/** + * Shut down the GPS module and terminate the GPS driver. + */ +void gps_terminate(); + +/** + * Turn on the GPS module. + */ +void gps_enable(); + +/** + * Turn off GPS module. + */ +void gps_disable(); + +/** + * Detect if a GPS module is present in the system, it can be called also + * when driver is not initialised. + * @param timeout: timeout for GPS detection, in milliseconds. + * @return true if a GPS module is present, false otherwise. + */ +bool gps_detect(uint16_t timeout); + +/** + * Read a NMEA sentence from the GPS module, blocking function. + * @param buf: buffer to which the NMEA sentence is written. + * @param maxLength: maximum writable length inside the buffer. + * @return number of characters written in the buffer or -1 on error. + */ +int gps_getNmeaSentence(char *buf, const size_t maxLength); + +#endif /* GPS_H */ diff --git a/platform/drivers/GPS/GPS_MDx.c b/platform/drivers/GPS/GPS_MDx.c new file mode 100644 index 00000000..31d4d461 --- /dev/null +++ b/platform/drivers/GPS/GPS_MDx.c @@ -0,0 +1,173 @@ +/*************************************************************************** + * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN * + * Frederik Saraci IU2NRO * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include "GPS.h" + +static int8_t detectStatus = -1; +size_t bufPos = 0; +size_t maxPos = 0; +char *dataBuf; +bool receiving = false; + +OS_FLAG_GRP sentenceReady; +OS_ERR err; + +void __attribute__((used)) USART3_IRQHandler() +{ + if(USART3->SR & USART_SR_RXNE) + { + char value = USART3->DR; + + if((receiving == false) && (value == '$') && (bufPos == 0)) + { + receiving = true; + } + + if(receiving) + { + if(bufPos == maxPos) + { + receiving = false; + } + + char prevChar = dataBuf[bufPos - 1]; + dataBuf[bufPos] = value; + bufPos += 1; + + if((prevChar == '\r') && (value == '\n')) + { + receiving = false; + bufPos -= 1; + } + } + + if((receiving == false) && (bufPos != 0)) + { + uint8_t flag = (bufPos < maxPos) ? 0x01 : 0x02; + OSFlagPost(&sentenceReady, flag, OS_OPT_POST_FLAG_SET, &err); + } + } + + USART3->SR = 0; +} + + +void gps_init(const uint16_t baud) +{ + gpio_setMode(GPS_EN, OUTPUT); + gpio_setMode(GPS_DATA, ALTERNATE); + gpio_setAlternateFunction(GPS_DATA, 7); + + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; + __DSB(); + + const unsigned int quot = 2*42000000/baud; + USART3->BRR = quot/2 + (quot & 1); + USART3->CR3 |= USART_CR3_ONEBIT; + USART3->CR1 = USART_CR1_RE + | USART_CR1_RXNEIE; + + NVIC_ClearPendingIRQ(USART3_IRQn); + NVIC_SetPriority(USART3_IRQn, 14); + + OSFlagCreate(&sentenceReady, "", 0, &err); +} + +void gps_terminate() +{ + OSFlagDel(&sentenceReady, OS_OPT_DEL_NO_PEND, &err); + gps_disable(); + RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN; +} + +void gps_enable() +{ + gpio_setPin(GPS_EN); + USART3->CR1 |= USART_CR1_UE; +} + +void gps_disable() +{ + gpio_clearPin(GPS_EN); + USART3->CR1 &= ~USART_CR1_UE; + NVIC_DisableIRQ(USART3_IRQn); +} + +bool gps_detect(uint16_t timeout) +{ + if(detectStatus == -1) + { + gpio_setMode(GPS_DATA, INPUT_PULL_DOWN); + gpio_setMode(GPS_EN, OUTPUT); + gpio_setPin(GPS_EN); + + while((gpio_readPin(GPS_DATA) == 0) && (timeout > 0)) + { + delayMs(1); + timeout--; + } + + gpio_clearPin(GPS_EN); + gpio_setMode(GPS_EN, INPUT); + + if(timeout > 0) + { + detectStatus = 1; + } + else + { + detectStatus = 0; + } + } + + return (detectStatus == 1) ? true : false; +} + +int gps_getNmeaSentence(char *buf, const size_t maxLength) +{ + if(detectStatus != 1) return -1; + + memset(buf, 0x00, maxLength); + bufPos = 0; + maxPos = 0; + dataBuf = buf; + + NVIC_EnableIRQ(USART3_IRQn); + + OS_FLAGS status = OSFlagPend(&sentenceReady, 0x03, 0, + OS_OPT_PEND_FLAG_SET_ANY | + OS_OPT_PEND_FLAG_CONSUME | + OS_OPT_PEND_BLOCKING, NULL, &err); + + NVIC_DisableIRQ(USART3_IRQn); + + if(status & 0x01) + { + return bufPos; + } + + return -1; +} + diff --git a/platform/targets/MD-3x0/hwconfig.h b/platform/targets/MD-3x0/hwconfig.h index 0068f1d3..9ed6e234 100644 --- a/platform/targets/MD-3x0/hwconfig.h +++ b/platform/targets/MD-3x0/hwconfig.h @@ -138,4 +138,8 @@ #define FM_MUTE GPIOE,13 #define MIC_PWR GPIOA,14 +/* GPS, for the devices who have it */ +#define GPS_EN GPIOD,8 +#define GPS_DATA GPIOD,9 + #endif diff --git a/tests/platform/gps_test_MDx.c b/tests/platform/gps_test_MDx.c index bd7edef6..991583d1 100644 --- a/tests/platform/gps_test_MDx.c +++ b/tests/platform/gps_test_MDx.c @@ -25,9 +25,7 @@ #include #include #include - -#define GPS_EN GPIOD,8 -#define GPS_DATA GPIOD,9 +#include char line[MINMEA_MAX_LENGTH*10]; @@ -35,116 +33,104 @@ int main() { platform_init(); - gpio_setMode(GPS_EN, OUTPUT); - gpio_setMode(GPS_DATA, INPUT_PULL_DOWN); + printf("Checking for GPS... "); + bool hasGps = gps_detect(5000); + printf(" %s.\r\n", hasGps ? "OK" : "TIMEOUT"); - gpio_setPin(GPS_EN); + gps_init(9600); + gps_enable(); - uint8_t elapsedTime = 0; - - printf("Waiting for GPS_DATA to rise"); - while((gpio_readPin(GPS_DATA) == 0) && (elapsedTime < 20)) - { - printf("."); - elapsedTime += 1; - delayMs(500); - } - - printf(" %s.\r\n", elapsedTime < 20 ? "OK" : "TIMEOUT"); - - gpio_setMode(GPS_DATA, ALTERNATE); - gpio_setAlternateFunction(GPS_DATA, 7); - - RCC->APB1ENR |= RCC_APB1ENR_USART3EN; - __DSB(); - - const unsigned int quot = 2*42000000/9600; - USART3->BRR = quot/2 + (quot & 1); - USART3->CR3 |= USART_CR3_ONEBIT; - USART3->CR1 = USART_CR1_UE - | USART_CR1_RE; - - int i = 0; while(1) { - while((USART3->SR & USART_SR_RXNE) == 0) ; - line[i++] = USART3->DR; - // If a NMEA sentence is complete - if (line[i - 1] == '\n') { - line[i] = '\0'; - printf("%s\n\r", line); - switch (minmea_sentence_id(line, false)) { - case MINMEA_SENTENCE_RMC: - { - struct minmea_sentence_rmc frame; - if (minmea_parse_rmc(&frame, line)) { - printf("$RMC: raw coordinates and speed: (%d/%d,%d/%d) %d/%d\n\r", - frame.latitude.value, frame.latitude.scale, - frame.longitude.value, frame.longitude.scale, - frame.speed.value, frame.speed.scale); - printf("$RMC fixed-point coordinates and speed scaled to three decimal places: (%d,%d) %d\n\r", - minmea_rescale(&frame.latitude, 1000), - minmea_rescale(&frame.longitude, 1000), - minmea_rescale(&frame.speed, 1000)); - printf("$RMC floating point degree coordinates and speed: (%f,%f) %f\n\r", - minmea_tocoord(&frame.latitude), - minmea_tocoord(&frame.longitude), - minmea_tofloat(&frame.speed)); - } - } break; - - case MINMEA_SENTENCE_GGA: - { - struct minmea_sentence_gga frame; - if (minmea_parse_gga(&frame, line)) { - printf("$GGA: fix quality: %d\n\r", frame.fix_quality); - } - } break; - - case MINMEA_SENTENCE_GSV: - { - struct minmea_sentence_gsv frame; - if (minmea_parse_gsv(&frame, line)) { - printf("$GSV: message %d of %d\n\r", frame.msg_nr, frame.total_msgs); - printf("$GSV: satellites in view: %d\n\r", frame.total_sats); - for (int i = 0; i < 4; i++) - printf("$GSV: sat nr %d, elevation: %d, azimuth: %d, snr: %d dbm\n\r", - frame.sats[i].nr, - frame.sats[i].elevation, - frame.sats[i].azimuth, - frame.sats[i].snr); - } - } break; - - case MINMEA_SENTENCE_VTG: - { - - } break; - - // Ignore this message as we take data from RMC - case MINMEA_SENTENCE_GLL: - ; - break; - - // These messages are never sent by the Jumpstar JS-M710 Module - case MINMEA_SENTENCE_GSA: break; - case MINMEA_SENTENCE_GST: break; - case MINMEA_SENTENCE_ZDA: break; - - // Error handling - case MINMEA_INVALID: - { - printf("Error: Invalid NMEA sentence!\n\r"); - } break; - - case MINMEA_UNKNOWN: - { - printf("Error: Unsupported NMEA sentence!\n\r"); - } break; - } - i = 0; + int len = gps_getNmeaSentence(line, MINMEA_MAX_LENGTH*10); + if(len != -1) + { + printf("Got sentence with length %d:\r\n", len); + printf("%s\r\n", line); } } +// int i = 0; +// while(1) +// { +// while((USART3->SR & USART_SR_RXNE) == 0) ; +// line[i++] = USART3->DR; +// // If a NMEA sentence is complete +// if (line[i - 1] == '\n') { +// line[i] = '\0'; +// printf("%s\n\r", line); +// switch (minmea_sentence_id(line, false)) { +// case MINMEA_SENTENCE_RMC: +// { +// struct minmea_sentence_rmc frame; +// if (minmea_parse_rmc(&frame, line)) { +// printf("$RMC: raw coordinates and speed: (%d/%d,%d/%d) %d/%d\n\r", +// frame.latitude.value, frame.latitude.scale, +// frame.longitude.value, frame.longitude.scale, +// frame.speed.value, frame.speed.scale); +// printf("$RMC fixed-point coordinates and speed scaled to three decimal places: (%d,%d) %d\n\r", +// minmea_rescale(&frame.latitude, 1000), +// minmea_rescale(&frame.longitude, 1000), +// minmea_rescale(&frame.speed, 1000)); +// printf("$RMC floating point degree coordinates and speed: (%f,%f) %f\n\r", +// minmea_tocoord(&frame.latitude), +// minmea_tocoord(&frame.longitude), +// minmea_tofloat(&frame.speed)); +// } +// } break; +// +// case MINMEA_SENTENCE_GGA: +// { +// struct minmea_sentence_gga frame; +// if (minmea_parse_gga(&frame, line)) { +// printf("$GGA: fix quality: %d\n\r", frame.fix_quality); +// } +// } break; +// +// case MINMEA_SENTENCE_GSV: +// { +// struct minmea_sentence_gsv frame; +// if (minmea_parse_gsv(&frame, line)) { +// printf("$GSV: message %d of %d\n\r", frame.msg_nr, frame.total_msgs); +// printf("$GSV: satellites in view: %d\n\r", frame.total_sats); +// for (int i = 0; i < 4; i++) +// printf("$GSV: sat nr %d, elevation: %d, azimuth: %d, snr: %d dbm\n\r", +// frame.sats[i].nr, +// frame.sats[i].elevation, +// frame.sats[i].azimuth, +// frame.sats[i].snr); +// } +// } break; +// +// case MINMEA_SENTENCE_VTG: +// { +// +// } break; +// +// // Ignore this message as we take data from RMC +// case MINMEA_SENTENCE_GLL: +// ; +// break; +// +// // These messages are never sent by the Jumpstar JS-M710 Module +// case MINMEA_SENTENCE_GSA: break; +// case MINMEA_SENTENCE_GST: break; +// case MINMEA_SENTENCE_ZDA: break; +// +// // Error handling +// case MINMEA_INVALID: +// { +// printf("Error: Invalid NMEA sentence!\n\r"); +// } break; +// +// case MINMEA_UNKNOWN: +// { +// printf("Error: Unsupported NMEA sentence!\n\r"); +// } break; +// } +// i = 0; +// } +// } + return 0; }