kopia lustrzana https://github.com/mikaelnousiainen/RS41ng
Implementing Si4063 radio chip support for DFM17 sonde. Work in progress.
rodzic
0e50f0a334
commit
4af4005dd7
48
src/config.h
48
src/config.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
11
src/gpio.h
11
src/gpio.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
11
src/main.c
11
src/main.c
|
@ -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;
|
||||
|
||||
|
|
186
src/radio.c
186
src/radio.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Ładowanie…
Reference in New Issue