kopia lustrzana https://github.com/bristol-seds/pico-tracker
Working RTTY! And new gps stuff
rodzic
d477adeecc
commit
299725405d
|
@ -25,134 +25,13 @@
|
|||
#ifndef GPS_H
|
||||
#define GPS_H
|
||||
|
||||
/* We use the packed attribute so we can copy direct to structs */
|
||||
#define __PACKED__ __attribute__((packed))
|
||||
void gps_update();
|
||||
|
||||
/**
|
||||
* UBX CFG ANT Antenna Control Settings
|
||||
*/
|
||||
volatile struct ubx_cfg_ant {
|
||||
uint16_t flags;
|
||||
uint16_t pins;
|
||||
} __PACKED__ ubx_cfg_ant;
|
||||
/**
|
||||
* UBX CFG NAV5 Navigation Engine Settings
|
||||
*/
|
||||
volatile struct ubx_cfg_nav5 {
|
||||
uint16_t mask;
|
||||
uint8_t dynModel;
|
||||
uint8_t fixMode;
|
||||
int32_t fixedAlt;
|
||||
uint32_t fixedAltVar;
|
||||
int8_t minElev;
|
||||
uint8_t drLimit;
|
||||
uint16_t pDop;
|
||||
uint16_t tDop;
|
||||
uint16_t pAcc;
|
||||
uint16_t tAcc;
|
||||
uint8_t staticHoldThresh;
|
||||
uint8_t dgpsTimeOut;
|
||||
uint32_t res2;
|
||||
uint32_t res3;
|
||||
uint32_t res4;
|
||||
} __PACKED__ ubx_cfg_nav5;
|
||||
/**
|
||||
* UBX CFG TP TimePulse Parameters
|
||||
*/
|
||||
volatile struct ubx_cfg_tp {
|
||||
uint32_t interval;
|
||||
uint32_t length;
|
||||
int8_t status;
|
||||
uint8_t timeRef;
|
||||
uint8_t flags;
|
||||
uint8_t res;
|
||||
int16_t antennaCableDelay;
|
||||
int16_t rfGroupDelay;
|
||||
int32_t userDelay;
|
||||
} __PACKED__ ubx_cfg_tp;
|
||||
/**
|
||||
* UBX CFG TP5 TimePulse Parameters
|
||||
*/
|
||||
volatile struct ubx_cfg_tp5 {
|
||||
uint8_t tpIdx;
|
||||
uint8_t res0;
|
||||
uint16_t res1;
|
||||
int16_t antCableDelay;
|
||||
int16_t rfGroupDelay;
|
||||
uint32_t freqPeriod;
|
||||
uint32_t freqPeriodLoc;
|
||||
uint32_t pulseLenRatio;
|
||||
uint32_t pulseLenRatioLock;
|
||||
int32_t userConfigDelay;
|
||||
uint32_t flags;
|
||||
} __PACKED__ ubx_cfg_tp5;
|
||||
/**
|
||||
* UBX NAV POSLLH Geodetic Position Solution
|
||||
*/
|
||||
volatile struct ubx_nav_posllh {
|
||||
uint32_t iTOW;
|
||||
int32_t lon;
|
||||
int32_t lat;
|
||||
int32_t height;
|
||||
int32_t hMSL;
|
||||
uint32_t hAcc;
|
||||
uint32_t vAcc;
|
||||
} __PACKED__ ubx_nav_posllh;
|
||||
/**
|
||||
* UBX NAV TIMEUTC
|
||||
*/
|
||||
volatile struct ubx_nav_timeutc {
|
||||
uint32_t iTOW;
|
||||
uint32_t tAcc;
|
||||
int32_t nano;
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t valid;
|
||||
} __PACKED__ ubx_nav_timeutc;
|
||||
/**
|
||||
* UBX NAV SOL Navigation Solution Information
|
||||
*/
|
||||
volatile struct ubx_nav_sol {
|
||||
uint32_t iTOW;
|
||||
int32_t fTOW;
|
||||
uint16_t week;
|
||||
uint8_t gpsFix;
|
||||
uint8_t flags;
|
||||
int32_t ecefX;
|
||||
int32_t ecefY;
|
||||
int32_t ecefZ;
|
||||
uint32_t pAcc;
|
||||
int32_t ecefVX;
|
||||
int32_t ecefVY;
|
||||
int32_t ecefVZ;
|
||||
uint32_t sAcc;
|
||||
uint16_t pDOP;
|
||||
uint8_t res1;
|
||||
uint8_t numSV;
|
||||
uint32_t res2;
|
||||
} __PACKED__ ubx_nav_sol;
|
||||
struct ubx_nav_posllh gps_get_nav_posllh();
|
||||
struct ubx_nav_sol gps_get_nav_sol();
|
||||
struct ubx_nav_timeutc gps_get_nav_timeutc();
|
||||
|
||||
/**
|
||||
* UBX Dynamic Platform Model
|
||||
*/
|
||||
enum {
|
||||
UBX_PLATFORM_MODEL_PORTABLE = 0,
|
||||
UBX_PLATFORM_MODEL_STATIONARY = 2,
|
||||
UBX_PLATFORM_MODEL_PEDESTRIAN = 3,
|
||||
UBX_PLATFORM_MODEL_AUTOMOTIVE = 4,
|
||||
UBX_PLATFORM_MODEL_SEA = 5,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_1G = 6,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_2G = 7,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_4G = 8,
|
||||
};
|
||||
|
||||
|
||||
void usart_loopback_test(void);
|
||||
char* gps_get_frame(void);
|
||||
void gps_init(void);
|
||||
void usart_loopback_test(void);
|
||||
|
||||
#endif /* GPS_H */
|
||||
|
|
|
@ -76,8 +76,7 @@
|
|||
#define GPS_TIME_PIN PIN_PA28
|
||||
#define GPS_TIME_PINMUX PINMUX_PA28H_GCLK_IO0
|
||||
#define GPS_SERCOM_MUX USART_RX_1_TX_0_XCK_1
|
||||
#define GPS_TIMEPULSE_FREQ 4000000
|
||||
// 32768
|
||||
#define GPS_TIMEPULSE_FREQ 1000
|
||||
#define GPS_PLATFORM_MODEL UBX_PLATFORM_MODEL_AIRBORNE_1G
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Bit-bangs RTTY
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RTTY_H
|
||||
#define RTTY_H
|
||||
|
||||
int rtty_active(void);
|
||||
int rtty_set_string(char* string, uint32_t length);
|
||||
void rtty_tick(void);
|
||||
|
||||
#endif /* RTTY_H */
|
|
@ -35,7 +35,7 @@ void si4060_shutdown(void);
|
|||
|
||||
#define XO_FREQ 16000000UL
|
||||
#define RF_FREQ_HZ 434600000.0f
|
||||
#define RF_DEV_HZ 100.0f
|
||||
#define RF_DEV_HZ 200.0f
|
||||
|
||||
#define F_INT (2 * XO_FREQ / 8)
|
||||
#define FDIV_INTE ( (RF_FREQ_HZ / F_INT) - 1)
|
||||
|
|
|
@ -394,6 +394,19 @@ enum system_clock_apb_bus {
|
|||
SYSTEM_CLOCK_APB_APBC,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible NVM flash wait state settings
|
||||
*/
|
||||
enum system_wait_states {
|
||||
/** Wait state maximum frequencies at 1.8V */
|
||||
SYSTEM_WAIT_STATE_1_8V_14MHZ = 0,
|
||||
SYSTEM_WAIT_STATE_1_8V_28MHZ = 1,
|
||||
SYSTEM_WAIT_STATE_1_8V_42MHZ = 2,
|
||||
SYSTEM_WAIT_STATE_1_8V_48MHZ = 3,
|
||||
/** Wait state maximum frequencies at 3.3V */
|
||||
SYSTEM_WAIT_STATE_3_3V_24MHZ = 0,
|
||||
SYSTEM_WAIT_STATE_3_3V_48MHZ = 1,
|
||||
};
|
||||
|
||||
void system_clock_source_osc8m_set_config(enum system_osc8m_div prescaler,
|
||||
bool run_in_standby,
|
||||
|
@ -819,7 +832,7 @@ void system_clock_init(void);
|
|||
*
|
||||
* \param[in] wait_states Number of wait states to use for internal flash
|
||||
*/
|
||||
static inline void system_flash_set_waitstates(uint8_t wait_states)
|
||||
static inline void system_flash_set_waitstates(const enum system_wait_states wait_states)
|
||||
{
|
||||
assert(NVMCTRL_CTRLB_RWS((uint32_t)wait_states) ==
|
||||
((uint32_t)wait_states << NVMCTRL_CTRLB_RWS_Pos));
|
||||
|
|
|
@ -543,9 +543,9 @@ void tc_set_top_value (Tc* const hw,
|
|||
const uint32_t top_value);
|
||||
|
||||
void tc_enable_events(Tc* const hw,
|
||||
struct tc_events *const events);
|
||||
struct tc_events *const events);
|
||||
void tc_disable_events(Tc* const hw,
|
||||
struct tc_events *const events);
|
||||
struct tc_events *const events);
|
||||
|
||||
enum tc_status_t tc_init(Tc* const hw,
|
||||
enum gclk_generator source_clock,
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* UBX Message definitions
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef UBX_MESSAGES_H
|
||||
#define UBX_MESSAGES_H
|
||||
|
||||
#include "samd20.h"
|
||||
|
||||
/** We use the packed attribute so we can copy direct to structs */
|
||||
#define __PACKED__ __attribute__((packed))
|
||||
/** UBX Message IDs are 16-bit types */
|
||||
typedef uint16_t ubx_message_id_t;
|
||||
/** Used for storing the state of each packet */
|
||||
enum ubx_packet_state {
|
||||
UBX_PACKET_WAITING,
|
||||
UBX_PACKET_ACK,
|
||||
UBX_PACKET_NACK,
|
||||
};
|
||||
/** Generic UBX Message Type. Each message type extended is from this */
|
||||
typedef struct {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
} ubx_message_t;
|
||||
|
||||
/** UBX Class Types */
|
||||
enum {
|
||||
UBX_NAV = 0x01,
|
||||
UBX_RXM = 0x02,
|
||||
UBX_INF = 0x04,
|
||||
UBX_ACK = 0x05,
|
||||
UBX_CFG = 0x06,
|
||||
UBX_MON = 0x0A,
|
||||
UBX_AID = 0x0B,
|
||||
UBX_TIM = 0x0D,
|
||||
UBX_ESF = 0x10,
|
||||
};
|
||||
|
||||
/**
|
||||
* =============================================================================
|
||||
* UBX CFG Message Types =======================================================
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* UBX CFG ANT Antenna Control Settings
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_ant {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint16_t flags;
|
||||
uint16_t pins;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG NAV5 Navigation Engine Settings
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_nav5 {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint16_t mask;
|
||||
uint8_t dynModel;
|
||||
uint8_t fixMode;
|
||||
int32_t fixedAlt;
|
||||
uint32_t fixedAltVar;
|
||||
int8_t minElev;
|
||||
uint8_t drLimit;
|
||||
uint16_t pDop;
|
||||
uint16_t tDop;
|
||||
uint16_t pAcc;
|
||||
uint16_t tAcc;
|
||||
uint8_t staticHoldThresh;
|
||||
uint8_t dgpsTimeOut;
|
||||
uint32_t res2;
|
||||
uint32_t res3;
|
||||
uint32_t res4;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG TP TimePulse Parameters
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_tp {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint32_t interval;
|
||||
uint32_t length;
|
||||
int8_t status;
|
||||
uint8_t timeRef;
|
||||
uint8_t flags;
|
||||
uint8_t res;
|
||||
int16_t antennaCableDelay;
|
||||
int16_t rfGroupDelay;
|
||||
int32_t userDelay;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG TP5 TimePulse Parameters
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_tp5 {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint8_t tpIdx;
|
||||
uint8_t res0;
|
||||
uint16_t res1;
|
||||
int16_t antCableDelay;
|
||||
int16_t rfGroupDelay;
|
||||
uint32_t freqPeriod;
|
||||
uint32_t freqPeriodLoc;
|
||||
uint32_t pulseLenRatio;
|
||||
uint32_t pulseLenRatioLock;
|
||||
int32_t userConfigDelay;
|
||||
uint32_t flags;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX CFG PRT Polls the configuration for one I/O Port
|
||||
*/
|
||||
__PACKED__ struct ubx_cfg_prt {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint8_t portID;
|
||||
uint8_t res0;
|
||||
uint16_t txReady;
|
||||
uint32_t mode;
|
||||
uint32_t baudRate;
|
||||
uint16_t inProtoMask;
|
||||
uint16_t outProtoMask;
|
||||
uint16_t flags;
|
||||
uint16_t res3;
|
||||
} payload;
|
||||
};
|
||||
|
||||
/**
|
||||
* UBX Dynamic Platform Model
|
||||
*/
|
||||
enum {
|
||||
UBX_PLATFORM_MODEL_PORTABLE = 0,
|
||||
UBX_PLATFORM_MODEL_STATIONARY = 2,
|
||||
UBX_PLATFORM_MODEL_PEDESTRIAN = 3,
|
||||
UBX_PLATFORM_MODEL_AUTOMOTIVE = 4,
|
||||
UBX_PLATFORM_MODEL_SEA = 5,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_1G = 6,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_2G = 7,
|
||||
UBX_PLATFORM_MODEL_AIRBORNE_4G = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* =============================================================================
|
||||
* UBX NAV Message Types =======================================================
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* UBX NAV POSLLH Geodetic Position Solution
|
||||
*/
|
||||
__PACKED__ struct ubx_nav_posllh {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint32_t iTOW;
|
||||
int32_t lon;
|
||||
int32_t lat;
|
||||
int32_t height;
|
||||
int32_t hMSL;
|
||||
uint32_t hAcc;
|
||||
uint32_t vAcc;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX NAV TIMEUTC
|
||||
*/
|
||||
__PACKED__ struct ubx_nav_timeutc {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint32_t iTOW;
|
||||
uint32_t tAcc;
|
||||
int32_t nano;
|
||||
uint16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t valid;
|
||||
} payload;
|
||||
};
|
||||
/**
|
||||
* UBX NAV SOL Navigation Solution Information
|
||||
*/
|
||||
__PACKED__ struct ubx_nav_sol {
|
||||
ubx_message_id_t id;
|
||||
enum ubx_packet_state state;
|
||||
struct {
|
||||
uint32_t iTOW;
|
||||
int32_t fTOW;
|
||||
uint16_t week;
|
||||
uint8_t gpsFix;
|
||||
uint8_t flags;
|
||||
int32_t ecefX;
|
||||
int32_t ecefY;
|
||||
int32_t ecefZ;
|
||||
uint32_t pAcc;
|
||||
int32_t ecefVX;
|
||||
int32_t ecefVY;
|
||||
int32_t ecefVZ;
|
||||
uint32_t sAcc;
|
||||
uint16_t pDOP;
|
||||
uint8_t res1;
|
||||
uint8_t numSV;
|
||||
uint32_t res2;
|
||||
} payload;
|
||||
};
|
||||
|
||||
#endif /* UBX_MESSAGES_H */
|
|
@ -33,45 +33,14 @@
|
|||
#include "sercom/sercom.h"
|
||||
#include "sercom/usart.h"
|
||||
#include "util/dbuffer.h"
|
||||
#include "ubx_messages.h"
|
||||
#include "gps.h"
|
||||
|
||||
/**
|
||||
* UBX Constants
|
||||
*/
|
||||
const uint16_t ubx_header = (0xB5 | (0x62 << 8));
|
||||
/**
|
||||
* UBX Class Types
|
||||
*/
|
||||
enum {
|
||||
UBX_NAV = 0x01,
|
||||
UBX_RXM = 0x02,
|
||||
UBX_INF = 0x04,
|
||||
UBX_ACK = 0x05,
|
||||
UBX_CFG = 0x06,
|
||||
UBX_MON = 0x0A,
|
||||
UBX_AID = 0x0B,
|
||||
UBX_TIM = 0x0D,
|
||||
UBX_ESF = 0x10,
|
||||
};
|
||||
/**
|
||||
* UBX NAV Message Types
|
||||
*/
|
||||
enum {
|
||||
UBX_NAV_POSLLH = (UBX_NAV | (0x02 << 8)),
|
||||
UBX_NAV_SOL = (UBX_NAV | (0x06 << 8)),
|
||||
UBX_NAV_TIMEGPS = (UBX_NAV | (0x20 << 8)),
|
||||
UBX_NAV_TIMEUTC = (UBX_NAV | (0x21 << 8)),
|
||||
};
|
||||
/**
|
||||
* UBX CFG Message Types
|
||||
*/
|
||||
enum {
|
||||
UBX_CFG_PRT = (UBX_CFG | (0x00 << 8)),
|
||||
UBX_CFG_TP = (UBX_CFG | (0x07 << 8)),
|
||||
UBX_CFG_ANT = (UBX_CFG | (0x13 << 8)),
|
||||
UBX_CFG_NAV5 = (UBX_CFG | (0x24 << 8)),
|
||||
UBX_CFG_TP5 = (UBX_CFG | (0x31 << 8)),
|
||||
};
|
||||
|
||||
/**
|
||||
* UBX ACK Message Types
|
||||
*/
|
||||
|
@ -80,8 +49,10 @@ enum {
|
|||
UBX_ACK_ACK = (UBX_ACK | (0x01 << 8)),
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal buffers and things
|
||||
*/
|
||||
#define UBX_BUFFER_LEN 0x80
|
||||
|
||||
#define SFD1 0xB5
|
||||
#define SFD2 0x62
|
||||
|
||||
|
@ -94,104 +65,102 @@ int32_t ubx_index = SFD_WAITING;
|
|||
uint16_t ubx_payload_length = 0;
|
||||
uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
|
||||
|
||||
#define _send_buffer(tx_data, length) \
|
||||
usart_write_buffer_wait(GPS_SERCOM, tx_data, length)
|
||||
#define _get_buffer(rx_data, length) \
|
||||
usart_read_buffer_wait(GPS_SERCOM, rx_data, length)
|
||||
/**
|
||||
* UBX Messages
|
||||
*/
|
||||
volatile struct ubx_cfg_ant ubx_cfg_ant = { .id = (UBX_CFG | (0x07 << 8)) };
|
||||
volatile struct ubx_cfg_nav5 ubx_cfg_nav5 = { .id = (UBX_CFG | (0x24 << 8)) };
|
||||
volatile struct ubx_cfg_tp ubx_cfg_tp = { .id = (UBX_CFG | (0x07 << 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_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)) };
|
||||
/**
|
||||
* UBX Message Type List
|
||||
*/
|
||||
volatile ubx_message_t* const ubx_messages[] = {
|
||||
(ubx_message_t*)&ubx_cfg_ant,
|
||||
(ubx_message_t*)&ubx_cfg_nav5,
|
||||
(ubx_message_t*)&ubx_cfg_tp,
|
||||
(ubx_message_t*)&ubx_cfg_tp5,
|
||||
(ubx_message_t*)&ubx_cfg_prt,
|
||||
(ubx_message_t*)&ubx_nav_posllh,
|
||||
(ubx_message_t*)&ubx_nav_timeutc,
|
||||
(ubx_message_t*)&ubx_nav_sol};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Flags for pending ubx pakcets
|
||||
* Platform specific handlers
|
||||
*/
|
||||
enum ubx_packet_state {
|
||||
UBX_PACKET_WAITING,
|
||||
UBX_PACKET_ACK,
|
||||
UBX_PACKET_NACK,
|
||||
};
|
||||
enum ubx_packet_state _ubx_cfg_tp_state;
|
||||
enum ubx_packet_state _ubx_cfg_tp5_state;
|
||||
#define _send_buffer(tx_data, length) \
|
||||
usart_write_buffer_wait(GPS_SERCOM, tx_data, length)
|
||||
#define _error_handler(error_type) \
|
||||
/* TODO */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Processes UBX ack/nack packets
|
||||
*/
|
||||
void ubx_process_ack(uint16_t message, enum ubx_packet_state state)
|
||||
void ubx_process_ack(ubx_message_id_t message_id, enum ubx_packet_state state)
|
||||
{
|
||||
switch (message) {
|
||||
case UBX_CFG_TP:
|
||||
_ubx_cfg_tp_state = state;
|
||||
break;
|
||||
case UBX_CFG_TP5:
|
||||
_ubx_cfg_tp5_state = state;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Macro for the function below
|
||||
*/
|
||||
#define UBX_POPULATE_STRUCT(ubx_type) \
|
||||
if (payload_length == sizeof(ubx_type)) { \
|
||||
memcpy((void*)&ubx_type, frame + 4, payload_length); \
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
|
||||
/* Checksum.. */
|
||||
|
||||
switch (frame[0]) { /* Switch by Class */
|
||||
case UBX_NAV:
|
||||
switch (frame16[0]) {
|
||||
case UBX_NAV_SOL: /* Navigation Solution Information */
|
||||
UBX_POPULATE_STRUCT(ubx_nav_sol);
|
||||
break;
|
||||
case UBX_NAV_TIMEUTC: /* UTC Time Solution */
|
||||
UBX_POPULATE_STRUCT(ubx_nav_timeutc);
|
||||
break;
|
||||
case UBX_NAV_POSLLH: /* Geodetic Position Solution */
|
||||
UBX_POPULATE_STRUCT(ubx_nav_posllh);
|
||||
break;
|
||||
/** Parse the message ID */
|
||||
if (message_id == UBX_ACK_ACK) {
|
||||
/* Ack */
|
||||
ubx_process_ack(frame16[2], UBX_PACKET_ACK);
|
||||
|
||||
} else if (message_id == UBX_ACK_NACK) {
|
||||
/* Nack */
|
||||
ubx_process_ack(frame16[2], UBX_PACKET_NACK);
|
||||
|
||||
} 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);
|
||||
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case UBX_CFG:
|
||||
switch (frame16[0]) {
|
||||
case UBX_CFG_NAV5: /* Navigation Engine Settings */
|
||||
UBX_POPULATE_STRUCT(ubx_cfg_nav5);
|
||||
break;
|
||||
case UBX_CFG_ANT: /* Antenna Control Settings */
|
||||
UBX_POPULATE_STRUCT(ubx_cfg_ant);
|
||||
break;
|
||||
case UBX_CFG_TP: /* TimePulse Parameters */
|
||||
UBX_POPULATE_STRUCT(ubx_cfg_tp);
|
||||
break;
|
||||
case UBX_CFG_TP5: /* TimePulse Parameters */
|
||||
UBX_POPULATE_STRUCT(ubx_cfg_tp5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case UBX_ACK:
|
||||
if (payload_length == 2) { /* All ACK packets should have a payload len of 2 */
|
||||
switch (frame16[0]) {
|
||||
case UBX_ACK_ACK:
|
||||
ubx_process_ack(frame16[2], UBX_PACKET_ACK);
|
||||
break;
|
||||
case UBX_ACK_NACK:
|
||||
ubx_process_ack(frame16[2], UBX_PACKET_NACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unknown frame */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Rx Callback. Processes a stream of
|
||||
* Rx Callback. Processes a stream of usart bytes
|
||||
*/
|
||||
void gps_rx_callback(SercomUsart* const hw, uint16_t data)
|
||||
{
|
||||
|
@ -259,26 +228,32 @@ uint16_t _ubx_checksum(uint8_t* data, uint8_t len)
|
|||
/**
|
||||
* Sends a standard UBX message
|
||||
*/
|
||||
void _ubx_send_message(uint16_t message, uint8_t* payload, uint16_t length)
|
||||
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;
|
||||
|
||||
/* Copy little endian */
|
||||
memcpy(ubx_buffer, &ubx_header, 2); ubx_buffer += 2; /* Header */
|
||||
memcpy(ubx_buffer, &message, 2); ubx_buffer += 2; /* Message Type */
|
||||
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*/
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* Sends a UBX Poll Request
|
||||
* Polls the GPS for packets
|
||||
*/
|
||||
void _ubx_poll(uint16_t message) {
|
||||
void _ubx_poll(ubx_message_t* message) {
|
||||
/* Clear the packet state */
|
||||
message->state = UBX_PACKET_WAITING;
|
||||
|
||||
_ubx_send_message(message, NULL, 0);
|
||||
|
||||
/* Wait for acknoledge */
|
||||
while (message->state == UBX_PACKET_WAITING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,36 +261,65 @@ void _ubx_poll(uint16_t message) {
|
|||
*/
|
||||
void gps_disable_nmea(void)
|
||||
{
|
||||
for (int i = 0; i < 1000*100; i++);
|
||||
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 = 9600;
|
||||
ubx_cfg_prt.payload.inProtoMask = 0x7; /* UBX */
|
||||
ubx_cfg_prt.payload.outProtoMask = 0x1; /* UBX */
|
||||
ubx_cfg_prt.payload.flags = 0;
|
||||
|
||||
uint8_t setNMEAoff[] = {
|
||||
0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,
|
||||
0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
_ubx_send_message(UBX_CFG_PRT, setNMEAoff, sizeof(setNMEAoff)/sizeof(uint8_t));
|
||||
_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++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the navigation status to determine the quality of the
|
||||
* fix currently held by the receiver with a NAV-STATUS message.
|
||||
* Sends messages to the GPS to update the messages we want
|
||||
*/
|
||||
void gps_check_lock()
|
||||
void gps_update()
|
||||
{
|
||||
/* Send the poll request */
|
||||
_ubx_poll(UBX_NAV_SOL);
|
||||
_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_timeutc, NULL, 0);
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the uBlox 6 GPS receiver is set to the <1g airborne
|
||||
* navigaion mode.
|
||||
*/
|
||||
void gps_check_nav(void)
|
||||
void gps_set_platform_model(void)
|
||||
{
|
||||
/* Send the poll request */
|
||||
_ubx_poll(UBX_CFG_NAV5);
|
||||
_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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,60 +327,42 @@ void gps_check_nav(void)
|
|||
*/
|
||||
void gps_set_timepulse(void)
|
||||
{
|
||||
/* Clear the packet state */
|
||||
_ubx_cfg_tp_state = UBX_PACKET_WAITING;
|
||||
|
||||
/* Send the Request */
|
||||
_ubx_poll(UBX_CFG_TP);
|
||||
_ubx_poll((ubx_message_t*)&ubx_cfg_tp);
|
||||
|
||||
/* Define the settings we want */
|
||||
struct ubx_cfg_tp timepulse;
|
||||
memset(&timepulse, 0, sizeof(ubx_cfg_tp));
|
||||
timepulse.interval = 2; /* 2µS */
|
||||
timepulse.length = 1; /* 1µS */
|
||||
timepulse.status = 1; /* On, Positive */
|
||||
timepulse.timeRef = 1; /* Align GPS time */
|
||||
timepulse.flags = 0x1; /* Run outside lock */
|
||||
timepulse.antennaCableDelay = 50; /* 50 nS */
|
||||
ubx_cfg_tp.payload.interval = 2; /* 2µS */
|
||||
ubx_cfg_tp.payload.length = 1; /* 1µS */
|
||||
ubx_cfg_tp.payload.status = 1; /* On, Positive */
|
||||
ubx_cfg_tp.payload.timeRef = 1; /* Align GPS time */
|
||||
ubx_cfg_tp.payload.flags = 0x1; /* Run outside lock */
|
||||
ubx_cfg_tp.payload.antennaCableDelay = 50; /* 50 nS */
|
||||
|
||||
/* Wait for acknoledge */
|
||||
while (_ubx_cfg_tp_state == UBX_PACKET_WAITING);
|
||||
|
||||
/* Compare with current settings */
|
||||
if (memcmp((void*)&ubx_cfg_tp, &timepulse, sizeof(ubx_cfg_tp)) != 0) {
|
||||
/* Write the new settings */
|
||||
_ubx_send_message(UBX_CFG_TP, (uint8_t*)&timepulse, sizeof(ubx_cfg_tp));
|
||||
}
|
||||
/* Write the new settings */
|
||||
_ubx_send_message((ubx_message_t*)&ubx_cfg_tp,
|
||||
(uint8_t*)&ubx_cfg_tp.payload,
|
||||
sizeof(ubx_cfg_tp.payload));
|
||||
}
|
||||
/**
|
||||
* Set the GPS timepulse settings using the CFG_TP5 message
|
||||
*/
|
||||
void gps_set_timepulse_five(uint32_t frequency)
|
||||
{
|
||||
/* Clear the packet state */
|
||||
_ubx_cfg_tp5_state = UBX_PACKET_WAITING;
|
||||
|
||||
/* Send the Request */
|
||||
_ubx_poll(UBX_CFG_TP5);
|
||||
_ubx_poll((ubx_message_t*)&ubx_cfg_tp5);
|
||||
|
||||
/* Define the settings we want */
|
||||
struct ubx_cfg_tp5 timepulse5;
|
||||
memset(&timepulse5, 0, sizeof(ubx_cfg_tp5));
|
||||
timepulse5.tpIdx = 0;
|
||||
timepulse5.antCableDelay = 50; /* 50 nS */
|
||||
ubx_cfg_tp5.payload.tpIdx = 0;
|
||||
ubx_cfg_tp5.payload.antCableDelay = 50; /* 50 nS */
|
||||
/* GPS time, duty cyle, frequency, lock to GPS, active */
|
||||
timepulse5.flags = 0x80 | 0x8 | 0x3;
|
||||
timepulse5.freqPeriod = frequency;
|
||||
timepulse5.pulseLenRatio = 0x80000000; /* 50 % duty cycle*/
|
||||
ubx_cfg_tp5.payload.flags = 0x80 | 0x8 | 0x3;
|
||||
ubx_cfg_tp5.payload.freqPeriod = frequency;
|
||||
ubx_cfg_tp5.payload.pulseLenRatio = 0x80000000; /* 50 % duty cycle*/
|
||||
|
||||
/* Wait for acknoledge */
|
||||
while (_ubx_cfg_tp5_state == UBX_PACKET_WAITING);
|
||||
|
||||
/* Compare with current settings */
|
||||
if (memcmp((void*)&ubx_cfg_tp5, &timepulse5, sizeof(ubx_cfg_tp5)) != 0) {
|
||||
/* Write the new settings */
|
||||
_ubx_send_message(UBX_CFG_TP5, (uint8_t*)&timepulse5, sizeof(ubx_cfg_tp5));
|
||||
}
|
||||
/* Write the new settings */
|
||||
_ubx_send_message((ubx_message_t*)&ubx_cfg_tp5,
|
||||
(uint8_t*)&ubx_cfg_tp5.payload,
|
||||
sizeof(ubx_cfg_tp5.payload));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,13 +406,8 @@ void gps_init(void)
|
|||
/* Incoming ubx messages are handled in an irq */
|
||||
usart_register_rx_callback(GPS_SERCOM, gps_rx_callback, 0);
|
||||
|
||||
/* Fill some configuration structures */
|
||||
|
||||
gps_check_lock();
|
||||
_ubx_poll(UBX_CFG_ANT);
|
||||
|
||||
/* */
|
||||
gps_check_nav();
|
||||
/* Set the platform model */
|
||||
gps_set_platform_model();
|
||||
|
||||
/* Set the timepulse */
|
||||
gps_set_timepulse_five(GPS_TIMEPULSE_FREQ);
|
||||
|
@ -473,4 +454,3 @@ void usart_loopback_test(void)
|
|||
|
||||
semihost_printf("Rx'ed: 0x%02x\n", data);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,11 +31,14 @@
|
|||
#include "system/system.h"
|
||||
#include "sercom/usart.h"
|
||||
#include "system/port.h"
|
||||
#include "tc/tc_driver.h"
|
||||
#include "gps.h"
|
||||
#include "timepulse.h"
|
||||
//#include "si406x.h"
|
||||
#include "si4060.h"
|
||||
#include "spi_bitbang.h"
|
||||
#include "rtty.h"
|
||||
#include "system/interrupt.h"
|
||||
|
||||
void si4060_hw_init(void)
|
||||
{
|
||||
|
@ -58,23 +61,65 @@ void si4060_hw_init(void)
|
|||
/* Put the SEL pin in reset */
|
||||
_si406x_cs_disable();
|
||||
|
||||
/* Configure the serial port */
|
||||
spi_bitbang_init(SI406X_SERCOM_MOSI_PIN,
|
||||
SI406X_SERCOM_MISO_PIN,
|
||||
SI406X_SERCOM_SCK_PIN);
|
||||
}
|
||||
void si4060_gpio_init()
|
||||
{
|
||||
/* Configure the GPIO and IRQ pins */
|
||||
port_pin_set_config(SI406X_GPIO0_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
port_pin_set_output_level(SI406X_GPIO0_PIN, 0);
|
||||
|
||||
/* Configure the serial port */
|
||||
spi_bitbang_init(SI406X_SERCOM_MOSI_PIN,
|
||||
SI406X_SERCOM_MISO_PIN,
|
||||
SI406X_SERCOM_SCK_PIN);
|
||||
/* Configure the GPIO and IRQ pins */
|
||||
port_pin_set_config(SI406X_GPIO1_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 0);
|
||||
}
|
||||
void set_timer(uint32_t time)
|
||||
{
|
||||
bool capture_channel_enables[] = {false, false};
|
||||
uint32_t compare_channel_values[] = {time, 0x0000};
|
||||
|
||||
tc_init(TC2,
|
||||
GCLK_GENERATOR_0,
|
||||
TC_COUNTER_SIZE_32BIT,
|
||||
TC_CLOCK_PRESCALER_DIV1,
|
||||
TC_WAVE_GENERATION_NORMAL_FREQ,
|
||||
TC_RELOAD_ACTION_GCLK,
|
||||
TC_COUNT_DIRECTION_UP,
|
||||
TC_WAVEFORM_INVERT_OUTPUT_NONE,
|
||||
false, /* Oneshot = false */
|
||||
false, /* Run in standby = false */
|
||||
0x0000, /* Initial value */
|
||||
time+1, /* Top value */
|
||||
capture_channel_enables, /* Capture Channel Enables */
|
||||
compare_channel_values); /* Compare Channels Values */
|
||||
|
||||
struct tc_events ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.generate_event_on_compare_channel[0] = true;
|
||||
ev.event_action = TC_EVENT_ACTION_RETRIGGER;
|
||||
|
||||
tc_enable_events(TC2, &ev);
|
||||
|
||||
irq_register_handler(TC2_IRQn, 3);
|
||||
|
||||
tc_enable(TC2);
|
||||
tc_start_counter(TC2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Clock up to 28MHz with 1 wait state */
|
||||
system_flash_set_waitstates(1);
|
||||
/* Clock up to 14MHz with 0 wait states */
|
||||
system_flash_set_waitstates(SYSTEM_WAIT_STATE_1_8V_14MHZ);
|
||||
|
||||
/* Up the clock rate to 4MHz */
|
||||
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_2, /* Prescaler */
|
||||
|
@ -87,39 +132,19 @@ int main(void)
|
|||
/* Get the current CPU Clock */
|
||||
SystemCoreClock = system_cpu_clock_get_hz();
|
||||
|
||||
/* Set LED0 as output */
|
||||
//PORTA.DIRSET.reg = (1 << SI406X_HF_CLK_PIN);
|
||||
|
||||
/* Configure the SysTick for cpu/1000 output*//*for 50ms interrupts */
|
||||
//SysTick_Config(500); //SystemCoreClock / 20);
|
||||
|
||||
/* Configure Sleep Mode */
|
||||
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);
|
||||
//TODO: system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
|
||||
|
||||
semihost_printf("Hello World %fHz\n", RF_FREQ_HZ);
|
||||
|
||||
|
||||
/* Initialise GPS */
|
||||
gps_init();
|
||||
/* Wait for GPS timepulse to stabilise */
|
||||
for (int i = 0; i < 1000*100; i++);
|
||||
|
||||
|
||||
/* For the moment output GCLK_MAIN / 2 on HF CLK */
|
||||
switch_gclk_main_to_timepulse();
|
||||
/* Wait for GCLK to stabilise */
|
||||
for (int i = 0; i < 1000*100; i++);
|
||||
|
||||
//half_glck_main_on_hf_clk();
|
||||
timepulse_init();
|
||||
/* Wait for HF CLK to stabilise */
|
||||
for (int i = 0; i < 1000*100; i++);
|
||||
|
||||
semihost_printf("GCLK_MAIN = %d\n", gclk_main_frequency());
|
||||
|
||||
/* Drop the CPU clock to 1.5Mhz */
|
||||
//system_cpu_clock_set_divider(SYSTEM_MAIN_CLOCK_DIV_16);
|
||||
/* Configure the SysTick for 50Hz triggering */
|
||||
SysTick_Config(SystemCoreClock / 50);
|
||||
|
||||
/* Initialise Si4060 */
|
||||
si4060_hw_init();
|
||||
|
@ -133,30 +158,42 @@ int main(void)
|
|||
while(1);
|
||||
}
|
||||
|
||||
si4060_power_up();
|
||||
si4060_setup(MOD_TYPE_CW);
|
||||
si4060_start_tx(0);
|
||||
/* si4060_power_up(); */
|
||||
/* si4060_setup(MOD_TYPE_2FSK); */
|
||||
|
||||
uint32_t ll = 0;
|
||||
/* si4060_gpio_init(); */
|
||||
/* si4060_start_tx(0); */
|
||||
|
||||
/* Set the watchdog timer. On 32kHz ULP internal clock */
|
||||
/* wdt_set_config(true, /\* Lock WDT *\/ */
|
||||
/* true, /\* Enable WDT *\/ */
|
||||
/* GCLK_GENERATOR_4, /\* Clock Source *\/ */
|
||||
/* WDT_PERIOD_16384CLK, /\* Timeout Period *\/ */
|
||||
/* WDT_PERIOD_NONE, /\* Window Period *\/ */
|
||||
/* WDT_PERIOD_NONE); /\* Early Warning Period *\/ */
|
||||
|
||||
while (1) {
|
||||
semihost_printf("State is %d %d\n", si4060_get_state(), ll++);
|
||||
si4060_get_freq();
|
||||
for (int i = 0; i < 1000*10; i++);
|
||||
port_pin_set_output_level(SI406X_GPIO0_PIN, 0);
|
||||
//si4060_start_tx(0);
|
||||
for (int i = 0; i < 1000*10; i++);
|
||||
port_pin_set_output_level(SI406X_GPIO0_PIN, 1);
|
||||
/* Send the last packet */
|
||||
while (rtty_active());
|
||||
|
||||
/* Send requests to the gps */
|
||||
gps_update();
|
||||
|
||||
/* Wait between frames */
|
||||
for (int i = 0; i < 100*1000; i++);
|
||||
|
||||
/* Set the next packet */
|
||||
set_telemetry_string();
|
||||
|
||||
//system_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at 50Hz
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* Toggle LED0 */
|
||||
//PORTA.OUTTGL.reg = (1 << SI406X_HF_CLK_PIN);
|
||||
/* Output RTTY */
|
||||
rtty_tick();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Bit-bangs RTTY
|
||||
* 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/port.h"
|
||||
|
||||
/**
|
||||
* Interface to the physical world.
|
||||
*/
|
||||
#define RTTY_ACTIVATE()
|
||||
#define RTTY_DEACTIVATE()
|
||||
#define RTTY_SET(b) port_pin_set_output_level(SI406X_GPIO1_PIN, b);
|
||||
#define RTTY_NEXT()
|
||||
|
||||
/**
|
||||
* Formatting 8N2
|
||||
*/
|
||||
#define ASCII_BITS 8
|
||||
#define BITS_PER_CHAR 11
|
||||
|
||||
/**
|
||||
* Output String
|
||||
*/
|
||||
#define RTTY_STRING_MAX 0x200
|
||||
|
||||
/**
|
||||
* Where we currently are in the rtty output byte
|
||||
*
|
||||
* 0 = Start Bit
|
||||
* 1-8 = Data Bit
|
||||
* 10 = Stop Bit
|
||||
* 11 = Stop Bit
|
||||
*/
|
||||
uint8_t rtty_phase;
|
||||
/**
|
||||
* Where we are in the current output string
|
||||
*/
|
||||
uint32_t rtty_index;
|
||||
|
||||
/**
|
||||
* Details of the string that is currently being output
|
||||
*/
|
||||
char rtty_string[RTTY_STRING_MAX];
|
||||
uint32_t rtty_string_length = 0;
|
||||
|
||||
/**
|
||||
* Returns 1 if we're currently outputting.
|
||||
*/
|
||||
int rtty_active(void) {
|
||||
return (rtty_string_length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an output string.
|
||||
*
|
||||
* Returns 0 on success, 1 if a string is already active or 2 if the
|
||||
* specified string was too long.
|
||||
*/
|
||||
int rtty_set_string(char* string, uint32_t length) {
|
||||
if (length > RTTY_STRING_MAX) return 2; // To long
|
||||
|
||||
if (!rtty_active()) {
|
||||
// Copy
|
||||
memcpy(rtty_string, string, length);
|
||||
rtty_string_length = length;
|
||||
// Initialise
|
||||
rtty_index = 0;
|
||||
rtty_phase = 0;
|
||||
|
||||
return 0; // Success
|
||||
} else {
|
||||
return 1; // Already active
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at the baud rate, outputs bits of rtty
|
||||
*/
|
||||
void rtty_tick(void) {
|
||||
if (rtty_active()) {
|
||||
RTTY_ACTIVATE();
|
||||
|
||||
if (rtty_phase == 0) { // Start
|
||||
// Low
|
||||
//RTTY_SET(0);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 0);
|
||||
} else if (rtty_phase < ASCII_BITS + 1) {
|
||||
// Data
|
||||
if ((rtty_string[rtty_index] >> (rtty_phase - 1)) & 1) {
|
||||
//RTTY_SET(1);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 1);
|
||||
} else {
|
||||
//RTTY_SET(0);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 0);
|
||||
}
|
||||
} else if (rtty_phase < BITS_PER_CHAR) { // Stop
|
||||
// High
|
||||
//RTTY_SET(1);
|
||||
port_pin_set_output_level(SI406X_GPIO1_PIN, 1);
|
||||
}
|
||||
|
||||
rtty_phase++;
|
||||
|
||||
if (rtty_phase >= BITS_PER_CHAR) { // Next character
|
||||
rtty_phase = 0; rtty_index++; RTTY_NEXT();
|
||||
|
||||
if (rtty_index >= rtty_string_length) { // All done, deactivate
|
||||
rtty_string_length = 0; // Deactivate
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// RTTY_DEACTIVATE();
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ void si4060_power_up(void) {
|
|||
spi_select();
|
||||
spi_write(CMD_POWER_UP);
|
||||
spi_write(FUNC);
|
||||
spi_write(0x01);/* TCXO used */
|
||||
spi_write(0x00);/* TCXO not used */
|
||||
spi_write((uint8_t) (XO_FREQ >> 24));
|
||||
spi_write((uint8_t) (XO_FREQ >> 16));
|
||||
spi_write((uint8_t) (XO_FREQ >> 8));
|
||||
|
@ -393,8 +393,8 @@ void si4060_setup(uint8_t mod_type) {
|
|||
GLOBAL_CONFIG,
|
||||
GLOBAL_RESERVED | POWER_MODE_HIGH_PERF | SEQUENCER_MODE_FAST);
|
||||
/* set up GPIOs */
|
||||
si4060_gpio_pin_cfg(GPIO_MODE_DONOTHING,
|
||||
GPIO_MODE_DONOTHING,
|
||||
si4060_gpio_pin_cfg(GPIO_MODE_INPUT,
|
||||
PULL_CTL + GPIO_MODE_INPUT,
|
||||
GPIO_MODE_DONOTHING,
|
||||
PULL_CTL + GPIO_MODE_INPUT,
|
||||
DRV_STRENGTH_HIGH);
|
||||
|
@ -409,7 +409,7 @@ void si4060_setup(uint8_t mod_type) {
|
|||
/* use 2FSK from async GPIO0 */
|
||||
si4060_set_property_8(PROP_MODEM,
|
||||
MODEM_MOD_TYPE,
|
||||
(mod_type & 0x07) | MOD_SOURCE_DIRECT | MOD_GPIO_0 | MOD_DIRECT_MODE_ASYNC);
|
||||
(mod_type & 0x07) | MOD_SOURCE_DIRECT | MOD_GPIO_1 | MOD_DIRECT_MODE_ASYNC);
|
||||
/* setup frequency deviation */
|
||||
si4060_set_property_24(PROP_MODEM,
|
||||
MODEM_FREQ_DEV,
|
||||
|
|
|
@ -506,7 +506,7 @@ void tc_set_top_value(Tc* const hw,
|
|||
* \param[in] events Struct containing flags of events to enable
|
||||
*/
|
||||
void tc_enable_events(Tc* const hw,
|
||||
struct tc_events *const events)
|
||||
struct tc_events *const events)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
assert(hw);
|
||||
|
@ -679,7 +679,7 @@ enum tc_status_t tc_init(Tc* const hw,
|
|||
/* Write Start Value */
|
||||
tc_set_count_value(hw, value);
|
||||
|
||||
/* Write Top Value - Only cool for 8 bit!*/
|
||||
/* Write Top Value */
|
||||
tc_set_top_value(hw, top_value);
|
||||
|
||||
/* Write Compare Values */
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Telemetry strings and formatting
|
||||
* 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 "samd20.h"
|
||||
#include "semihosting.h"
|
||||
#include "gps.h"
|
||||
#include "ubx_messages.h"
|
||||
|
||||
#define SEMIHOST_LOG
|
||||
|
||||
char telemetry_string[0x200];
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void set_telemetry_string(void)
|
||||
{
|
||||
/* Time */
|
||||
struct ubx_nav_timeutc time = gps_get_nav_timeutc();
|
||||
uint8_t hours = time.payload.hour;
|
||||
uint8_t minutes = time.payload.min;
|
||||
uint8_t seconds = time.payload.sec;
|
||||
|
||||
/* GPS Position */
|
||||
struct ubx_nav_posllh pos = gps_get_nav_posllh();
|
||||
double lat_fmt = (double)pos.payload.lat / 10000000.0;
|
||||
double lon_fmt = (double)pos.payload.lon / 10000000.0;
|
||||
uint32_t altitude = pos.payload.height / 1000;
|
||||
|
||||
/* GPS Status */
|
||||
struct ubx_nav_sol sol = gps_get_nav_sol();
|
||||
uint8_t fix_type = sol.payload.gpsFix;
|
||||
uint8_t satillite_count = sol.payload.numSV;
|
||||
|
||||
/* Analogue */
|
||||
|
||||
|
||||
#ifdef SEMIHOST_LOG
|
||||
|
||||
semihost_printf("%02.7f,%03.7f,%ld", lat_fmt, lon_fmt, altitude);
|
||||
semihost_printf("Fix: %d Sats: %d\n", fix_type, satillite_count);
|
||||
semihost_printf("%02u:%02u:%02u\n", hours, minutes, seconds);
|
||||
|
||||
|
||||
#else
|
||||
/* sprintf */
|
||||
sprintf(telemetry_string, "$$emf,%02.7f,%03.7f,%ld,%u",
|
||||
lat_fmt, lon_fmt, altitude, ubx_nav_sol.numSV);
|
||||
|
||||
rtty_set_string(telemetry_string, strlen(telemetry_string));
|
||||
#endif
|
||||
}
|
Ładowanie…
Reference in New Issue