kopia lustrzana https://github.com/mikaelnousiainen/RS41ng
Porównaj commity
10 Commity
7818133f52
...
8f3d9cf612
Autor | SHA1 | Data |
---|---|---|
Mikael Nousiainen | 8f3d9cf612 | |
Mikael Nousiainen | 9cd9a64a16 | |
Mikael Nousiainen | f9d964ab8e | |
Mikael Nousiainen | 61e428789a | |
Mikael Nousiainen | 18b6e1ffb4 | |
Mikael Nousiainen | 6462371a14 | |
Mike Hojnowski | 591749fa98 | |
Mike Hojnowski | a34c9b9e1f | |
Mike Hojnowski | 0901b02de4 | |
Mike Hojnowski | 324c3bf83b |
13
README.md
13
README.md
|
@ -329,8 +329,9 @@ Now you can flash the firmware using instructions below (skip the build instruct
|
|||
|
||||
Software requirements:
|
||||
|
||||
* [GNU GCC toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/9-2-2019-12)
|
||||
version 8.3.0 or higher for cross-compiling the firmware for the ARM Cortex-M3 architecture (`arm-none-eabi-gcc`)
|
||||
* [GNU GCC toolchain](https://developer.arm.com/downloads/-/gnu-rm)
|
||||
for cross-compiling the firmware for the ARM Cortex-M3 architecture (`arm-none-eabi-gcc`)
|
||||
* Pick the latest toolchain version available for your operating system.
|
||||
* [CMake](https://cmake.org/) version 3.6 or higher for building the firmware
|
||||
* [OpenOCD](http://openocd.org/) version 0.10.0 or higher for flashing the firmware
|
||||
|
||||
|
@ -475,7 +476,8 @@ _____
|
|||
It is possible to receive log messages from the firmware program and to perform debugging of the firmware using GNU GDB.
|
||||
|
||||
Also, please note that Red Hat/Fedora do not provide GDB for ARM architectures, so you will need to manually download
|
||||
and install GDB from [ARM GNU GCC toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/9-2-2019-12).
|
||||
and install GDB from [ARM GNU GCC toolchain](https://developer.arm.com/downloads/-/gnu-rm).
|
||||
Pick the latest version available for your operating system.
|
||||
|
||||
Semihosting allows the firmware to send log messages via special system calls to OpenOCD, so that you
|
||||
can get real-time feedback and debug output from the application.
|
||||
|
@ -514,7 +516,9 @@ otherwise the firmware will not run.**
|
|||
To load debugging symbols for settings breakpoints and to perform more detailed inspection,
|
||||
use command `file src/RS41ng.elf`.
|
||||
|
||||
## Si4032 Bell FSK modulation hack for APRS (notes by Mikael OH3BHX)
|
||||
## Si4032 Bell FSK modulation hack for APRS
|
||||
|
||||
Notes by Mikael OH3BHX:
|
||||
|
||||
The idea behind the APRS / Bell 202 modulation implementation is based on RS41HUP project and its "ancestors"
|
||||
and I'm describing it here, since it has not been documented elsewhere.
|
||||
|
@ -598,6 +602,7 @@ rtl_fm -f 432500000 -M fm -s 250k -r 48000 -g 22 - | ./aprs -
|
|||
* http://happysat.nl/RS-41/RS41.html - Vaisala RS-41 SGP Modification and info about the original firmware settings
|
||||
* https://destevez.net/2018/06/flashing-a-vaisala-rs41-radiosonde/
|
||||
* https://destevez.net/2017/11/tracking-an-rs41-sgp-radiosonde-and-reporting-to-aprs/
|
||||
* https://github.com/digiampietro/esp8266-rs41 - A tool for reconfiguring RS41s via its serial port
|
||||
|
||||
## Graw DFM-17 hardware documentation
|
||||
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
#define BANK_GREEN_LED GPIOC
|
||||
#define PIN_GREEN_LED GPIO_Pin_6
|
||||
|
||||
#define BANK_YELLOW_LED GPIOC
|
||||
#define PIN_YELLOW_LED GPIO_Pin_7
|
||||
|
||||
#define BANK_MOSI GPIOA
|
||||
#define PIN_MOSI GPIO_Pin_7
|
||||
#define BANK_SCK GPIOA
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -34,8 +34,8 @@ void data_timer_init(uint32_t baud_rate)
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM2_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
||||
|
@ -48,8 +48,8 @@ void data_timer_uninit()
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM2_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelCmd = DISABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ void delay_init()
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM3_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include <stm32f10x_rcc.h>
|
||||
#include <stm32f10x_tim.h>
|
||||
#include <misc.h>
|
||||
|
||||
#include "src/hal/millis.h"
|
||||
|
||||
static uint32_t millis_counter;
|
||||
|
||||
void millis_timer_init(void)
|
||||
{
|
||||
TIM_DeInit(TIM7);
|
||||
|
||||
TIM_TimeBaseInitTypeDef tim_init;
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
|
||||
RCC_APB2PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
|
||||
|
||||
// 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); // set up period of 1 millisecond
|
||||
tim_init.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
tim_init.TIM_RepetitionCounter = 0;
|
||||
|
||||
TIM_TimeBaseInit(TIM7, &tim_init);
|
||||
|
||||
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
|
||||
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
|
||||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM7_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
||||
TIM_Cmd(TIM7, ENABLE);
|
||||
}
|
||||
|
||||
void millis_timer_uninit()
|
||||
{
|
||||
TIM_Cmd(TIM7, DISABLE);
|
||||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM7_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelCmd = DISABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
||||
TIM_ITConfig(TIM7, TIM_IT_Update, DISABLE);
|
||||
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +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
|
||||
|
191
src/hal/pwm.c
191
src/hal/pwm.c
|
@ -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)
|
||||
|
@ -43,8 +42,8 @@ void pwm_data_timer_init()
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM2_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -117,7 +110,7 @@ void pwm_timer_init(uint32_t frequency_hz_100)
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
@ -126,86 +119,6 @@ void pwm_timer_init(uint32_t frequency_hz_100)
|
|||
TIM_Cmd(TIM15, ENABLE);
|
||||
}
|
||||
|
||||
static void pwm_dma_init_channel()
|
||||
{
|
||||
DMA_InitTypeDef dma_init;
|
||||
dma_init.DMA_BufferSize = PWM_TIMER_DMA_BUFFER_SIZE;
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
dma_init.DMA_MemoryBaseAddr = (uint32_t) pwm_timer_dma_buffer;
|
||||
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
|
||||
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
dma_init.DMA_Mode = DMA_Mode_Circular;
|
||||
dma_init.DMA_PeripheralBaseAddr = (uint32_t) &TIM15->ARR;
|
||||
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // DMA_PeripheralDataSize_Word ?
|
||||
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
|
||||
DMA_Init(pwm_dma_channel, &dma_init);
|
||||
}
|
||||
|
||||
inline void pwm_dma_interrupt_enable(bool enabled)
|
||||
{
|
||||
DMA_ClearITPendingBit(DMA1_IT_HT2);
|
||||
DMA_ClearITPendingBit(DMA1_IT_TC2);
|
||||
DMA_ITConfig(pwm_dma_channel, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, enabled ? ENABLE : DISABLE);
|
||||
}
|
||||
|
||||
void pwm_dma_init()
|
||||
{
|
||||
DMA_DeInit(pwm_dma_channel);
|
||||
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
|
||||
pwm_dma_init_channel();
|
||||
|
||||
pwm_dma_interrupt_enable(true);
|
||||
|
||||
DMA_Cmd(pwm_dma_channel, ENABLE);
|
||||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = DMA1_Channel2_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 1;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
}
|
||||
|
||||
void pwm_dma_start()
|
||||
{
|
||||
//pwm_dma_init_channel();
|
||||
//pwm_dma_interrupt_enable(true);
|
||||
// TODO: Why doesn't timer DMA request restart without reinitializing the timer?
|
||||
pwm_timer_init(100 * 100);
|
||||
pwm_timer_pwm_enable(true);
|
||||
pwm_timer_use(true);
|
||||
DMA_SetCurrDataCounter(pwm_dma_channel, PWM_TIMER_DMA_BUFFER_SIZE);
|
||||
DMA_Cmd(pwm_dma_channel, ENABLE);
|
||||
pwm_data_timer_dma_request_enable(true);
|
||||
}
|
||||
|
||||
void pwm_dma_stop()
|
||||
{
|
||||
pwm_data_timer_dma_request_enable(false);
|
||||
DMA_Cmd(pwm_dma_channel, DISABLE);
|
||||
//pwm_dma_interrupt_enable(false);
|
||||
}
|
||||
|
||||
void DMA1_Channel2_IRQHandler(void)
|
||||
{
|
||||
if (DMA_GetITStatus(DMA1_IT_TE2)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_TE2);
|
||||
log_info("DMA Transfer Error\n");
|
||||
}
|
||||
if (DMA_GetITStatus(DMA1_IT_HT2)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_HT2);
|
||||
pwm_handle_dma_transfer_half(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
|
||||
}
|
||||
if (DMA_GetITStatus(DMA1_IT_TC2)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_TC2);
|
||||
pwm_handle_dma_transfer_full(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void pwm_timer_pwm_enable(bool enabled)
|
||||
{
|
||||
#ifdef RS41
|
||||
|
@ -243,12 +156,96 @@ inline uint16_t pwm_calculate_period(uint32_t frequency_hz_100)
|
|||
|
||||
inline void pwm_timer_set_frequency(uint32_t pwm_period)
|
||||
{
|
||||
// TIM_CtrlPWMOutputs(TIM15, DISABLE);
|
||||
// TIM_Cmd(TIM15, DISABLE);
|
||||
|
||||
TIM_SetAutoreload(TIM15, pwm_period);
|
||||
// TIM_SetCompare2(TIM15, pwm_period / 2);
|
||||
|
||||
// TIM_Cmd(TIM15, ENABLE);
|
||||
// TIM_CtrlPWMOutputs(TIM15, ENABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
dma_init.DMA_BufferSize = PWM_TIMER_DMA_BUFFER_SIZE;
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
dma_init.DMA_MemoryBaseAddr = (uint32_t) pwm_timer_dma_buffer;
|
||||
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
|
||||
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
dma_init.DMA_Mode = DMA_Mode_Circular;
|
||||
dma_init.DMA_PeripheralBaseAddr = (uint32_t) &TIM15->ARR;
|
||||
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // DMA_PeripheralDataSize_Word ?
|
||||
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
|
||||
DMA_Init(pwm_dma_channel, &dma_init);
|
||||
}
|
||||
|
||||
inline void pwm_dma_interrupt_enable(bool enabled)
|
||||
{
|
||||
DMA_ClearITPendingBit(DMA1_IT_HT2);
|
||||
DMA_ClearITPendingBit(DMA1_IT_TC2);
|
||||
DMA_ITConfig(pwm_dma_channel, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, enabled ? ENABLE : DISABLE);
|
||||
}
|
||||
|
||||
void pwm_dma_init()
|
||||
{
|
||||
DMA_DeInit(pwm_dma_channel);
|
||||
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
|
||||
pwm_dma_init_channel();
|
||||
|
||||
pwm_dma_interrupt_enable(true);
|
||||
|
||||
DMA_Cmd(pwm_dma_channel, ENABLE);
|
||||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = DMA1_Channel2_IRQn;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 0;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
}
|
||||
|
||||
void pwm_dma_start()
|
||||
{
|
||||
//pwm_dma_init_channel();
|
||||
//pwm_dma_interrupt_enable(true);
|
||||
// TODO: Why doesn't timer DMA request restart without reinitializing the timer?
|
||||
pwm_timer_init(100 * 100);
|
||||
pwm_timer_pwm_enable(true);
|
||||
pwm_timer_use(true);
|
||||
DMA_SetCurrDataCounter(pwm_dma_channel, PWM_TIMER_DMA_BUFFER_SIZE);
|
||||
DMA_Cmd(pwm_dma_channel, ENABLE);
|
||||
pwm_data_timer_dma_request_enable(true);
|
||||
}
|
||||
|
||||
void pwm_dma_stop()
|
||||
{
|
||||
pwm_data_timer_dma_request_enable(false);
|
||||
DMA_Cmd(pwm_dma_channel, DISABLE);
|
||||
//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)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_TE2);
|
||||
log_info("DMA Transfer Error\n");
|
||||
}
|
||||
if (DMA_GetITStatus(DMA1_IT_HT2)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_HT2);
|
||||
pwm_handle_dma_transfer_half(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
|
||||
}
|
||||
if (DMA_GetITStatus(DMA1_IT_TC2)) {
|
||||
DMA_ClearITPendingBit(DMA1_IT_TC2);
|
||||
pwm_handle_dma_transfer_full(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "delay.h"
|
||||
#include "log.h"
|
||||
#include "gpio.h"
|
||||
#include "millis.h"
|
||||
|
||||
#define BUTTON_PRESS_LONG_COUNT SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND
|
||||
|
||||
|
@ -126,6 +127,14 @@ static void gpio_init()
|
|||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(BANK_RED_LED, &gpio_init);
|
||||
|
||||
#ifdef DFM17
|
||||
// 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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,6 +352,18 @@ void system_set_red_led(bool enabled)
|
|||
#endif
|
||||
}
|
||||
|
||||
void system_set_yellow_led(bool enabled)
|
||||
{
|
||||
#ifdef DFM17
|
||||
// Only DFM-17 has a yellow LED
|
||||
if (enabled) {
|
||||
GPIO_SetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
|
||||
} else {
|
||||
GPIO_ResetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void system_disable_irq()
|
||||
{
|
||||
__disable_irq();
|
||||
|
@ -360,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;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
#ifndef __HAL_SYSTEM_H
|
||||
#define __HAL_SYSTEM_H
|
||||
|
||||
#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();
|
||||
|
@ -17,6 +15,9 @@ void system_disable_irq();
|
|||
void system_enable_irq();
|
||||
void system_set_green_led(bool enabled);
|
||||
void system_set_red_led(bool enabled);
|
||||
#ifdef DFM17
|
||||
void system_set_yellow_led(bool enabled);
|
||||
#endif
|
||||
uint16_t system_get_battery_voltage_millivolts();
|
||||
uint16_t system_get_button_adc_value();
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void usart_gps_init(uint32_t baud_rate, bool enable_irq)
|
|||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = USART_IRQ;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 15;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 3;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
|
20
src/main.c
20
src/main.c
|
@ -19,6 +19,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef DFM17
|
||||
#include "hal/clock_calibration.h"
|
||||
#include "drivers/si4063/si4063.h"
|
||||
#endif
|
||||
|
||||
|
@ -74,6 +75,17 @@ void set_red_led(bool enabled)
|
|||
system_set_red_led(enabled);
|
||||
}
|
||||
|
||||
#ifdef DFM17
|
||||
void set_yellow_led(bool enabled)
|
||||
{
|
||||
if ((LEDS_DISABLE_ALTITUDE_METERS > 0) && (current_gps_data.altitude_mm / 1000 > LEDS_DISABLE_ALTITUDE_METERS)) {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
system_set_yellow_led(enabled);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bool success;
|
||||
|
@ -115,6 +127,11 @@ int main(void)
|
|||
goto gps_init;
|
||||
}
|
||||
|
||||
#ifdef DFM17
|
||||
log_info("Timepulse init\n");
|
||||
timepulse_init();
|
||||
#endif
|
||||
|
||||
#if defined(RS41)
|
||||
log_info("Si4032 init\n");
|
||||
si4032_init();
|
||||
|
@ -175,6 +192,9 @@ int main(void)
|
|||
|
||||
while (true) {
|
||||
radio_handle_main_loop();
|
||||
#ifdef DFM17
|
||||
clock_calibration_adjust();
|
||||
#endif
|
||||
//NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE);
|
||||
//__WFI();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
// TODO: Add support for multiple APRS baud rates
|
||||
// This delay is for DFM-17 radiosondes
|
||||
#define symbol_delay_bell_202_1200bps_us 820
|
||||
#define symbol_delay_bell_202_1200bps_us 821
|
||||
|
||||
static volatile bool radio_si4063_state_change = false;
|
||||
static volatile uint32_t radio_si4063_freq = 0;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "drivers/si4032/si4032.h"
|
||||
#endif
|
||||
#ifdef DFM17
|
||||
#include "hal/clock_calibration.h"
|
||||
#include "drivers/si4063/si4063.h"
|
||||
#endif
|
||||
|
||||
|
@ -71,6 +72,11 @@ void telemetry_collect(telemetry_data *data)
|
|||
data->gps.climb_cm_per_second = 0;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@ typedef struct _telemetry_data {
|
|||
gps_data gps;
|
||||
|
||||
char locator[LOCATOR_PAIR_COUNT_FULL * 2 + 1];
|
||||
|
||||
int clock_calibration_trim;
|
||||
uint16_t clock_calibration_count;
|
||||
} telemetry_data;
|
||||
|
||||
void telemetry_collect(telemetry_data *data);
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue