2014-07-13 13:33:10 +00:00
|
|
|
/*
|
2014-10-06 18:05:11 +00:00
|
|
|
* Bristol SEDS pico-tracker
|
2014-07-13 13:33:10 +00:00
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <math.h>
|
2014-08-31 10:54:20 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "samd20.h"
|
2014-07-13 13:33:10 +00:00
|
|
|
#include "semihosting.h"
|
2014-08-23 21:18:49 +00:00
|
|
|
#include "hw_config.h"
|
|
|
|
#include "system/system.h"
|
|
|
|
#include "sercom/usart.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
#include "system/port.h"
|
2014-08-30 20:11:35 +00:00
|
|
|
#include "tc/tc_driver.h"
|
2014-08-23 21:18:49 +00:00
|
|
|
#include "gps.h"
|
2014-08-31 10:02:22 +00:00
|
|
|
#include "system/wdt.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
#include "timepulse.h"
|
2014-08-31 10:02:22 +00:00
|
|
|
#include "telemetry.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
//#include "si406x.h"
|
|
|
|
#include "si4060.h"
|
|
|
|
#include "spi_bitbang.h"
|
2014-08-30 20:11:35 +00:00
|
|
|
#include "rtty.h"
|
|
|
|
#include "system/interrupt.h"
|
2014-08-27 18:57:03 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Configure the serial port */
|
|
|
|
spi_bitbang_init(SI406X_SERCOM_MOSI_PIN,
|
|
|
|
SI406X_SERCOM_MISO_PIN,
|
|
|
|
SI406X_SERCOM_SCK_PIN);
|
|
|
|
}
|
|
|
|
void si4060_gpio_init()
|
|
|
|
{
|
2014-08-27 18:57:03 +00:00
|
|
|
/* 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);
|
2014-08-30 20:11:35 +00:00
|
|
|
/* 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);
|
2014-08-27 18:57:03 +00:00
|
|
|
}
|
2014-10-06 18:05:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialises the status LED
|
|
|
|
*/
|
|
|
|
static inline void led_init(void)
|
|
|
|
{
|
|
|
|
port_pin_set_config(LED0_PIN,
|
|
|
|
PORT_PIN_DIR_OUTPUT, /* Direction */
|
|
|
|
PORT_PIN_PULL_NONE, /* Pull */
|
|
|
|
false); /* Powersave */
|
|
|
|
port_pin_set_output_level(LED0_PIN, 1); /* LED is active low */
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Turns the status LED on
|
|
|
|
*/
|
|
|
|
static inline void led_on(void)
|
|
|
|
{
|
|
|
|
port_pin_set_output_level(LED0_PIN, 0); /* LED is active low */
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Turns the status lED off
|
|
|
|
*/
|
|
|
|
static inline void led_off(void)
|
|
|
|
{
|
|
|
|
port_pin_set_output_level(LED0_PIN, 1); /* LED is active low */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
/* void wdt_init() { */
|
|
|
|
/* /\* 64 seconds timeout. So 2^(15+6) cycles of the wdt clock *\/ */
|
|
|
|
/* system_gclk_gen_set_config(WDT_GCLK, */
|
|
|
|
/* GCLK_SOURCE_OSCULP32K, /\* Source *\/ */
|
|
|
|
/* false, /\* High When Disabled *\/ */
|
|
|
|
/* 128, /\* Division Factor *\/ */
|
|
|
|
/* false, /\* Run in standby *\/ */
|
|
|
|
/* true); /\* Output Pin Enable *\/ */
|
|
|
|
/* system_gclk_gen_enable(WDT_GCLK); */
|
|
|
|
|
|
|
|
/* /\* Set the watchdog timer. On 256Hz gclk 4 *\/ */
|
|
|
|
/* 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 *\/ */
|
|
|
|
/* } */
|
2014-07-13 13:33:10 +00:00
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
2014-10-06 18:05:11 +00:00
|
|
|
/**
|
|
|
|
* Internal initialisation
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Clock up to 14MHz with 0 wait states */
|
|
|
|
system_flash_set_waitstates(SYSTEM_WAIT_STATE_1_8V_14MHZ);
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
/* Up the clock rate to 4MHz */
|
|
|
|
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_2, /* Prescaler */
|
2014-08-23 21:18:49 +00:00
|
|
|
false, /* Run in Standby */
|
|
|
|
false); /* Run on Demand */
|
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
/* Restart the GCLK Module */
|
|
|
|
system_gclk_init();
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
/* Get the current CPU Clock */
|
|
|
|
SystemCoreClock = system_cpu_clock_get_hz();
|
2014-08-23 21:18:49 +00:00
|
|
|
|
|
|
|
/* Configure Sleep Mode */
|
|
|
|
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);
|
|
|
|
//TODO: system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
|
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
/* Configure the SysTick for 50Hz triggering */
|
|
|
|
SysTick_Config(SystemCoreClock / 50);
|
|
|
|
|
2014-07-13 13:33:10 +00:00
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
/**
|
|
|
|
* System initialisation
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
*/
|
2014-08-31 10:54:20 +00:00
|
|
|
|
2014-10-06 18:05:11 +00:00
|
|
|
led_init();
|
2014-08-23 21:18:49 +00:00
|
|
|
gps_init();
|
2014-08-27 18:57:03 +00:00
|
|
|
|
|
|
|
/* Initialise Si4060 */
|
|
|
|
si4060_hw_init();
|
2014-10-08 15:08:36 +00:00
|
|
|
si4060_gpio_init();
|
2014-08-27 18:57:03 +00:00
|
|
|
si4060_reset();
|
|
|
|
|
|
|
|
/* check radio communication */
|
|
|
|
int i = si4060_part_info();
|
|
|
|
if (i != 0x4063) {
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
2014-10-08 15:08:36 +00:00
|
|
|
si4060_power_up();
|
|
|
|
si4060_setup(MOD_TYPE_2FSK);
|
2014-08-31 10:02:22 +00:00
|
|
|
|
2014-10-08 15:08:36 +00:00
|
|
|
si4060_gpio_init();
|
|
|
|
si4060_start_tx(0);
|
2014-08-30 20:11:35 +00:00
|
|
|
|
2014-08-23 21:18:49 +00:00
|
|
|
while (1) {
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Send the last packet */
|
2014-10-08 15:08:36 +00:00
|
|
|
while (rtty_active());
|
2014-08-31 10:54:20 +00:00
|
|
|
|
2014-10-08 15:08:36 +00:00
|
|
|
port_pin_set_output_level(SI406X_GPIO0_PIN, 0);
|
2014-08-31 10:02:22 +00:00
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Send requests to the gps */
|
|
|
|
gps_update();
|
2014-08-27 18:57:03 +00:00
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Wait between frames */
|
2014-10-06 18:05:11 +00:00
|
|
|
led_on();
|
|
|
|
for (int i = 0; i < 100*1000; i++);
|
|
|
|
led_off();
|
2014-08-30 20:11:35 +00:00
|
|
|
for (int i = 0; i < 100*1000; i++);
|
2014-08-27 18:57:03 +00:00
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Set the next packet */
|
2014-10-08 15:08:36 +00:00
|
|
|
set_telemetry_string();
|
2014-08-31 10:54:20 +00:00
|
|
|
|
2014-10-08 15:08:36 +00:00
|
|
|
port_pin_set_output_level(SI406X_GPIO0_PIN, 1);
|
2014-08-31 10:54:20 +00:00
|
|
|
|
2014-08-27 18:57:03 +00:00
|
|
|
//system_sleep();
|
2014-08-23 21:18:49 +00:00
|
|
|
}
|
2014-07-13 13:33:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-30 20:11:35 +00:00
|
|
|
/**
|
|
|
|
* Called at 50Hz
|
|
|
|
*/
|
2014-07-13 13:33:10 +00:00
|
|
|
void SysTick_Handler(void)
|
|
|
|
{
|
2014-08-30 20:11:35 +00:00
|
|
|
/* Output RTTY */
|
|
|
|
rtty_tick();
|
2014-07-13 13:33:10 +00:00
|
|
|
}
|