RX ready for testing

chibios
Marshal Horn 2020-07-20 11:50:24 -07:00
rodzic dede6b7bef
commit 3aed3f52f5
13 zmienionych plików z 191 dodań i 49 usunięć

Wyświetl plik

@ -33,6 +33,14 @@
* @name ISRs suppressed in standard drivers
* @{
*/
#define STM32_TIM1_SUPPRESS_ISR
#define STM32_TIM2_SUPPRESS_ISR
#define STM32_TIM3_SUPPRESS_ISR
#define STM32_TIM14_SUPPRESS_ISR
#define STM32_TIM15_SUPPRESS_ISR
#define STM32_TIM16_SUPPRESS_ISR
#define STM32_TIM17_SUPPRESS_ISR
#define STM32_USART1_SUPPRESS_ISR
#define STM32_USART2_SUPPRESS_ISR
#define STM32_USART3_SUPPRESS_ISR

Wyświetl plik

@ -120,7 +120,13 @@ LDSCRIPT= $(STARTUPLD)/STM32F051x8.ld
# setting.
CSRC = $(ALLCSRC) \
$(TESTSRC) \
main.c radio/rx.c drivers/si5351.c trig.c
main.c \
radio/hilbert.c \
radio/rx.c \
radio/ssb.c \
drivers/si5351.c \
drivers/speaker.c \
trig.c
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
# setting.

Wyświetl plik

@ -79,7 +79,7 @@
* @brief Enables the GPT subsystem.
*/
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
#define HAL_USE_GPT FALSE
#define HAL_USE_GPT TRUE
#endif
/**

Wyświetl plik

@ -94,7 +94,7 @@
#define STM32_GPT_USE_TIM1 FALSE
#define STM32_GPT_USE_TIM2 FALSE
#define STM32_GPT_USE_TIM3 FALSE
#define STM32_GPT_USE_TIM14 FALSE
#define STM32_GPT_USE_TIM14 TRUE
#define STM32_GPT_TIM1_IRQ_PRIORITY 2
#define STM32_GPT_TIM2_IRQ_PRIORITY 2
#define STM32_GPT_TIM3_IRQ_PRIORITY 2

Wyświetl plik

@ -31,11 +31,16 @@ void synthStop(struct synth * cfg){
i2cMasterTransmitTimeout(&I2CD1, si5351, buf, 2, NULL, 0, TIME_MS2I(100));
}
void synthSetPhase(struct synth * cfg, uint8_t phase){
cfg->phase = phase;
void synthSetPhase(struct synth * cfg, float degrees){
if(degrees < 0)
degrees += 360; // Only allow positive delay
//FIXME: If more than 180 degrees, we should use the clock invert feature
// Since the delay is before the divider, we scale by the divide ratio
degrees *= ((1./360)*(cfg->reg.synth))/(1<<25);
cfg->phase = degrees > 127 ? 127 : degrees;
uint8_t buf[2];
buf[0]=cfg->channel+165;
buf[1]=phase;
buf[1]=cfg->phase;
i2cMasterTransmitTimeout(&I2CD1, si5351, buf, 2, NULL, 0, TIME_MS2I(100));
pll_reset(cfg->PLLx);
}
@ -55,6 +60,11 @@ void synthWriteParam(uint8_t reg, uint64_t val, uint8_t div){
i2cMasterTransmitTimeout(&I2CD1, si5351, buf, 9, NULL, 0, TIME_MS2I(100));
}
void synthWriteConfig(struct synth * cfg){
synthWriteParam(cfg->PLLx, cfg->reg.pll, 0);
synthWriteParam(cfg->channel+2, cfg->reg.synth, cfg->reg.divide);
}
void synthSetCarrier(struct synth * cfg, float carrier){
// Calculate PLL and Multisynth values
const double xtal = 27e6;
@ -81,9 +91,7 @@ void synthSetCarrier(struct synth * cfg, float carrier){
cfg->reg.shift = delta_shift;
cfg->reg.divide = div2;
// Write changes to chip
synthWriteParam(cfg->PLLx, cfg->reg.pll, 0);
synthWriteParam(cfg->channel+2, cfg->reg.synth, cfg->reg.divide);
synthWriteConfig(cfg);
}
void synthSetBaseband(struct synth * cfg, int32_t baseband){

Wyświetl plik

@ -29,7 +29,13 @@ void synthStart(struct synth * cfg);
void synthSetCarrier(struct synth * cfg, float carrier);
void synthSetBaseband(struct synth * cfg, int32_t baseband);
void synthWriteParam(uint8_t reg, uint64_t val, uint8_t div);
void synthSetPhase(struct synth * cfg, uint8_t phase);
void synthWriteConfig(struct synth * cfg);
/* Sets the initial phase offset
*
* Note that this has limited resolution and range. The maximum delay is 31.75x the PLL clock period,
* which means you will have a difficult time getting a 90-degree phase shift on the 80m band.
*/
void synthSetPhase(struct synth * cfg, float degrees);
void synthStop(struct synth * cfg);

Wyświetl plik

@ -17,20 +17,67 @@
* advantages like increased dynamic range and noise rejection.
*/
uint16_t spkr_dma_buf[spkr_buffer_len];
objects_fifo_t spkr_fifo;
void speakerUpdate(int16_t data, int len);
void speakerInit(void){
size_t objsize = spkr_buffer_len*sizeof(int16_t);
msg_t * msg_buf = chCoreAllocFromBase(spkr_fifo_len*sizeof(msg_t), sizeof(msg_t), 0);
void * obj_buf = chCoreAllocFromBase(objsize*spkr_fifo_len, 4, 0);
chFifoObjectInit(&spkr_fifo, objsize, spkr_fifo_len, obj_buf, msg_buf);
}
msg_t speakerUpdate(int16_t * data, int len){
static int16_t * buf = 0;
static size_t i = 0;
for(int n = 0; n < len; ++n){
if(!buf){
i = 0;
buf = (int16_t *)chFifoTakeObjectTimeout(&spkr_fifo, TIME_IMMEDIATE);
if(!buf)
return MSG_TIMEOUT;
}
buf[i]=data[n];
++i;
if(i>=spkr_buffer_len){
chFifoSendObject(&spkr_fifo, (void*)buf);
buf=0;
}
}
return MSG_OK;
}
/** Copies audio data to PWM
*
*/
void speaker_callback(PWMDriver * pwmp){
//FIXME: Copy data into DMA buffer. Or interrupt every period.
void speaker_callback(GPTDriver * gptp){
static size_t i=0;
static uint16_t * buf = 0;
(void)gptp; // We don't use the gpt driver info
if(!buf){
//get next buffer
msg_t result = chFifoReceiveObjectTimeout(&spkr_fifo, (void**)&buf, TIME_IMMEDIATE);
//If fifo is empty, return.
if(MSG_TIMEOUT == result)
return;
}
// Convert signed integer to unsigned with offset
buf[i] += 0x8000;
// Scale to 11 bits
buf[i]>>=(16-11);
// Update PWM
pwmEnableChannel(&PWMD3, 0, buf[i]);
// increment to next sample
++i;
if(i >= spkr_buffer_len){
//Free this buffer
chFifoReturnObject(&spkr_fifo, buf);
buf = NULL;
}
}
static PWMConfig spkr = {
.frequency = 4096000, /* 4MHz PWM clock frequency. */
.period = 4096, /* Initial PWM period 1ms. */
.frequency = 32e6, // Run at full processor speed
.period = (1<<10), // 11 bits of data to give a 16 kHz update rate
.callback = NULL,
.channels = {
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
@ -39,32 +86,22 @@ static PWMConfig spkr = {
{PWM_OUTPUT_DISABLED, NULL}
},
.cr2 = 0,
.dier = STM32_TIM_DIER_CC1DE, // DMA request on channel 1 compare match
.dier = 0,
};
const uint32_t dma_config = 0
| STM32_DMA_CR_DIR_M2P // Memory to peripheral
| STM32_DMA_CR_CIRC // Circular buffer
| STM32_DMA_CR_MINC // Memory Increment Mode
| STM32_DMA_CR_PSIZE_WORD // 16-bit peripheral space
| STM32_DMA_CR_MSIZE_WORD // 16-bit buffer width in RAM
| STM32_DMA_CR_PL(3) // High priority
| STM32_DMA_CR_TCIE // Transfer Complete Interrupt
| STM32_DMA_CR_HTIE // Half-transfer Interrupt
;
static GPTConfig gpt_config = {
.callback = speaker_callback,
};
void speakerStart(void){
static stm32_dma_stream_t * stream =
dmaStreamAlloc(STM32_PWM_TIM3_DMA_STREAM, 2, speaker_callback, NULL);
dmaStreamSetPeripheral(stream, &TIM3->DMAR);
dmaStreamSetMemory0(stream, spkr_dma_buf);
dmaStreamSetTransactionSize(stream, spkr_buffer_len);
dmaStreamSetMode(stream, dma_config);
dmaStreamEnable(stream);
void speakerStart(float sample_rate){
pwmStart(&PWMD3, &spkr);
gpt_config.frequency = sample_rate;
gptStart(&GPTD14, &gpt_config);
gptStartContinuous(&GPTD14, 1);
}
void speakerStop(void){
pwmStop(&PWMD3);
dmaStreamDisable(stream);
gptStopTimer(&GPTD14);
gptStop(&GPTD14);
}

Wyświetl plik

@ -1,8 +1,41 @@
#include "hal.h"
#include <stdint.h>
const size_t spkr_buffer_len = 64;
/// The number of samples in one fifo element. This is used to reduce overhead.
static const size_t spkr_buffer_len = 16;
/// The number of elements in the fifo. This must be at least 3.
static const size_t spkr_fifo_len = 4;
void speakerStart(void);
/** Starts the speaker PWM
*
* @param sample_rate How quickly you want the samples to be played.
*/
void speakerStart(float sample_rate);
/* Stops the speaker PWM
*
*/
void speakerStop(void);
void speakerUpdate(int16_t data, int len);
/** Copies data into speaker fifo
*
* @param data 16-bit signed data to write to speaker. Note that the audio might not be 16-bit resolution
* @param len The number of samples top copy
*
* @returns MSG_OK on sucess, MSG_TIMEOUT if not all data fit
*/
msg_t speakerUpdate(int16_t * data, int len);
/** Copies audio data to PWM
*
* This function is called via a timer callback, and should
* not be called explicitly under normal circumstances.
*/
void speaker_callback(GPTDriver *gpt);
/** Allocates memory for speaker fifo
*
* This function must only be called once.
* It is not automatically called by halInit().
*/
void speakerInit(void);

Wyświetl plik

@ -5,16 +5,20 @@
* Author: marshal
*/
#include <stdint.h>
#include "hilbert.h"
int16_t hilbert19(int16_t * src){
const size_t M = 19/2;
const int32_t coef[M/2+1];
/* Hilbert coeffecients with a hamming window
* Values are 2/pi, 2/3pi, 2/7pi, 2/9pi, etc
* Stored in 15.16 fixed-point
*/
const int16_t coef[] = {40564, 10709, 3839, 1118, 371};
int32_t sum;
sum = (src[M-1]-src[M+1]) * coef[0];
sum += (src[M-3]-src[M+3]) * coef[1];
sum += (src[M-5]-src[M+5]) * coef[2];
sum += (src[M-7]-src[M+7]) * coef[3];
sum += (src[M-9]-src[M+9]) * coef[4];
sum = (src[M-1]-src[M+1]) * (int32_t)coef[0];
sum += (src[M-3]-src[M+3]) * (int32_t)coef[1];
sum += (src[M-5]-src[M+5]) * (int32_t)coef[2];
sum += (src[M-7]-src[M+7]) * (int32_t)coef[3];
sum += (src[M-9]-src[M+9]) * (int32_t)coef[4];
return sum>>16;
}

Wyświetl plik

@ -0,0 +1,9 @@
#include <stdint.h>
#include <stddef.h>
/** 19-element Hilbert transform
*
* Generated with hamming window
*/
int16_t hilbert19(int16_t * src);

Wyświetl plik

@ -8,10 +8,16 @@
#include "rx.h"
#include "ssb.h"
#include "../drivers/speaker.h"
#include "../drivers/si5351.h"
/** Mailbox for received data */
mailbox_t new_sample;
struct{
float frequency;
enum radio_mode mode;
}rx_cfg;
THD_WORKING_AREA(waradio_rx, 128);
THD_FUNCTION(radio_rx, arg){
(void)arg;
@ -26,9 +32,9 @@ THD_FUNCTION(radio_rx, arg){
}
/** Process the received data */
int16_t out[len];
ssb(out, data, len);
ssb_rx(out, data, len);
/** Fill buffer for audio out */
speaker_update(out, len);
speakerUpdate(out, len);
}
}
@ -117,3 +123,27 @@ void adc_rx_init(void){
adcStartConversion(&ADCD1, &qsd_in, samples, len);
}
void rxStart(enum radio_mode mode, float frequency){
rx_cfg.mode = mode;
rx_cfg.frequency = frequency;
// Set up the clocks with 90-degree phase offset
struct synth clk1;
synthInit(&clk1, 0, 0);
synthSetCarrier(&clk1, frequency);
synthStart(&clk1);
struct synth clk2 = clk1; // Re-use the frequency calculation
synthInit(&clk2, 1, 0);
synthWriteConfig(&clk2);
synthSetPhase(&clk2, 90);
synthStart(&clk2);
adc_rx_init();
speakerStart(5e3); // 5kHz audo sample rate
}
void rxStop(void){
adcStop(&ADCD1);
speakerStop();
}

Wyświetl plik

@ -4,7 +4,6 @@
* Created on: Jul 9, 2020
* Author: marshal
*/
#include <stdint.h>
#include "ssb.h"
void ssb_rx(int16_t * dest, int16_t * src, size_t qty){

Wyświetl plik

@ -4,6 +4,8 @@
* Created on: Jul 9, 2020
* Author: marshal
*/
#include <stdint.h>
#include <stddef.h>
/** Single sideband decoder
*