Initial plumbing for DFM17

pull/54/head
Mike Hojnowski 2023-09-12 10:05:15 -04:00
rodzic 8819d786b3
commit 49cc379d02
11 zmienionych plików z 937 dodań i 81 usunięć

Wyświetl plik

@ -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.

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

106
src/gpio.h 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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
}
}

Wyświetl plik

@ -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 {

406
src/radio_si4063.c 100644
Wyświetl plik

@ -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

14
src/radio_si4063.h 100644
Wyświetl plik

@ -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