Start re-organising clocks for hf lf clock structure where the microcontroller runs on its own lf clock during sleep.

main-solar-only
Richard Meadows 2015-11-19 22:28:40 +00:00
rodzic b72a496f9f
commit 939d30ebfe
10 zmienionych plików z 259 dodań i 216 usunięć

Wyświetl plik

@ -42,22 +42,46 @@
## Clock Layout
### At startup
```
[osc8m] --> [glck0] +
|--> [tc5]
|--> [adc]
|--> [extint]
|--> [cm0+, apbs etc.]
|\
[osc8m]--> 0| |
| | --> [glck1] +--> [tc0, telemetry tick]
tcxo --> [xosc] --> 1| | |--> [tc2, count tcxo] <-- gps timepulse
|/ |--> [glck7] --> [tc5] --> si_gpio1
| |--> [gps usart]
*USE_XOSC*
[osculp32k] --> [gclk4] --> [wdt]
[osc8m] --> [glck0] -> [core]
```
### Once configured
```
|\
[osculp32k] --> 0| |
| | ------+ (22-42kHz)
lftimer -> [glck_io0] --> 1| | |
|/ |
| |
*USE_LFTIMER* | |\
+--> 0| |
| | --> [gclk0] +--> [core]
+--> 1| | |--> [tc4, wakeup, measure gclk0]
| |/
| |
|\ | awake?
[osc8m]--> 0| | |
| | ------+ (8MHz/16.369MHz)
tcxo --> [xosc] --> 1| |
|/
|
*USE_XOSC*
|\
|\ 0| |
[osc8m]--> 0| | | | ---> [glck1] +--> [tc0, telemetry tick]
| | ---> 1| | |--> [tc2, count tcxo]
tcxo --> [xosc] --> 1| | |/ |--> [glck7] --> [tc5, aprs carrier] --> si_gpio1
|/ | |--> [adc]
| awake? |--> [extint]
*USE_XOSC* |--> [sercoms]
```

Wyświetl plik

@ -195,11 +195,17 @@
#define RF_POWER_8dBm 36
/**
* XOSC
* LF Clock
*/
#define USE_LFTIMER 0
/**
* HF Clock
*/
#define USE_XOSC 1
#define XOSC_FREQUENCY 16369000
#define XOSC_GCLK1_DIVIDE 2
#define XOSC_GCLK_DIVIDE 2 /* ~8MHz on GCLK*/
#define OSC8M_GCLK_DIVIDE 1 /* ~8MHz on GCLK */
/**
* Telemetry

Wyświetl plik

@ -28,7 +28,6 @@
#include "samd20.h"
#include "hw_config.h"
#include "system/port.h"
#include "timer.h"
enum init_type {
INIT_NORMAL,
@ -57,6 +56,6 @@ static inline void led_toggle(void)
port_pin_toggle_output_level(LED0_PIN);
}
void init(timepulse_callback_t callback, enum init_type init_t);
void init(enum init_type init_t);
#endif /* INIT_H */

Wyświetl plik

@ -1,33 +0,0 @@
/*
* Functions for running system timings
* Copyright (C) 2015 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 TIMER_H
#define TIMER_H
typedef void (*timepulse_callback_t)(uint32_t sequence);
void timepulse_extint_init(void);
void timepulse_set_callback(timepulse_callback_t callback);
#endif /* TIMER_H */

Wyświetl plik

@ -28,19 +28,27 @@
#include "samd20.h"
enum xosc_measurement_t {
XOSC_MEASURE_OSC8M,
XOSC_MEASURE_GCLK0,
XOSC_MEASURE_TIMEPULSE,
};
struct osc8m_calibration_t {
uint8_t temperature;
uint8_t process;
};
typedef void (*measurement_result_t)(uint32_t result);
void xosc_init(void);
struct osc8m_calibration_t osc8m_get_calibration(void);
void osc8m_set_calibration(struct osc8m_calibration_t calib);
/** HF Clock */
void hf_clock_init(void);
void hf_clock_enable(void);
void hf_clock_disable(void);
/** GCLK0 */
void glck0_to_hf_clock(void);
void gclk0_to_lf_clock(void);
/** GCLK1 */
void gclk1_enable(void);
void gclk1_disable(void);
/** Measurement */
void measure_xosc(enum xosc_measurement_t measurement_t, measurement_result_t callback);
#endif /* XOSC_H */

