Clean up DFM-17 clock calibration implementation and make RS41 compile properly

dfm17
Mikael Nousiainen 2023-10-14 11:41:06 +03:00
rodzic 61e428789a
commit f9d964ab8e
23 zmienionych plików z 323 dodań i 318 usunięć

Wyświetl plik

@ -30,7 +30,7 @@ size_t aprs_generate_position(uint8_t *payload, size_t length, telemetry_data *d
return snprintf((char *) payload,
length,
("%s%02d%02d.%02u%c%c%03d%02u.%02u%c%c%03d/%03d/A=%06d/P%dS%dT%02dV%04dC%02dR%02dU%02d%s"),
("%s%02d%02d.%02u%c%c%03d%02u.%02u%c%c%03d/%03d/A=%06d/P%dS%dT%02dV%04dC%02d%s"),
timestamp,
abs(la_degrees), la_minutes, la_h_minutes,
la_degrees > 0 ? 'N' : 'S',
@ -46,8 +46,6 @@ size_t aprs_generate_position(uint8_t *payload, size_t length, telemetry_data *d
(int) data->internal_temperature_celsius_100 / 100,
data->battery_voltage_millivolts,
(int16_t) ((float) data->gps.climb_cm_per_second / 100.0f),
data->clock_calibration,
data->clock_calibration_count,
comment
);
}

Wyświetl plik

@ -27,6 +27,8 @@
* $he - Heading in degrees (up to 3 chars)
* $pc - Pulse counter value (wraps to zero at 65535, 16-bit unsigned value)
* $ri - Radiation intensity in µR/h (up to 5 chars)
* $ct - Clock calibration trim value (0-31, only for DFM-17)
* $cc - Clock calibration change count (only for DFM-17)
*
* Allowed message lengths:
*

Wyświetl plik

@ -8,6 +8,9 @@
#if !defined(RS41) && !defined(DFM17)
#error "No hardware type specified. Please define RS41 or DFM17."
#endif
#if defined(RS41) && defined(DFM17)
#error "Please define either RS41 or DFM17."
#endif
// Enable semihosting to receive debug logs during development

Wyświetl plik

@ -13,6 +13,9 @@
// PARIS: 50 dot durations, 20 WPM -> 60ms per unit
#define MORSE_WPM_TO_SYMBOL_RATE(wpm) (1000 / (60 * 20 / wpm))
// Experimental fast frequency change routine for Si5351, not tested
#define SI5351_FAST_ENABLE false
#include <stdbool.h>
extern bool leds_enabled;

Wyświetl plik

@ -499,7 +499,7 @@ void si4063_configure()
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
// HERE
{
// Used only in synchronous mode (for GFSK modulation/filtering)
uint8_t data[] = {

Wyświetl plik

@ -0,0 +1,144 @@
#include "config.h"
#ifdef DFM17
#include "stm32f10x_exti.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "system.h"
#include "millis.h"
#include "clock_calibration.h"
// The HSI (internal oscillator) trim register mask, copied from stm_lib/src/stm32f10x_rcc.c
#define CR_HSITRIM_Mask ((uint32_t)0xFFFFFF07)
// Register definition for reading the HSI current trim out of the Calibration Register (CR).
// Resulting value will be between 0-31.
#define CURRENT_TRIM ((RCC->CR & ~CR_HSITRIM_Mask) >>3)
/**
* On the DFM-17, GPIO PB8 is wired to the GPS Timepulse. We take advantage of this to do a
* processor speed calibration. HSITRIM[4:0] allows for 32 values to adjust the HSI clock
* speed. The center (16) value is "neutral". Each trim value above or below 16 adjusts
* the clock by approximately 40kHZ (0.5% of the 8MHZ clock speed) (per AN2868).
* 0.5% is about 5ms per second, so if we detect that we're off by more than 5 milliseconds between time pulses,
* we will suggest a recalibration. The "trim_suggestion" variable is a static that will be maintained
* by the time pulse IRQ and can be used at any time it's convenient to adjust the clock speed.
*/
// Defaults, will be set it in the init routine below.
int trim_suggestion = 16;
int trim_current = 16;
uint32_t old_millis = 0;
uint16_t calibration_change_count = 0;
bool calibration_indicator_state = true;
uint8_t clock_calibration_get_trim()
{
return CURRENT_TRIM;
}
uint16_t clock_calibration_get_change_count()
{
return calibration_change_count;
}
void clock_calibration_adjust()
{
if (trim_suggestion == trim_current) {
return;
}
RCC_AdjustHSICalibrationValue(trim_suggestion);
trim_current = trim_suggestion;
calibration_change_count++;
calibration_indicator_state = !calibration_indicator_state;
system_set_yellow_led(calibration_indicator_state);
}
void timepulse_init()
{
// Initialize pin PB8 as floating input
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_8;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &gpio_init);
// PB8 is connected to interrupt line 8, set trigger on the configured edge and enable the interrupt
EXTI_InitTypeDef exti_init;
exti_init.EXTI_Line = EXTI_Line8;
exti_init.EXTI_Mode = EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger = EXTI_Trigger_Rising;
exti_init.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti_init);
// Attach interrupt line to port B
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);
// PB8 is connected to EXTI_Line8, which has EXTI9_5_IRQn vector. Use priority 0 for now.
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// Pull the current calibration to start
trim_current = CURRENT_TRIM;
trim_suggestion = trim_current;
// Set the yellow LED to help identify calibration changes
system_set_yellow_led(calibration_indicator_state);
}
// This handler is (at present) only being used for the GPS time pulse interrupt,
// so we shouldn't need to do additional testing for the cause of the interrupt.
void EXTI9_5_IRQHandler(void)
{
uint32_t current_millis = millis();
EXTI_ClearITPendingBit(EXTI_Line8);
if (old_millis == 0) {
// First timepulse. Just store millis.
old_millis = current_millis;
return;
}
if (current_millis < old_millis) {
// Milliseconds value wrapped to zero. Wait for the next interrupt.
return;
}
// Calculate milliseconds since last timepulse. Ideally there were 1000.
uint32_t millis_delta = current_millis - old_millis;
old_millis = current_millis;
// If too few clicks, speed up clock. If too many, slow down.
int delta = (int) (1000 - millis_delta) / 5;
// Take one step at a time in case we had a bad clock tick
if (delta > 1) {
delta = 1;
}
if (delta < -1) {
delta = -1;
}
// Don't allow calibration suggestion to go out of range
if (((delta + trim_current) >= 0) &&
((delta + trim_current <= 31))) {
// If the delta makes sense, apply to the suggestion. Otherwise, skip.
trim_suggestion = trim_current + delta;
}
}
#endif

