kopia lustrzana https://github.com/bristol-seds/pico-tracker
CW output on a version fitted with a 16MHz crystal
rodzic
4c908d1448
commit
847d674373
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 60 KiB |
|
@ -56,6 +56,36 @@ volatile struct ubx_cfg_nav5 {
|
|||
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
|
||||
*/
|
||||
|
@ -106,6 +136,19 @@ volatile struct ubx_nav_sol {
|
|||
uint32_t res2;
|
||||
} __PACKED__ ubx_nav_sol;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
|
|
@ -76,8 +76,19 @@
|
|||
#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 24000000
|
||||
// 32768
|
||||
#define GPS_PLATFORM_MODEL UBX_PLATFORM_MODEL_AIRBORNE_1G
|
||||
|
||||
/* Loopback Testing */
|
||||
/**
|
||||
* DFLL48
|
||||
*/
|
||||
#define DFLL48M_GCLK GCLK_GENERATOR_0
|
||||
#define DFLL48M_CLK 48000000
|
||||
|
||||
/**
|
||||
* USART Loopback Testing
|
||||
*/
|
||||
#define USART_MUX_LOOPBACK USART_RX_0_TX_0_XCK_1
|
||||
|
||||
/**
|
||||
|
@ -102,21 +113,25 @@
|
|||
/**
|
||||
* Radio
|
||||
*/
|
||||
#define RADIO_SERCOM (SercomSpi*)SERCOM3
|
||||
#define RADIO_SERCOM_MOSI_PIN PIN_PA19
|
||||
#define RADIO_SERCOM_MOSI_PINMUX PINMUX_PA19D_SERCOM3_PAD3
|
||||
#define RADIO_SERCOM_MISO_PIN PIN_PA22
|
||||
#define RADIO_SERCOM_MISO_PINMUX PINMUX_PA22C_SERCOM3_PAD0
|
||||
#define RADIO_SERCOM_SCK_PIN PIN_PA23
|
||||
#define RADIO_SERCOM_SCK_PINMUX PINMUX_PA23C_SERCOM3_PAD1
|
||||
#define RADIO_SEL_PIN PIN_PA18
|
||||
#define RADIO_IRQ_PIN PIN_PA24
|
||||
#define RADIO_IRQ_PINMUX PINMUX_PA24A_EIC_EXTINT12
|
||||
#define RADIO_HF_CLK_PIN PIN_PA17
|
||||
#define RADIO_HF_CLK_PINMUX PINMUX_PA17H_GCLK_IO3
|
||||
#define RADIO_SDN_PIN PIN_PA16
|
||||
#define RADIO_GPIO0_PIN PIN_PA27
|
||||
#define RADIO_GPIO1_PIN PIN_PA25 /* Shared with LED */
|
||||
#define SI406X_SERCOM (SercomSpi*)SERCOM3
|
||||
#define SI406X_SERCOM_MOSI_PIN PIN_PA19
|
||||
#define SI406X_SERCOM_MOSI_PINMUX PINMUX_PA19D_SERCOM3_PAD3
|
||||
#define SI406X_SERCOM_MISO_PIN PIN_PA22
|
||||
#define SI406X_SERCOM_MISO_PINMUX PINMUX_PA22C_SERCOM3_PAD0
|
||||
#define SI406X_SERCOM_SCK_PIN PIN_PA23
|
||||
#define SI406X_SERCOM_SCK_PINMUX PINMUX_PA23C_SERCOM3_PAD1
|
||||
#define SI406X_SERCOM_MUX SPI_SIGNAL_MUX_SETTING_D
|
||||
#define SI406X_SEL_PIN PIN_PA18
|
||||
#define SI406X_IRQ_PIN PIN_PA24
|
||||
#define SI406X_IRQ_PINMUX PINMUX_PA24A_EIC_EXTINT12
|
||||
#define SI406X_HF_GCLK GCLK_GENERATOR_3
|
||||
#define SI406X_HF_CLK_PIN PIN_PA17
|
||||
#define SI406X_HF_CLK_PINMUX PINMUX_PA17H_GCLK_IO3
|
||||
/* Currently half GPS TIMEPULSE */
|
||||
#define SI406X_HF_FREQUENCY (GPS_TIMEPULSE_FREQ / 2)
|
||||
#define SI406X_SDN_PIN PIN_PA16
|
||||
#define SI406X_GPIO0_PIN PIN_PA27
|
||||
#define SI406X_GPIO1_PIN PIN_PA25 /* Shared with LED */
|
||||
|
||||
/**
|
||||
* SWD
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* si4060 software library
|
||||
*
|
||||
* Stefan Biereigel
|
||||
*
|
||||
*/
|
||||
#ifndef SI4060_H_
|
||||
#define SI4060_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "samd20.h"
|
||||
#include "system/port.h"
|
||||
#include "hw_config.h"
|
||||
|
||||
|
||||
/**
|
||||
* Chip Select. Active Low (High = Inactive, Low = Active)
|
||||
*/
|
||||
#define _si406x_cs_enable() \
|
||||
port_pin_set_output_level(SI406X_SEL_PIN, 0)
|
||||
#define _si406x_cs_disable() \
|
||||
port_pin_set_output_level(SI406X_SEL_PIN, 1)
|
||||
|
||||
#define spi_select _si406x_cs_enable
|
||||
#define spi_deselect _si406x_cs_disable
|
||||
#define spi_write spi_bitbang_transfer
|
||||
#define spi_read() spi_bitbang_transfer(0xff)
|
||||
|
||||
#define __delay_cycles(n) do { \
|
||||
for (int cyc = 0; cyc < n; cyc++) { __NOP(); } \
|
||||
} while(0)
|
||||
|
||||
void si4060_shutdown(void);
|
||||
|
||||
|
||||
#define XO_FREQ 16000000UL
|
||||
#define RF_FREQ_HZ 434600000.0f
|
||||
#define RF_DEV_HZ 100.0f
|
||||
|
||||
#define F_INT (2 * XO_FREQ / 8)
|
||||
#define FDIV_INTE ( (RF_FREQ_HZ / F_INT) - 1)
|
||||
#define FDIV_FRAC ( (RF_FREQ_HZ - F_INT*(int)FDIV_INTE) * ((uint32_t)1 << 19) ) / F_INT
|
||||
#define FDEV ( ( ( (uint32_t)1 << 19) * 8 * RF_DEV_HZ)/ (2*XO_FREQ))
|
||||
|
||||
/* function prototypes */
|
||||
void si4060_shutdown (void);
|
||||
void si4060_wakeup (void);
|
||||
void si4060_reset (void);
|
||||
void si4060_power_up (void);
|
||||
void si4060_nop (void);
|
||||
uint8_t si4060_get_state(void);
|
||||
void si4060_get_freq(void);
|
||||
|
||||
void si4060_start_tx (uint8_t channel);
|
||||
void si4060_stop_tx (void);
|
||||
void si4060_setup (uint8_t mod_type);
|
||||
uint8_t si4060_get_property_8 (uint8_t group, uint8_t prop);
|
||||
uint16_t si4060_part_info (void);
|
||||
|
||||
/* ===== command definitions ===== */
|
||||
#define CMD_NOP 0x00
|
||||
#define CMD_PART_INFO 0x01
|
||||
#define CMD_POWER_UP 0x02
|
||||
#define CMD_SET_PROPERTY 0x11
|
||||
#define CMD_GET_PROPERTY 0x12
|
||||
#define CMD_GPIO_PIN_CFG 0x13
|
||||
#define CMD_START_TX 0x31
|
||||
#define CMD_REQUEST_STATE 0x33
|
||||
#define CMD_CHANGE_STATE 0x34
|
||||
#define CMD_READ_CMD_BUF 0x44
|
||||
|
||||
/* ===== device states ===== */
|
||||
#define STATE_NOCHANGE 0x00
|
||||
#define STATE_SLEEP 0x01
|
||||
#define STATE_SPI_ACTIVE 0x02
|
||||
#define STATE_READY 0x03
|
||||
#define STATE_TX_TUNE 0x05
|
||||
#define STATE_TXA 0x07
|
||||
|
||||
/* ===== property group definitions ===== */
|
||||
#define PROP_GLOBAL 0x00
|
||||
#define PROP_INT_CTL 0x01
|
||||
#define PROP_FRR_CTL 0x02
|
||||
#define PROP_PREAMBLE 0x10
|
||||
#define PROP_SYNC 0x11
|
||||
#define PROP_PKT 0x12
|
||||
#define PROP_MODEM 0x20
|
||||
#define PROP_PA 0x22
|
||||
#define PROP_SYNTH 0x23
|
||||
#define PROP_FREQ_CONTROL 0x40
|
||||
|
||||
/* ===== property definitions ===== */
|
||||
/* global properties */
|
||||
#define GLOBAL_XO_TUNE 0x00
|
||||
#define GLOBAL_CONFIG 0x03
|
||||
/* preamble properties */
|
||||
#define PREAMBLE_TX_LENGTH 0x00
|
||||
/* sync properties */
|
||||
#define SYNC_CONFIG 0x11
|
||||
/* modem properties */
|
||||
#define MODEM_MOD_TYPE 0x00
|
||||
#define MODEM_FREQ_DEV 0x0a
|
||||
#define MODEM_FREQ_OFFSET 0x0d
|
||||
#define MODEM_CLKGEN_BAND 0x51
|
||||
/* PA properties */
|
||||
#define PA_MODE 0x00
|
||||
#define PA_PWR_LVL 0x01
|
||||
#define PA_BIAS_CLKDUTY 0x02
|
||||
/* synthesizer properties */
|
||||
#define SYNTH_PFDCP_CPFF 0x00
|
||||
#define SYNTH_PFDCP_CPINT 0x01
|
||||
#define SYNTH_VCO_KV 0x02
|
||||
#define SYNTH_LPFILT3 0x03
|
||||
#define SYNTH_LPFILT2 0x04
|
||||
#define SYNTH_LPFILT1 0x05
|
||||
#define SYNTH_LPFILT0 0x06
|
||||
#define SYNTH_VCO_KVCAL 0x07
|
||||
/* frequency control properties */
|
||||
/* INTE shall be decreased by 1, because FRAC shall be between 1 and 2 */
|
||||
#define FREQ_CONTROL_INTE 0x00
|
||||
/* FRAC shall be added to 2**19, to ensure MSB is set! */
|
||||
#define FREQ_CONTROL_FRAC 0x01
|
||||
#define FREQ_CONTROL_CHANNEL_STEP_SIZE 0x04
|
||||
#define FREQ_CONTROL_W_SIZE 0x06
|
||||
|
||||
/* ===== command arguments ===== */
|
||||
/* POWER_UP arguments */
|
||||
/* byte 1 */
|
||||
#define PATCH ( 0x01 << 7) /* set patch mode */
|
||||
#define FUNC 0x01 /* power on device */
|
||||
/* byte 2 */
|
||||
#define TCXO 0x01/* select if TCXO (1) or crystal (0) is used */
|
||||
|
||||
/* GPIO_PIN_CFG arguments */
|
||||
/* bytes 1 .. 6 */
|
||||
#define PULL_CTL 0x40 /* enable or disable pull-up resistor */
|
||||
/* bytes 1 .. 4 */
|
||||
#define GPIO_MODE_DONOTHING 0x00/* pin behaviour is not changed */
|
||||
#define GPIO_MODE_TRISTATE 0x01/* input and output drivers are disabled */
|
||||
#define GPIO_MODE_DRIVE0 0x02/* CMOS output "low" */
|
||||
#define GPIO_MODE_DRIVE1 0x03/* CMOS output "high" */
|
||||
#define GPIO_MODE_INPUT 0x04/* GPIO is input, for TXDATA etc, function is not configured here */
|
||||
#define GPIO_MODE_32K_CLK 0x05/* outputs the 32kHz CLK when selected in CLK32_CLK_SEL */
|
||||
#define GPIO_MODE_BOOT_CLK 0x06/* outputs boot clock when SPI_ACTIVE */
|
||||
#define GPIO_MODE_DIV_CLK 0x07/* outputs divided xtal clk */
|
||||
#define GPIO_MODE_CTS 0x08/* output, '1' when device is ready to accept new command */
|
||||
#define GPIO_MODE_INV_CNT 0x09/* output, inverted CTS */
|
||||
#define GPIO_MODE_CMD_OVERLAP 0x0a/* output, '1' if a command was issued while not ready */
|
||||
#define GPIO_MODE_SDO 0x0b/* output, serial data out for SPI */
|
||||
#define GPIO_MODE_POR 0x0c/* output, '0' while in POR state */
|
||||
#define GPIO_MODE_CAL_WUT 0x0d/* output, '1' on expiration of wake up timer */
|
||||
#define GPIO_MODE_WUT 0x0e/* wake up timer output */
|
||||
#define GPIO_MODE_EN_PA 0x0f/* output, '1' when PA is enabled */
|
||||
#define GPIO_MODE_TX_DATA_CLK 0x10/* data clock output, for TX direct sync mode */
|
||||
#define GPIO_MODE_TX_DATA 0x11/* data output from TX FIFO, for debugging purposes */
|
||||
#define GPIO_MODE_IN_SLEEP 0x12/* output, '0' when in sleep state */
|
||||
#define GPIO_MODE_TX_STATE 0x13/* output, '1' when in TX state */
|
||||
#define GPIO_MODE_TX_FIFO_EMPTY 0x14/* output, '1' when FIFO is empty */
|
||||
#define GPIO_MODE_LOW_BATT 0x15/* output, '1' if low battery is detected */
|
||||
/* byte 5 omitted - no IRQ support */
|
||||
#define NIRQ_MODE_DONOTHING 0x00
|
||||
/* byte 6 omitted - no SDO reconfiguration support */
|
||||
#define SDO_MODE_DONOTHING 0x00
|
||||
/* byte 7 */
|
||||
#define DRV_STRENGTH_HIGH ( 0x00 << 5)
|
||||
#define DRV_STRENGTH_MED_HIGH ( 0x01 << 5)
|
||||
#define DRV_STRENGTH_MED_LOW ( 0x02 << 5)
|
||||
#define DRV_STRENGTH_LOW ( 0x03 << 5)
|
||||
|
||||
/* START_TX arguments */
|
||||
/* byte 2 */
|
||||
#define START_TX_TXC_STATE_NOCHANGE ( 0x00 << 4)
|
||||
#define START_TX_TXC_STATE_SLEEP ( 0x01 << 4)
|
||||
#define START_TX_TXC_STATE_SPI_ACTIVE ( 0x02 << 4)
|
||||
#define START_TX_TXC_STATE_READY ( 0x03 << 4)
|
||||
#define START_TX_RETRANSMIT_0 ( 0x00 << 2)/* send data that has been written to the TX FIFO */
|
||||
#define START_TX_START_IMM ( 0x00 << 0)/* start transmission immediately */
|
||||
|
||||
/* ===== property values ===== */
|
||||
/* GLOBAL_CONFIG values */
|
||||
#define GLOBAL_RESERVED ( 0x01 << 6) /* shall be set to 1 */
|
||||
#define POWER_MODE_LOW_POWER 0x00/* default */
|
||||
#define POWER_MODE_HIGH_PERF 0x01
|
||||
#define SEQUENCER_MODE_FAST ( 0x00 << 5)/* default */
|
||||
#define SEQUENCER_MODE_GUARANT ( 0x01 << 5)
|
||||
/* SYNC_CONFIG values */
|
||||
#define SYNC_XMIT ( 0x00 << 7)/* default */
|
||||
#define SYNC_NO_XMIT ( 0x01 << 7)
|
||||
/* MODEM_MOD_TYPE values */
|
||||
#define MOD_TYPE_CW 0x00
|
||||
#define MOD_TYPE_OOK 0x01
|
||||
#define MOD_TYPE_2FSK 0x02/* default */
|
||||
#define MOD_TYPE_2GFSK 0x03
|
||||
#define MOD_TYPE_4FSK 0x04
|
||||
#define MOD_TYPE_4GFSK 0x05
|
||||
#define MOD_SOURCE_PACKET ( 0x00 << 3) /* default */
|
||||
#define MOD_SOURCE_DIRECT ( 0x01 << 3)
|
||||
#define MOD_SOURCE_PSEUDO ( 0x02 << 3)
|
||||
#define MOD_GPIO_0 ( 0x00 << 5) /* default */
|
||||
#define MOD_GPIO_1 ( 0x01 << 5)
|
||||
#define MOD_GPIO_2 ( 0x02 << 5)
|
||||
#define MOD_GPIO_3 ( 0x03 << 5)
|
||||
#define MOD_DIRECT_MODE_SYNC ( 0x00 << 7) /* default */
|
||||
#define MOD_DIRECT_MODE_ASYNC ( 0x01 << 7)
|
||||
/* MODEM_CLKGEN_BAND values */
|
||||
#define SY_SEL_0 ( 0x00 << 3) /* low power */
|
||||
#define SY_SEL_1 ( 0x01 << 3) /* default */
|
||||
#define FVCO_DIV_4 0x00 /* default */
|
||||
#define FVCO_DIV_6 0x01
|
||||
#define FVCO_DIV_8 0x02 /* for 70cm ISM band */
|
||||
#define FVCO_DIV_12 0x03
|
||||
#define FVCO_DIV_16 0x04
|
||||
#define FVCO_DIV_24 0x05
|
||||
#define FVCO_DIV_24_2 0x06
|
||||
#define FVCO_DIV_24_3 0x07
|
||||
/* PA_MODE values*/
|
||||
/* PA_BIAS_CLKDUTY values */
|
||||
#define PA_BIAS_CLKDUTY_SIN_25 (0x03 << 6) /* for si4060 */
|
||||
#define PA_BIAS_CLKDUTY_DIFF_50 (0x00 << 6) /* for si4063 */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* <one line to give the program's name and a brief idea of what it does.>
|
||||
* 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 SI406X_H
|
||||
#define SI406X_H
|
||||
|
||||
void si406x_init(void);
|
||||
void spi_loopback_test(void);
|
||||
|
||||
#endif /* SI406X_H */
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Definitions and macros for the Si406x
|
||||
* 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 SI406X_DEFS_H
|
||||
#define SI406X_DEFS_H
|
||||
|
||||
/**
|
||||
* Si406x Boot Commands
|
||||
*/
|
||||
enum {
|
||||
SI_CMD_POWER_UP = 0x02,
|
||||
};
|
||||
/**
|
||||
* Si406x Common Commands
|
||||
*/
|
||||
enum {
|
||||
SI_CMD_NOP = 0x00,
|
||||
SI_CMD_PART_INFO = 0x01,
|
||||
SI_CMD_FUNC_INFO = 0x10,
|
||||
SI_CMD_SET_PROPERTY = 0x11,
|
||||
SI_CMD_GET_PROPERTY = 0x12,
|
||||
SI_CMD_GPIO_PIN_CFG = 0x13,
|
||||
SI_CMD_FIFO_INFO = 0x15,
|
||||
SI_CMD_GET_INT_STATUS = 0x20,
|
||||
SI_CMD_REQUEST_DEVICE_STATE = 0x33,
|
||||
SI_CMD_CHANGE_STATE = 0x34,
|
||||
SI_CMD_READ_CMD_BUFF = 0x44,
|
||||
SI_CMD_FRR_A_READ = 0x50,
|
||||
SI_CMD_FRR_B_READ = 0x51,
|
||||
SI_CMD_FRR_C_READ = 0x53,
|
||||
SI_CMD_FRR_D_READ = 0x57,
|
||||
};
|
||||
/**
|
||||
* Si406x Tx Commands
|
||||
*/
|
||||
enum {
|
||||
SI_CMD_START_TX = 0x31,
|
||||
SI_CMD_WRITE_TX_FIFO = 0x66,
|
||||
};
|
||||
/**
|
||||
* Si406x Rx Commands
|
||||
*/
|
||||
enum {
|
||||
SI_CMD_PACKET_INFO = 0x16,
|
||||
SI_CMD_GET_MODEM_STATUS = 0x22,
|
||||
SI_CMD_START_RX = 0x32,
|
||||
SI_CMD_RX_HOP = 0x36,
|
||||
SI_CMD_READ_RX_FIFO = 0x77,
|
||||
};
|
||||
/**
|
||||
* Si406x Advanced Commands
|
||||
*/
|
||||
enum {
|
||||
SI_CMD_GET_ADC_READING = 0x14,
|
||||
SI_CMD_PROTOCOL_CFG = 0x18,
|
||||
SI_CMD_GET_PH_STATUS = 0x21,
|
||||
SI_CMD_GET_CHIP_STATUS = 0x23,
|
||||
};
|
||||
|
||||
/**
|
||||
* Si406x State Change Commands
|
||||
*/
|
||||
enum {
|
||||
SI_STATE_CHANGE_NOCHANGE = (0 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_SLEEP = (1 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_SPI_ACTIVE = (2 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_READY = (3 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_TX_TUNE = (5 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_RX_TUNE = (6 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_TX = (7 << 8) | SI_CMD_CHANGE_STATE,
|
||||
SI_STATE_CHANGE_RX = (8 << 8) | SI_CMD_CHANGE_STATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic SPI Send / Receive for the Si406x
|
||||
*/
|
||||
void _si406x_transfer(int tx_count, int rx_count, const uint8_t *data);
|
||||
|
||||
/**
|
||||
* Chip Select. Active Low (High = Inactive, Low = Active)
|
||||
*/
|
||||
#define _si406x_cs_enable() \
|
||||
port_pin_set_output_level(SI406X_SEL_PIN, 0)
|
||||
#define _si406x_cs_disable() \
|
||||
port_pin_set_output_level(SI406X_SEL_PIN, 1)
|
||||
|
||||
/**
|
||||
* Shutdown. Active High (High = Shutdown, Low = Run)
|
||||
*/
|
||||
#define _si406x_sdn_enable() \
|
||||
port_pin_set_output_level(SI406X_SDN_PIN, 1)
|
||||
#define _si406x_sdn_disable() \
|
||||
port_pin_set_output_level(SI406X_SDN_PIN, 0)
|
||||
|
||||
/**
|
||||
* HF Clock
|
||||
*/
|
||||
#define _si406x_hf_clock_enable(void) \
|
||||
/* TODO: Clock is always enabled */
|
||||
#define _si406x_hf_clock_disable(void) \
|
||||
/* TODO: Clock is always enabled */
|
||||
|
||||
|
||||
/**
|
||||
* Convenience transfer functions
|
||||
*/
|
||||
static void _si406x_transfer_uint16(uint16_t value)
|
||||
{
|
||||
_si406x_transfer(2, 0, (uint8_t*)&value);
|
||||
}
|
||||
|
||||
/**
|
||||
* State changes
|
||||
*/
|
||||
#define si406x_state_ready() \
|
||||
_si406x_transfer_uint16(SI_STATE_CHANGE_READY)
|
||||
/**
|
||||
* Change to TX tune state
|
||||
*/
|
||||
#define si406x_state_tx_tune() \
|
||||
_si406x_transfer_uint16(SI_STATE_CHANGE_TX_TUNE)
|
||||
/**
|
||||
* Change to RX tune state
|
||||
*/
|
||||
#define si406x_state_rx_tune() \
|
||||
_si406x_transfer_uint16(SI_STATE_CHANGE_RX_TUNE)
|
||||
/**
|
||||
* Change to TX state
|
||||
*/
|
||||
#define si406x_state_tx() \
|
||||
_si406x_transfer_uint16(SI_STATE_CHANGE_TX)
|
||||
/**
|
||||
* Change to RX state
|
||||
*/
|
||||
#define si406x_state_rx() \
|
||||
_si406x_transfer_uint16(SI_STATE_CHANGE_RX)
|
||||
|
||||
|
||||
|
||||
#endif /* SI406X_DEFS_H */
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPI bit-banging! Yay
|
||||
* 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 SPI_BITBANG_H
|
||||
#define SPI_BITBANG_H
|
||||
|
||||
void spi_bitbang_init(const uint8_t mosi,
|
||||
const uint8_t miso,
|
||||
const uint8_t sck);
|
||||
uint8_t spi_bitbang_transfer(const uint8_t byte);
|
||||
|
||||
#endif /* SPI_BITBANG_H */
|
|
@ -82,7 +82,7 @@
|
|||
# define CONF_CLOCK_OSC32K_RUN_IN_STANDBY false
|
||||
|
||||
/* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */
|
||||
# define CONF_CLOCK_DFLL_ENABLE true
|
||||
# define CONF_CLOCK_DFLL_ENABLE false
|
||||
# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN
|
||||
# define CONF_CLOCK_DFLL_ON_DEMAND false
|
||||
|
||||
|
|
|
@ -272,10 +272,6 @@
|
|||
* device is two when running in 32-bit mode and four in 8-, and 16-bit modes.
|
||||
*/
|
||||
|
||||
//#include <clock.h>
|
||||
//#include <gclk.h>
|
||||
//#include <pinmux.h>
|
||||
|
||||
#include "samd20.h"
|
||||
#include "tc.h"
|
||||
#include <stdbool.h>
|
||||
|
@ -522,15 +518,15 @@ struct tc_pwm_channel {
|
|||
};
|
||||
|
||||
|
||||
static inline void tc_enable(Tc* const hw);
|
||||
static inline void tc_disable(Tc* const hw);
|
||||
void tc_enable(Tc* const hw);
|
||||
void tc_disable(Tc* const hw);
|
||||
|
||||
static inline void tc_start_counter(Tc* const hw);
|
||||
static inline void tc_stop_counter(Tc* const hw);
|
||||
void tc_start_counter(Tc* const hw);
|
||||
void tc_stop_counter(Tc* const hw);
|
||||
|
||||
static inline uint32_t tc_get_status(Tc* const hw);
|
||||
static inline void tc_clear_status(Tc* const hw,
|
||||
const uint32_t status_flags);
|
||||
uint32_t tc_get_status(Tc* const hw);
|
||||
void tc_clear_status(Tc* const hw,
|
||||
const uint32_t status_flags);
|
||||
|
||||
void tc_set_count_value(Tc* const hw, const uint32_t count);
|
||||
uint32_t tc_get_count_value(Tc* const hw);
|
||||
|
@ -546,9 +542,9 @@ void tc_reset(Tc* const hw);
|
|||
void tc_set_top_value (Tc* const hw,
|
||||
const uint32_t top_value);
|
||||
|
||||
static inline void tc_enable_events(Tc* const hw,
|
||||
void tc_enable_events(Tc* const hw,
|
||||
struct tc_events *const events);
|
||||
static inline void tc_disable_events(Tc* const hw,
|
||||
void tc_disable_events(Tc* const hw,
|
||||
struct tc_events *const events);
|
||||
|
||||
enum tc_status_t tc_init(Tc* const hw,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Functions for turning the GPS timepulse into a HF Clock
|
||||
* 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 TIMEPULSE_H
|
||||
#define TIMEPULSE_H
|
||||
|
||||
void timepulse_init(void);
|
||||
void switch_gclk_main_to_timepulse(void);
|
||||
|
||||
#endif /* TIMEPULSE_H */
|
|
@ -67,8 +67,10 @@ enum {
|
|||
*/
|
||||
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
|
||||
|
@ -77,19 +79,6 @@ enum {
|
|||
UBX_ACK_NACK = (UBX_ACK | (0x00 << 8)),
|
||||
UBX_ACK_ACK = (UBX_ACK | (0x01 << 8)),
|
||||
};
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
|
||||
#define UBX_BUFFER_LEN 0x80
|
||||
|
||||
|
@ -110,7 +99,33 @@ uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
|
|||
#define _get_buffer(rx_data, length) \
|
||||
usart_read_buffer_wait(GPS_SERCOM, rx_data, length)
|
||||
|
||||
/**
|
||||
* Flags for pending ubx pakcets
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Processes UBX ack/nack packets
|
||||
*/
|
||||
void ubx_process_ack(uint16_t message, 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;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Macro for the function below
|
||||
*/
|
||||
|
@ -118,7 +133,6 @@ uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
|
|||
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.
|
||||
*/
|
||||
|
@ -150,14 +164,25 @@ void ubx_process_frame(uint8_t* frame)
|
|||
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:
|
||||
switch (frame16[0]) {
|
||||
case UBX_ACK_ACK:
|
||||
break;
|
||||
case UBX_ACK_NACK:
|
||||
break;
|
||||
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:
|
||||
|
@ -293,6 +318,67 @@ void gps_check_nav(void)
|
|||
_ubx_poll(UBX_CFG_NAV5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the GPS timepulse settings using the CFG_TP message
|
||||
*/
|
||||
void gps_set_timepulse(void)
|
||||
{
|
||||
/* Clear the packet state */
|
||||
_ubx_cfg_tp_state = UBX_PACKET_WAITING;
|
||||
|
||||
/* Send the Request */
|
||||
_ubx_poll(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 */
|
||||
|
||||
/* 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));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/* 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 */
|
||||
/* GPS time, duty cyle, frequency, lock to GPS, active */
|
||||
timepulse5.flags = 0x80 | 0x8 | 0x3;
|
||||
timepulse5.freqPeriod = frequency;
|
||||
timepulse5.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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init
|
||||
*/
|
||||
|
@ -334,9 +420,16 @@ void gps_init(void)
|
|||
/* Incoming ubx messages are handled in an irq */
|
||||
usart_register_rx_callback(GPS_SERCOM, gps_rx_callback, 0);
|
||||
|
||||
gps_check_nav();
|
||||
/* Fill some configuration structures */
|
||||
|
||||
gps_check_lock();
|
||||
_ubx_poll(UBX_CFG_ANT);
|
||||
|
||||
/* */
|
||||
gps_check_nav();
|
||||
|
||||
/* Set the timepulse */
|
||||
gps_set_timepulse_five(GPS_TIMEPULSE_FREQ);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,49 +30,129 @@
|
|||
#include "hw_config.h"
|
||||
#include "system/system.h"
|
||||
#include "sercom/usart.h"
|
||||
#include "system/port.h"
|
||||
#include "gps.h"
|
||||
#include "timepulse.h"
|
||||
//#include "si406x.h"
|
||||
#include "si4060.h"
|
||||
#include "spi_bitbang.h"
|
||||
|
||||
void si4060_hw_init(void)
|
||||
{
|
||||
/* Configure the SDN pin */
|
||||
port_pin_set_config(SI406X_SDN_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Put the SI406x in shutdown */
|
||||
//_si406x_sdn_enable();
|
||||
si4060_shutdown();
|
||||
|
||||
/* Configure the SDN pin */
|
||||
port_pin_set_config(SI406X_SEL_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Put the SEL pin in reset */
|
||||
_si406x_cs_disable();
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SystemInit();
|
||||
/* Clock up to 28MHz with 1 wait state */
|
||||
system_flash_set_waitstates(1);
|
||||
|
||||
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_1, /* Prescaler */
|
||||
/* Up the clock rate to 4MHz */
|
||||
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_2, /* Prescaler */
|
||||
false, /* Run in Standby */
|
||||
false); /* Run on Demand */
|
||||
|
||||
/* Update the value of SystemCoreClock */
|
||||
SystemCoreClockUpdate();
|
||||
/* Restart the GCLK Module */
|
||||
system_gclk_init();
|
||||
|
||||
/* Get the current CPU Clock */
|
||||
SystemCoreClock = system_cpu_clock_get_hz();
|
||||
|
||||
/* Set LED0 as output */
|
||||
PORTA.DIRSET.reg = (1 << LED0_PIN);
|
||||
//PORTA.DIRSET.reg = (1 << SI406X_HF_CLK_PIN);
|
||||
|
||||
/* Configure the SysTick for 50ms interrupts */
|
||||
SysTick_Config(SystemCoreClock / 20);
|
||||
/* 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);
|
||||
|
||||
volatile double d, dd;
|
||||
semihost_printf("Hello World %fHz\n", RF_FREQ_HZ);
|
||||
|
||||
d = 2;
|
||||
dd = sqrt(d);
|
||||
|
||||
semihost_printf("Hello World %f\n", dd);
|
||||
|
||||
/* 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();
|
||||
//half_glck_main_on_hf_clk();
|
||||
/* 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);
|
||||
|
||||
/* Initialise Si4060 */
|
||||
si4060_hw_init();
|
||||
|
||||
/* reset the radio chip from shutdown */
|
||||
si4060_reset();
|
||||
|
||||
/* check radio communication */
|
||||
int i = si4060_part_info();
|
||||
if (i != 0x4063) {
|
||||
while(1);
|
||||
}
|
||||
|
||||
si4060_power_up();
|
||||
si4060_setup(MOD_TYPE_CW);
|
||||
si4060_start_tx(0);
|
||||
|
||||
uint32_t ll = 0;
|
||||
|
||||
while (1) {
|
||||
//system_sleep();
|
||||
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);
|
||||
|
||||
for (int i = 0; i < 1000*1000; i++);
|
||||
gps_check_lock();
|
||||
|
||||
|
||||
|
||||
//system_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* Toggle LED0 */
|
||||
PORTA.OUTTGL.reg = (1 << LED0_PIN);
|
||||
//PORTA.OUTTGL.reg = (1 << SI406X_HF_CLK_PIN);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* si4060 software library
|
||||
*
|
||||
* API description: see EZRadioPRO-API-v1.1.2.zip
|
||||
*
|
||||
* Stefan Biereigel
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "spi_bitbang.h"
|
||||
#include "si4060.h"
|
||||
#include "samd20.h"
|
||||
#include "semihosting.h"
|
||||
#include "hw_config.h"
|
||||
#include "system/port.h"
|
||||
|
||||
/*
|
||||
* si4060_shutdown
|
||||
*
|
||||
* makes the Si4060 go to shutdown state.
|
||||
* all register content is lost.
|
||||
*/
|
||||
void si4060_shutdown(void) {
|
||||
//P1OUT |= SI_SHDN;
|
||||
port_pin_set_output_level(SI406X_SDN_PIN, 1);
|
||||
/* wait 10us */
|
||||
__delay_cycles(2000);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_wakeup
|
||||
*
|
||||
* wakes up the Si4060 from shutdown state.
|
||||
* si4060_power_up and si4060_setup have to be called afterwards
|
||||
*/
|
||||
void si4060_wakeup(void) {
|
||||
//P1OUT &= ~SI_SHDN;
|
||||
port_pin_set_output_level(SI406X_SDN_PIN, 0);
|
||||
/* wait 20ms */
|
||||
__delay_cycles(20000);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_reset
|
||||
*
|
||||
* cleanly does the POR as specified in datasheet
|
||||
*/
|
||||
void si4060_reset(void) {
|
||||
si4060_shutdown();
|
||||
si4060_wakeup();
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_read_cmd_buf
|
||||
*
|
||||
* reads the Si4060 command buffer from via SPI
|
||||
*
|
||||
* deselect: whether to deselect the slave after reading the response or not.
|
||||
* any command reading subsequent bytes after the CTS should use this
|
||||
* function to get CTS and continue doing spi_read afterwards
|
||||
* and finally deselecting the slave.
|
||||
*
|
||||
* returns:the value of the first command buffer byte (i.e. CTS or not)
|
||||
*/
|
||||
uint8_t si4060_read_cmd_buf(uint8_t deselect) {
|
||||
uint8_t ret;
|
||||
spi_select();
|
||||
spi_write(CMD_READ_CMD_BUF);
|
||||
ret = spi_read();
|
||||
if (deselect) {
|
||||
spi_deselect();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_power_up
|
||||
*
|
||||
* powers up the Si4060 by issuing the POWER_UP command
|
||||
*
|
||||
* warning: the si4060 can lock after issuing this command if input clock
|
||||
* is not available for the internal RC oscillator calibration.
|
||||
*/
|
||||
void si4060_power_up(void) {
|
||||
/* wait for CTS */
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
spi_select();
|
||||
spi_write(CMD_POWER_UP);
|
||||
spi_write(FUNC);
|
||||
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));
|
||||
spi_write((uint8_t) XO_FREQ);
|
||||
spi_deselect();
|
||||
/* wait for CTS */
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_change_state
|
||||
*
|
||||
* changes the internal state machine state of the Si4060
|
||||
*/
|
||||
void si4060_change_state(uint8_t state) {
|
||||
spi_select();
|
||||
spi_write(CMD_CHANGE_STATE);
|
||||
spi_write(state);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_nop
|
||||
*
|
||||
* implements the NOP command on the Si4060
|
||||
*/
|
||||
void si4060_nop(void) {
|
||||
spi_select();
|
||||
spi_write(CMD_NOP);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_set_property_8
|
||||
*
|
||||
* sets an 8 bit (1 byte) property in the Si4060
|
||||
*
|
||||
* group:the group number of the property
|
||||
* prop:the number (index) of the property
|
||||
* val:the value to set
|
||||
*/
|
||||
void si4060_set_property_8(uint8_t group, uint8_t prop, uint8_t val) {
|
||||
spi_select();
|
||||
spi_write(CMD_SET_PROPERTY);
|
||||
spi_write(group);
|
||||
spi_write(1);
|
||||
spi_write(prop);
|
||||
spi_write(val);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_get_property_8
|
||||
*
|
||||
* gets an 8 bit (1 byte) property in the Si4060
|
||||
*
|
||||
* group:the group number of the property
|
||||
* prop:the number (index) of the property
|
||||
*
|
||||
* returns:the value of the property
|
||||
*/
|
||||
uint8_t si4060_get_property_8(uint8_t group, uint8_t prop) {
|
||||
uint8_t temp = 0;
|
||||
spi_select();
|
||||
spi_write(CMD_GET_PROPERTY);
|
||||
spi_write(group);
|
||||
spi_write(1);
|
||||
spi_write(prop);
|
||||
spi_deselect();
|
||||
while (temp != 0xff) {
|
||||
temp = si4060_read_cmd_buf(0);
|
||||
if (temp != 0xff) {
|
||||
spi_deselect();
|
||||
}
|
||||
}
|
||||
temp = spi_read(); /* read property */
|
||||
spi_deselect();
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_set_property_16
|
||||
*
|
||||
* sets an 16 bit (2 byte) property in the Si4060
|
||||
*
|
||||
* group:the group number of the property
|
||||
* prop:the number (index) of the property
|
||||
* val:the value to set
|
||||
*/
|
||||
void si4060_set_property_16(uint8_t group, uint8_t prop, uint16_t val) {
|
||||
spi_select();
|
||||
spi_write(CMD_SET_PROPERTY);
|
||||
spi_write(group);
|
||||
spi_write(2);
|
||||
spi_write(prop);
|
||||
spi_write(val >> 8);
|
||||
spi_write(val);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_set_property_24
|
||||
*
|
||||
* sets an 24 bit (3 byte) property in the Si4060
|
||||
*
|
||||
* group:the group number of the property
|
||||
* prop:the number (index) of the property
|
||||
* val:the value to set
|
||||
*/
|
||||
void si4060_set_property_24(uint8_t group, uint8_t prop, uint32_t val) {
|
||||
spi_select();
|
||||
spi_write(CMD_SET_PROPERTY);
|
||||
spi_write(group);
|
||||
spi_write(3);
|
||||
spi_write(prop);
|
||||
spi_write(val >> 16);
|
||||
spi_write(val >> 8);
|
||||
spi_write(val);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_set_property_32
|
||||
*
|
||||
* sets an 32 bit (4 byte) property in the Si4060
|
||||
*
|
||||
* group:the group number of the property
|
||||
* prop:the number (index) of the property
|
||||
* val:the value to set
|
||||
*/
|
||||
void si4060_set_property_32(uint8_t group, uint8_t prop, uint32_t val) {
|
||||
spi_select();
|
||||
spi_write(CMD_SET_PROPERTY);
|
||||
spi_write(group);
|
||||
spi_write(4);
|
||||
spi_write(prop);
|
||||
spi_write(val >> 24);
|
||||
spi_write(val >> 16);
|
||||
spi_write(val >> 8);
|
||||
spi_write(val);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_gpio_pin_cfg
|
||||
*
|
||||
* configures the GPIOs on the Si4060
|
||||
* see the GPIO_*-defines for reference
|
||||
*
|
||||
* gpio(0..3):setting flags for respective GPIOs
|
||||
* drvstrength:the driver strength
|
||||
*/
|
||||
void si4060_gpio_pin_cfg(uint8_t gpio0, uint8_t gpio1, uint8_t gpio2, uint8_t gpio3, uint8_t drvstrength) {
|
||||
spi_select();
|
||||
spi_write(CMD_GPIO_PIN_CFG);
|
||||
spi_write(gpio0);
|
||||
spi_write(gpio1);
|
||||
spi_write(gpio2);
|
||||
spi_write(gpio3);
|
||||
spi_write(NIRQ_MODE_DONOTHING);
|
||||
spi_write(SDO_MODE_DONOTHING);
|
||||
spi_write(drvstrength);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_part_info
|
||||
*
|
||||
* gets the PART_ID from the Si4060
|
||||
* this can be used to check for successful communication.
|
||||
* as the SPI bus returns 0xFF (MISO=high) when no slave is connected,
|
||||
* reading CTS can not verify communication to the Si4060.
|
||||
*
|
||||
* returns:the PART_ID - should be 0x4060
|
||||
*/
|
||||
uint16_t si4060_part_info(void) {
|
||||
uint16_t temp;
|
||||
|
||||
temp = 0;
|
||||
spi_select();
|
||||
spi_write(CMD_PART_INFO);
|
||||
spi_deselect();
|
||||
/* do not deselect after reading CTS */
|
||||
while (temp != 0xff) {
|
||||
temp = si4060_read_cmd_buf(0);
|
||||
if (temp != 0xff) {
|
||||
spi_deselect();
|
||||
}
|
||||
}
|
||||
spi_read(); /* ignore CHIPREV */
|
||||
temp = spi_read(); /* read PART[0] */
|
||||
temp = temp << 8;
|
||||
temp |= spi_read(); /* read PART[1] */
|
||||
spi_deselect();
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* si4060_get_state
|
||||
*
|
||||
* gets the current state of the Si4060
|
||||
*/
|
||||
uint8_t si4060_get_state(void)
|
||||
{
|
||||
uint16_t temp;
|
||||
|
||||
temp = 0;
|
||||
spi_select();
|
||||
spi_write(CMD_REQUEST_STATE);
|
||||
spi_deselect();
|
||||
/* do not deselect after reading CTS */
|
||||
while (temp != 0xff) {
|
||||
temp = si4060_read_cmd_buf(0);
|
||||
if (temp != 0xff) {
|
||||
spi_deselect();
|
||||
}
|
||||
}
|
||||
temp = spi_read() & 0x0F; /* Get MAIN_STATE */
|
||||
spi_deselect();
|
||||
return temp;
|
||||
}
|
||||
/**
|
||||
* si4060_get_freq
|
||||
*/
|
||||
void si4060_get_freq(void)
|
||||
{
|
||||
uint32_t inte, frac;
|
||||
uint16_t temp;
|
||||
|
||||
spi_select();
|
||||
spi_write(CMD_GET_PROPERTY);
|
||||
spi_write(PROP_FREQ_CONTROL);
|
||||
spi_write(0x4);
|
||||
spi_write(FREQ_CONTROL_INTE);
|
||||
spi_deselect();
|
||||
/* do not deselect after reading CTS */
|
||||
while (temp != 0xff) {
|
||||
temp = si4060_read_cmd_buf(0);
|
||||
if (temp != 0xff) {
|
||||
spi_deselect();
|
||||
}
|
||||
}
|
||||
|
||||
inte = spi_read(); /* Get FREQ_CONTROL_INTE */
|
||||
|
||||
frac = (spi_read() << 16); /* Get FREQ_CONTROL_FRAC MSB */
|
||||
frac |= (spi_read() << 8); /* Get FREQ_CONTROL_FRAC */
|
||||
frac |= (spi_read() << 0); /* Get FREQ_CONTROL_FRAC LSB */
|
||||
spi_deselect();
|
||||
|
||||
semihost_printf("INTE = 0x%02x, FRAC = 0x%06x\n", inte, frac);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_start_tx
|
||||
*
|
||||
* starts transmission by the Si4060.
|
||||
*
|
||||
* channel:the channel to start transmission on
|
||||
*/
|
||||
void si4060_start_tx(uint8_t channel) {
|
||||
spi_select();
|
||||
spi_write(CMD_START_TX);
|
||||
spi_write(channel);
|
||||
spi_write(START_TX_TXC_STATE_SLEEP | START_TX_RETRANSMIT_0 | START_TX_START_IMM);
|
||||
/* set length to 0 for direct mode (is this correct?) */
|
||||
spi_write(0x00);
|
||||
spi_write(0x00);
|
||||
spi_deselect();
|
||||
while (si4060_read_cmd_buf(1) != 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_stop_tx
|
||||
*
|
||||
* makes the Si4060 stop all transmissions by transistioning to SLEEP state
|
||||
*/
|
||||
void si4060_stop_tx(void) {
|
||||
si4060_change_state(STATE_SLEEP);
|
||||
}
|
||||
|
||||
/*
|
||||
* si4060_setup
|
||||
*
|
||||
* initializes the Si4060 by setting all neccesary internal registers.
|
||||
* has to be called after si4060_power_up.
|
||||
*
|
||||
* mod_type:the type of modulation to use, use the MODEM_MOD_TYPE values (MOD_TYPE_*)
|
||||
*/
|
||||
void si4060_setup(uint8_t mod_type) {
|
||||
|
||||
/* set high performance mode */
|
||||
si4060_set_property_8(PROP_GLOBAL,
|
||||
GLOBAL_CONFIG,
|
||||
GLOBAL_RESERVED | POWER_MODE_HIGH_PERF | SEQUENCER_MODE_FAST);
|
||||
/* set up GPIOs */
|
||||
si4060_gpio_pin_cfg(GPIO_MODE_DONOTHING,
|
||||
GPIO_MODE_DONOTHING,
|
||||
GPIO_MODE_DONOTHING,
|
||||
PULL_CTL + GPIO_MODE_INPUT,
|
||||
DRV_STRENGTH_HIGH);
|
||||
/* disable preamble */
|
||||
si4060_set_property_8(PROP_PREAMBLE,
|
||||
PREAMBLE_TX_LENGTH,
|
||||
0);
|
||||
/* do not transmit sync word */
|
||||
si4060_set_property_8(PROP_SYNC,
|
||||
SYNC_CONFIG,
|
||||
SYNC_NO_XMIT);
|
||||
/* 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);
|
||||
/* setup frequency deviation */
|
||||
si4060_set_property_24(PROP_MODEM,
|
||||
MODEM_FREQ_DEV,
|
||||
(uint32_t)FDEV);
|
||||
/* setup frequency deviation offset */
|
||||
si4060_set_property_16(PROP_MODEM,
|
||||
MODEM_FREQ_OFFSET,
|
||||
0x0000);
|
||||
/* setup divider to 8 (for 70cm ISM band */
|
||||
si4060_set_property_8(PROP_MODEM,
|
||||
MODEM_CLKGEN_BAND,
|
||||
SY_SEL_1 | FVCO_DIV_8);
|
||||
/* set up the PA power level */
|
||||
si4060_set_property_8(PROP_PA,
|
||||
PA_PWR_LVL,
|
||||
0x3f);
|
||||
/* set up the PA duty cycle */
|
||||
si4060_set_property_8(PROP_PA,
|
||||
PA_BIAS_CLKDUTY,
|
||||
PA_BIAS_CLKDUTY_DIFF_50);
|
||||
/* set up the integer divider */
|
||||
si4060_set_property_8(PROP_FREQ_CONTROL,
|
||||
FREQ_CONTROL_INTE,
|
||||
(uint8_t)(FDIV_INTE));
|
||||
/* set up the fractional divider */
|
||||
si4060_set_property_24(PROP_FREQ_CONTROL,
|
||||
FREQ_CONTROL_FRAC,
|
||||
(uint32_t)(FDIV_FRAC));
|
||||
/* TODO set the channel step size (if SPI frequency changing is used) */
|
||||
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Functions for controlling Si406x radios
|
||||
* 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 "system/port.h"
|
||||
#include "spi_bitbang.h"
|
||||
#include "si406x_defs.h"
|
||||
#include "hw_config.h"
|
||||
|
||||
#define RADIO_FREQ 434600000
|
||||
// Quite low power
|
||||
#define RADIO_PWR 0x7f
|
||||
#define VCXO_FREQ SI406X_HF_FREQUENCY
|
||||
|
||||
uint32_t active_freq = RADIO_FREQ;
|
||||
uint8_t active_pwr = RADIO_PWR;
|
||||
uint16_t si446x_powerlevel = RADIO_PWR;
|
||||
|
||||
/**
|
||||
* Generic SPI Send / Receive for the Si406x
|
||||
*/
|
||||
void _si406x_transfer(int tx_count, int rx_count, const uint8_t *data)
|
||||
{
|
||||
uint8_t response[100];
|
||||
|
||||
/* Send command */
|
||||
_si406x_cs_enable();
|
||||
|
||||
for (int i = 0; i < tx_count; i++) {
|
||||
spi_bitbang_transfer(data[i]);
|
||||
}
|
||||
|
||||
_si406x_cs_disable();
|
||||
|
||||
/**
|
||||
* Poll CTS. From the docs:
|
||||
*
|
||||
* READ_CMD_BUFF is used to poll the CTS signal via the SPI bus. The
|
||||
* NSEL line should be pulled low, followed by sending the
|
||||
* READ_CMD_BUFF command on SDI. While NSEL remains asserted low, an
|
||||
* additional eight clock pulses are sent on SCLK and the CTS
|
||||
* response byte is read on SDO. If the CTS response byte is not
|
||||
* 0xFF, the host MCU should pull NSEL high and repeat the polling
|
||||
* procedure.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 20000; i++); // 20µS
|
||||
_si406x_cs_enable();
|
||||
|
||||
do {
|
||||
/* Issue READ_CMD_BUFF */
|
||||
spi_bitbang_transfer(SI_CMD_READ_CMD_BUFF);
|
||||
response[0] = spi_bitbang_transfer(0xFF);
|
||||
|
||||
/* If the reply is 0xFF, read the response */
|
||||
if (response[0] == 0xFF) break;
|
||||
|
||||
/* Otherwise repeat the procedure */
|
||||
_si406x_cs_disable();
|
||||
for (int i = 0; i < 200; i++); // 20µS
|
||||
_si406x_cs_enable();
|
||||
|
||||
} while (1); /* TODO: Timeout? */
|
||||
|
||||
/**
|
||||
* Read response. From the docs:
|
||||
*
|
||||
* If the CTS response byte is 0xFF, the host MCU should keep NSEL
|
||||
* asserted low and provide additional clock cycles on SCLK to read
|
||||
* out as many response bytes (on SDO) as necessary. The host MCU
|
||||
* should pull NSEL high upon completion of reading the response
|
||||
* stream.
|
||||
*/
|
||||
for (int i = 1; i < rx_count; i++) {
|
||||
response[i] = spi_bitbang_transfer(0xFF);
|
||||
}
|
||||
|
||||
_si406x_cs_disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Si406x synthesiser to the given frequency
|
||||
*/
|
||||
static void si406x_set_frequency(uint32_t frequency)
|
||||
{
|
||||
uint8_t outdiv, band;
|
||||
|
||||
if (frequency < 705000000UL) {
|
||||
outdiv = 6; band = 1;
|
||||
}
|
||||
if (frequency < 525000000UL) {
|
||||
if (VCXO_FREQ < 24000000) { // clock < 24mhz
|
||||
outdiv = 4; band = 0;
|
||||
} else {
|
||||
outdiv = 8; band = 2;
|
||||
}
|
||||
}
|
||||
if (frequency < 353000000UL) {
|
||||
outdiv = 12; band = 3;
|
||||
}
|
||||
if (frequency < 239000000UL) {
|
||||
outdiv = 16; band = 4;
|
||||
}
|
||||
if (frequency < 177000000UL) {
|
||||
outdiv = 24; band = 5;
|
||||
}
|
||||
|
||||
uint32_t f_pfd = 2 * VCXO_FREQ / outdiv;
|
||||
|
||||
uint16_t n = ((uint16_t)(frequency / f_pfd)) - 1;
|
||||
|
||||
float ratio = (float)frequency / (float)f_pfd;
|
||||
float rest = ratio - (float)n;
|
||||
|
||||
uint32_t m = (uint32_t)(rest * 524288UL); // 2^19
|
||||
|
||||
// set the band parameter
|
||||
uint8_t sy_sel = 8;
|
||||
uint8_t set_band_property_command[] = {0x11, 0x20, 0x01, 0x51, (band + sy_sel)};
|
||||
// send parameters
|
||||
_si406x_transfer(5, 1, set_band_property_command);
|
||||
|
||||
// Set the pll parameters
|
||||
uint16_t m2 = m / 0x10000;
|
||||
uint16_t m1 = (m - m2 * 0x10000) / 0x100;
|
||||
uint16_t m0 = (m - m2 * 0x10000 - m1 * 0x100);
|
||||
|
||||
// assemble parameter string
|
||||
const uint8_t set_frequency_control_inte[] = {0x11, 0x40, 0x04, 0x00, n, m2, m1, m0};
|
||||
// const uint8_t set_frequency_control_inte[] = {
|
||||
// 0x11, 0x40, 0x08, 0x00, n, m2, m1, m0, 0x0B, 0x61, 0x20, 0xFA};
|
||||
//const uint8_t set_frequency_control_inte[] = {0x11, 0x40, 0x08, 0x00, n, m2, m1, m0, 0x0B, 0x61, 0x20, 0xFA};
|
||||
|
||||
// send parameters
|
||||
_si406x_transfer(8, 1, set_frequency_control_inte);
|
||||
|
||||
// Read parameters
|
||||
const uint8_t get_frequency_control[] = { 0x12, 0x40, 0x04, 0x00 };
|
||||
_si406x_transfer(4, 5, get_frequency_control);
|
||||
}
|
||||
|
||||
void si406x_init(void)
|
||||
{
|
||||
/* Configure the SDN pin */
|
||||
port_pin_set_config(SI406X_SDN_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Put the SI406x in shutdown */
|
||||
_si406x_sdn_enable();
|
||||
|
||||
/* Configure the SDN pin */
|
||||
port_pin_set_config(SI406X_SEL_PIN,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Put the SEL pin in reset */
|
||||
_si406x_cs_disable();
|
||||
|
||||
/* Configure the GPIO and IRQ pins */
|
||||
|
||||
/* Configure the serial port */
|
||||
spi_bitbang_init(SI406X_SERCOM_MOSI_PIN,
|
||||
SI406X_SERCOM_MISO_PIN,
|
||||
SI406X_SERCOM_SCK_PIN);
|
||||
|
||||
/* Boot */
|
||||
for (int i = 0; i < 15*10000; i++); // 15ms
|
||||
_si406x_sdn_disable();
|
||||
for (int i = 0; i < 15*10000; i++); // 15ms
|
||||
|
||||
const uint8_t PART_INFO_command[] = {0x01}; // Part Info
|
||||
_si406x_transfer(1, 9, PART_INFO_command);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the modem into CW mode
|
||||
*/
|
||||
static void si446xSetModem(void)
|
||||
{
|
||||
// Set to CW mode
|
||||
const uint8_t set_modem_mod_type_command[] = {0x11, 0x20, 0x01, 0x00, 0x00};
|
||||
_si406x_transfer(5, 1, set_modem_mod_type_command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tx power
|
||||
*/
|
||||
void si446xSetPower(uint8_t pwr)
|
||||
{
|
||||
// Set the Power
|
||||
// uint8_t set_pa_pwr_lvl_property_command[] = {0x11, 0x22, 0x01, 0x01, pwr};
|
||||
// _si406x_transfer(5, 1, set_pa_pwr_lvl_property_command);
|
||||
}
|
||||
|
||||
// Config reset ----------------------------------------------------------
|
||||
static void si446xReset(void)
|
||||
{
|
||||
// _si406x_hf_clock_enable();
|
||||
_si406x_sdn_enable(); // active high shutdown = reset
|
||||
|
||||
for (int i = 0; i < 15*10000; i++); // 15ms
|
||||
_si406x_sdn_disable(); // booting
|
||||
for (int i = 0; i < 15*10000; i++); // 15ms
|
||||
|
||||
|
||||
const uint8_t PART_INFO_command[] = {0x01}; // Part Info
|
||||
_si406x_transfer(1, 9, PART_INFO_command);
|
||||
|
||||
//divide VCXO_FREQ into its bytes; MSB first
|
||||
uint16_t x3 = VCXO_FREQ / 0x1000000;
|
||||
uint16_t x2 = (VCXO_FREQ - x3 * 0x1000000) / 0x10000;
|
||||
uint16_t x1 = (VCXO_FREQ - x3 * 0x1000000 - x2 * 0x10000) / 0x100;
|
||||
uint16_t x0 = (VCXO_FREQ - x3 * 0x1000000 - x2 * 0x10000 - x1 * 0x100);
|
||||
|
||||
/* ---- POWER_UP ---- */
|
||||
/* no patch, boot main app. img, FREQ_VCXO, return 1 byte */
|
||||
/* */
|
||||
const uint8_t init_command[] = {0x02, 0x01, 0x01, x3, x2, x1, x0};
|
||||
_si406x_transfer(7, 1 , init_command);
|
||||
|
||||
|
||||
// Clear all pending interrupts and get the interrupt status back
|
||||
const uint8_t get_int_status_command[] = {0x20, 0x00, 0x00, 0x00};
|
||||
_si406x_transfer(4, 9, get_int_status_command);
|
||||
// cliPrint("Radio ready\n");
|
||||
|
||||
const uint8_t set_int_ctrl_enable[] = {0x11, 0x01, 0x01, 0x00, 0x00};
|
||||
_si406x_transfer(5, 1, set_int_ctrl_enable);
|
||||
// cliPrint("Setting no Interrupts (see WDS)\n");
|
||||
|
||||
// Set all GPIOs LOW; Link NIRQ to CTS; Link SDO to MISO; Max drive strength
|
||||
const uint8_t gpio_pin_cfg_command[] = {0x13, 0x02, 0x02, 0x02, 0x02, 0x08, 0x0B, 0x00};
|
||||
_si406x_transfer(8, 8, gpio_pin_cfg_command);
|
||||
// cliPrint("LEDs should be switched off at this point\n");
|
||||
|
||||
//const uint8_t set_global_config1[] = {0x11, 0x00, 0x01, 0x03, 0x60};
|
||||
//_si406x_transfer(5, 1, set_global_config1);
|
||||
// Sequencer Mode = Fast, Fifo = Half Duplex
|
||||
// cliPrint("Setting special global Config 1 changes (see WDS)\n");
|
||||
|
||||
// const uint8_t set_global_xo_tune_command[] = {0x11, 0x00, 0x01, 0x00, 0x00};
|
||||
//_si406x_transfer(5, 1, set_global_xo_tune_command);
|
||||
// cliPrint("Setting no additional capacitance on VXCO\n");
|
||||
|
||||
si406x_set_frequency(active_freq);
|
||||
|
||||
si446xSetPower(active_pwr);
|
||||
|
||||
si446xSetModem();
|
||||
// cliPrint("CW mode set\n");
|
||||
|
||||
si406x_state_tx_tune();
|
||||
// cliPrint("TX tune\n");
|
||||
}
|
||||
|
||||
void si446xPTTOn(void)
|
||||
{
|
||||
si446xReset();
|
||||
|
||||
// turn on the LED (GPIO0) to indicate TX
|
||||
// Set GPIOs LOW; Link NIRQ to CTS; Link SDO to MISO; Max drive strength
|
||||
const uint8_t gpio_pin_cfg_command2[] = {0x13, 0x02, 0x02, 0x02, 0x02, 0x08, 0x0B, 0x00};
|
||||
_si406x_transfer(8, 1, gpio_pin_cfg_command2);
|
||||
|
||||
si406x_state_tx();
|
||||
|
||||
const uint8_t get_state[] = {0x33};
|
||||
_si406x_transfer(1, 3, get_state);
|
||||
}
|
||||
|
||||
void si446xPTTOff(void)
|
||||
{
|
||||
si406x_state_ready();
|
||||
|
||||
// turn off the LED (GPIO1)
|
||||
// Set GPIO0 HIGH
|
||||
const uint8_t gpio_pin_cfg_command0[] = {0x13, 0x03, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00};
|
||||
_si406x_transfer(8, 1, gpio_pin_cfg_command0);
|
||||
|
||||
_si406x_sdn_enable(); // active high = shutdown
|
||||
_si406x_hf_clock_disable(); // keep enabled for now
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick and dirty loopback test. Should print 0x34
|
||||
*/
|
||||
void spi_loopback_test(void)
|
||||
{
|
||||
/* spi_init(SI406X_SERCOM, */
|
||||
/* SPI_MODE_MASTER, /\** SPI mode *\/ */
|
||||
/* SPI_DATA_ORDER_MSB, /\** Data order *\/ */
|
||||
/* SPI_TRANSFER_MODE_0, /\** Transfer mode *\/ */
|
||||
/* SI406X_SERCOM_MUX, /\** Mux setting *\/ */
|
||||
/* SPI_CHARACTER_SIZE_8BIT, /\** SPI character size *\/ */
|
||||
/* false, /\** Enabled in sleep *\/ */
|
||||
/* true, /\** Enable receiver *\/ */
|
||||
/* 100000, /\** Master - Baud rate *\/ */
|
||||
/* 0, /\** Slave - Frame format *\/ */
|
||||
/* 0, /\** Slave - Address mode *\/ */
|
||||
/* 0, /\** Slave - Address *\/ */
|
||||
/* 0, /\** Slave - Address mask *\/ */
|
||||
/* false, /\** Slave - Preload data *\/ */
|
||||
/* GCLK_GENERATOR_0, /\** GCLK generator to use *\/ */
|
||||
/* SI406X_SERCOM_MOSI_PINMUX, /\** Pinmux *\/ */
|
||||
/* SI406X_SERCOM_MISO_PINMUX, /\** Pinmux *\/ */
|
||||
/* SI406X_SERCOM_SCK_PINMUX, /\** Pinmux *\/ */
|
||||
/* PINMUX_UNUSED); /\** Pinmux *\/ */
|
||||
|
||||
/* Init loopback */
|
||||
spi_bitbang_init(SI406X_SERCOM_MOSI_PIN,
|
||||
SI406X_SERCOM_MOSI_PIN,
|
||||
SI406X_SERCOM_SCK_PIN);
|
||||
|
||||
/* Enable */
|
||||
|
||||
/* Test transfer */
|
||||
uint8_t data = spi_bitbang_transfer(0x34);
|
||||
|
||||
/* Print result */
|
||||
semihost_printf("Rx'ed: 0x%02x\n", data);
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* SPI bit-banging! Yay
|
||||
* 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 "system/port.h"
|
||||
|
||||
|
||||
/** Should be at least 20ns or something. Why am I bit-banging this? */
|
||||
#define BIT_DELAY __NOP
|
||||
|
||||
#define BIT_TOGGLE(bit) do { \
|
||||
PORTA.OUTTGL.reg = bit; } while (0)
|
||||
#define BIT_SET(bit) do { \
|
||||
PORTA.OUTSET.reg = bit; } while (0)
|
||||
#define BIT_CLEAR(bit) do { \
|
||||
PORTA.OUTCLR.reg = bit; } while (0)
|
||||
#define BIT_READ(bit) (PORTA.IN.reg & bit)
|
||||
|
||||
uint32_t mosi_mask = 0;
|
||||
uint32_t miso_mask = 0;
|
||||
uint32_t sck_mask = 0;
|
||||
|
||||
void spi_bitbang_init(const uint8_t mosi,
|
||||
const uint8_t miso,
|
||||
const uint8_t sck)
|
||||
{
|
||||
/* Set the masks */
|
||||
mosi_mask = (1 << mosi);
|
||||
miso_mask = (1 << miso);
|
||||
sck_mask = (1 << sck);
|
||||
|
||||
/* Configure the output pins */
|
||||
if (mosi == miso) { /* Loopback */
|
||||
port_pin_set_config(mosi,
|
||||
PORT_PIN_DIR_OUTPUT_WTH_READBACK,/* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
} else { /* No loopback */
|
||||
port_pin_set_config(mosi,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
port_pin_set_config(miso,
|
||||
PORT_PIN_DIR_INPUT, /* Direction */
|
||||
PORT_PIN_PULL_UP, /* Pull */
|
||||
false); /* Powersave */
|
||||
}
|
||||
port_pin_set_config(sck,
|
||||
PORT_PIN_DIR_OUTPUT, /* Direction */
|
||||
PORT_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Set output pins to default values */
|
||||
BIT_SET(mosi_mask);
|
||||
BIT_CLEAR(sck_mask);
|
||||
}
|
||||
uint8_t spi_bitbang_transfer(uint8_t byte)
|
||||
{
|
||||
for (uint8_t counter = 0; counter < 8; counter++) {
|
||||
/* Set output data */
|
||||
if (byte & 0x80) {
|
||||
BIT_SET(mosi_mask);
|
||||
} else {
|
||||
BIT_CLEAR(mosi_mask);
|
||||
}
|
||||
byte <<= 1;
|
||||
BIT_DELAY();
|
||||
|
||||
/* Latch Data into Slave */
|
||||
BIT_TOGGLE(sck_mask);
|
||||
BIT_DELAY();
|
||||
|
||||
/* Read Data */
|
||||
if (BIT_READ(miso_mask)) {
|
||||
byte |= 0x1;
|
||||
}
|
||||
|
||||
/* Slave shifts out next data bit */
|
||||
BIT_TOGGLE(sck_mask);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
|
@ -379,6 +379,7 @@ void system_clock_source_dfll_set_config(
|
|||
rev &= DSU_DID_REVISION_Msk;
|
||||
rev = rev >> DSU_DID_REVISION_Pos;
|
||||
|
||||
/* Calculate the Value register */
|
||||
if (rev < _SYSTEM_MCU_REVISION_D) {
|
||||
val =
|
||||
_SYSTEM_OLD_DFLLVAL_COARSE(coarse_value) |
|
||||
|
@ -389,6 +390,7 @@ void system_clock_source_dfll_set_config(
|
|||
_SYSTEM_NEW_DFLLVAL_FINE(fine_value);
|
||||
}
|
||||
|
||||
/* Calculate the Control register */
|
||||
control =
|
||||
(uint32_t)wakeup_lock |
|
||||
(uint32_t)stable_tracking |
|
||||
|
@ -396,8 +398,8 @@ void system_clock_source_dfll_set_config(
|
|||
(uint32_t)chill_cycle |
|
||||
((uint32_t)on_demand << SYSCTRL_DFLLCTRL_ONDEMAND_Pos);
|
||||
|
||||
/* Set the Multiplication register for closed loop mode */
|
||||
if (loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
|
||||
|
||||
if(rev < _SYSTEM_MCU_REVISION_D) {
|
||||
mul =
|
||||
_SYSTEM_OLD_DFLLMUL_CSTEP(coarse_max_step) |
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
* \note When the counter is configured to re-trigger on an event, the counter
|
||||
* will not start until the start function is used.
|
||||
*/
|
||||
static inline void tc_enable(Tc* const hw)
|
||||
void tc_enable(Tc* const hw)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -83,7 +83,7 @@ static inline void tc_enable(Tc* const hw)
|
|||
/**
|
||||
* Disables a TC module and stops the counter.
|
||||
*/
|
||||
static inline void tc_disable(Tc* const hw)
|
||||
void tc_disable(Tc* const hw)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -96,7 +96,7 @@ static inline void tc_disable(Tc* const hw)
|
|||
/**
|
||||
* Starts or restarts an initialized TC module's counter.
|
||||
*/
|
||||
static inline void tc_start_counter(Tc* const hw)
|
||||
void tc_start_counter(Tc* const hw)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -114,7 +114,7 @@ static inline void tc_start_counter(Tc* const hw)
|
|||
* counting up, or max or the top value if the counter was counting
|
||||
* down when stopped.
|
||||
*/
|
||||
static inline void tc_stop_counter(Tc* const hw)
|
||||
void tc_stop_counter(Tc* const hw)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -135,7 +135,7 @@ static inline void tc_stop_counter(Tc* const hw)
|
|||
* \retval TC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed
|
||||
* \retval TC_STATUS_COUNT_OVERFLOW Timer count value has overflowed
|
||||
*/
|
||||
static inline uint32_t tc_get_status(Tc* const hw)
|
||||
uint32_t tc_get_status(Tc* const hw)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -174,8 +174,8 @@ static inline uint32_t tc_get_status(Tc* const hw)
|
|||
*
|
||||
* \param[in] status_flags Bitmask of \c TC_STATUS_* flags to clear
|
||||
*/
|
||||
static inline void tc_clear_status(Tc* const hw,
|
||||
const uint32_t status_flags)
|
||||
void tc_clear_status(Tc* const hw,
|
||||
const uint32_t status_flags)
|
||||
{
|
||||
assert(hw);
|
||||
|
||||
|
@ -336,7 +336,6 @@ void tc_set_compare_value(Tc* const hw,
|
|||
const uint32_t compare)
|
||||
{
|
||||
assert(hw);
|
||||
assert(compare);
|
||||
|
||||
WAIT_FOR_SYNC(hw);
|
||||
|
||||
|
@ -506,7 +505,7 @@ void tc_set_top_value(Tc* const hw,
|
|||
*
|
||||
* \param[in] events Struct containing flags of events to enable
|
||||
*/
|
||||
static inline void tc_enable_events(Tc* const hw,
|
||||
void tc_enable_events(Tc* const hw,
|
||||
struct tc_events *const events)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
|
@ -545,7 +544,7 @@ static inline void tc_enable_events(Tc* const hw,
|
|||
*
|
||||
* \param[in] events Struct containing flags of events to disable
|
||||
*/
|
||||
static inline void tc_disable_events(Tc* const hw,
|
||||
void tc_disable_events(Tc* const hw,
|
||||
struct tc_events *const events)
|
||||
{
|
||||
assert(hw);
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Functions for turning the GPS timepulse into a HF Clock
|
||||
* 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 "system/clock.h"
|
||||
#include "system/gclk.h"
|
||||
#include "system/pinmux.h"
|
||||
#include "tc/tc_driver.h"
|
||||
#include "hw_config.h"
|
||||
|
||||
#define DFLL48_MUL (DFLL48M_CLK / GPS_TIMEPULSE_FREQ)
|
||||
|
||||
/* Check that DFLL48_MUL is an integer */
|
||||
//#if ((DFLL48M_CLK * 100000000) / GPS_TIMEPULSE_FREQ != (DFLL48_MUL * 100000000))
|
||||
//#error DFLL48M_CLK must be a integer multiple of GPS_TIMEPULSE_FREQ!
|
||||
//#endif
|
||||
|
||||
void timepulse_init(void)
|
||||
{
|
||||
/* Set up the DFLL GCLK channel */
|
||||
system_gclk_chan_set_config(SYSCTRL_GCLK_ID_DFLL48, DFLL48M_GCLK);
|
||||
system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48);
|
||||
|
||||
/* Configure DFLL48 */
|
||||
system_clock_source_dfll_set_config(
|
||||
SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED, /* Loop Mode */
|
||||
false, /* On demand */
|
||||
SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE, /* Quick Lock */
|
||||
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE, /* Chill Cycle */
|
||||
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP, /* Lock during wakeup */
|
||||
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK,
|
||||
0x1f / 4, /* Open Loop - Coarse calibration value */
|
||||
0xff / 4, /* Open Loop - Fine calibration value */
|
||||
1, /* Closed Loop - Coarse Maximum step */
|
||||
1, /* Closed Loop - Fine Maximum step */
|
||||
DFLL48_MUL); /* Frequency Multiplication Factor */
|
||||
|
||||
/* Enable DFLL48 */
|
||||
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL);
|
||||
|
||||
/* Wait for it to be ready */
|
||||
while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL));
|
||||
|
||||
/* system_clock_source_xosc_set_config(SYSTEM_CLOCK_EXTERNAL_CLOCK, */
|
||||
/* SYSTEM_XOSC_STARTUP_16384, */
|
||||
/* true, /\* Auto gain control *\/ */
|
||||
/* 16000000UL, /\* Frequency *\/ */
|
||||
/* true, /\* Run in Standby *\/ */
|
||||
/* false); /\* Run on demand *\/ */
|
||||
/* system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC); */
|
||||
|
||||
/* Configure the HF GCLK */
|
||||
system_gclk_gen_set_config(SI406X_HF_GCLK,
|
||||
GCLK_SOURCE_DFLL48M, /* Source */
|
||||
false, /* High When Disabled */
|
||||
48, /* Division Factor */
|
||||
false, /* Run in standby */
|
||||
true); /* Output Pin Enable */
|
||||
|
||||
/* Configure the output pin */
|
||||
system_pinmux_pin_set_config(SI406X_HF_CLK_PINMUX >> 16, /* GPIO Pin */
|
||||
SI406X_HF_CLK_PINMUX & 0xFFFF, /* Mux Position */
|
||||
SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */
|
||||
SYSTEM_PINMUX_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Enable the HF GCLK */
|
||||
system_gclk_gen_enable(SI406X_HF_GCLK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches GCLK_MAIN (a.k.a. GCLK0) to the gps timepulse
|
||||
*/
|
||||
void switch_gclk_main_to_timepulse(void)
|
||||
{
|
||||
/* Enable GCLK_IO[0] */
|
||||
system_pinmux_pin_set_config(GPS_TIME_PINMUX >> 16, /* GPIO Pin */
|
||||
GPS_TIME_PINMUX & 0xFFFF, /* Mux Position */
|
||||
SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */
|
||||
SYSTEM_PINMUX_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
/* Switch GCLK_MAIN to GCLK_IO[0] */
|
||||
system_gclk_gen_set_config(GCLK_GENERATOR_0, /* GCLK 0 */
|
||||
GCLK_SOURCE_GCLKIN,/* Source from pin */
|
||||
false, /* High When Disabled */
|
||||
1, /* Division Factor */
|
||||
true, /* Run in standby */
|
||||
true); /* Output Pin Enable */
|
||||
|
||||
/* Wait for switch? */
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs GCLK0 div 2 on the HF CLK pin
|
||||
*/
|
||||
void half_glck_main_on_hf_clk(void)
|
||||
{
|
||||
bool capture_channel_enables[] = {true, true};
|
||||
uint32_t compare_channel_values[] = {0x0000, 0x0000};
|
||||
|
||||
tc_init(TC2,
|
||||
GCLK_GENERATOR_0,
|
||||
TC_COUNTER_SIZE_8BIT,
|
||||
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 */
|
||||
0x0000, /* Top value */
|
||||
capture_channel_enables, /* Capture Channel Enables */
|
||||
compare_channel_values); /* Compare Channels Values */
|
||||
|
||||
/* Enable the output pin */
|
||||
system_pinmux_pin_set_config(PINMUX_PA17F_TC2_WO1 >> 16, /* GPIO Pin */
|
||||
PINMUX_PA17F_TC2_WO1 & 0xFFFF, /* Mux Position */
|
||||
SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */
|
||||
SYSTEM_PINMUX_PIN_PULL_NONE, /* Pull */
|
||||
false); /* Powersave */
|
||||
|
||||
tc_enable(TC2);
|
||||
tc_start_counter(TC2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current GCLK_MAIN frequency, as measured against OSC8M
|
||||
*/
|
||||
uint32_t gclk_main_frequency(void)
|
||||
{
|
||||
uint32_t osc8m_frequency = 8000000UL >> SYSCTRL->OSC8M.bit.PRESC;
|
||||
|
||||
/* Configure GCLK Gen 6 as reference */
|
||||
system_gclk_gen_set_config(GCLK_GENERATOR_6,
|
||||
GCLK_SOURCE_OSC8M, /* Source */
|
||||
false, /* High When Disabled */
|
||||
4, /* Division Factor */
|
||||
false, /* Run in standby */
|
||||
false); /* Output Pin Enable */
|
||||
/* Enable GCLK 6 */
|
||||
system_gclk_gen_enable(GCLK_GENERATOR_6);
|
||||
|
||||
/* Timer 0 free runs on GLCK 0 */
|
||||
bool t0_capture_channel_enables[] = {false, false};
|
||||
uint32_t t0_compare_channel_values[] = {0x0000, 0x0000};
|
||||
|
||||
tc_init(TC0,
|
||||
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, /* Run in standby */
|
||||
0x0000, /* Initial value */
|
||||
0xFFFFFFFF, /* Top value */
|
||||
t0_capture_channel_enables, /* Capture Channel Enables */
|
||||
t0_compare_channel_values); /* Compare Channels Values */
|
||||
|
||||
/* Timer 3 counts 10000 cycles of GLCK 6 */
|
||||
bool t1_capture_channel_enables[] = {false, false};
|
||||
uint32_t t1_compare_channel_values[] = {10000, 0x0000};
|
||||
|
||||
tc_init(TC3,
|
||||
GCLK_GENERATOR_6,
|
||||
TC_COUNTER_SIZE_16BIT,
|
||||
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, /* Run in standby */
|
||||
0x0000, /* Initial value */
|
||||
0xFFFF, /* Top value */
|
||||
t1_capture_channel_enables, /* Capture Channel Enables */
|
||||
t1_compare_channel_values); /* Compare Channels Values */
|
||||
|
||||
tc_enable(TC0);
|
||||
tc_enable(TC3);
|
||||
tc_start_counter(TC0);
|
||||
tc_start_counter(TC3);
|
||||
|
||||
/* Wait 10000 cycles of GCLK 6 */
|
||||
while (!(tc_get_status(TC3) & TC_STATUS_CHANNEL_0_MATCH));
|
||||
|
||||
uint32_t gclk_main_count = tc_get_count_value(TC0) - 50;
|
||||
|
||||
return gclk_main_count / 10;
|
||||
}
|
Ładowanie…
Reference in New Issue