Wyświetl plik

@ -33,7 +33,6 @@
#include "si_trx.h"
#include "watchdog.h"
#include "xosc.h"
#include "timer.h"
#include "cron.h"
#include "data.h"
#include "memory.h"
@ -68,7 +67,7 @@ void powermananger_init(void)
* Internal initialisation
* =============================================================================
*/
void init(timepulse_callback_t callback, enum init_type init_t)
void init(enum init_type init_t)
{
/**
* Reset to get the system in a safe state
@ -131,10 +130,6 @@ void init(timepulse_callback_t callback, enum init_type init_t)
/* GPS init */
gps_init();
/* Enable timer interrupt and event channel */
timepulse_extint_init();
timepulse_set_callback(callback);
}
/* Initialise Si4060 interface */

Wyświetl plik

@ -33,7 +33,6 @@
#include "mfsk.h"
#include "watchdog.h"
#include "telemetry.h"
#include "timer.h"
#include "contestia.h"
#include "aprs.h"
#include "location.h"
@ -246,7 +245,7 @@ void gps_tick(uint32_t sequence)
int main(void)
{
/* Init */
init(gps_tick, INIT_NORMAL);
init(INIT_NORMAL);
/* Maybe do some rf tests */
rf_tests();

Wyświetl plik

@ -1,105 +0,0 @@
/*
* Functions for running system timings
* Copyright (C) 2015 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 "timer.h"
#include "system/extint.h"
#include "system/events.h"
#include "system/interrupt.h"
#include "system/port.h"
#include "watchdog.h"
volatile uint32_t gps_timepulse_count = 0;
uint32_t timepulse_sequence = 0;
timepulse_callback_t _timer_callback;
/**
* Enables an interrupt on the GPS_TIMEPULSE and routes it to event channel 0
*/
void timepulse_extint_init(void) {
/* Enable extint events for gps timepulse */
struct extint_events events;
memset(&events, 0, sizeof(struct extint_events));
events.generate_event_on_detect[GPS_TIMEPULSE_EXTINT] = true;
extint_enable_events(&events);
/* Configure extinit channel */
/**
* We trigger on both edges so that we get woken up at 2x the tick
* rate. This means we can kick the watchdog often enough.
*/
struct extint_chan_conf config;
config.gpio_pin = GPS_TIMEPULSE_PIN;
config.gpio_pin_mux = GPS_TIMEPULSE_PINMUX;
config.gpio_pin_pull = EXTINT_PULL_DOWN;
config.wake_if_sleeping = true;
config.filter_input_signal = false;
config.detection_criteria = EXTINT_DETECT_BOTH;
extint_chan_set_config(GPS_TIMEPULSE_EXTINT, &config);
/* We route this event to event channel 0 */
events_allocate(0,
EVENTS_EDGE_DETECT_NONE, /* Don't care for async path */
EVENTS_PATH_ASYNCHRONOUS,
0xC + GPS_TIMEPULSE_EXTINT, /* External Interrupt Number */
0);
/* Interrupt handler below */
EIC->INTENSET.reg = (1 << GPS_TIMEPULSE_EXTINT);
irq_register_handler(EIC_IRQn, EIC_INT_PRIO);
extint_enable();
}
void timepulse_set_callback(timepulse_callback_t callback) {
_timer_callback = callback;
}
/**
* EIC Handler, triggered by the GPS at GPS_TIMEPULSE_FREQ Hz
*/
void EIC_Handler(void)
{
awake_do_watchdog();
if (EIC->INTFLAG.reg & (1 << GPS_TIMEPULSE_EXTINT)) {
EIC->INTFLAG.reg = (1 << GPS_TIMEPULSE_EXTINT);
gps_timepulse_count++;
/* Runs at 1Hz */
if (gps_timepulse_count >= GPS_TIMEPULSE_FREQ * 2) { /* Both */
gps_timepulse_count = 0;
/* Make the callback if we have one */
if (_timer_callback) {
_timer_callback(timepulse_sequence++);
}
}
}
}

Wyświetl plik

@ -28,6 +28,7 @@
#include "system/clock.h"
#include "system/gclk.h"
#include "system/interrupt.h"
#include "system/port.h"
#include "system/pinmux.h"
#include "system/events.h"
#include "system/extint.h"
@ -44,11 +45,37 @@ enum xosc_measurement_t _measurement_t;
measurement_result_t _callback;
/**
* Configures external oscillator, waits for it to stabilise, and
* connects it to GLCK1.
* =============================================================================
* HF Clock =======================================================
* =============================================================================
*/
void xosc_init(void) {
/**
* Init hf clock
*/
void hf_clock_init(void)
{
#ifdef SI4xxx_TCXO_REG_EN_PIN /* TCXO enable/disable pin */
port_pin_set_config(SI4xxx_TCXO_REG_EN_PIN,
PORT_PIN_DIR_OUTPUT, /* Direction */
PORT_PIN_PULL_NONE, /* Pull */
false); /* Powersave */
port_pin_set_output_level(SI4xxx_TCXO_REG_EN_PIN, 1); /* Enable by default */
#endif
}
/**
* Enables a high frequency clock for the system, either XOSC or OSC8M
*/
void hf_clock_enable(void)
{
#if USE_XOSC
/* Enable TCXO if required */
#ifdef SI4xxx_TCXO_REG_EN_PIN
port_pin_set_output_level(SI4xxx_TCXO_REG_EN_PIN, 1);
#endif
/* Setup XOSC */
system_clock_source_xosc_set_config(SYSTEM_CLOCK_EXTERNAL_CLOCK,
SYSTEM_XOSC_STARTUP_1,
true,
@ -57,10 +84,58 @@ void xosc_init(void) {
false);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC);
/* Wait for it to stabilise */
while (!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_XOSC));
#else
/* Setup OSC8M */
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_2, /* Prescaler */
false, /* Run in Standby */
false); /* Run on Demand */
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC8M);
/* Wait for it to stabilise */
while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_OSC8M));
#endif
}
/**
* Disables the high frequency clock for the system, either XOSC or OSC8M
*/
void hf_clock_disable(void)
{
#if USE_XOSC
/* Enable XOSC */
system_clock_source_disable(SYSTEM_CLOCK_SOURCE_XOSC);
/* Disable TCXO to save power */
#ifdef SI4xxx_TCXO_REG_EN_PIN
port_pin_set_output_level(SI4xxx_TCXO_REG_EN_PIN, 1);
#endif
/* Configure GCLK1 to XOSC */
#else
/* Disable OSC8M */
system_clock_source_disable(SYSTEM_CLOCK_SOURCE_OSC8M);
#endif
}
/**
* =============================================================================
* GCLK0 =======================================================
* =============================================================================
*/
/**
* Switches GLCK0 to the HF clock
*/
void glck0_to_hf_clock(void)
{
/* Configure GCLK0 to XOSC / OSC8M */
system_gclk_gen_set_config(GCLK_GENERATOR_1,
#if USE_XOSC
GCLK_SOURCE_XOSC, /* Source */
@ -68,29 +143,80 @@ void xosc_init(void) {
GCLK_SOURCE_OSC8M, /* Source */
#endif
false, /* High When Disabled */
XOSC_GCLK1_DIVIDE, /* Division Factor */
#if USE_XOSC
XOSC_GCLK_DIVIDE, /* Division Factor */
#else
OSC8M_GCLK_DIVIDE, /* Division Factor */
#endif
false, /* Run in standby */
false); /* Output Pin Enable */
}
/**
* Switches GCLK0 to the LF clock
*/
void gclk0_to_lf_clock(void)
{
/* Configure GCLK0 to GCLK_IO[0] / OSCULP32K */
system_gclk_gen_set_config(GCLK_GENERATOR_0,
#if USE_LFTIMER
GCLK_SOURCE_GCLKIN, /* Source */
#else
GCLK_SOURCE_OSCULP32K, /* Source */
#endif
false, /* High When Disabled */
1, /* Division Factor */
false, /* Run in standby */
false); /* Output Pin Enable */
}
/**
* =============================================================================
* GCLK1 =======================================================
* =============================================================================
*/
/**
* Enables GCLK1. The appropriate source should have been disabled already
*/
void gclk1_enable(void)
{
/* Configure GCLK1 */
system_gclk_gen_set_config(GCLK_GENERATOR_1,
#if USE_XOSC
GCLK_SOURCE_XOSC, /* Source */
#else
GCLK_SOURCE_OSC8M, /* Source */
#endif
false, /* High When Disabled */
#if USE_XOSC
XOSC_GCLK_DIVIDE, /* Division Factor */
#else
OSC8M_GCLK_DIVIDE,/* Division Factor */
#endif
false, /* Run in standby */
false); /* Output Pin Enable */
/* Enable GCLK1 */
system_gclk_gen_enable(GCLK_GENERATOR_1);
}
struct osc8m_calibration_t osc8m_get_calibration(void) {
uint16_t calib_word = SYSCTRL->OSC8M.bit.CALIB;
struct osc8m_calibration_t calib;
calib.temperature = (calib_word >> 6) & 0x3F;
calib.process = (calib_word >> 0) & 0x3F;
return calib;
/**
* Disable GCLK1
*/
void gclk1_disable(void)
{
system_gclk_gen_disable(GCLK_GENERATOR_1);
}
void osc8m_set_calibration(struct osc8m_calibration_t calib) {
uint16_t calib_word = ((calib.temperature & 0x3F) << 6) | (calib.process & 0x3F);
system_clock_source_write_calibration(SYSTEM_CLOCK_SOURCE_OSC8M, calib_word, 0x1);
}
/**
* =============================================================================
* Measurement =======================================================
* =============================================================================
*/
@ -99,7 +225,7 @@ void osc8m_set_calibration(struct osc8m_calibration_t calib) {
*/
/* void osc8m_event_source(void) { */
/* /\* Timer 4 runs on GCLK0 (4MHz) *\/ */
/* /\* Timer 4 runs on GCLK0 *\/ */
/* bool t4_capture_channel_enables[] = {false, false}; */
/* uint32_t t4_compare_channel_values[] = {15625, 0x0000}; */
/* /\* Divide by 256*15625 = 1Hz events *\/ */
@ -154,11 +280,35 @@ void osc8m_set_calibration(struct osc8m_calibration_t calib) {
/**
* Configure the timepulse extint to generate events
*/
void timepulse_extint_event_source(void) {
/* Nothing to do: event should be already in place */
void timepulse_extint_event_source(void)
{
/* Enable extint events for timepulse */
struct extint_events events;
memset(&events, 0, sizeof(struct extint_events));
events.generate_event_on_detect[GPS_TIMEPULSE_EXTINT] = true;
extint_enable_events(&events);
/* Configure extinit channel */
struct extint_chan_conf config;
config.gpio_pin = GPS_TIMEPULSE_PIN;
config.gpio_pin_mux = GPS_TIMEPULSE_PINMUX;
config.gpio_pin_pull = EXTINT_PULL_DOWN;
config.wake_if_sleeping = true;
config.filter_input_signal = false;
config.detection_criteria = EXTINT_DETECT_RISING;
extint_chan_set_config(GPS_TIMEPULSE_EXTINT, &config);
/* We route this event to event channel 0 */
events_allocate(0,
EVENTS_EDGE_DETECT_NONE, /* Don't care for async path */
EVENTS_PATH_ASYNCHRONOUS,
0xC + GPS_TIMEPULSE_EXTINT, /* External Interrupt Number */
0);
extint_enable();
}
void timepulse_extint_event_source_disable(void) {
/* Nothing to do here */
extint_disable();
}
/**
@ -173,7 +323,7 @@ void measure_xosc(enum xosc_measurement_t measurement_t,
_measurement_t = measurement_t;
_callback = callback;
/* Timer 2 runs on GLCK1: XOSC */
/* Timer 2 runs on GLCK1 */
bool t2_capture_channel_enables[] = {true, true};
uint32_t t2_compare_channel_values[] = {0x0000, 0x0000};
@ -211,7 +361,7 @@ void measure_xosc(enum xosc_measurement_t measurement_t,
/* Configure an event source */
switch (measurement_t) {
case XOSC_MEASURE_OSC8M:
case XOSC_MEASURE_GCLK0:
// osc8m_event_source(); // osc8m issues events
break;
case XOSC_MEASURE_TIMEPULSE:
@ -226,7 +376,7 @@ void measure_xosc_disable(enum xosc_measurement_t measurement_t) {
tc_disable(TC2);
switch (measurement_t) {
case XOSC_MEASURE_OSC8M:
case XOSC_MEASURE_GCLK0:
// osc8m_event_source_disable();
break;
case XOSC_MEASURE_TIMEPULSE:
@ -235,6 +385,8 @@ void measure_xosc_disable(enum xosc_measurement_t measurement_t) {
}
}
/**
* Triggered on timer 2 capture
*/
@ -242,8 +394,6 @@ void TC2_Handler(void) {
uint32_t capture_value;
uint32_t source_freq;
awake_do_watchdog();
if (tc_get_status(TC2) & TC_STATUS_CHANNEL_0_MATCH) {
tc_clear_status(TC2, TC_STATUS_CHANNEL_0_MATCH);
@ -255,13 +405,13 @@ void TC2_Handler(void) {
/* Measurement done. Read off data */
capture_value = tc_get_capture_value(TC2, 0);
/* Calcuate the frequency of XOSC relative to this source */
/* Calcuate the frequency of GLCK1 relative to this source */
switch (_measurement_t) {
case XOSC_MEASURE_OSC8M:
source_freq = capture_value * XOSC_GCLK1_DIVIDE;
case XOSC_MEASURE_GCLK0:
source_freq = capture_value * XOSC_GCLK_DIVIDE;
break;
case XOSC_MEASURE_TIMEPULSE:
source_freq = capture_value * XOSC_GCLK1_DIVIDE * GPS_TIMEPULSE_FREQ * 2;
source_freq = capture_value * XOSC_GCLK_DIVIDE * GPS_TIMEPULSE_FREQ;
break;
}

Wyświetl plik

@ -27,19 +27,19 @@ void osc8m_tc_xosc_measure_callback(uint32_t result) {
/* Function */
__verification__ void osc8m_calib_tc(void) {
struct osc8m_calibration_t calib;
/* struct osc8m_calibration_t calib; */
calib.process = 9;
calib.temperature = 28;
osc8m_set_calibration(calib);
/* calib.process = 9; */
/* calib.temperature = 28; */
/* osc8m_set_calibration(calib, 0x1); */
_result = 0;
measure_xosc(XOSC_MEASURE_TIMEPULSE, osc8m_tc_xosc_measure_callback);
/* _result = 0; */
/* measure_xosc(XOSC_MEASURE_TIMEPULSE, osc8m_tc_xosc_measure_callback); */
while (_result == 0);
osc8m_calib_tc_results.result = _result;
/* while (_result == 0); */
/* osc8m_calib_tc_results.result = _result; */
calib = osc8m_get_calibration();
osc8m_calib_tc_results.c_process = calib.process;
osc8m_calib_tc_results.c_temp = calib.temperature;
/* calib = osc8m_get_calibration(); */
/* osc8m_calib_tc_results.c_process = calib.process; */
/* osc8m_calib_tc_results.c_temp = calib.temperature; */
}