Wyświetl plik

@ -0,0 +1,15 @@
#ifndef __CLOCK_CALIBRATION_H
#define __CLOCK_CALIBRATION_H
#include "config.h"
#ifdef DFM17
extern void timepulse_init();
extern uint8_t clock_calibration_get_trim();
extern uint16_t clock_calibration_get_change_count();
extern void clock_calibration_adjust();
#endif
#endif

Wyświetl plik

@ -61,8 +61,6 @@ void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
system_handle_data_timer_tick();
}
}

Wyświetl plik

@ -17,7 +17,7 @@ void millis_timer_init(void)
// The data timer assumes a 24 MHz clock source
tim_init.TIM_Prescaler = 24 - 1; // tick every 1/1000000 s
tim_init.TIM_CounterMode = TIM_CounterMode_Up;
tim_init.TIM_Period = (uint16_t) (1000 - 1); // Timer pop 1/millisec
tim_init.TIM_Period = (uint16_t) (1000 - 1); // set up period of 1 millisecond
tim_init.TIM_ClockDivision = TIM_CKD_DIV1;
tim_init.TIM_RepetitionCounter = 0;
@ -55,13 +55,11 @@ void TIM7_IRQHandler(void)
{
if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
millis_counter++;
}
}
uint32_t millis(void)
{
return millis_counter;
return millis_counter;
}

Wyświetl plik

@ -1,10 +1,12 @@
#ifndef __MILLIS_H
#define __MILLIS_H
#include <stdint.h>
extern void millis_timer_init(void);
extern void millis_timer_uninit();
extern uint32_t millis();
#endif // __MILLIS_H
#endif

Wyświetl plik

