Implementing Si4063 radio chip support for DFM17 sonde. Work in progress.

pull/55/head
Mikael Nousiainen 2023-09-12 20:16:37 +03:00
rodzic 0e50f0a334
commit 4af4005dd7
15 zmienionych plików z 605 dodań i 241 usunięć

Wyświetl plik

@ -1,15 +1,15 @@
#ifndef __CONFIG_H
#define __CONFIG_H
// Define SONDE Type. Must be DFM17 or RS41
// Define radiosonde type. Must be either RS41 or DFM17.
//#define RS41
#define DFM17
// Enable semihosting to receive debug logs during development
// See the README for details on how to set up debugging and debug logs with GDB
// NOTE: Semihosting has to be disabled when the RS41 radiosonde is not connected to an STM32 programmer dongle, otherwise the firmware will not run.
//#define SEMIHOSTING_ENABLE
//#define LOGGING_ENABLE
#define SEMIHOSTING_ENABLE
#define LOGGING_ENABLE
/**
* Global configuration
@ -130,11 +130,11 @@
#define RADIO_SI4032_TX_CW_COUNT 1
#define RADIO_SI4032_TX_PIP false
#define RADIO_SI4032_TX_PIP_COUNT 6
#define RADIO_SI4032_TX_APRS true
#define RADIO_SI4032_TX_APRS false
#define RADIO_SI4032_TX_APRS_COUNT 2
#define RADIO_SI4032_TX_HORUS_V1 false
#define RADIO_SI4032_TX_HORUS_V1_COUNT 1
#define RADIO_SI4032_TX_HORUS_V2 true
#define RADIO_SI4032_TX_HORUS_V2 false
#define RADIO_SI4032_TX_HORUS_V2_COUNT 6
// Continuous transmit mode can be enabled for *either* Horus V1 or V2, but not both. This disables all other transmission modes.
@ -151,6 +151,41 @@
#define RADIO_SI4032_TX_FREQUENCY_HORUS_V1 432501000
#define RADIO_SI4032_TX_FREQUENCY_HORUS_V2 432501000
/**
* Built-in Si4063 radio chip transmission configuration
*/
// Si4063 transmit power: 0..127
// TODO: Document Si4063 transmit power levels
#define RADIO_SI4063_TX_POWER 127
// Which modes to transmit using the built-in Si4063 transmitter chip
// The COUNT settings define the number of times that each type of transmission is repeated
#define RADIO_SI4063_TX_CW false
#define RADIO_SI4063_TX_CW_COUNT 1
#define RADIO_SI4063_TX_PIP false
#define RADIO_SI4063_TX_PIP_COUNT 6
#define RADIO_SI4063_TX_APRS false
#define RADIO_SI4063_TX_APRS_COUNT 2
#define RADIO_SI4063_TX_HORUS_V1 false
#define RADIO_SI4063_TX_HORUS_V1_COUNT 1
#define RADIO_SI4063_TX_HORUS_V2 true
#define RADIO_SI4063_TX_HORUS_V2_COUNT 6
// Continuous transmit mode can be enabled for *either* Horus V1 or V2, but not both. This disables all other transmission modes.
// The continuous mode transmits Horus 4FSK preamble between transmissions
// to allow Horus receivers to keep frequency synchronization at all times, which improves reception.
#define RADIO_SI4063_TX_HORUS_V1_CONTINUOUS false
#define RADIO_SI4063_TX_HORUS_V2_CONTINUOUS false
// Transmit frequencies for the Si4063 transmitter modes
#define RADIO_SI4063_TX_FREQUENCY_CW 432500000
#define RADIO_SI4063_TX_FREQUENCY_PIP 432500000
#define RADIO_SI4063_TX_FREQUENCY_APRS_1200 432500000
// Use a frequency offset to place FSK tones slightly above the defined frequency for SSB reception
#define RADIO_SI4063_TX_FREQUENCY_HORUS_V1 432501000
#define RADIO_SI4063_TX_FREQUENCY_HORUS_V2 432501000
/**
* External Si5351 radio chip transmission configuration
*/
@ -240,6 +275,7 @@
*/
#define HORUS_FREQUENCY_OFFSET_SI4032 0
#define HORUS_FREQUENCY_OFFSET_SI4063 0
/**
* Horus V1 4FSK mode settings (deprecated, please use Horus V2 mode)
@ -250,6 +286,7 @@
// Please request a new payload ID in GitHub according to the instructions at: https://github.com/projecthorus/horusdemodlib/wiki#how-do-i-transmit-it
#define HORUS_V1_PAYLOAD_ID 0
#define HORUS_V1_BAUD_RATE_SI4032 100
#define HORUS_V1_BAUD_RATE_SI4063 100
#define HORUS_V1_BAUD_RATE_SI5351 50
#define HORUS_V1_PREAMBLE_LENGTH 16
#define HORUS_V1_IDLE_PREAMBLE_LENGTH 32
@ -269,6 +306,7 @@
// Please request a new payload ID in GitHub according to the instructions at: https://github.com/projecthorus/horusdemodlib/wiki#how-do-i-transmit-it
#define HORUS_V2_PAYLOAD_ID 256
#define HORUS_V2_BAUD_RATE_SI4032 100
#define HORUS_V2_BAUD_RATE_SI4063 100
#define HORUS_V2_BAUD_RATE_SI5351 50
#define HORUS_V2_PREAMBLE_LENGTH 16
#define HORUS_V2_IDLE_PREAMBLE_LENGTH 32

Wyświetl plik

@ -1,49 +1,158 @@
#include <stdbool.h>
#include <stm32f10x_gpio.h>
#include "hal/hal.h"
#include "hal/delay.h"
#include "hal/spi.h"
#include "si4063.h"
#include "gpio.h"
#include "log.h"
#define SPI_WRITE_FLAG 0x80
#define SI4063_CLOCK 25600000UL
#define SI4063_CLOCK 26.0f
#define GPIO_SI4063_SDN GPIOC
#define GPIO_PIN_SI4063_SDN GPIO_Pin_3
#define GPIO_SI4063_NSEL GPIOC
#define GPIO_PIN_SI4063_NSEL GPIO_Pin_13
#define GPIO_SI4063_NSEL GPIOB
#define GPIO_PIN_SI4063_NSEL GPIO_Pin_2
#define GPIO_SI4063_SDI GPIOB
#define GPIO_PIN_SI4063_SDI GPIO_Pin_15
#define GPIO_SI4063_SDI GPIOA
#define GPIO_PIN_SI4063_SDI GPIO_Pin_7
static inline uint8_t si4063_write(uint8_t reg, uint8_t value)
#define GPIO_SI4063_GPIO2 GPIOD
#define GPIO_PIN_SI4063_GPIO2 GPIO_Pin_0
#define GPIO_SI4063_GPIO3 GPIOA
#define GPIO_PIN_SI4063_GPIO3 GPIO_Pin_4
#define SI4063_COMMAND_PART_INFO 0x01
#define SI4063_COMMAND_POWER_UP 0x02
#define SI4063_COMMAND_SET_PROPERTY 0x11
#define SI4063_COMMAND_START_TX 0x31
#define SI4063_COMMAND_CHANGE_STATE 0x34
#define SI4063_COMMAND_GET_ADC_READING 0x14
#define SI4063_STATE_SLEEP 0x01
#define SI4063_STATE_SPI_ACTIVE 0x02
#define SI4063_STATE_READY 0x03
#define SI4063_STATE_TX_TUNE 0x05
#define SI4063_STATE_TX 0x07
static inline void si4063_set_chip_select(bool select)
{
return spi_send_and_receive(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL, ((reg | SPI_WRITE_FLAG) << 8U) | value);
spi_set_chip_select(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL, select);
}
static inline uint8_t si4063_read(uint8_t reg)
static int si4063_wait_for_cts()
{
return spi_send_and_receive(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL, (reg << 8U) | 0xFFU);
uint16_t timeout = 0xFFFF;
uint8_t response;
// Poll CTS over SPI
do
{
si4063_set_chip_select(true);
spi_send(0x44);
response = spi_read();
si4063_set_chip_select(false);
} while (response != 0xFF && timeout--);
return timeout > 0 ? HAL_OK : HAL_ERROR;
}
void si4063_soft_reset()
static int si4063_read_response(uint8_t length, uint8_t *data)
{
si4063_write(0x07, 0x80);
uint16_t timeout = 0xFFFF;
uint8_t response;
// Poll CTS over SPI
do {
si4063_set_chip_select(true);
spi_send(0x44);
response = spi_read();
if (response == 0xFF) {
break;
}
si4063_set_chip_select(false);
delay_us(10);
} while(timeout--);
if (timeout == 0) {
si4063_set_chip_select(false);
return HAL_ERROR;
}
// Read the requested data
while (length--) {
*(data++) = spi_read();
}
si4063_set_chip_select(false);
return HAL_OK;
}
static void si4063_send_command(uint8_t command, uint8_t length, uint8_t *data)
{
si4063_wait_for_cts();
si4063_set_chip_select(true);
// Output enable time, 20ns
for (uint32_t i = 0; i < 0xFFFF; i++);
spi_send(command);
while (length--) {
spi_send(*(data++));
}
si4063_set_chip_select(false);
}
static void si4063_power_up()
{
uint8_t data[] = {
0x01, //
0x01, // No patch, boot main app. img, TXCO
(SI4063_CLOCK >> 24) & 0xFF, // VCXO frequency
(SI4063_CLOCK >> 16) & 0xFF,
(SI4063_CLOCK >> 8) & 0xFF,
SI4063_CLOCK & 0xFF
};
si4063_send_command(SI4063_COMMAND_POWER_UP, sizeof(data), data);
}
static void si4603_set_shutdown(bool active)
{
if (active) {
GPIO_SetBits(GPIO_SI4063_SDN, GPIO_PIN_SI4063_SDN);
} else {
GPIO_ResetBits(GPIO_SI4063_SDN, GPIO_PIN_SI4063_SDN);
}
}
static void si4063_set_state(uint8_t state)
{
si4063_send_command(SI4063_COMMAND_CHANGE_STATE, 1, &state);
}
void si4063_enable_tx()
{
// Modified to set the PLL and Crystal enable bits to high. Not sure if this makes much difference.
si4063_write(0x07, 0x4B);
si4063_set_state(SI4063_STATE_TX);
}
void si4063_inhibit_tx()
{
// Sleep mode, but with PLL idle mode enabled, in an attempt to reduce drift on key-up.
si4063_write(0x07, 0x43);
si4063_set_state(SI4063_STATE_READY);
}
void si4063_disable_tx()
{
si4063_write(0x07, 0x40);
// Is this needed?
si4063_set_state(SI4063_STATE_SLEEP);
}
void si4063_use_direct_mode(bool use)
@ -55,86 +164,182 @@ void si4063_use_direct_mode(bool use)
}
}
void si4063_set_tx_frequency(const float frequency_mhz)
void si4063_set_tx_frequency(const uint32_t frequency_hz)
{
uint8_t hbsel = (uint8_t) ((frequency_mhz * (30.0f / SI4063_CLOCK)) >= 480.0f ? 1 : 0);
uint8_t outdiv, band;
uint32_t f_pfd, n, m;
float ratio, rest;
uint8_t fb = (uint8_t) ((((uint8_t) ((frequency_mhz * (30.0f / SI4063_CLOCK)) / 10) - 24) - (24 * hbsel)) /
(1 + hbsel));
uint8_t gen_div = 3; // constant - not possible to change!
uint16_t fc = (uint16_t) (((frequency_mhz / ((SI4063_CLOCK / gen_div) * (hbsel + 1))) - fb - 24) * 64000);
si4063_write(0x75, (uint8_t) (0b01000000 | (fb & 0b11111) | ((hbsel & 0b1) << 5)));
si4063_write(0x76, (uint8_t) (((uint16_t) fc >> 8U) & 0xffU));
si4063_write(0x77, (uint8_t) ((uint16_t) fc & 0xff));
/* Set the output divider according to the recommended ranges in the si406x datasheet */
if (frequency_hz < 177000000UL) {
outdiv = 24;
band = 5;
} else if (frequency_hz < 239000000UL) {
outdiv = 16;
band = 4;
} else if (frequency_hz < 353000000UL) {
outdiv = 12;
band = 3;
} else if (frequency_hz < 525000000UL) {
outdiv = 8;
band = 2;
} else if (frequency_hz < 705000000UL) {
outdiv = 6;
band = 1;
} else {
outdiv = 4;
band = 0;
}
f_pfd = 2 * SI4063_CLOCK / outdiv;
n = frequency_hz / f_pfd - 1;
ratio = (float) frequency_hz / f_pfd;
rest = ratio - n;
m = rest * 524288UL;
// Set the frequency band
{
uint8_t data[] = {
0x20, // 0x20 = Group MODEM
0x01, // Set 1 property
0x51, // 0x51 = MODEM_CLKGEN_BAND
0x08 + band // 0x08 = SY_SEL: High Performance mode (fixed prescaler = Div-by-2). Finer tuning.
};
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
// Set the PLL parameters
{
uint8_t data[] = {
0x40, // 0x40 = Group FREQ_CONTROL
0x06, // Set 6 properties
0x00, // 0x00 = Start from FREQ_CONTROL_INTE
n, // 0 (FREQ_CONTROL_INTE): Frac-N PLL Synthesizer integer divide number.
(m >> 16) & 0xFF, // 1 (FREQ_CONTROL_FRAC): Frac-N PLL fraction number.
(m >> 8) & 0xFF, // 2 (FREQ_CONTROL_FRAC): Frac-N PLL fraction number.
m & 0xFF, // 3 (FREQ_CONTROL_FRAC): Frac-N PLL fraction number.
0x00, // 4 (FREQ_CONTROL_CHANNEL_STEP_SIZE): EZ Frequency Programming channel step size.
0x02 // 5 (FREQ_CONTROL_CHANNEL_STEP_SIZE): EZ Frequency Programming channel step size.
};
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
}
void si4063_set_tx_power(uint8_t power)
{
si4063_write(0x6D, power & 0x7U);
uint8_t data[] = {
0x22, // 0x20 = Group PA
0x01, // Set 1 property
0x01, // 0x01 = PA_PWR_LVL
power & 0x7F // Power level from 00..7F
};
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
/**
* The frequency offset can be calculated as Offset = 156.25 Hz x (hbsel + 1) x fo[7:0]. fo[9:0] is a twos complement value. fo[9] is the sign bit.
* For 70cm band hbsel is 1, so offset step is 312.5 Hz
*/
void si4063_set_frequency_offset(uint16_t offset)
{
si4063_write(0x73, offset);
si4063_write(0x74, 0);
uint8_t data[] = {
0x20, // 0x20 = Group MODEM
0x02, // Set 2 properties (2 bytes)
0x0D, // 0x0D = MODEM_FREQ_OFFSET
offset >> 8, // Upper 8 bits of the offset
offset & 0xFF // Lower 8 bits of the offset
};
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
inline void si4063_set_frequency_offset_small(uint8_t offset)
void si4063_set_frequency_deviation(uint32_t deviation)
{
si4063_write(0x73, offset);
}
uint8_t data[] = {
0x20, // 0x20 = Group MODEM
0x03, // Set 3 properties (3 bytes)
0x0A, // 0x0A = MODEM_FREQ_DEV
(deviation >> 16) & 0xFF,
(deviation >> 8) & 0xFF,
deviation & 0xFF
};
void si4063_set_frequency_deviation(uint8_t deviation)
{
// The frequency deviation can be calculated: Fd = 625 Hz x fd[8:0].
// Zero disables deviation between 0/1 bits
si4063_write(0x72, deviation);
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
void si4063_set_modulation_type(si4063_modulation_type type)
{
uint8_t value;
uint8_t data[] = {
0x20, // 0x20 = Group MODEM
0x01, // Set 1 property
0x00, // 0x00 = MODEM_MOD_TYPE
0x80 | // 0x80 = Direct async mode (MCU-controlled)
0x40 | // 0x40 = Use GPIO2 as source for FSK modulation (alternatively, use 0x60 for GPIO3)
0x08 // 0x08 = Direct modulation source (MCU-controlled)
};
switch (type) {
case SI4063_MODULATION_TYPE_NONE:
// No modulation (for modulating via frequency offset, e.g. for RTTY)
value = 0x00;
case SI4063_MODULATION_TYPE_CW:
// Pure carrier wave modulation (for modulating via frequency offset, e.g. for RTTY)
data[3] |= 0x00;
break;
case SI4063_MODULATION_TYPE_OOK:
// Direct Async Mode with OOK modulation
value = 0b00010001;
data[3] |= 0x01;
break;
case SI4063_MODULATION_TYPE_FSK:
// Direct Async Mode with FSK modulation
value = 0b00010010;
data[3] |= 0x02;
break;
default:
return;
}
si4063_write(0x71, value);
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
}
int32_t si4063_read_temperature_celsius_100()
{
// Set the input for ADC to the temperature sensor, "Register 0Fh. ADC Configuration"—adcsel[2:0] = 000
// Set the reference for ADC, "Register 0Fh. ADC Configuration"—adcref[1:0] = 00
si4063_write(0x0f, 0b00000000);
// Set the temperature range for ADC, "Register 12h. Temperature Sensor Calibration"—tsrange[1:0]
// Range: –64 ... 64 °C, Slope 8 mV/°C, ADC8 LSB 0.5 °C
si4063_write(0x12, 0b00100000);
// Set entsoffs = 1, "Register 12h. Temperature Sensor Calibration"
// Trigger ADC reading, "Register 0Fh. ADC Configuration"—adcstart = 1
si4063_write(0x0f, 0b10000000);
// Read temperature value—Read contents of "Register 11h. ADC Value"
int32_t raw_value = (int32_t) si4063_read(0x11);
uint8_t response[6];
int32_t temperature;
uint8_t data[] = {
0x10,
0x00
};
int32_t temperature = (int32_t) (-6400 + (raw_value * 100 * 500 / 1000));
si4063_send_command(SI4063_COMMAND_GET_ADC_READING, sizeof(data), data);
return temperature;
si4063_read_response(sizeof(response), response);
for (int i = 0; i < sizeof(response); i++) {
log_info("response: %02x\n", response[i]);
}
// Calculate the temperature in C * 10
temperature = (response[4] << 8) | response[5];
temperature *= 568;
temperature /= 256;
temperature -= 2970;
log_info("temp: %d\n", (int) (temperature / 10));
return temperature * 10;
}
uint8_t si4063_read_part_info()
{
uint8_t response[8];
si4063_send_command(SI4063_COMMAND_PART_INFO, 0, NULL);
si4063_read_response(sizeof(response), response);
for (int i = 0; i < sizeof(response); i++) {
log_info("part info: %02x\n", response[i]);
}
return response[0];
}
static void si4063_set_nsel_pin(bool high)
@ -173,27 +378,33 @@ void si4063_init()
{
GPIO_InitTypeDef gpio_init;
// Si4032 chip select pin
// Si4063 shutdown pin
gpio_init.GPIO_Pin = GPIO_PIN_SI4063_SDN;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_SI4063_SDN, &gpio_init);
// Si4063 chip select pin
gpio_init.GPIO_Pin = GPIO_PIN_SI4063_NSEL;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_SI4063_NSEL, &gpio_init);
si4063_set_nsel_pin(true);
si4603_set_shutdown(true);
delay_us(20);
si4603_set_shutdown(false);
si4063_soft_reset();
si4063_set_tx_power(0);
si4063_power_up();
// Temperature Value Offset
si4063_write(0x13, 0xF0);
// Temperature Sensor Calibration
si4063_write(0x12, 0x00);
si4063_read_part_info();
// ADC configuration
si4063_write(0x0f, 0x80);
si4063_set_tx_power(0x00);
si4063_set_frequency_offset(0);
si4063_set_frequency_deviation(5); // Was: 5 for APRS in RS41HUP?
// NOTE: 0x22 sets shift at about 450 Hz
si4063_set_frequency_deviation(0x22);
si4063_set_modulation_type(SI4063_MODULATION_TYPE_NONE);
si4063_set_modulation_type(SI4063_MODULATION_TYPE_CW);
si4063_set_state(SI4063_STATE_READY);
}

Wyświetl plik

@ -5,21 +5,19 @@
#include <stdbool.h>
typedef enum _si4063_modulation_type {
SI4063_MODULATION_TYPE_NONE = 0,
SI4063_MODULATION_TYPE_CW = 0,
SI4063_MODULATION_TYPE_OOK,
SI4063_MODULATION_TYPE_FSK,
} si4063_modulation_type;
void si4063_soft_reset();
void si4063_enable_tx();
void si4063_inhibit_tx();
void si4063_disable_tx();
void si4063_use_direct_mode(bool use);
void si4063_set_tx_frequency(float frequency_mhz);
void si4063_set_tx_frequency(uint32_t frequency_hz);
void si4063_set_tx_power(uint8_t power);
void si4063_set_frequency_offset(uint16_t offset);
void si4063_set_frequency_offset_small(uint8_t offset);
void si4063_set_frequency_deviation(uint8_t deviation);
void si4063_set_frequency_deviation(uint32_t deviation);
void si4063_set_modulation_type(si4063_modulation_type type);
int32_t si4063_read_temperature_celsius_100();
void si4063_set_sdi_pin(bool high);

Wyświetl plik

@ -505,7 +505,7 @@ bool ubxg6010_enable_power_save_mode()
ubxg6010_send_packet(&packet);
success = ubxg6010_wait_for_ack();
if (!success) {
log_error("GPS: Entering power-saving mode failed\n")
log_error("GPS: Entering power-saving mode failed\n");
}
return success;

Wyświetl plik

@ -1,5 +1,6 @@
#ifndef __GPIO_H
#define __GPIO_H
#include <system_stm32f10x.h>
#include <stm32f10x_gpio.h>
@ -37,6 +38,7 @@
#define PIN_MISO GPIO_Pin_14
#define APBPERIPHERAL_SPI RCC_APB1Periph_SPI2
#define PERIPHERAL_SPI SPI2
#define RCC_SPIPeriphClockCmd RCC_APB1PeriphClockCmd
#define PIN_USART_TX GPIO_Pin_9
#define BANK_USART_TX GPIOA
@ -73,16 +75,9 @@
#define PIN_SCK GPIO_Pin_5
#define BANK_MISO GPIOA
#define PIN_MISO GPIO_Pin_6
#define BANK_NSEL GPIOB
#define PIN_NSEL GPIO_Pin_2
#define BANK_SDN GPIOC
#define PIN_SDN GPIO_Pin_3
#define BANK_4063_GPIO2 GPIOD
#define PIN_4064_GPIO2 GPIO_Pin_0
#define BANK_4063_GPIO3 GPIOA
#define PIN_4064_GPIO3 GPIO_Pin_4
#define APBPERIPHERAL_SPI RCC_APB2Periph_SPI1
#define PERIPHERAL_SPI SPI1
#define RCC_SPIPeriphClockCmd RCC_APB2PeriphClockCmd
#define PIN_USART_TX GPIO_Pin_2
#define BANK_USART_TX GPIOA

Wyświetl plik

@ -27,19 +27,35 @@ void spi_init()
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_MISO, &gpio_init);
RCC_APB1PeriphClockCmd(APBPERIPHERAL_SPI, ENABLE);
RCC_SPIPeriphClockCmd(APBPERIPHERAL_SPI, ENABLE);
SPI_InitTypeDef spi_init;
SPI_StructInit(&spi_init);
spi_init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi_init.SPI_Mode = SPI_Mode_Master;
#ifdef RS41
spi_init.SPI_DataSize = SPI_DataSize_16b;
#endif
#ifdef DFM17
spi_init.SPI_DataSize = SPI_DataSize_8b;
#endif
spi_init.SPI_CPOL = SPI_CPOL_Low;
spi_init.SPI_CPHA = SPI_CPHA_1Edge;
#ifdef RS41
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
#endif
#ifdef DFM17
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
#endif
spi_init.SPI_FirstBit = SPI_FirstBit_MSB;
#ifdef RS41
spi_init.SPI_CRCPolynomial = 7;
#endif
#ifdef DFM17
spi_init.SPI_CRCPolynomial = 10;
spi_init.SPI_NSS = SPI_NSS_Soft;
#endif
SPI_Init(PERIPHERAL_SPI, &spi_init);
SPI_SSOutputCmd(PERIPHERAL_SPI, ENABLE);
@ -53,7 +69,7 @@ void spi_uninit()
SPI_I2S_DeInit(PERIPHERAL_SPI);
SPI_Cmd(PERIPHERAL_SPI, DISABLE);
SPI_SSOutputCmd(PERIPHERAL_SPI, DISABLE);
RCC_APB1PeriphClockCmd(APBPERIPHERAL_SPI, DISABLE);
RCC_SPIPeriphClockCmd(APBPERIPHERAL_SPI, DISABLE);
GPIO_InitTypeDef gpio_init;
@ -82,6 +98,21 @@ inline uint8_t spi_receive()
return (uint8_t) SPI_I2S_ReceiveData(PERIPHERAL_SPI);
}
inline uint8_t spi_read()
{
spi_send(0xFF);
return spi_receive();
}
void spi_set_chip_select(GPIO_TypeDef *gpio_cs, uint16_t pin_cs, bool select)
{
if (select) {
GPIO_ResetBits(gpio_cs, pin_cs);
} else {
GPIO_SetBits(gpio_cs, pin_cs);
}
}
uint8_t spi_send_and_receive(GPIO_TypeDef *gpio_cs, uint16_t pin_cs, uint16_t data) {
GPIO_ResetBits(gpio_cs, pin_cs);

Wyświetl plik

@ -1,6 +1,7 @@
#ifndef __SPI_H
#define __SPI_H
#include <stdbool.h>
#include <stdint.h>
#include <stm32f10x.h>
@ -12,6 +13,10 @@ void spi_send(uint16_t data);
uint8_t spi_receive();
uint8_t spi_read();
void spi_set_chip_select(GPIO_TypeDef *gpio_cs, uint16_t pin_cs, bool select);
uint8_t spi_send_and_receive(GPIO_TypeDef *gpio_cs, uint16_t pin_cs, uint16_t data);
#endif

Wyświetl plik

@ -40,7 +40,7 @@ static void rcc_init()
{
RCC_DeInit();
#ifdef RS41
// We don't have an external clock on the DFM17.
// The RS41 hardware uses an external clock
RCC_HSEConfig(RCC_HSE_ON);
ErrorStatus hse_status = RCC_WaitForHSEStartUp();
@ -48,7 +48,15 @@ static void rcc_init()
// If HSE fails to start up, the application will have incorrect clock configuration.
while (true) {}
}
#endif //RS41
#endif
#ifdef DFM17
// The DFM17 hardware uses the internal clock
RCC_AdjustHSICalibrationValue(0x10U);
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_4);
RCC_HSICmd(ENABLE);
RCC_PLLCmd(ENABLE);
#endif
//SystemInit();
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
@ -60,11 +68,15 @@ static void rcc_init()
RCC_PCLK2Config(RCC_HCLK_Div1); // Was: 4
RCC_PCLK1Config(RCC_HCLK_Div1); // Was: 2
#ifdef RS41
// DFM17 does not have an external clock
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
while (RCC_GetSYSCLKSource() != 0x04);
#endif //RS41
#endif
#ifdef DFM17
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08);
#endif
}
static void gpio_init()
@ -99,7 +111,6 @@ static void gpio_init()
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(BANK_BUTTON, &gpio_init);
// Green LED
gpio_init.GPIO_Pin = PIN_GREEN_LED;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
@ -111,28 +122,6 @@ 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
// 4063 SDN (shutdown) pin
gpio_init.GPIO_Pin = PIN_SDN;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_SDN, &gpio_init);
// 4063 GPIO2 pin
gpio_init.GPIO_Pin = PIN_4064_GPIO2;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_4063_GPIO2, &gpio_init);
// 4063 GPIO3 pin
gpio_init.GPIO_Pin = PIN_4064_GPIO3;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_4063_GPIO3, &gpio_init);
#endif //DFM17
}
/**

Wyświetl plik

@ -10,7 +10,7 @@
#define log_error printf
#define log_warn printf
#define log_info printf
#define log_debug(...)
#define log_debug printf
#define log_trace(...)
#else

Wyświetl plik

@ -1,12 +1,10 @@
#include "hal/system.h"
#include "hal/i2c.h"
#include "hal/spi.h"
#include "hal/usart_gps.h"
#include "hal/usart_ext.h"
#include "hal/delay.h"
#include "hal/datatimer.h"
#include "drivers/ubxg6010/ubxg6010.h"
#include "drivers/si4032/si4032.h"
#include "drivers/pulse_counter/pulse_counter.h"
#include "bmp280_handler.h"
#include "radsens_handler.h"
@ -15,6 +13,15 @@
#include "config.h"
#include "log.h"
#ifdef RS41
#include "hal/i2c.h"
#include "drivers/si4032/si4032.h"
#endif
#ifdef DFM17
#include "drivers/si4063/si4063.h"
#endif
uint32_t counter = 0;
bool led_state = true;

Wyświetl plik

@ -13,7 +13,12 @@
#include "codecs/jtencode/jtencode.h"
#include "drivers/ubxg6010/ubxg6010.h"
#include "radio_internal.h"
#ifdef RS41
#include "radio_si4032.h"
#endif
#ifdef DFM17
#include "radio_si4063.h"
#endif
#include "radio_si5351.h"
#include "radio_payload_cw.h"
#include "radio_payload_aprs_position.h"
@ -25,6 +30,8 @@
#include "radio_payload_fsq.h"
radio_transmit_entry radio_transmit_schedule[] = {
#ifdef RS41
// Si4032
#if RADIO_SI4032_TX_HORUS_V1_CONTINUOUS
{
.enabled = RADIO_SI4032_TX_HORUS_V1,
@ -155,6 +162,145 @@ radio_transmit_entry radio_transmit_schedule[] = {
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#endif
#endif
#endif
#ifdef DFM17
// Si4063
#if RADIO_SI4063_TX_HORUS_V1_CONTINUOUS
{
.enabled = RADIO_SI4063_TX_HORUS_V1,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V1,
.time_sync_seconds = HORUS_V1_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V1_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V1,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V1_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v1_payload_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
{
.enabled = RADIO_SI4063_TX_HORUS_V1,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V1,
.time_sync_seconds = HORUS_V1_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V1_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V1,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V1_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v1_idle_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#elif RADIO_SI4063_TX_HORUS_V2_CONTINUOUS
{
.enabled = RADIO_SI4063_TX_HORUS_V2,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V2,
.time_sync_seconds = HORUS_V2_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V2_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V2,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V2_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v2_payload_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
{
.enabled = RADIO_SI4063_TX_HORUS_V2,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V2,
.time_sync_seconds = HORUS_V2_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V2_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V2,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V2_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v2_idle_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#else
#if RADIO_SI4063_TX_PIP
{
.enabled = RADIO_SI4063_TX_PIP,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_PIP,
.transmit_count = RADIO_SI4063_TX_PIP_COUNT,
.time_sync_seconds = PIP_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = PIP_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_PIP,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = MORSE_WPM_TO_SYMBOL_RATE(PIP_SPEED_WPM),
.payload_encoder = &radio_cw_payload_encoder,
.fsk_encoder_api = &morse_fsk_encoder_api,
},
#endif
#if RADIO_SI4063_TX_CW
{
.enabled = RADIO_SI4063_TX_CW,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_CW,
.transmit_count = RADIO_SI4063_TX_CW_COUNT,
.time_sync_seconds = CW_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = CW_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_CW,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = MORSE_WPM_TO_SYMBOL_RATE(CW_SPEED_WPM),
.payload_encoder = &radio_cw_payload_encoder,
.fsk_encoder_api = &morse_fsk_encoder_api,
},
#endif
#if RADIO_SI4063_TX_APRS
{
.enabled = RADIO_SI4063_TX_APRS,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_APRS_1200,
.transmit_count = RADIO_SI4063_TX_APRS_COUNT,
.time_sync_seconds = APRS_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = APRS_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_APRS_1200,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = 1200,
#if APRS_WEATHER_REPORT_ENABLE
.payload_encoder = &radio_aprs_weather_report_payload_encoder,
#else
.payload_encoder = &radio_aprs_position_payload_encoder,
#endif
.fsk_encoder_api = &bell_fsk_encoder_api,
},
#endif
#if RADIO_SI4063_TX_HORUS_V1
{
.enabled = RADIO_SI4063_TX_HORUS_V1,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V1,
.transmit_count = RADIO_SI4063_TX_HORUS_V1_COUNT,
.time_sync_seconds = HORUS_V1_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V1_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V1,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V1_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v1_payload_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#endif
#if RADIO_SI4063_TX_HORUS_V2
{
.enabled = RADIO_SI4063_TX_HORUS_V2,
.radio_type = RADIO_TYPE_SI4063,
.data_mode = RADIO_DATA_MODE_HORUS_V2,
.transmit_count = RADIO_SI4063_TX_HORUS_V2_COUNT,
.time_sync_seconds = HORUS_V2_TIME_SYNC_SECONDS,
.time_sync_seconds_offset = HORUS_V2_TIME_SYNC_OFFSET_SECONDS,
.frequency = RADIO_SI4063_TX_FREQUENCY_HORUS_V2,
.tx_power = RADIO_SI4063_TX_POWER,
.symbol_rate = HORUS_V2_BAUD_RATE_SI4063,
.payload_encoder = &radio_horus_v2_payload_encoder,
.fsk_encoder_api = &mfsk_fsk_encoder_api,
},
#endif
#endif
#endif
// Si5351
#if RADIO_SI5351_ENABLE
#if RADIO_SI5351_TX_PIP
{
@ -300,7 +446,6 @@ radio_transmit_entry radio_transmit_schedule[] = {
.fsk_encoder_api = &jtencode_fsk_encoder_api,
},
#endif
#endif
#endif
{
.end = true,
@ -329,6 +474,8 @@ uint16_t radio_current_payload_length = 0;
uint8_t radio_current_symbol_data[RADIO_SYMBOL_DATA_MAX_LENGTH];
uint32_t precalculated_pwm_periods[FSK_TONE_COUNT_MAX];
static volatile uint32_t start_tick = 0, end_tick = 0;
telemetry_data current_telemetry_data;
@ -515,9 +662,16 @@ static bool radio_start_transmit(radio_transmit_entry *entry)
}
switch (entry->radio_type) {
#ifdef RS41
case RADIO_TYPE_SI4032:
success = radio_start_transmit_si4032(entry, &radio_shared_state);
break;
#endif
#ifdef DFM17
case RADIO_TYPE_SI4063:
success = radio_start_transmit_si4063(entry, &radio_shared_state);
break;
#endif
case RADIO_TYPE_SI5351:
success = radio_start_transmit_si5351(entry, &radio_shared_state);
break;
@ -562,9 +716,16 @@ static bool radio_stop_transmit(radio_transmit_entry *entry)
bool success;
switch (entry->radio_type) {
#ifdef RS41
case RADIO_TYPE_SI4032:
success = radio_stop_transmit_si4032(entry, &radio_shared_state);
break;
#endif
#ifdef DFM17
case RADIO_TYPE_SI4063:
success = radio_stop_transmit_si4063(entry, &radio_shared_state);
break;
#endif
case RADIO_TYPE_SI5351:
success = radio_stop_transmit_si5351(entry, &radio_shared_state);
break;
@ -620,9 +781,16 @@ static bool radio_transmit_symbol(radio_transmit_entry *entry)
bool success;
switch (entry->radio_type) {
#ifdef RS41
case RADIO_TYPE_SI4032:
success = radio_transmit_symbol_si4032(entry, &radio_shared_state);
break;
#endif
#ifdef DFM17
case RADIO_TYPE_SI4063:
success = radio_transmit_symbol_si4063(entry, &radio_shared_state);
break;
#endif
case RADIO_TYPE_SI5351:
success = radio_transmit_symbol_si5351(entry, &radio_shared_state);
break;
@ -687,7 +855,12 @@ void radio_handle_timer_tick()
void radio_handle_data_timer_tick()
{
#ifdef RS41
radio_handle_data_timer_si4032();
#endif
#ifdef DFM17
radio_handle_data_timer_si4063();
#endif
radio_handle_data_timer_si5351();
}
@ -788,7 +961,13 @@ void radio_handle_main_loop()
radio_start_transmit_entry = radio_current_transmit_entry;
}
#ifdef RS41
radio_handle_main_loop_si4032(radio_current_transmit_entry, &radio_shared_state);
#endif
#ifdef DFM17
radio_handle_main_loop_si4063(radio_current_transmit_entry, &radio_shared_state);
#endif
radio_handle_main_loop_si5351(radio_current_transmit_entry, &radio_shared_state);
bool first_symbol = false;
@ -901,7 +1080,12 @@ void radio_init()
radio_current_transmit_entry = &radio_transmit_schedule[radio_current_transmit_entry_index];
}
#ifdef RS41
radio_init_si4032();
#endif
#ifdef DFM17
radio_init_si4063();
#endif
radio_module_initialized = true;
}

Wyświetl plik

@ -81,5 +81,6 @@ typedef struct _radio_module_state {
extern radio_transmit_entry *radio_current_transmit_entry;
extern radio_module_state radio_shared_state;
extern uint32_t precalculated_pwm_periods[];
#endif

Wyświetl plik

@ -27,14 +27,12 @@
static bool si4032_use_dma = false;
// TODO: Add support for multiple APRS baud rates
uint16_t symbol_delay_bell_202_1200bps_us = 823;
#define symbol_delay_bell_202_1200bps_us 823
static volatile bool radio_si4032_state_change = false;
static volatile uint32_t radio_si4032_freq = 0;
static volatile int8_t radio_dma_transfer_stop_after_counter = -1;
uint32_t precalculated_pwm_periods[FSK_TONE_COUNT_MAX];
uint16_t radio_si4032_fill_pwm_buffer(uint16_t offset, uint16_t length, uint16_t *buffer);
bool radio_start_transmit_si4032(radio_transmit_entry *entry, radio_module_state *shared_state)

Wyświetl plik

@ -1,7 +1,6 @@
#ifdef DFM17
#include <stdint.h>
#include <string.h>
#include "config.h"
#ifdef DFM17
#include "hal/system.h"
#include "hal/spi.h"
#include "hal/pwm.h"
@ -15,28 +14,11 @@
#define CW_SYMBOL_RATE_MULTIPLIER 4
/**
* I have attempted to implement Bell 202 frequency generation using hardware DMA and PWM, but have failed to generate
* correct symbol rate that other APRS equipment are able to decode. I have tried to decode the DMA-based modulation with
* some tools intended for debugging APRS and while some bytes are decoded correctly every once in a while,
* the timings are mostly off for some unknown reason.
*
* The Bell 202 modulation implementation uses hardware PWM to generate the individual tone frequencies,
* but when si4063_use_dma is false, the symbol timing is created in a loop with delay that was chosen
* carefully via experiments.
*/
static bool si4063_use_dma = false;
// TODO: Add support for multiple APRS baud rates
uint16_t symbol_delay_bell_202_1200bps_us = 823;
#define symbol_delay_bell_202_1200bps_us 823
static volatile bool radio_si4063_state_change = false;
static volatile uint32_t radio_si4063_freq = 0;
static volatile int8_t radio_dma_transfer_stop_after_counter = -1;
uint32_t precalculated_pwm_periods[FSK_TONE_COUNT_MAX];
uint16_t radio_si4063_fill_pwm_buffer(uint16_t offset, uint16_t length, uint16_t *buffer);
bool radio_start_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
{
@ -55,23 +37,19 @@ bool radio_start_transmit_si4063(radio_transmit_entry *entry, radio_module_state
break;
case RADIO_DATA_MODE_RTTY:
frequency_offset = 0;
modulation_type = SI4063_MODULATION_TYPE_NONE;
modulation_type = SI4063_MODULATION_TYPE_CW;
use_direct_mode = false;
break;
case RADIO_DATA_MODE_APRS_1200:
frequency_offset = 0;
modulation_type = SI4063_MODULATION_TYPE_FSK;
use_direct_mode = true;
if (si4063_use_dma) {
pwm_data_timer_init();
radio_si4063_fill_pwm_buffer(0, PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2: {
fsk_tone *idle_tone = mfsk_get_idle_tone(&entry->fsk_encoder);
frequency_offset = (uint16_t) idle_tone->index + HORUS_FREQUENCY_OFFSET_SI4063;
modulation_type = SI4063_MODULATION_TYPE_OOK;
modulation_type = SI4063_MODULATION_TYPE_CW;
use_direct_mode = false;
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
@ -105,14 +83,7 @@ bool radio_start_transmit_si4063(radio_transmit_entry *entry, radio_module_state
shared_state->radio_interrupt_transmit_active = true;
break;
case RADIO_DATA_MODE_APRS_1200:
if (si4063_use_dma) {
shared_state->radio_dma_transfer_active = true;
radio_dma_transfer_stop_after_counter = -1;
system_disable_tick();
pwm_dma_start();
} else {
shared_state->radio_manual_transmit_active = true;
}
shared_state->radio_manual_transmit_active = true;
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
@ -256,14 +227,14 @@ inline void radio_handle_data_timer_si4063()
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();
break;
}
si4063_set_frequency_offset_small(tone_index + HORUS_FREQUENCY_OFFSET_SI4063);
si4063_set_frequency_offset(tone_index + HORUS_FREQUENCY_OFFSET_SI4063);
radio_shared_state.radio_symbol_count_interrupt++;
break;
@ -312,10 +283,6 @@ bool radio_stop_transmit_si4063(radio_transmit_entry *entry, radio_module_state
system_enable_tick();
break;
case RADIO_DATA_MODE_APRS_1200:
if (si4063_use_dma) {
pwm_data_timer_uninit();
system_enable_tick();
}
break;
case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
@ -328,79 +295,8 @@ bool radio_stop_transmit_si4063(radio_transmit_entry *entry, radio_module_state
return true;
}
uint16_t radio_si4063_fill_pwm_buffer(uint16_t offset, uint16_t length, uint16_t *buffer)
{
uint16_t count = 0;
for (uint16_t i = offset; i < (offset + length); i++, count++) {
uint32_t frequency = radio_next_symbol_si4063(radio_current_transmit_entry, &radio_shared_state);
if (frequency == 0) {
// TODO: fill the other side of the buffer with zeroes too?
memset(buffer + offset, 0, (length - i) * sizeof(uint16_t));
break;
}
buffer[i] = pwm_calculate_period(frequency);
}
return count;
}
bool radio_si4063_stop_dma_transfer_if_requested(radio_module_state *shared_state)
{
if (radio_dma_transfer_stop_after_counter > 0) {
radio_dma_transfer_stop_after_counter--;
} else if (radio_dma_transfer_stop_after_counter == 0) {
pwm_dma_stop();
radio_dma_transfer_stop_after_counter = -1;
shared_state->radio_transmission_finished = true;
shared_state->radio_dma_transfer_active = false;
return true;
}
return false;
}
uint16_t radio_si4063_handle_pwm_transfer_half(uint16_t buffer_size, uint16_t *buffer)
{
if (radio_si4063_stop_dma_transfer_if_requested(&radio_shared_state)) {
return 0;
}
if (radio_shared_state.radio_transmission_finished) {
log_info("Should not be here, half-transfer!\n");
}
uint16_t length = radio_si4063_fill_pwm_buffer(0, buffer_size / 2, buffer);
if (radio_dma_transfer_stop_after_counter < 0 && length < buffer_size / 2) {
radio_dma_transfer_stop_after_counter = 2;
}
return length;
}
uint16_t radio_si4063_handle_pwm_transfer_full(uint16_t buffer_size, uint16_t *buffer)
{
if (radio_si4063_stop_dma_transfer_if_requested(&radio_shared_state)) {
return 0;
}
if (radio_shared_state.radio_transmission_finished) {
log_info("Should not be here, transfer complete!\n");
}
uint16_t length = radio_si4063_fill_pwm_buffer(buffer_size / 2, buffer_size / 2, buffer);
if (radio_dma_transfer_stop_after_counter < 0 && length < buffer_size / 2) {
radio_dma_transfer_stop_after_counter = 2;
}
return length;
}
void radio_init_si4063()
{
pwm_handle_dma_transfer_half = radio_si4063_handle_pwm_transfer_half;
pwm_handle_dma_transfer_full = radio_si4063_handle_pwm_transfer_full;
if (si4063_use_dma) {
pwm_data_timer_init();
pwm_dma_init();
}
}
#endif //DFM17

Wyświetl plik

@ -1,6 +1,5 @@
#include "telemetry.h"
#include "hal/system.h"
#include "drivers/si4032/si4032.h"
#include "drivers/ubxg6010/ubxg6010.h"
#include "drivers/pulse_counter/pulse_counter.h"
#include "bmp280_handler.h"
@ -9,6 +8,13 @@
#include "config.h"
#include "log.h"
#ifdef RS41
#include "drivers/si4032/si4032.h"
#endif
#ifdef DFM17
#include "drivers/si4063/si4063.h"
#endif
// Initialize leap seconds with a known good value
int8_t gps_time_leap_seconds = GPS_TIME_LEAP_SECONDS;
@ -20,7 +26,12 @@ void telemetry_collect(telemetry_data *data)
data->button_adc_value = system_get_button_adc_value();
data->battery_voltage_millivolts = system_get_battery_voltage_millivolts();
#ifdef RS41
data->internal_temperature_celsius_100 = si4032_read_temperature_celsius_100();
#endif
#ifdef DFM17
data->internal_temperature_celsius_100 = si4063_read_temperature_celsius_100();
#endif
if (bmp280_enabled) {
bmp280_read_telemetry(data);