kopia lustrzana https://github.com/mikaelnousiainen/RS41ng
Initial plumbing for DFM17
rodzic
8819d786b3
commit
49cc379d02
|
@ -1,6 +1,10 @@
|
|||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
// Define SONDE Type. Must be DFM17 or RS41
|
||||
//#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.
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
#include <stm32f10x_gpio.h>
|
||||
|
||||
#include "hal/spi.h"
|
||||
#include "si4063.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define SPI_WRITE_FLAG 0x80
|
||||
|
||||
#define SI4063_CLOCK 26.0f
|
||||
|
||||
#define GPIO_SI4063_NSEL GPIOC
|
||||
#define GPIO_PIN_SI4063_NSEL GPIO_Pin_13
|
||||
|
||||
#define GPIO_SI4063_SDI GPIOB
|
||||
#define GPIO_PIN_SI4063_SDI GPIO_Pin_15
|
||||
|
||||
static inline uint8_t si4063_write(uint8_t reg, uint8_t value)
|
||||
{
|
||||
return spi_send_and_receive(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL, ((reg | SPI_WRITE_FLAG) << 8U) | value);
|
||||
}
|
||||
|
||||
static inline uint8_t si4063_read(uint8_t reg)
|
||||
{
|
||||
return spi_send_and_receive(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL, (reg << 8U) | 0xFFU);
|
||||
}
|
||||
|
||||
void si4063_soft_reset()
|
||||
{
|
||||
si4063_write(0x07, 0x80);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void si4063_disable_tx()
|
||||
{
|
||||
si4063_write(0x07, 0x40);
|
||||
}
|
||||
|
||||
void si4063_use_direct_mode(bool use)
|
||||
{
|
||||
if (use) {
|
||||
GPIO_SetBits(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL);
|
||||
}
|
||||
}
|
||||
|
||||
void si4063_set_tx_frequency(const float frequency_mhz)
|
||||
{
|
||||
uint8_t hbsel = (uint8_t) ((frequency_mhz * (30.0f / SI4063_CLOCK)) >= 480.0f ? 1 : 0);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
void si4063_set_tx_power(uint8_t power)
|
||||
{
|
||||
si4063_write(0x6D, power & 0x7U);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
inline void si4063_set_frequency_offset_small(uint8_t offset)
|
||||
{
|
||||
si4063_write(0x73, offset);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void si4063_set_modulation_type(si4063_modulation_type type)
|
||||
{
|
||||
uint8_t value;
|
||||
switch (type) {
|
||||
case SI4063_MODULATION_TYPE_NONE:
|
||||
// No modulation (for modulating via frequency offset, e.g. for RTTY)
|
||||
value = 0x00;
|
||||
break;
|
||||
case SI4063_MODULATION_TYPE_OOK:
|
||||
// Direct Async Mode with OOK modulation
|
||||
value = 0b00010001;
|
||||
break;
|
||||
case SI4063_MODULATION_TYPE_FSK:
|
||||
// Direct Async Mode with FSK modulation
|
||||
value = 0b00010010;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
si4063_write(0x71, value);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
int32_t temperature = (int32_t) (-6400 + (raw_value * 100 * 500 / 1000));
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
static void si4063_set_nsel_pin(bool high)
|
||||
{
|
||||
if (high) {
|
||||
GPIO_SetBits(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI4063_NSEL, GPIO_PIN_SI4063_NSEL);
|
||||
}
|
||||
}
|
||||
|
||||
void si4063_set_sdi_pin(bool high)
|
||||
{
|
||||
if (high) {
|
||||
GPIO_SetBits(GPIO_SI4063_SDI, GPIO_PIN_SI4063_SDI);
|
||||
} else {
|
||||
GPIO_ResetBits(GPIO_SI4063_SDI, GPIO_PIN_SI4063_SDI);
|
||||
}
|
||||
}
|
||||
|
||||
void si4063_use_sdi_pin(bool use)
|
||||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
si4063_set_nsel_pin(true);
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_PIN_SI4063_SDI;
|
||||
gpio_init.GPIO_Mode = use ? GPIO_Mode_Out_PP : GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIO_SI4063_SDI, &gpio_init);
|
||||
|
||||
si4063_set_sdi_pin(false);
|
||||
}
|
||||
|
||||
void si4063_init()
|
||||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// Si4032 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);
|
||||
|
||||
si4063_soft_reset();
|
||||
si4063_set_tx_power(0);
|
||||
|
||||
// Temperature Value Offset
|
||||
si4063_write(0x13, 0xF0);
|
||||
// Temperature Sensor Calibration
|
||||
si4063_write(0x12, 0x00);
|
||||
|
||||
// ADC configuration
|
||||
si4063_write(0x0f, 0x80);
|
||||
|
||||
si4063_set_frequency_offset(0);
|
||||
si4063_set_frequency_deviation(5); // Was: 5 for APRS in RS41HUP?
|
||||
|
||||
si4063_set_modulation_type(SI4063_MODULATION_TYPE_NONE);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef __SI4063_H
|
||||
#define __SI4063_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum _si4063_modulation_type {
|
||||
SI4063_MODULATION_TYPE_NONE = 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_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_modulation_type(si4063_modulation_type type);
|
||||
int32_t si4063_read_temperature_celsius_100();
|
||||
void si4063_set_sdi_pin(bool high);
|
||||
void si4063_use_sdi_pin(bool use);
|
||||
void si4063_init();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef __GPIO_H
|
||||
#define __GPIO_H
|
||||
#include <system_stm32f10x.h>
|
||||
#include <stm32f10x_gpio.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
// GPIO definitions for devices we use
|
||||
|
||||
#if defined (RS41)
|
||||
|
||||
#define BANK_SHUTDOWN GPIOA
|
||||
#define PIN_SHUTDOWN GPIO_Pin_12
|
||||
|
||||
#define BANK_VOLTAGE GPIOA
|
||||
#define PIN_VOLTAGE GPIO_Pin_5
|
||||
#define ADC_VOLTAGE ADC1
|
||||
#define CHANNEL_VOLTAGE ADC_Channel_5
|
||||
|
||||
#define BANK_BUTTON GPIOA
|
||||
#define PIN_BUTTON GPIO_Pin_6
|
||||
#define ADC_BUTTON ADC1
|
||||
#define CHANNEL_BUTTON ADC_Channel_6
|
||||
|
||||
#define BANK_RED_LED GPIOB
|
||||
#define PIN_RED_LED GPIO_Pin_8
|
||||
|
||||
#define BANK_GREEN_LED GPIOB
|
||||
#define PIN_GREEN_LED GPIO_Pin_7
|
||||
|
||||
#define BANK_MOSI GPIOB
|
||||
#define PIN_MOSI GPIO_Pin_15
|
||||
#define BANK_SCK GPIOB
|
||||
#define PIN_SCK GPIO_Pin_13
|
||||
#define BANK_MISO GPIOB
|
||||
#define PIN_MISO GPIO_Pin_14
|
||||
#define APBPERIPHERAL_SPI RCC_APB1Periph_SPI2
|
||||
#define PERIPHERAL_SPI SPI2
|
||||
|
||||
#define PIN_USART_TX GPIO_Pin_9
|
||||
#define BANK_USART_TX GPIOA
|
||||
#define PIN_USART_RX GPIO_Pin_10
|
||||
#define BANK_USART_RX GPIOA
|
||||
#define USART_IRQ USART1_IRQn
|
||||
#define USART_IT USART1
|
||||
#define APBPERIPHERAL_USART RCC_APB2Periph_USART1
|
||||
#define USART_IRQ_HANDLER USART1_IRQHandler
|
||||
|
||||
#elif defined (DFM17)
|
||||
|
||||
#define BANK_SHUTDOWN GPIOC
|
||||
#define PIN_SHUTDOWN GPIO_Pin_0
|
||||
|
||||
#define BANK_VOLTAGE GPIOA // Needs confirmation
|
||||
#define PIN_VOLTAGE GPIO_Pin_0 // Needs confirmation
|
||||
#define ADC_VOLTAGE ADC1 // Needs confirmation
|
||||
#define CHANNEL_VOLTAGE ADC_Channel_0 // Needs confirmation
|
||||
|
||||
#define BANK_BUTTON GPIOC
|
||||
#define PIN_BUTTON GPIO_Pin_8
|
||||
// No ADC available on the GPIOC, so we have to use digital reads/writes for the button
|
||||
|
||||
#define BANK_RED_LED GPIOB
|
||||
#define PIN_RED_LED GPIO_Pin_12
|
||||
|
||||
#define BANK_GREEN_LED GPIOC
|
||||
#define PIN_GREEN_LED GPIO_Pin_6
|
||||
|
||||
#define BANK_MOSI GPIOA
|
||||
#define PIN_MOSI GPIO_Pin_7
|
||||
#define BANK_SCK GPIOA
|
||||
#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 PIN_USART_TX GPIO_Pin_2
|
||||
#define BANK_USART_TX GPIOA
|
||||
#define PIN_USART_RX GPIO_Pin_3
|
||||
#define BANK_USART_RX GPIOA
|
||||
#define USART_IRQ USART2_IRQn
|
||||
#define USART_IT USART2
|
||||
#define APBPERIPHERAL_USART RCC_APB1Periph_USART2
|
||||
#define USART_IRQ_HANDLER USART2_IRQHandler
|
||||
|
||||
#else
|
||||
Compiler error. You must define RS41 or DFM17.
|
||||
#endif // RS41 or DFM17
|
||||
|
||||
// Hardware Sanity Check
|
||||
|
||||
#if defined (RS41) && defined (DFM17)
|
||||
Compiler error. You must define RS41 or DFM17 but not both.
|
||||
#endif
|
||||
|
||||
#endif // __GPIO_H
|
|
@ -3,24 +3,31 @@
|
|||
#include <stm32f10x_spi.h>
|
||||
|
||||
#include "spi.h"
|
||||
#include "gpio.h"
|
||||
|
||||
void spi_init()
|
||||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// SPI2_SCK & SPI2_MOSI
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
|
||||
// SCK
|
||||
gpio_init.GPIO_Pin = PIN_SCK;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_Init(BANK_SCK, &gpio_init);
|
||||
|
||||
// SPI2_MISO
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_14;
|
||||
// MOSI
|
||||
gpio_init.GPIO_Pin = PIN_MOSI;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(BANK_MOSI, &gpio_init);
|
||||
|
||||
// MISO
|
||||
gpio_init.GPIO_Pin = PIN_MISO;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_Init(BANK_MISO, &gpio_init);
|
||||
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
|
||||
RCC_APB1PeriphClockCmd(APBPERIPHERAL_SPI, ENABLE);
|
||||
|
||||
SPI_InitTypeDef spi_init;
|
||||
SPI_StructInit(&spi_init);
|
||||
|
@ -33,55 +40,55 @@ void spi_init()
|
|||
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
|
||||
spi_init.SPI_FirstBit = SPI_FirstBit_MSB;
|
||||
spi_init.SPI_CRCPolynomial = 7;
|
||||
SPI_Init(SPI2, &spi_init);
|
||||
SPI_Init(PERIPHERAL_SPI, &spi_init);
|
||||
|
||||
SPI_SSOutputCmd(SPI2, ENABLE);
|
||||
SPI_SSOutputCmd(PERIPHERAL_SPI, ENABLE);
|
||||
|
||||
SPI_Cmd(SPI2, ENABLE);
|
||||
SPI_Init(SPI2, &spi_init);
|
||||
SPI_Cmd(PERIPHERAL_SPI, ENABLE);
|
||||
SPI_Init(PERIPHERAL_SPI, &spi_init);
|
||||
}
|
||||
|
||||
void spi_uninit()
|
||||
{
|
||||
SPI_I2S_DeInit(SPI2);
|
||||
SPI_Cmd(SPI2, DISABLE);
|
||||
SPI_SSOutputCmd(SPI2, DISABLE);
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, DISABLE);
|
||||
SPI_I2S_DeInit(PERIPHERAL_SPI);
|
||||
SPI_Cmd(PERIPHERAL_SPI, DISABLE);
|
||||
SPI_SSOutputCmd(PERIPHERAL_SPI, DISABLE);
|
||||
RCC_APB1PeriphClockCmd(APBPERIPHERAL_SPI, DISABLE);
|
||||
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_14;
|
||||
gpio_init.GPIO_Pin = PIN_MISO;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_Init(BANK_MISO, &gpio_init);
|
||||
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_15;
|
||||
gpio_init.GPIO_Pin = PIN_MOSI;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP; // was: GPIO_Mode_Out_PP; // GPIO_Mode_AF_PP
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_Init(BANK_MOSI, &gpio_init);
|
||||
}
|
||||
|
||||
inline void spi_send(uint16_t data)
|
||||
{
|
||||
// Wait for TX buffer
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(SPI2, data);
|
||||
while (SPI_I2S_GetFlagStatus(PERIPHERAL_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(PERIPHERAL_SPI, data);
|
||||
}
|
||||
|
||||
inline uint8_t spi_receive()
|
||||
{
|
||||
// Wait for data in RX buffer
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
return (uint8_t) SPI_I2S_ReceiveData(SPI2);
|
||||
while (SPI_I2S_GetFlagStatus(PERIPHERAL_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
return (uint8_t) SPI_I2S_ReceiveData(PERIPHERAL_SPI);
|
||||
}
|
||||
|
||||
uint8_t spi_send_and_receive(GPIO_TypeDef *gpio_cs, uint16_t pin_cs, uint16_t data) {
|
||||
GPIO_ResetBits(gpio_cs, pin_cs);
|
||||
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(SPI2, data);
|
||||
while (SPI_I2S_GetFlagStatus(PERIPHERAL_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(PERIPHERAL_SPI, data);
|
||||
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
while (SPI_I2S_GetFlagStatus(PERIPHERAL_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
GPIO_SetBits(gpio_cs, pin_cs);
|
||||
return (uint8_t) SPI_I2S_ReceiveData(SPI2);
|
||||
return (uint8_t) SPI_I2S_ReceiveData(PERIPHERAL_SPI);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "system.h"
|
||||
#include "delay.h"
|
||||
#include "log.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define BUTTON_PRESS_LONG_COUNT SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND
|
||||
|
||||
|
@ -38,6 +39,8 @@ static void nvic_init()
|
|||
static void rcc_init()
|
||||
{
|
||||
RCC_DeInit();
|
||||
#ifdef RS41
|
||||
// We don't have an external clock on the DFM17.
|
||||
RCC_HSEConfig(RCC_HSE_ON);
|
||||
|
||||
ErrorStatus hse_status = RCC_WaitForHSEStartUp();
|
||||
|
@ -45,6 +48,7 @@ static void rcc_init()
|
|||
// If HSE fails to start up, the application will have incorrect clock configuration.
|
||||
while (true) {}
|
||||
}
|
||||
#endif //RS41
|
||||
//SystemInit();
|
||||
|
||||
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
|
||||
|
@ -55,9 +59,12 @@ static void rcc_init()
|
|||
RCC_HCLKConfig(RCC_SYSCLK_Div1); // Was: RCC_SYSCLK_Div4
|
||||
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
|
||||
}
|
||||
|
||||
static void gpio_init()
|
||||
|
@ -72,28 +79,60 @@ static void gpio_init()
|
|||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// Shutdown request
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_12;
|
||||
gpio_init.GPIO_Pin = PIN_SHUTDOWN;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
GPIO_Init(BANK_SHUTDOWN, &gpio_init);
|
||||
#ifdef DFM17
|
||||
GPIO_SetBits(BANK_SHUTDOWN, PIN_SHUTDOWN); // Pull high to keep BMS from removing battery power after startup
|
||||
#endif //DFM17
|
||||
|
||||
// Battery voltage (analog)
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_5;
|
||||
gpio_init.GPIO_Pin = PIN_VOLTAGE;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AIN;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
GPIO_Init(BANK_VOLTAGE, &gpio_init);
|
||||
|
||||
// Button state (analog)
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_6;
|
||||
gpio_init.GPIO_Pin = PIN_BUTTON;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AIN;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
GPIO_Init(BANK_BUTTON, &gpio_init);
|
||||
|
||||
// LEDs
|
||||
gpio_init.GPIO_Pin = GPIO_PIN_LED_GREEN | GPIO_PIN_LED_RED;
|
||||
|
||||
// Green LED
|
||||
gpio_init.GPIO_Pin = PIN_GREEN_LED;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
GPIO_Init(BANK_GREEN_LED, &gpio_init);
|
||||
|
||||
// Red LED
|
||||
gpio_init.GPIO_Pin = PIN_RED_LED;
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,7 +147,12 @@ static void dma_adc_init()
|
|||
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
|
||||
|
||||
#ifdef RS41
|
||||
dma_init.DMA_BufferSize = 2;
|
||||
#endif //RS41
|
||||
#ifdef DFM17
|
||||
dma_init.DMA_BufferSize = 1;
|
||||
#endif //DFM17
|
||||
dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
dma_init.DMA_M2M = DMA_M2M_Disable;
|
||||
dma_init.DMA_MemoryBaseAddr = (uint32_t) &dma_buffer_adc;
|
||||
|
@ -132,11 +176,21 @@ static void dma_adc_init()
|
|||
adc_init.ADC_ContinuousConvMode = ENABLE;
|
||||
adc_init.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
|
||||
adc_init.ADC_DataAlign = ADC_DataAlign_Right;
|
||||
#ifdef RS41
|
||||
adc_init.ADC_NbrOfChannel = 2;
|
||||
#endif //RS41
|
||||
#ifdef DFM17
|
||||
adc_init.ADC_NbrOfChannel = 1;
|
||||
#endif //DFM17
|
||||
ADC_Init(ADC1, &adc_init);
|
||||
|
||||
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_28Cycles5);
|
||||
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 2, ADC_SampleTime_28Cycles5);
|
||||
ADC_RegularChannelConfig(ADC1, CHANNEL_VOLTAGE, 1, ADC_SampleTime_28Cycles5);
|
||||
#ifdef RS41
|
||||
ADC_RegularChannelConfig(ADC1, CHANNEL_BUTTON, 2, ADC_SampleTime_28Cycles5);
|
||||
#endif //RS41
|
||||
#ifdef DFM17
|
||||
// Not using ADC for button on DFM17
|
||||
#endif //DFM17
|
||||
|
||||
// ADC1 DMA requests are routed to DMA1 Channel1
|
||||
ADC_DMACmd(ADC1, ENABLE);
|
||||
|
@ -160,12 +214,23 @@ uint16_t system_get_battery_voltage_millivolts()
|
|||
|
||||
uint16_t system_get_button_adc_value()
|
||||
{
|
||||
#ifdef RS41
|
||||
return (uint16_t) dma_buffer_adc[1];
|
||||
#endif //RS41
|
||||
#ifdef DFM17
|
||||
// Fake being an ADC. Take the binary value and if non-zero, make it trigger button-down
|
||||
return ( ((int) GPIO_ReadInputDataBit(BANK_BUTTON,PIN_BUTTON)) * 2100);
|
||||
#endif //DFM17
|
||||
}
|
||||
|
||||
void system_shutdown()
|
||||
{
|
||||
GPIO_SetBits(GPIOA, GPIO_Pin_12);
|
||||
#ifdef RS41
|
||||
GPIO_SetBits(BANK_SHUTDOWN, PIN_SHUTDOWN);
|
||||
#endif // RS41
|
||||
#ifdef DFM17
|
||||
GPIO_ResetBits(BANK_SHUTDOWN, PIN_SHUTDOWN);
|
||||
#endif //DFM17
|
||||
}
|
||||
|
||||
void system_handle_button()
|
||||
|
@ -252,18 +317,18 @@ void system_enable_tick()
|
|||
void system_set_green_led(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
GPIO_ResetBits(GPIOB, GPIO_PIN_LED_GREEN);
|
||||
GPIO_ResetBits(BANK_GREEN_LED, PIN_GREEN_LED);
|
||||
} else {
|
||||
GPIO_SetBits(GPIOB, GPIO_PIN_LED_GREEN);
|
||||
GPIO_SetBits(BANK_GREEN_LED, PIN_GREEN_LED);
|
||||
}
|
||||
}
|
||||
|
||||
void system_set_red_led(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
GPIO_ResetBits(GPIOB, GPIO_PIN_LED_RED);
|
||||
GPIO_ResetBits(BANK_RED_LED, PIN_RED_LED);
|
||||
} else {
|
||||
GPIO_SetBits(GPIOB, GPIO_PIN_LED_RED);
|
||||
GPIO_SetBits(BANK_RED_LED, PIN_RED_LED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <misc.h>
|
||||
|
||||
#include "usart_gps.h"
|
||||
#include "gpio.h"
|
||||
|
||||
void (*usart_gps_handle_incoming_byte)(uint8_t data) = NULL;
|
||||
|
||||
|
@ -13,25 +14,29 @@ void usart_gps_init(uint32_t baud_rate, bool enable_irq)
|
|||
{
|
||||
GPIO_InitTypeDef gpio_init;
|
||||
|
||||
// USART1 TX
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_9;
|
||||
// USART TX
|
||||
gpio_init.GPIO_Pin = PIN_USART_TX;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
GPIO_Init(BANK_USART_TX, &gpio_init);
|
||||
|
||||
// USART1 RX
|
||||
gpio_init.GPIO_Pin = GPIO_Pin_10;
|
||||
// USART RX
|
||||
gpio_init.GPIO_Pin = PIN_USART_RX;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(GPIOA, &gpio_init);
|
||||
GPIO_Init(BANK_USART_RX, &gpio_init);
|
||||
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
|
||||
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||
USART_ClearITPendingBit(USART1, USART_IT_ORE);
|
||||
NVIC_DisableIRQ(USART_IRQ);
|
||||
USART_ITConfig(USART_IT, USART_IT_RXNE, DISABLE);
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_RXNE);
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_ORE);
|
||||
|
||||
USART_Cmd(USART1, DISABLE);
|
||||
USART_Cmd(USART_IT, DISABLE);
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||
#if defined(RS41)
|
||||
RCC_APB2PeriphClockCmd(APBPERIPHERAL_USART, ENABLE);
|
||||
#elif defined(DFM17)
|
||||
RCC_APB1PeriphClockCmd(APBPERIPHERAL_USART, ENABLE);
|
||||
#endif
|
||||
|
||||
USART_InitTypeDef usart_init;
|
||||
usart_init.USART_BaudRate = baud_rate;
|
||||
|
@ -40,65 +45,69 @@ void usart_gps_init(uint32_t baud_rate, bool enable_irq)
|
|||
usart_init.USART_Parity = USART_Parity_No;
|
||||
usart_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
usart_init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
||||
USART_Init(USART1, &usart_init);
|
||||
USART_Init(USART_IT, &usart_init);
|
||||
|
||||
NVIC_InitTypeDef nvic_init;
|
||||
nvic_init.NVIC_IRQChannel = USART1_IRQn;
|
||||
nvic_init.NVIC_IRQChannel = USART_IRQ;
|
||||
nvic_init.NVIC_IRQChannelPreemptionPriority = 15;
|
||||
nvic_init.NVIC_IRQChannelSubPriority = 2;
|
||||
nvic_init.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic_init);
|
||||
|
||||
USART_Cmd(USART1, ENABLE);
|
||||
USART_Cmd(USART_IT, ENABLE);
|
||||
if (enable_irq) {
|
||||
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
USART_ITConfig(USART_IT, USART_IT_RXNE, ENABLE);
|
||||
NVIC_EnableIRQ(USART_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
static void usart_gps_enable_irq(bool enabled) {
|
||||
if (enabled) {
|
||||
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
USART_ITConfig(USART_IT, USART_IT_RXNE, ENABLE);
|
||||
NVIC_EnableIRQ(USART_IRQ);
|
||||
} else {
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
|
||||
NVIC_DisableIRQ(USART_IRQ);
|
||||
USART_ITConfig(USART_IT, USART_IT_RXNE, DISABLE);
|
||||
}
|
||||
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||
USART_ClearITPendingBit(USART1, USART_IT_ORE);
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_RXNE);
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_ORE);
|
||||
}
|
||||
|
||||
void usart_gps_uninit()
|
||||
{
|
||||
usart_gps_enable_irq(false);
|
||||
USART_Cmd(USART1, DISABLE);
|
||||
USART_DeInit(USART1);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, DISABLE);
|
||||
USART_Cmd(USART_IT, DISABLE);
|
||||
USART_DeInit(USART_IT);
|
||||
#ifdef defined(RS41)
|
||||
RCC_APB2PeriphClockCmd(APBPERIPHERAL_USART, DISABLE);
|
||||
#elif defined(DFM17)
|
||||
RCC_APB1PeriphClockCmd(APBPERIPHERAL_USART, DISABLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usart_gps_enable(bool enabled)
|
||||
{
|
||||
usart_gps_enable_irq(enabled);
|
||||
USART_Cmd(USART1, enabled ? ENABLE : DISABLE);
|
||||
USART_Cmd(USART_IT, enabled ? ENABLE : DISABLE);
|
||||
}
|
||||
|
||||
void usart_gps_send_byte(uint8_t data)
|
||||
{
|
||||
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
|
||||
USART_SendData(USART1, data);
|
||||
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
|
||||
while (USART_GetFlagStatus(USART_IT, USART_FLAG_TC) == RESET) {}
|
||||
USART_SendData(USART_IT, data);
|
||||
while (USART_GetFlagStatus(USART_IT, USART_FLAG_TC) == RESET) {}
|
||||
}
|
||||
|
||||
void USART1_IRQHandler(void)
|
||||
void USART_IRQ_HANDLER(void)
|
||||
{
|
||||
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
|
||||
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||
uint8_t data = (uint8_t) USART_ReceiveData(USART1);
|
||||
if (USART_GetITStatus(USART_IT, USART_IT_RXNE) != RESET) {
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_RXNE);
|
||||
uint8_t data = (uint8_t) USART_ReceiveData(USART_IT);
|
||||
usart_gps_handle_incoming_byte(data);
|
||||
} else if (USART_GetITStatus(USART1, USART_IT_ORE) != RESET) {
|
||||
USART_ClearITPendingBit(USART1, USART_IT_ORE);
|
||||
USART_ReceiveData(USART1);
|
||||
} else if (USART_GetITStatus(USART_IT, USART_IT_ORE) != RESET) {
|
||||
USART_ClearITPendingBit(USART_IT, USART_IT_ORE);
|
||||
USART_ReceiveData(USART_IT);
|
||||
} else {
|
||||
USART_ReceiveData(USART1);
|
||||
USART_ReceiveData(USART_IT);
|
||||
}
|
||||
}
|
||||
|
|
16
src/main.c
16
src/main.c
|
@ -90,7 +90,10 @@ int main(void)
|
|||
pulse_counter_init(PULSE_COUNTER_PIN_MODE, PULSE_COUNTER_INTERRUPT_EDGE);
|
||||
} else {
|
||||
log_info("I2C init: clock speed %d kHz\n", I2C_BUS_CLOCK_SPEED / 1000);
|
||||
#ifdef RS41
|
||||
// dfm17 does not use i2c
|
||||
i2c_init(I2C_BUS_CLOCK_SPEED);
|
||||
#endif //RS41
|
||||
}
|
||||
|
||||
log_info("SPI init\n");
|
||||
|
@ -105,8 +108,15 @@ int main(void)
|
|||
goto gps_init;
|
||||
}
|
||||
|
||||
#if defined(RS41)
|
||||
log_info("Si4032 init\n");
|
||||
si4032_init();
|
||||
#elif defined(DFM17)
|
||||
log_info("Si4063 init\n");
|
||||
si4063_init();
|
||||
#else
|
||||
Error. Must defined RS41 or DFM17
|
||||
#endif
|
||||
|
||||
if (bmp280_enabled) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
@ -162,6 +172,12 @@ int main(void)
|
|||
radio_handle_main_loop();
|
||||
//NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE);
|
||||
//__WFI();
|
||||
#ifdef DFM17
|
||||
//DFM17 testing... delete next two lines eventually
|
||||
log_info("Fix: %d, Time: %02d:%02d:%02d.\n", (int) current_gps_data.fix_ok, current_gps_data.hours, current_gps_data.minutes, current_gps_data.seconds);
|
||||
delay_ms(1000);
|
||||
#endif //DFM17
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
typedef enum _radio_type {
|
||||
RADIO_TYPE_SI4032 = 1,
|
||||
RADIO_TYPE_SI5351,
|
||||
RADIO_TYPE_SI4063,
|
||||
} radio_type;
|
||||
|
||||
typedef enum _radio_data_mode {
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
#ifdef DFM17
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hal/system.h"
|
||||
#include "hal/spi.h"
|
||||
#include "hal/pwm.h"
|
||||
#include "hal/delay.h"
|
||||
#include "hal/datatimer.h"
|
||||
#include "drivers/si4063/si4063.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "radio_si4063.h"
|
||||
#include "codecs/mfsk/mfsk.h"
|
||||
|
||||
#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;
|
||||
|
||||
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)
|
||||
{
|
||||
uint16_t frequency_offset;
|
||||
si4063_modulation_type modulation_type;
|
||||
bool use_direct_mode;
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP:
|
||||
frequency_offset = 1;
|
||||
modulation_type = SI4063_MODULATION_TYPE_OOK;
|
||||
use_direct_mode = false;
|
||||
|
||||
data_timer_init(entry->symbol_rate * CW_SYMBOL_RATE_MULTIPLIER);
|
||||
break;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
frequency_offset = 0;
|
||||
modulation_type = SI4063_MODULATION_TYPE_NONE;
|
||||
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;
|
||||
use_direct_mode = false;
|
||||
|
||||
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
si4063_set_tx_frequency(((float) entry->frequency) / 1000000.0f);
|
||||
si4063_set_tx_power(entry->tx_power);
|
||||
si4063_set_frequency_offset(frequency_offset);
|
||||
si4063_set_modulation_type(modulation_type);
|
||||
|
||||
si4063_enable_tx();
|
||||
|
||||
if (use_direct_mode) {
|
||||
spi_uninit();
|
||||
pwm_timer_init(100 * 100); // TODO: Idle tone
|
||||
pwm_timer_use(true);
|
||||
pwm_timer_pwm_enable(true);
|
||||
si4063_use_direct_mode(true);
|
||||
}
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP:
|
||||
spi_uninit();
|
||||
system_disable_tick();
|
||||
si4063_use_sdi_pin(true);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case RADIO_DATA_MODE_HORUS_V1:
|
||||
case RADIO_DATA_MODE_HORUS_V2:
|
||||
system_disable_tick();
|
||||
shared_state->radio_interrupt_transmit_active = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t radio_next_symbol_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
||||
{
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP:
|
||||
return 0;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
return 0;
|
||||
case RADIO_DATA_MODE_APRS_1200: {
|
||||
int8_t next_tone_index = entry->fsk_encoder_api->next_tone(&entry->fsk_encoder);
|
||||
if (next_tone_index < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shared_state->radio_current_fsk_tones[next_tone_index].frequency_hz_100;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool radio_transmit_symbol_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
||||
{
|
||||
uint32_t frequency = radio_next_symbol_si4063(entry, shared_state);
|
||||
|
||||
if (frequency == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
radio_si4063_freq = frequency;
|
||||
radio_si4063_state_change = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void radio_handle_main_loop_manual_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
||||
{
|
||||
fsk_encoder_api *fsk_encoder_api = entry->fsk_encoder_api;
|
||||
fsk_encoder *fsk_enc = &entry->fsk_encoder;
|
||||
|
||||
for (uint8_t i = 0; i < shared_state->radio_current_fsk_tone_count; i++) {
|
||||
precalculated_pwm_periods[i] = pwm_calculate_period(shared_state->radio_current_fsk_tones[i].frequency_hz_100);
|
||||
}
|
||||
|
||||
system_disable_tick();
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_APRS_1200: {
|
||||
int8_t tone_index;
|
||||
|
||||
while ((tone_index = fsk_encoder_api->next_tone(fsk_enc)) >= 0) {
|
||||
pwm_timer_set_frequency(precalculated_pwm_periods[tone_index]);
|
||||
shared_state->radio_symbol_count_loop++;
|
||||
delay_us(symbol_delay_bell_202_1200bps_us);
|
||||
}
|
||||
|
||||
radio_si4063_state_change = false;
|
||||
shared_state->radio_transmission_finished = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
system_enable_tick();
|
||||
}
|
||||
|
||||
void radio_handle_main_loop_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
||||
{
|
||||
if (entry->radio_type != RADIO_TYPE_SI4063 || shared_state->radio_interrupt_transmit_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shared_state->radio_manual_transmit_active) {
|
||||
radio_handle_main_loop_manual_si4063(entry, shared_state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (radio_si4063_state_change) {
|
||||
radio_si4063_state_change = false;
|
||||
pwm_timer_set_frequency(radio_si4063_freq);
|
||||
shared_state->radio_symbol_count_loop++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void radio_handle_data_timer_si4063()
|
||||
{
|
||||
static int cw_symbol_rate_multiplier = CW_SYMBOL_RATE_MULTIPLIER;
|
||||
|
||||
if (radio_current_transmit_entry->radio_type != RADIO_TYPE_SI4063 || !radio_shared_state.radio_interrupt_transmit_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (radio_current_transmit_entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP: {
|
||||
cw_symbol_rate_multiplier--;
|
||||
if (cw_symbol_rate_multiplier > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
cw_symbol_rate_multiplier = CW_SYMBOL_RATE_MULTIPLIER;
|
||||
|
||||
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) {
|
||||
si4063_set_sdi_pin(false);
|
||||
log_info("CW TX finished\n");
|
||||
radio_shared_state.radio_interrupt_transmit_active = false;
|
||||
radio_shared_state.radio_transmission_finished = true;
|
||||
system_enable_tick();
|
||||
break;
|
||||
}
|
||||
|
||||
si4063_set_sdi_pin(tone_index == 0 ? false : true);
|
||||
|
||||
radio_shared_state.radio_symbol_count_interrupt++;
|
||||
break;
|
||||
}
|
||||
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");
|
||||
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);
|
||||
|
||||
radio_shared_state.radio_symbol_count_interrupt++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool radio_stop_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state)
|
||||
{
|
||||
bool use_direct_mode = false;
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP:
|
||||
si4063_use_sdi_pin(false);
|
||||
data_timer_uninit();
|
||||
spi_init();
|
||||
break;
|
||||
case RADIO_DATA_MODE_RTTY:
|
||||
case RADIO_DATA_MODE_HORUS_V1:
|
||||
case RADIO_DATA_MODE_HORUS_V2:
|
||||
data_timer_uninit();
|
||||
break;
|
||||
case RADIO_DATA_MODE_APRS_1200:
|
||||
use_direct_mode = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (use_direct_mode) {
|
||||
si4063_use_direct_mode(false);
|
||||
pwm_timer_pwm_enable(false);
|
||||
pwm_timer_use(false);
|
||||
pwm_timer_uninit();
|
||||
spi_init();
|
||||
}
|
||||
|
||||
si4063_inhibit_tx();
|
||||
|
||||
switch (entry->data_mode) {
|
||||
case RADIO_DATA_MODE_CW:
|
||||
case RADIO_DATA_MODE_PIP:
|
||||
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:
|
||||
system_enable_tick();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef __RADIO_SI4063_H
|
||||
#define __RADIO_SI4063_H
|
||||
|
||||
#ifdef DFM17
|
||||
#include "radio_internal.h"
|
||||
|
||||
bool radio_start_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state);
|
||||
bool radio_transmit_symbol_si4063(radio_transmit_entry *entry, radio_module_state *shared_state);
|
||||
void radio_handle_main_loop_si4063(radio_transmit_entry *entry, radio_module_state *shared_state);
|
||||
void radio_handle_data_timer_si4063();
|
||||
bool radio_stop_transmit_si4063(radio_transmit_entry *entry, radio_module_state *shared_state);
|
||||
void radio_init_si4063();
|
||||
#endif //DFM17
|
||||
#endif //__RADIO_SI4063_H
|
Ładowanie…
Reference in New Issue