@ -14,7 +14,6 @@ uint16_t (*pwm_handle_dma_transfer_full)(uint16_t buffer_size, uint16_t *buffer)
DMA_Channel_TypeDef *pwm_dma_channel = DMA1_Channel2;
void pwm_data_timer_init()
{
// Timer frequency = TIM_CLK/(TIM_PSC+1)/(TIM_ARR + 1)
@ -52,12 +51,6 @@ void pwm_data_timer_init()
TIM_Cmd(TIM2, ENABLE);
}
void pwm_data_timer_dma_request_enable(bool enabled)
{
// TIM2 Update DMA requests are routed to DMA1 Channel2
TIM_DMACmd(TIM2, TIM_DMA_Update, enabled ? ENABLE : DISABLE);
}
void pwm_data_timer_uninit()
{
TIM_Cmd(TIM2, DISABLE);
@ -126,6 +119,51 @@ void pwm_timer_init(uint32_t frequency_hz_100)
TIM_Cmd(TIM15, ENABLE);
}
void pwm_timer_pwm_enable(bool enabled)
{
#ifdef RS41
TIM_CtrlPWMOutputs(TIM15, enabled ? ENABLE : DISABLE);
#endif
}
void pwm_timer_use(bool use)
{
#ifdef RS41
// Remapping the TIM15 outputs will allow TIM15 channel 2 can be used to drive pin PB15,
// which is connected to RS41 Si4032 SDI pin for direct modulation
GPIO_PinRemapConfig(GPIO_Remap_TIM15, use ? ENABLE : DISABLE);
#endif
}
void pwm_timer_uninit()
{
TIM_CtrlPWMOutputs(TIM15, DISABLE);
TIM_Cmd(TIM15, DISABLE);
TIM_DeInit(TIM15);
#ifdef RS41
GPIO_PinRemapConfig(GPIO_Remap_TIM15, DISABLE);
#endif
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, DISABLE);
}
inline uint16_t pwm_calculate_period(uint32_t frequency_hz_100)
{
return (uint16_t) (((100.0f * 1000000.0f) / (frequency_hz_100 * 2.0f))) - 1;
}
inline void pwm_timer_set_frequency(uint32_t pwm_period)
{
TIM_SetAutoreload(TIM15, pwm_period);
}
/**
* Below are experimental DMA routines for supplying PWM data for APRS modulation.
* This does not work correctly, but is left for future reference.
*/
static void pwm_dma_init_channel()
{
DMA_InitTypeDef dma_init;
@ -190,6 +228,12 @@ void pwm_dma_stop()
//pwm_dma_interrupt_enable(false);
}
void pwm_data_timer_dma_request_enable(bool enabled)
{
// TIM2 Update DMA requests are routed to DMA1 Channel2
TIM_DMACmd(TIM2, TIM_DMA_Update, enabled ? ENABLE : DISABLE);
}
void DMA1_Channel2_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TE2)) {
@ -205,51 +249,3 @@ void DMA1_Channel2_IRQHandler(void)
pwm_handle_dma_transfer_full(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
}
void pwm_timer_pwm_enable(bool enabled)
{
#ifdef RS41
TIM_CtrlPWMOutputs(TIM15, enabled ? ENABLE : DISABLE);
#endif
}
void pwm_timer_use(bool use)
{
#ifdef RS41
// Remapping the TIM15 outputs will allow TIM15 channel 2 can be used to drive pin PB15,
// which is connected to RS41 Si4032 SDI pin for direct modulation
GPIO_PinRemapConfig(GPIO_Remap_TIM15, use ? ENABLE : DISABLE);
#endif
}
void pwm_timer_uninit()
{
TIM_CtrlPWMOutputs(TIM15, DISABLE);
TIM_Cmd(TIM15, DISABLE);
TIM_DeInit(TIM15);
#ifdef RS41
GPIO_PinRemapConfig(GPIO_Remap_TIM15, DISABLE);
#endif
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, DISABLE);
}
inline uint16_t pwm_calculate_period(uint32_t frequency_hz_100)
{
return (uint16_t) (((100.0f * 1000000.0f) / (frequency_hz_100 * 2.0f))) - 1;
}
inline void pwm_timer_set_frequency(uint32_t pwm_period)
{
// TIM_CtrlPWMOutputs(TIM15, DISABLE);
// TIM_Cmd(TIM15, DISABLE);
// TIM_SetAutoreload(TIM15, pwm_period);
TIM_SetAutoreload(TIM15, pwm_period);
// TIM_SetCompare2(TIM15, pwm_period / 2);
// TIM_Cmd(TIM15, ENABLE);
// TIM_CtrlPWMOutputs(TIM15, ENABLE);
}

