kopia lustrzana https://github.com/bristol-seds/pico-tracker
627 wiersze
17 KiB
C
627 wiersze
17 KiB
C
/*
|
|
* Functions for the UBLOX 8 GPS
|
|
* Copyright (C) 2014 Richard Meadows <richardeoin>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* 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 AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "samd20.h"
|
|
|
|
#include "hw_config.h"
|
|
#include "system/system.h"
|
|
#include "system/port.h"
|
|
#include "system/interrupt.h"
|
|
#include "sercom/sercom.h"
|
|
#include "sercom/usart.h"
|
|
#include "util/dbuffer.h"
|
|
#include "ubx_messages.h"
|
|
#include "gps.h"
|
|
#include "watchdog.h"
|
|
|
|
/**
|
|
* UBX Constants
|
|
*/
|
|
const uint16_t ubx_header = (0xB5 | (0x62 << 8));
|
|
|
|
/**
|
|
* UBX ACK Message Types
|
|
*/
|
|
enum {
|
|
UBX_ACK_NACK = (UBX_ACK | (0x00 << 8)),
|
|
UBX_ACK_ACK = (UBX_ACK | (0x01 << 8)),
|
|
};
|
|
|
|
/**
|
|
* Internal buffers and things
|
|
*/
|
|
#define UBX_BUFFER_LEN 0x80
|
|
#define SFD1 0xB5
|
|
#define SFD2 0x62
|
|
|
|
enum sfd_state {
|
|
SFD_WAITING = -1,
|
|
SFD_GOT1,
|
|
} sfd_state = SFD_WAITING;
|
|
|
|
int32_t ubx_index = SFD_WAITING;
|
|
uint16_t ubx_payload_length = 0;
|
|
uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
|
|
|
|
volatile enum gps_error_t gps_error_state;
|
|
|
|
/**
|
|
* UBX Messages
|
|
*/
|
|
volatile struct ubx_cfg_ant ubx_cfg_ant = { .id = (UBX_CFG | (0x13 << 8)) };
|
|
volatile struct ubx_cfg_gnss ubx_cfg_gnss = { .id = (UBX_CFG | (0x3E << 8)) };
|
|
volatile struct ubx_cfg_nav5 ubx_cfg_nav5 = { .id = (UBX_CFG | (0x24 << 8)) };
|
|
volatile struct ubx_cfg_tp5 ubx_cfg_tp5 = { .id = (UBX_CFG | (0x31 << 8)) };
|
|
volatile struct ubx_cfg_prt ubx_cfg_prt = { .id = (UBX_CFG | (0x00 << 8)) };
|
|
volatile struct ubx_cfg_pwr ubx_cfg_pwr = { .id = (UBX_CFG | (0x57 << 8)) };
|
|
volatile struct ubx_cfg_rxm ubx_cfg_rxm = { .id = (UBX_CFG | (0x11 << 8)) };
|
|
volatile struct ubx_nav_posllh ubx_nav_posllh = { .id = (UBX_NAV | (0x02 << 8)) };
|
|
volatile struct ubx_nav_timeutc ubx_nav_timeutc = { .id = (UBX_NAV | (0x21 << 8)) };
|
|
volatile struct ubx_nav_sol ubx_nav_sol = { .id = (UBX_NAV | (0x06 << 8)) };
|
|
volatile struct ubx_nav_status ubx_nav_status = { .id = (UBX_NAV | (0x03 << 8)) };
|
|
/**
|
|
* UBX Message Type List
|
|
*/
|
|
volatile ubx_message_t* const ubx_messages[] = {
|
|
(ubx_message_t*)&ubx_cfg_ant,
|
|
(ubx_message_t*)&ubx_cfg_gnss,
|
|
(ubx_message_t*)&ubx_cfg_nav5,
|
|
(ubx_message_t*)&ubx_cfg_tp5,
|
|
(ubx_message_t*)&ubx_cfg_prt,
|
|
(ubx_message_t*)&ubx_cfg_pwr,
|
|
(ubx_message_t*)&ubx_cfg_rxm,
|
|
(ubx_message_t*)&ubx_nav_posllh,
|
|
(ubx_message_t*)&ubx_nav_timeutc,
|
|
(ubx_message_t*)&ubx_nav_sol,
|
|
(ubx_message_t*)&ubx_nav_status};
|
|
|
|
/**
|
|
* Platform specific handlers
|
|
*/
|
|
#define _send_buffer(tx_data, length) \
|
|
do { usart_write_buffer_wait(GPS_SERCOM, tx_data, length); } while (0)
|
|
#define _error_handler(error_type) \
|
|
do { gps_error_state = error_type; } while (0)
|
|
|
|
|
|
|
|
/**
|
|
* Calculate a UBX checksum using 8-bit Fletcher (RFC1145)
|
|
*/
|
|
uint16_t _ubx_checksum(uint8_t* data, uint8_t len)
|
|
{
|
|
uint16_t ck = 0;
|
|
uint8_t* cka = (uint8_t*)&ck;
|
|
uint8_t* ckb = (cka + 1);
|
|
for(uint8_t i = 0; i < len; i++) {
|
|
*cka += *data;
|
|
*ckb += *cka;
|
|
data++;
|
|
}
|
|
|
|
return ck;
|
|
}
|
|
|
|
/**
|
|
* Processes UBX ack/nack packets
|
|
*/
|
|
void ubx_process_ack(ubx_message_id_t message_id, enum ubx_packet_state state)
|
|
{
|
|
for (uint32_t i = 0; i < sizeof(ubx_messages)/sizeof(ubx_message_t*); i++) {
|
|
if (message_id == ubx_messages[i]->id) { /* Match! */
|
|
/* Set the message state */
|
|
ubx_messages[i]->state = state;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Process a single ubx frame. Runs in the IRQ so should be short and sweet.
|
|
*/
|
|
void ubx_process_frame(uint8_t* frame)
|
|
{
|
|
uint16_t* frame16 = (uint16_t*)frame;
|
|
uint16_t message_id = frame16[0];
|
|
uint16_t payload_length = frame16[1];
|
|
uint16_t checksum = ((uint16_t*)(frame + payload_length + 4))[0];
|
|
uint16_t calculated_checksum = _ubx_checksum(frame, payload_length + 4);
|
|
|
|
/* Checksum.. */
|
|
if (calculated_checksum != checksum) {
|
|
_error_handler(GPS_ERROR_BAD_CHECKSUM);
|
|
return;
|
|
}
|
|
|
|
/** Parse the message ID */
|
|
if (message_id == UBX_ACK_ACK) {
|
|
/* Ack */
|
|
ubx_process_ack(frame16[2], UBX_PACKET_ACK);
|
|
return;
|
|
|
|
} else if (message_id == UBX_ACK_NACK) {
|
|
/* Nack */
|
|
ubx_process_ack(frame16[2], UBX_PACKET_NACK);
|
|
return;
|
|
|
|
} else {
|
|
/** Otherwise it could be a message frame, search for a type */
|
|
for (uint32_t i = 0; i < sizeof(ubx_messages)/sizeof(ubx_message_t*); i++) {
|
|
if (message_id == ubx_messages[i]->id) { // Match!
|
|
/* Populate struct */
|
|
memcpy((void*)(ubx_messages[i]+1), frame + 4, payload_length);
|
|
|
|
/* Set the message state */
|
|
ubx_messages[i]->state = UBX_PACKET_UPDATED;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Unknown frame */
|
|
_error_handler(GPS_ERROR_INVALID_FRAME);
|
|
}
|
|
|
|
/**
|
|
* Rx Callback. Processes a stream of usart bytes
|
|
*/
|
|
void gps_rx_callback(SercomUsart* const hw, uint16_t data)
|
|
{
|
|
(void)hw;
|
|
|
|
/* Start of Frame Delimeter 1 */
|
|
if (data == SFD1) {
|
|
sfd_state = SFD_GOT1;
|
|
} else {
|
|
/* SFD2 preceeded by SFD1 */
|
|
if (sfd_state == SFD_GOT1 && data == SFD2) {
|
|
|
|
/* Start a new frame */
|
|
ubx_index = 0;
|
|
ubx_payload_length = 0;
|
|
sfd_state = SFD_WAITING;
|
|
return;
|
|
}
|
|
|
|
sfd_state = SFD_WAITING;
|
|
}
|
|
|
|
/**
|
|
* If we have a valid index. That is:
|
|
* We're in a frame
|
|
* And we've not reached class/message + length + payload + checksum
|
|
* And we've not reached the end of the buffer
|
|
*/
|
|
if (ubx_index != SFD_WAITING &&
|
|
ubx_index < (4 + ubx_payload_length + 2) &&
|
|
ubx_index < UBX_BUFFER_LEN) {
|
|
|
|
/* Data in */
|
|
ubx_irq_buffer[ubx_index++] = data;
|
|
|
|
/* Extract length */
|
|
if (ubx_index == 4) {
|
|
ubx_payload_length = ((uint16_t*)ubx_irq_buffer)[1];
|
|
}
|
|
|
|
/* Complete Frame? */
|
|
if (ubx_index >= (4 + ubx_payload_length + 2)) {
|
|
/* Process it */
|
|
ubx_process_frame(ubx_irq_buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sends a standard UBX message
|
|
*/
|
|
void _ubx_send_message(ubx_message_t* message, uint8_t* payload, uint16_t length)
|
|
{
|
|
uint8_t ubx[UBX_BUFFER_LEN];
|
|
uint8_t* ubx_buffer = ubx;
|
|
|
|
/* Clear the message state */
|
|
message->state = UBX_PACKET_WAITING;
|
|
|
|
/* Clear error state */
|
|
gps_error_state = GPS_NOERROR;
|
|
|
|
/* Copy little endian */
|
|
memcpy(ubx_buffer, &ubx_header, 2); ubx_buffer += 2; /* Header */
|
|
memcpy(ubx_buffer, &message->id, 2); ubx_buffer += 2; /* Message Type */
|
|
memcpy(ubx_buffer, &length, 2); ubx_buffer += 2; /* Length */
|
|
memcpy(ubx_buffer, payload, length); ubx_buffer += length; /* Payload */
|
|
uint16_t checksum = _ubx_checksum(ubx + 2, length + 4);
|
|
memcpy(ubx_buffer, &checksum, 2); ubx_buffer += 2; /* Checksum */
|
|
|
|
_send_buffer(ubx, length + 8);
|
|
}
|
|
/**
|
|
* Polls the GPS for packets
|
|
*/
|
|
enum gps_error_t _ubx_poll(ubx_message_t* message) {
|
|
/* Send the message */
|
|
_ubx_send_message(message, NULL, 0);
|
|
|
|
/* Wait for acknoledge */
|
|
while (message->state == UBX_PACKET_WAITING &&
|
|
gps_error_state == GPS_NOERROR);
|
|
|
|
return gps_error_state;
|
|
}
|
|
|
|
/**
|
|
* Disable NMEA messages on the uBlox
|
|
*/
|
|
void gps_set_io_config(uint32_t baud_rate)
|
|
{
|
|
ubx_cfg_prt.payload.portID = 1;
|
|
ubx_cfg_prt.payload.res0 = 0;
|
|
ubx_cfg_prt.payload.txReady = 0;
|
|
ubx_cfg_prt.payload.mode = 0x08D0; /* 8 bit, No Parity */
|
|
ubx_cfg_prt.payload.baudRate = baud_rate;
|
|
ubx_cfg_prt.payload.inProtoMask = 0x7; /* UBX */
|
|
ubx_cfg_prt.payload.outProtoMask = 0x1; /* UBX */
|
|
ubx_cfg_prt.payload.flags = 0;
|
|
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_prt,
|
|
(uint8_t*)&ubx_cfg_prt.payload,
|
|
sizeof(ubx_cfg_prt.payload));
|
|
|
|
for (int i = 0; i < 1000*100; i++);
|
|
}
|
|
|
|
/**
|
|
* Sends messages to the GPS to update the time
|
|
*/
|
|
void gps_update_time(void)
|
|
{
|
|
_ubx_send_message((ubx_message_t*)&ubx_nav_timeutc, NULL, 0);
|
|
};
|
|
/**
|
|
* Sends messages to the GPS to update the position
|
|
*/
|
|
void gps_update_position(void)
|
|
{
|
|
_ubx_send_message((ubx_message_t*)&ubx_nav_posllh, NULL, 0);
|
|
_ubx_send_message((ubx_message_t*)&ubx_nav_sol, NULL, 0);
|
|
|
|
// _ubx_send_message((ubx_message_t*)&ubx_nav_status, NULL, 0);
|
|
}
|
|
/**
|
|
* Indicates a pending time update from the GPS
|
|
*/
|
|
int gps_update_time_pending(void)
|
|
{
|
|
return (ubx_nav_timeutc.state == UBX_PACKET_WAITING &&
|
|
gps_error_state == GPS_NOERROR);
|
|
}
|
|
/**
|
|
* Indicates a pending position update from the GPS
|
|
*/
|
|
int gps_update_position_pending(void)
|
|
{
|
|
return (((ubx_nav_posllh.state == UBX_PACKET_WAITING) ||
|
|
(ubx_nav_sol.state == UBX_PACKET_WAITING)) &&
|
|
gps_error_state == GPS_NOERROR);
|
|
|
|
//(ubx_nav_status.state == UBX_PACKET_WAITING);
|
|
}
|
|
/**
|
|
* Gets the current error state of the GPS to check validity of last
|
|
* request
|
|
*/
|
|
enum gps_error_t gps_get_error_state(void)
|
|
{
|
|
return gps_error_state;
|
|
}
|
|
/**
|
|
* Return the latest received messages
|
|
*/
|
|
struct ubx_nav_posllh gps_get_nav_posllh()
|
|
{
|
|
return ubx_nav_posllh;
|
|
}
|
|
struct ubx_nav_sol gps_get_nav_sol()
|
|
{
|
|
return ubx_nav_sol;
|
|
}
|
|
struct ubx_nav_timeutc gps_get_nav_timeutc()
|
|
{
|
|
return ubx_nav_timeutc;
|
|
}
|
|
/**
|
|
* Returns if the GPS has a position lock
|
|
*/
|
|
uint8_t gps_is_locked(void)
|
|
{
|
|
return (ubx_nav_sol.payload.gpsFix == 0x2) ||
|
|
(ubx_nav_sol.payload.gpsFix == 0x3) ||
|
|
(ubx_nav_sol.payload.gpsFix == 0x4);
|
|
}
|
|
|
|
/**
|
|
* Verify that the uBlox 6 GPS receiver is set to the <1g airborne
|
|
* navigaion mode.
|
|
*/
|
|
void gps_set_platform_model(void)
|
|
{
|
|
/* Poll for the current settings */
|
|
_ubx_poll((ubx_message_t*)&ubx_cfg_nav5);
|
|
|
|
/* If we need to update */
|
|
if (ubx_cfg_nav5.payload.dynModel != GPS_PLATFORM_MODEL) {
|
|
/* Update */
|
|
ubx_cfg_nav5.payload.dynModel = GPS_PLATFORM_MODEL;
|
|
/* Send */
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_nav5,
|
|
(uint8_t*)&ubx_cfg_nav5.payload,
|
|
sizeof(ubx_cfg_nav5.payload));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the GPS timepulse settings using the CFG_TP5 message
|
|
*/
|
|
void gps_set_timepulse_five(uint32_t frequency)
|
|
{
|
|
/* Poll for the current settings */
|
|
_ubx_poll((ubx_message_t*)&ubx_cfg_tp5);
|
|
|
|
/* Define the settings we want */
|
|
ubx_cfg_tp5.payload.tpIdx = 0;
|
|
ubx_cfg_tp5.payload.antCableDelay = 50; /* 50 nS */
|
|
|
|
/* frequency, lock to GPS, active */
|
|
ubx_cfg_tp5.payload.flags =
|
|
UBX_TP5_ENABLE | UBX_TP5_LOCK_TO_GPS | UBX_TP5_IS_FREQ |
|
|
UBX_TP5_ALIGN_RISING | UBX_TP5_USE_GRID_UTC;
|
|
|
|
ubx_cfg_tp5.payload.freqPeriod = frequency;
|
|
ubx_cfg_tp5.payload.pulseLenRatio = 0x80000000; /* 50 % duty cycle*/
|
|
|
|
/* Write the new settings */
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_tp5,
|
|
(uint8_t*)&ubx_cfg_tp5.payload,
|
|
sizeof(ubx_cfg_tp5.payload));
|
|
}
|
|
/**
|
|
* Set which GNSS constellations to use
|
|
*/
|
|
void gps_set_gnss(void)
|
|
{
|
|
/* Poll for the current settings */
|
|
_ubx_poll((ubx_message_t*)&ubx_cfg_gnss);
|
|
|
|
switch (ubx_cfg_gnss.payload.msgVer) {
|
|
case 0:
|
|
/* For each configuration block */
|
|
for (uint8_t i = 0; i < ubx_cfg_gnss.payload.numConfigBlocks; i++) {
|
|
|
|
/* If it's the configuration for something other than GPS */
|
|
if (ubx_cfg_gnss.payload.block[i].gnssID != UBX_GNSS_GPS) {
|
|
|
|
/* Disable this GNSS system */
|
|
ubx_cfg_gnss.payload.block[i].flags &= ~0x1;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Write the new settings */
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_gnss,
|
|
(uint8_t*)&ubx_cfg_gnss.payload,
|
|
4 + (8 * ubx_cfg_gnss.payload.numConfigBlocks));
|
|
}
|
|
/**
|
|
* Sets the powersave mode
|
|
*/
|
|
void gps_set_powersave(bool powersave_on)
|
|
{
|
|
ubx_cfg_rxm.payload.lpMode = (powersave_on ? UBX_POWERSAVE_ON : UBX_POWERSAVE_OFF);
|
|
|
|
/* Write the new settings */
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_rxm,
|
|
(uint8_t*)&ubx_cfg_rxm.payload,
|
|
sizeof(ubx_cfg_rxm.payload));
|
|
}
|
|
/**
|
|
* Sets the PWR power state
|
|
*/
|
|
void gps_set_power_state(bool gnss_running)
|
|
{
|
|
ubx_cfg_pwr.payload.messageVersion = 1;
|
|
ubx_cfg_pwr.payload.state = (gnss_running ? UBX_PWR_STATE_GNSS_RUNNING : UBX_PWR_STATE_GNSS_STOPPED);
|
|
|
|
/* Write the new settings */
|
|
_ubx_send_message((ubx_message_t*)&ubx_cfg_pwr,
|
|
(uint8_t*)&ubx_cfg_pwr.payload,
|
|
sizeof(ubx_cfg_pwr.payload));
|
|
}
|
|
/**
|
|
* Sets the powersave mode automatically based on if we're locked.
|
|
*
|
|
* Only call after we've updated our position
|
|
*/
|
|
bool _last_gps_is_locked = false;
|
|
void gps_set_powersave_auto(void)
|
|
{
|
|
bool is_locked = gps_is_locked();
|
|
|
|
if (is_locked != _last_gps_is_locked) {
|
|
if (is_locked) { /* Just locked */
|
|
gps_set_powersave(true);
|
|
|
|
} else { /* Just unlocked */
|
|
gps_set_powersave(false);
|
|
}
|
|
|
|
_last_gps_is_locked = is_locked;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Init + enable for the usart at the given baud rate
|
|
*/
|
|
void gps_usart_init_enable(uint32_t baud_rate)
|
|
{
|
|
/* USART */
|
|
usart_init(GPS_SERCOM,
|
|
USART_DATAORDER_LSB, /** Bit order (MSB or LSB first) */
|
|
USART_TRANSFER_ASYNCHRONOUSLY, /** Asynchronous or synchronous mode */
|
|
USART_PARITY_NONE, /** USART parity */
|
|
USART_STOPBITS_1, /** Number of stop bits */
|
|
USART_CHARACTER_SIZE_8BIT, /** USART character size */
|
|
GPS_SERCOM_MUX, /** USART pinout */
|
|
false, /** Immediate buffer overflow notification */
|
|
false, /** Enable IrDA encoding format */
|
|
19, /** Minimum pulse length required for IrDA rx */
|
|
false, /** Enable LIN Slave Support */
|
|
false, /** Enable start of frame dection */
|
|
false, /** Enable collision dection */
|
|
baud_rate, /** USART Baud rate */
|
|
true, /** Enable receiver */
|
|
true, /** Enable transmitter */
|
|
false, /** Sample on the rising edge of XLCK */
|
|
false, /** Use the external clock applied to the XCK pin. */
|
|
0, /** External clock frequency in synchronous mode. */
|
|
true, /** Run in standby */
|
|
GPS_GCLK, /** GCLK generator source */
|
|
GPS_SERCOM_MOGI_PINMUX, /** PAD0 pinmux */
|
|
GPS_SERCOM_MIGO_PINMUX, /** PAD1 pinmux */
|
|
PINMUX_UNUSED, /** PAD2 pinmux */
|
|
PINMUX_UNUSED); /** PAD3 pinmux */
|
|
|
|
usart_enable(GPS_SERCOM);
|
|
}
|
|
|
|
/**
|
|
* GPS reset pin
|
|
*/
|
|
void gps_reset_on(void)
|
|
{
|
|
#ifdef GPS_RESET_PIN
|
|
port_pin_set_output_level(GPS_RESET_PIN, 0); /* active low */
|
|
#endif
|
|
}
|
|
void gps_reset_off(void)
|
|
{
|
|
#ifdef GPS_RESET_PIN
|
|
port_pin_set_output_level(GPS_RESET_PIN, 1); /* active low */
|
|
#endif
|
|
}
|
|
/**
|
|
* Reset. Places the GPS in a RESET state
|
|
*/
|
|
void gps_reset(void)
|
|
{
|
|
#ifdef GPS_RESET_PIN
|
|
port_pin_set_config(GPS_RESET_PIN,
|
|
PORT_PIN_DIR_OUTPUT, /* Direction */
|
|
PORT_PIN_PULL_NONE, /* Pull */
|
|
false); /* Powersave */
|
|
port_pin_set_output_level(GPS_RESET_PIN, 0); /* active low */
|
|
#endif
|
|
}
|
|
/**
|
|
* Init
|
|
*/
|
|
void gps_init(void)
|
|
{
|
|
/* Bring GPS out of reset */
|
|
gps_reset_off();
|
|
|
|
/* Enable usart */
|
|
gps_usart_init_enable(GPS_BAUD_RATE);
|
|
|
|
kick_the_watchdog();
|
|
|
|
/* We use ubx protocol */
|
|
gps_set_io_config(GPS_BAUD_RATE);
|
|
|
|
/* Incoming ubx messages are handled in an irq */
|
|
usart_register_rx_callback(GPS_SERCOM, gps_rx_callback, GPS_SERCOM_INT_PRIO);
|
|
|
|
kick_the_watchdog();
|
|
|
|
/* Set the platform model */
|
|
gps_set_platform_model();
|
|
|
|
/* Set which GNSS constellation we'd like to use */
|
|
gps_set_gnss();
|
|
|
|
kick_the_watchdog();
|
|
|
|
/* Exit powersave mode to start */
|
|
gps_set_powersave(false);
|
|
|
|
/* Set the timepulse */
|
|
gps_set_timepulse_five(GPS_TIMEPULSE_FREQ);
|
|
}
|
|
|
|
|
|
/**
|
|
* Quick and dirty loopback test. Should print 0x34
|
|
*/
|
|
void usart_loopback_test(void)
|
|
{
|
|
uint16_t data;
|
|
|
|
usart_init(GPS_SERCOM,
|
|
USART_DATAORDER_LSB, /** Bit order (MSB or LSB first) */
|
|
USART_TRANSFER_ASYNCHRONOUSLY, /** Asynchronous or synchronous mode */
|
|
USART_PARITY_NONE, /** USART parity */
|
|
USART_STOPBITS_1, /** Number of stop bits */
|
|
USART_CHARACTER_SIZE_8BIT, /** USART character size */
|
|
USART_MUX_LOOPBACK, /** USART pin out */
|
|
false, /** Immediate buffer overflow notification */
|
|
false, /** Enable IrDA encoding format */
|
|
19, /** Minimum pulse length required for IrDA rx */
|
|
false, /** Enable LIN Slave Support */
|
|
false, /** Enable start of frame dection */
|
|
false, /** Enable collision dection */
|
|
GPS_BAUD_RATE, /** USART Baud rate */
|
|
true, /** Enable receiver */
|
|
true, /** Enable transmitter */
|
|
false, /** Sample on the rising edge of XLCK */
|
|
false, /** Use the external clock applied to the XCK pin. */
|
|
0, /** External clock frequency in synchronous mode. */
|
|
false, /** Run in standby */
|
|
GPS_GCLK, /** GCLK generator source */
|
|
GPS_SERCOM_MOGI_PINMUX, /** PAD0 pinmux */
|
|
GPS_SERCOM_MIGO_PINMUX, /** PAD1 pinmux */
|
|
PINMUX_UNUSED, /** PAD2 pinmux */
|
|
PINMUX_UNUSED); /** PAD3 pinmux */
|
|
|
|
usart_enable(GPS_SERCOM);
|
|
|
|
usart_write_wait(GPS_SERCOM, 0x34);
|
|
usart_read_wait(GPS_SERCOM, &data);
|
|
|
|
usart_disable(GPS_SERCOM);
|
|
}
|