Wyświetl plik

@ -129,13 +129,12 @@ static void gpio_init()
GPIO_Init(BANK_RED_LED, &gpio_init);
#ifdef DFM17
// Yellow LED
// Yellow LED (only in DFM-17)
gpio_init.GPIO_Pin = PIN_YELLOW_LED;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_YELLOW_LED, &gpio_init);
#endif //DFM17
#endif
}
/**
@ -355,14 +354,8 @@ void system_set_red_led(bool enabled)
void system_set_yellow_led(bool enabled)
{
#ifdef RS41
if (enabled) {
GPIO_ResetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
} else {
GPIO_SetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
}
#endif
#ifdef DFM17
// Only DFM-17 has a yellow LED
if (enabled) {
GPIO_SetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
} else {
@ -388,7 +381,10 @@ void system_init()
gpio_init();
dma_adc_init();
delay_init();
#ifdef DFM17
// The millis timer is used for clock calibration on DFM-17 only
millis_timer_init();
#endif
system_scheduler_timer_init();
RCC_ClocksTypeDef RCC_Clocks;

Wyświetl plik

@ -4,9 +4,6 @@
#include "config.h"
#include "hal.h"
#define GPIO_PIN_LED_GREEN GPIO_Pin_7
#define GPIO_PIN_LED_RED GPIO_Pin_8
#define SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND 10000
void system_init();
@ -20,7 +17,7 @@ void system_set_green_led(bool enabled);
void system_set_red_led(bool enabled);
#ifdef DFM17
void system_set_yellow_led(bool enabled);
#endif //DFM17
#endif
uint16_t system_get_battery_voltage_millivolts();
uint16_t system_get_button_adc_value();

Wyświetl plik

@ -1,120 +0,0 @@
#include "stm32f10x_exti.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "config.h"
#include "system.h"
#include "millis.h"
#include "timepulse.h"
// This define copied from .../src/hal/stm_lib/src/stm32f10x_rcc.c
#define CR_HSITRIM_Mask ((uint32_t)0xFFFFFF07)
// Define below pulls the current trim register value out of the Calibration Register (CR)
// Resulting value will be between 0-31.
#define CURRENT_TRIM ((RCC->CR & ~CR_HSITRIM_Mask) >>3)
/*
On the DFM-17, PB8 is wired to the GPS Timepulse. We take advantage of this to do a
processor speed calibration. HSITRIM[4:0] allows for 32 values to adjust the HSI clock
speed. The center (16) value is "neutral". Each trim value above or below 16 adjusts
the clock by approximately 40kHZ (0.5% of the 8MHZ clock speed) (per AN2868). 0.5% is about
5ms per second, so if we detect that we're off by more than 5 millisconds between timepulses, we
will suggest a recalibration. The "calib_suggestion" variable is a static that will be maintained
by the timepulse IRQ and can be used at any time it's convenient to adjust the clock speed.
*/
int calib_suggestion = 16; // Default, but we will check it in the init routine below.
int calib_current = 16; // Default, but we will check it in the init routine below.
uint32_t old_millis = 0;
volatile int timepulsed = 0;
volatile uint32_t d_millis = 0;
bool yellowLEDstate = true;
uint16_t calib_change_count = 0;
uint8_t get_clock_calibration(void)
{
return(CURRENT_TRIM);
}
uint16_t get_calib_change_count(void)
{
return(calib_change_count);
}
void adjust_clock_calibration(void)
{
if (calib_suggestion != calib_current) {
RCC_AdjustHSICalibrationValue(calib_suggestion);
calib_current = calib_suggestion;
yellowLEDstate = !yellowLEDstate;
system_set_yellow_led(yellowLEDstate);
calib_change_count++;
}
}
void timepulse_init(void)
{
// Initialize pin PB8 as floating input
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_8;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &gpio_init);
// PB8 is connected to interrupt line 8, set trigger on the configured edge and enable the interrupt
EXTI_InitTypeDef exti_init;
exti_init.EXTI_Line = EXTI_Line8;
exti_init.EXTI_Mode = EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger = EXTI_Trigger_Rising;
exti_init.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti_init);
// Attach interrupt line to port B
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);
// PB8 is connected to EXTI_Line8, which has EXTI9_5_IRQn vector. Use priority 0 for now.
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// Pull the current calibration to start
calib_current = CURRENT_TRIM;
calib_suggestion = calib_current;
// Set the yellow LED to help identify calibration changes
system_set_yellow_led(yellowLEDstate);
}
// This handler is (at present) only being used for the Timepulse interrupt, so we shouldn't need
// to do additional testing for the cause of the interrupt.
void EXTI9_5_IRQHandler(void)
{
uint32_t m = millis();
int delta;
EXTI_ClearITPendingBit(EXTI_Line8);
timepulsed++;
if (old_millis == 0) {
old_millis = m; // First timepulse. Just store millis.
} else {
d_millis = m - old_millis; // mS since last timepulse. Ideally there were 1000.
old_millis = m;
delta = (int) (1000 - d_millis) / 5; // If too few clicks, speed up clock. If too many, slow down.
if (delta > 1) delta = 1; // Take one step at a time in case we had a bad clock tick
if (delta < -1) delta = -1;
// Don't allow calibration suggestion to go out of range
if (((delta + calib_current) >= 0) &&
((delta + calib_current <= 31)) ) {
// If the delta makes sense, apply to the suggestion. Otherwise, skip.
calib_suggestion = calib_current + delta;
}
}
}

Wyświetl plik

@ -1,11 +0,0 @@
#ifndef __TIMEPULSE_H
#define __TIMEPULSE_H
extern uint8_t get_clock_calibration(void);
extern uint16_t get_calib_change_count(void);
extern void timepulse_init(void);
extern void adjust_clock_calibration(void);
extern volatile int timepulsed;
#endif // __TIMEPULSE_H

Wyświetl plik

@ -1,4 +1,3 @@
#include "hal/stm_lib/inc/stm32f10x_rcc.h"
#include "hal/system.h"
#include "hal/spi.h"
#include "hal/usart_gps.h"
@ -13,8 +12,6 @@
#include "radio.h"
#include "config.h"
#include "log.h"
#include "hal/timepulse.h"
#include "hal/millis.h"
#ifdef RS41
#include "hal/i2c.h"
@ -22,6 +19,7 @@
#endif
#ifdef DFM17
#include "hal/clock_calibration.h"
#include "drivers/si4063/si4063.h"
#endif
@ -86,8 +84,7 @@ void set_yellow_led(bool enabled)
system_set_yellow_led(enabled);
}
#endif //DFM17
#endif
int main(void)
{
@ -133,16 +130,7 @@ int main(void)
#ifdef DFM17
log_info("Timepulse init\n");
timepulse_init();
/*
while (1) {
if (timepulsed != 0) {
log_info("Time Pulse. Calib: %d\n", get_clock_calibration());
timepulsed = 0;
adjust_clock_calibration();
}
}
*/
#endif //DFM17
#endif
#if defined(RS41)
log_info("Si4032 init\n");
@ -205,8 +193,8 @@ int main(void)
while (true) {
radio_handle_main_loop();
#ifdef DFM17
adjust_clock_calibration();
#endif //DFM17
clock_calibration_adjust();
#endif
//NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE);
//__WFI();
}

Wyświetl plik

@ -1,7 +1,6 @@
#include "config.h"
#ifdef RS41
#include <stdint.h>
#include <string.h>
#include "hal/system.h"
@ -260,7 +259,7 @@ inline void radio_handle_data_timer_si4032()
tone_index = fsk_encoder_api->next_tone(fsk_enc);
if (tone_index < 0) {
log_info("Horus V1 TX finished\n");
log_info("Horus TX finished\n");
radio_shared_state.radio_interrupt_transmit_active = false;
radio_shared_state.radio_transmission_finished = true;
system_enable_tick();

Wyświetl plik

@ -8,8 +8,6 @@
#define CW_SYMBOL_RATE_MULTIPLIER 4
static bool use_fast_si5351 = false;
static volatile bool radio_si5351_state_change = false;
static volatile uint64_t radio_si5351_freq = 0;
static volatile bool radio_si5351_frequency_not_set = false;
@ -27,26 +25,18 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state
set_frequency_early = false;
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
//use_fast_si5351 = true;
break;
default:
break;
}
// TODO: handle Si5351 errors
if (use_fast_si5351) {
si5351_set_drive_strength_fast(SI5351_CLOCK_CLK0, entry->tx_power);
if (set_frequency_early) {
si5351_set_frequency_fast(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL);
si5351_output_enable_fast(SI5351_CLOCK_CLK0, true);
}
} else {
si5351_set_drive_strength(SI5351_CLOCK_CLK0, entry->tx_power);
if (set_frequency_early) {
si5351_set_frequency(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL);
si5351_output_enable(SI5351_CLOCK_CLK0, true);
}
si5351_set_drive_strength(SI5351_CLOCK_CLK0, entry->tx_power);
if (set_frequency_early) {
si5351_set_frequency(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL);
si5351_output_enable(SI5351_CLOCK_CLK0, true);
}
switch (entry->data_mode) {
@ -58,6 +48,7 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state
radio_si5351_frequency_not_set = true;
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
system_disable_tick();
shared_state->radio_interrupt_transmit_active = true;
break;
@ -73,8 +64,8 @@ bool radio_transmit_symbol_si5351(radio_transmit_entry *entry, radio_module_stat
switch (entry->data_mode) {
case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP:
return false;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
return false;
default: {
int8_t next_tone_index = entry->fsk_encoder_api->next_tone(&entry->fsk_encoder);
@ -152,14 +143,15 @@ inline void radio_handle_data_timer_si5351()
radio_shared_state.radio_symbol_count_interrupt++;
break;
}
case RADIO_DATA_MODE_HORUS_V1: {
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2: {
fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api;
fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder;
int8_t tone_index;
tone_index = fsk_encoder_api->next_tone(fsk_enc);
if (tone_index < 0) {
log_info("Horus V1 TX finished\n");
log_info("Horus TX finished\n");
radio_shared_state.radio_interrupt_transmit_active = false;
radio_shared_state.radio_transmission_finished = true;
system_enable_tick();
@ -181,30 +173,13 @@ inline void radio_handle_data_timer_si5351()
bool radio_stop_transmit_si5351(radio_transmit_entry *entry, radio_module_state *shared_state)
{
switch (entry->data_mode) {
case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP:
break;
case RADIO_DATA_MODE_HORUS_V1:
// use_fast_si5351 = true;
break;
default:
break;
}
if (use_fast_si5351) {
si5351_output_enable_fast(SI5351_CLOCK_CLK0, false);
} else {
si5351_output_enable(SI5351_CLOCK_CLK0, false);
}
si5351_output_enable(SI5351_CLOCK_CLK0, false);
switch (entry->data_mode) {
case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP:
data_timer_uninit();
system_enable_tick();
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
data_timer_uninit();
system_enable_tick();
break;

Wyświetl plik

@ -1,10 +1,64 @@
#include "drivers/si5351/si5351.h"
#include "config.h"
#if SI5351_FAST_ENABLE
#include "drivers/si5351fast/si5351mcu.h"
#else
#include "drivers/si5351/si5351.h"
#endif
#include "si5351_handler.h"
Si5351 *si5351;
#if SI5351_FAST_ENABLE
Si5351mcu si5351_fast;
#else
Si5351 *si5351;
#endif
#if SI5351_FAST_ENABLE
bool si5351_handler_init()
{
si5351_fast.init(&DEFAULT_I2C_PORT, SIADDR);
return true;
}
bool si5351_set_frequency(si5351_clock_id clock, uint64_t frequency_hz_100)
{
si5351_fast.setFreq((uint8_t) clock, frequency_hz_100 / 100L);
return true;
}
void si5351_output_enable(si5351_clock_id clock, bool enabled)
{
if (enabled) {
si5351_fast.enable((uint8_t) clock);
} else {
si5351_fast.disable((uint8_t) clock);
}
}
void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive)
{
int si5351_drive;
switch (drive) {
case 0:
si5351_drive = SIOUT_2mA;
break;
case 1:
si5351_drive = SIOUT_4mA;
break;
case 2:
si5351_drive = SIOUT_6mA;
break;
case 3:
si5351_drive = SIOUT_8mA;
break;
default:
si5351_drive = SIOUT_2mA;
}
si5351_fast.setPower(si5351_drive, (uint8_t) clock);
}
#else
bool si5351_handler_init()
{
si5351 = new Si5351(&DEFAULT_I2C_PORT);
@ -14,9 +68,6 @@ bool si5351_handler_init()
if (!si5351_found) {
return si5351_found;
}
// si5351_fast.init(&DEFAULT_I2C_PORT, SIADDR);
return si5351_found;
}
@ -53,42 +104,4 @@ void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive)
si5351->drive_strength((enum si5351_clock) clock, si5351_drive);
}
bool si5351_set_frequency_fast(si5351_clock_id clock, uint64_t frequency_hz_100)
{
si5351_fast.setFreq((uint8_t) clock, frequency_hz_100 / 100L);
return true;
}
void si5351_output_enable_fast(si5351_clock_id clock, bool enabled)
{
if (enabled) {
si5351_fast.enable((uint8_t) clock);
} else {
si5351_fast.disable((uint8_t) clock);
}
}
void si5351_set_drive_strength_fast(si5351_clock_id clock, uint8_t drive)
{
int si5351_drive;
switch (drive) {
case 0:
si5351_drive = SIOUT_2mA;
break;
case 1:
si5351_drive = SIOUT_4mA;
break;
case 2:
si5351_drive = SIOUT_6mA;
break;
case 3:
si5351_drive = SIOUT_8mA;
break;
default:
si5351_drive = SIOUT_2mA;
}
si5351_fast.setPower(si5351_drive, (uint8_t) clock);
}
#endif

Wyświetl plik

@ -23,9 +23,6 @@ bool si5351_handler_init();
bool si5351_set_frequency(si5351_clock_id clock, uint64_t frequency_hz_100);
void si5351_output_enable(si5351_clock_id clock, bool enabled);
void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive);
bool si5351_set_frequency_fast(si5351_clock_id clock, uint64_t frequency_hz_100);
void si5351_output_enable_fast(si5351_clock_id clock, bool enabled);
void si5351_set_drive_strength_fast(si5351_clock_id clock, uint8_t drive);
#ifdef __cplusplus
}

Wyświetl plik

@ -7,12 +7,12 @@
#include "locator.h"
#include "config.h"
#include "log.h"
#include "hal/timepulse.h"
#ifdef RS41
#include "drivers/si4032/si4032.h"
#endif
#ifdef DFM17
#include "hal/clock_calibration.h"
#include "drivers/si4063/si4063.h"
#endif
@ -71,8 +71,11 @@ void telemetry_collect(telemetry_data *data)
data->gps.heading_degrees_100000 = 0;
data->gps.climb_cm_per_second = 0;
}
data->clock_calibration = get_clock_calibration();
data->clock_calibration_count = get_calib_change_count();
#ifdef DFM17
data->clock_calibration_trim = clock_calibration_get_trim();
data->clock_calibration_count = clock_calibration_get_change_count();
#endif
locator_from_lonlat(data->gps.longitude_degrees_1000000, data->gps.latitude_degrees_1000000,
LOCATOR_PAIR_COUNT_FULL, data->locator);

Wyświetl plik

@ -21,7 +21,8 @@ typedef struct _telemetry_data {
gps_data gps;
char locator[LOCATOR_PAIR_COUNT_FULL * 2 + 1];
int clock_calibration;
int clock_calibration_trim;
uint16_t clock_calibration_count;
} telemetry_data;

Wyświetl plik

@ -111,6 +111,14 @@ size_t template_replace(char *dest, size_t dest_len, char *src, telemetry_data *
strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$ri", replacement);
snprintf(replacement, sizeof(replacement), "%d", (int) data->clock_calibration_trim);
strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$ct", replacement);
snprintf(replacement, sizeof(replacement), "%d", (int) data->clock_calibration_count);
strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$cc", replacement);
free(temp);
return len;