NanoVNA/main.c

657 lines
14 KiB
C
Raw Normal View History

2016-09-05 00:27:44 +02:00
#include "ch.h"
#include "hal.h"
#include "usbcfg.h"
#include "si5351.h"
#include "nanovna.h"
#include <chprintf.h>
#include <shell.h>
#include <stdlib.h>
#include <string.h>
2016-09-28 15:48:53 +02:00
#include <math.h>
2016-09-05 00:27:44 +02:00
RTCDateTime timespec;
static const I2CConfig i2ccfg = {
0x00300506, //voodoo magic 400kHz @ HSI 8MHz
//0x00902025, //voodoo magic
2016-09-05 00:27:44 +02:00
//0x00420F13, // 100kHz @ 72MHz
0,
0
};
void I2CWrite(int addr, uint8_t d0, uint8_t d1)
{
uint8_t buf[] = { d0, d1 };
i2cAcquireBus(&I2CD1);
(void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, 2, NULL, 0, 1000);
i2cReleaseBus(&I2CD1);
}
int I2CRead(int addr, uint8_t d0)
{
uint8_t buf[] = { d0 };
i2cAcquireBus(&I2CD1);
i2cMasterTransmitTimeout(&I2CD1, addr, buf, 1, buf, 1, 1000);
i2cReleaseBus(&I2CD1);
return buf[0];
}
2016-09-28 01:47:46 +02:00
void scan_lcd(void);
2016-09-28 02:35:20 +02:00
static MUTEX_DECL(mutex);
2016-09-28 01:47:46 +02:00
static THD_WORKING_AREA(waThread1, 512);
2016-09-05 00:27:44 +02:00
static THD_FUNCTION(Thread1, arg)
{
(void)arg;
chRegSetThreadName("blink");
palSetPadMode(GPIOC, 13, PAL_MODE_OUTPUT_PUSHPULL);
while (1)
{
2016-09-28 01:47:46 +02:00
#if 0
2016-09-17 16:48:18 +02:00
systime_t time = 500;
if (serusbcfg.usbp->state != USB_ACTIVE)
palClearPad(GPIOC, 13);
2016-09-05 00:27:44 +02:00
chThdSleepMilliseconds(time);
palSetPad(GPIOC, 13);
chThdSleepMilliseconds(time);
2016-09-28 01:47:46 +02:00
#else
2016-09-28 02:35:20 +02:00
chMtxLock(&mutex);
2016-09-28 01:47:46 +02:00
scan_lcd();
2016-09-28 02:35:20 +02:00
chMtxUnlock(&mutex);
2016-09-28 01:47:46 +02:00
#endif
2016-09-05 00:27:44 +02:00
}
}
2016-09-28 02:35:20 +02:00
void
pause_sweep(void)
{
chMtxLock(&mutex);
}
void
resume_sweep(void)
{
chMtxUnlockAll();
}
static void cmd_pause(BaseSequentialStream *chp, int argc, char *argv[])
{
2016-09-28 15:48:53 +02:00
(void)chp;
2016-09-28 02:35:20 +02:00
(void)argc;
(void)argv;
pause_sweep();
}
static void cmd_resume(BaseSequentialStream *chp, int argc, char *argv[])
{
2016-09-28 15:48:53 +02:00
(void)chp;
2016-09-28 02:35:20 +02:00
(void)argc;
(void)argv;
resume_sweep();
}
2016-09-05 00:27:44 +02:00
static void cmd_reset(BaseSequentialStream *chp, int argc, char *argv[])
{
(void)argc;
(void)argv;
chprintf(chp, "Performing reset\r\n");
rccEnableWWDG(FALSE);
WWDG->CFR = 0x60;
WWDG->CR = 0xff;
while (1)
;
}
2016-09-28 02:35:20 +02:00
2016-09-05 00:27:44 +02:00
int32_t frequency_offset = 5000;
int32_t frequency = 10000000;
uint8_t drive_strength = SI5351_CLK_DRIVE_STRENGTH_2MA;
2016-09-05 00:27:44 +02:00
2016-09-24 03:25:13 +02:00
int set_frequency(int freq)
2016-09-05 00:27:44 +02:00
{
#if 0
2016-09-05 00:27:44 +02:00
si5351_set_frequency(0, freq + frequency_offset);
si5351_set_frequency(1, freq);
2016-09-24 03:25:13 +02:00
frequency = freq;
#else
2016-09-24 03:25:13 +02:00
int delay;
delay = si5351_set_frequency_with_offset(freq, frequency_offset, drive_strength);
frequency = freq;
return delay;
#endif
2016-09-05 00:27:44 +02:00
}
static void cmd_offset(BaseSequentialStream *chp, int argc, char *argv[])
{
if (argc != 1) {
chprintf(chp, "usage: offset {frequency offset(Hz)}\r\n");
return;
}
frequency_offset = atoi(argv[0]);
set_frequency(frequency);
}
static void cmd_freq(BaseSequentialStream *chp, int argc, char *argv[])
{
int freq;
2016-09-28 02:35:20 +02:00
pause_sweep();
2016-09-05 00:27:44 +02:00
if (argc != 1) {
chprintf(chp, "usage: freq {frequency(Hz)}\r\n");
return;
}
freq = atoi(argv[0]);
set_frequency(freq);
}
static void cmd_power(BaseSequentialStream *chp, int argc, char *argv[])
{
if (argc != 1) {
chprintf(chp, "usage: power {0-3}\r\n");
return;
}
drive_strength = atoi(argv[0]);
set_frequency(frequency);
}
2016-09-05 00:27:44 +02:00
static void cmd_time(BaseSequentialStream *chp, int argc, char *argv[])
{
(void)argc;
(void)argv;
rtcGetTime(&RTCD1, &timespec);
chprintf(chp, "%d/%d/%d %d\r\n", timespec.year+1980, timespec.month, timespec.day, timespec.millisecond);
}
static const DACConfig dac1cfg1 = {
2016-09-17 16:48:18 +02:00
//init: 2047U,
init: 1922U,
2016-09-05 00:27:44 +02:00
datamode: DAC_DHRM_12BIT_RIGHT
};
static void cmd_dac(BaseSequentialStream *chp, int argc, char *argv[])
{
int value;
if (argc != 1) {
chprintf(chp, "usage: dac {value(0-4095)}\r\n");
return;
}
value = atoi(argv[0]);
dacPutChannelX(&DACD2, 0, value);
}
static struct {
int16_t rms[2];
int16_t ave[2];
int callback_count;
int32_t last_counter_value;
int32_t interval_cycles;
int32_t busy_cycles;
} stat;
int16_t rx_buffer[AUDIO_BUFFER_LEN * 2];
int16_t dump_buffer[AUDIO_BUFFER_LEN];
2016-09-19 02:50:03 +02:00
volatile int16_t wait_count = 0;
2016-09-18 03:11:18 +02:00
int16_t dump_selection = 0;
2016-09-05 00:27:44 +02:00
2016-09-19 02:50:03 +02:00
int16_t dsp_disabled = FALSE;
2016-10-04 01:16:01 +02:00
float measured[101][4];
uint32_t frequencies[101];
2016-09-19 02:50:03 +02:00
2016-09-05 00:27:44 +02:00
void i2s_end_callback(I2SDriver *i2sp, size_t offset, size_t n)
{
#if PORT_SUPPORTS_RT
int32_t cnt_s = port_rt_get_counter_value();
int32_t cnt_e;
#endif
int16_t *p = &rx_buffer[offset];
(void)i2sp;
2016-09-05 01:33:05 +02:00
(void)n;
//palClearPad(GPIOC, GPIOC_LED);
2016-09-18 03:11:18 +02:00
2016-09-19 02:50:03 +02:00
if (!dsp_disabled)
dsp_process(p, n);
2016-09-05 00:27:44 +02:00
2016-09-19 02:50:03 +02:00
if (wait_count > 0) {
2016-09-18 03:11:18 +02:00
if (dump_selection == 1)
p = samp_buf;
else if (dump_selection == 2)
p = ref_buf;
else if (dump_selection == 3)
2016-09-19 02:31:50 +02:00
p = refiq_buf;
2016-09-19 02:50:03 +02:00
if (wait_count == 1)
2016-09-05 00:27:44 +02:00
memcpy(dump_buffer, p, sizeof dump_buffer);
2016-09-19 02:50:03 +02:00
--wait_count;
2016-09-05 00:27:44 +02:00
}
#if PORT_SUPPORTS_RT
cnt_e = port_rt_get_counter_value();
stat.interval_cycles = cnt_s - stat.last_counter_value;
stat.busy_cycles = cnt_e - cnt_s;
stat.last_counter_value = cnt_s;
#endif
stat.callback_count++;
//palSetPad(GPIOC, GPIOC_LED);
2016-09-05 00:27:44 +02:00
}
static const I2SConfig i2sconfig = {
NULL, // TX Buffer
rx_buffer, // RX Buffer
AUDIO_BUFFER_LEN * 2,
NULL, // tx callback
i2s_end_callback, // rx callback
0, // i2scfgr
2 // i2spr
};
static void cmd_data(BaseSequentialStream *chp, int argc, char *argv[])
{
int i, j;
2016-09-18 03:11:18 +02:00
int len;
2016-09-28 02:35:20 +02:00
pause_sweep();
2016-09-18 03:11:18 +02:00
if (argc == 1)
dump_selection = atoi(argv[0]);
2016-09-19 02:50:03 +02:00
wait_count = 3;
2016-09-18 03:11:18 +02:00
//palClearPad(GPIOC, GPIOC_LED);
2016-09-19 02:50:03 +02:00
while (wait_count)
2016-09-05 00:27:44 +02:00
;
2016-09-18 03:11:18 +02:00
len = AUDIO_BUFFER_LEN;
2016-09-19 02:31:50 +02:00
if (dump_selection == 1 || dump_selection == 2)
2016-09-18 03:11:18 +02:00
len /= 2;
for (i = 0; i < len; ) {
2016-09-05 00:27:44 +02:00
for (j = 0; j < 16; j++, i++) {
2016-09-19 02:31:50 +02:00
chprintf(chp, "%04x ", 0xffff & (int)dump_buffer[i]);
2016-09-05 00:27:44 +02:00
}
chprintf(chp, "\r\n");
}
2016-09-18 03:11:18 +02:00
//palSetPad(GPIOC, GPIOC_LED);
2016-09-05 00:27:44 +02:00
}
2016-09-19 02:31:50 +02:00
static void cmd_gamma(BaseSequentialStream *chp, int argc, char *argv[])
{
2016-10-04 01:16:01 +02:00
float gamma[2];
2016-09-19 02:31:50 +02:00
(void)argc;
(void)argv;
2016-10-04 01:16:01 +02:00
2016-09-28 02:35:20 +02:00
pause_sweep();
wait_count = 4;
2016-09-19 02:50:03 +02:00
while (wait_count)
2016-09-19 02:31:50 +02:00
;
2016-09-19 02:50:03 +02:00
dsp_disabled = TRUE;
2016-10-04 01:16:01 +02:00
calclate_gamma(gamma);
2016-09-19 02:50:03 +02:00
dsp_disabled = FALSE;
2016-10-04 01:16:01 +02:00
chprintf(chp, "%d %d\r\n", gamma[0], gamma[1]);
2016-09-19 02:31:50 +02:00
}
2016-09-24 11:51:32 +02:00
int32_t freq_start = 1000000;
int32_t freq_stop = 300000000;
int16_t sweep_points = 101;
static void cmd_scan(BaseSequentialStream *chp, int argc, char *argv[])
{
2016-10-04 01:16:01 +02:00
float gamma[2];
int i;
2016-09-28 15:48:53 +02:00
int32_t freq, step;
2016-09-24 03:25:13 +02:00
int delay;
(void)argc;
(void)argv;
2016-09-28 02:35:20 +02:00
pause_sweep();
2016-09-24 11:51:32 +02:00
freq = freq_start;
step = (freq_stop - freq_start) / (sweep_points-1);
2016-09-24 03:25:13 +02:00
delay = set_frequency(freq);
delay += 2;
2016-09-24 11:51:32 +02:00
for (i = 0; i < sweep_points; i++) {
2016-09-24 03:25:13 +02:00
freq = freq + step;
wait_count = delay;
while (wait_count)
;
2016-09-24 03:25:13 +02:00
//dsp_disabled = TRUE;
__disable_irq();
delay = set_frequency(freq);
palClearPad(GPIOC, GPIOC_LED);
2016-10-04 01:16:01 +02:00
calclate_gamma(gamma);
palSetPad(GPIOC, GPIOC_LED);
2016-09-24 03:25:13 +02:00
//dsp_disabled = FALSE;
__enable_irq();
2016-10-04 01:16:01 +02:00
chprintf(chp, "%d %d\r\n", gamma[0], gamma[1]);
}
}
2016-09-28 01:47:46 +02:00
void scan_lcd(void)
{
int i;
int delay;
int first = TRUE;
2016-10-04 01:16:01 +02:00
delay = set_frequency(frequencies[0]);
2016-09-28 01:47:46 +02:00
delay += 2;
for (i = 0; i < sweep_points; i++) {
wait_count = delay;
2016-09-28 15:48:53 +02:00
tlv320aic3204_select_in3();
2016-09-28 01:47:46 +02:00
while (wait_count)
;
palClearPad(GPIOC, GPIOC_LED);
__disable_irq();
2016-10-04 01:16:01 +02:00
calclate_gamma(&measured[i][0]);
2016-09-28 01:47:46 +02:00
__enable_irq();
2016-09-28 16:33:43 +02:00
tlv320aic3204_select_in1();
2016-09-30 02:42:49 +02:00
wait_count = 3;
2016-09-28 16:33:43 +02:00
while (wait_count)
;
__disable_irq();
2016-10-04 01:16:01 +02:00
calclate_gamma(&measured[i][2]);
2016-09-28 16:33:43 +02:00
__enable_irq();
2016-10-04 01:16:01 +02:00
delay = set_frequency(frequencies[(i+1)%sweep_points]);
#if 0
sweep_plot(frequencies[i], first, measured[i]);
2016-09-28 01:47:46 +02:00
first = FALSE;
2016-10-04 01:16:01 +02:00
#endif
2016-09-28 01:47:46 +02:00
palSetPad(GPIOC, GPIOC_LED);
}
2016-10-04 01:16:01 +02:00
#if 1
for (i = 0; i < sweep_points; i++) {
sweep_plot(frequencies[i], first, measured[i]);
first = FALSE;
}
#endif
2016-09-28 01:47:46 +02:00
sweep_tail();
2016-10-04 01:16:01 +02:00
polar_plot(measured);
2016-09-28 01:47:46 +02:00
}
static void cmd_scan_lcd(BaseSequentialStream *chp, int argc, char *argv[])
{
2016-09-28 15:48:53 +02:00
(void)chp;
2016-09-28 01:47:46 +02:00
(void)argc;
(void)argv;
2016-09-28 02:35:20 +02:00
pause_sweep();
2016-09-28 01:47:46 +02:00
scan_lcd();
}
2016-10-04 01:16:01 +02:00
void
set_frequencies(void)
{
int i;
int32_t span = (freq_stop - freq_start)/100;
for (i = 0; i < sweep_points; i++)
frequencies[i] = freq_start + span * i / (sweep_points - 1) * 100;
}
2016-09-24 11:51:32 +02:00
static void cmd_sweep(BaseSequentialStream *chp, int argc, char *argv[])
{
if (argc == 0) {
chprintf(chp, "%d %d %d\r\n", freq_start, freq_stop, sweep_points);
return;
} else if (argc > 3) {
chprintf(chp, "usage: sweep {start(Hz)} [stop] [points]\r\n");
return;
}
if (argc >= 1) {
int32_t x = atoi(argv[0]);
if (x < 300000) {
chprintf(chp, "bad parameter\r\n");
return;
}
freq_start = x;
}
if (argc >= 2) {
int32_t x = atoi(argv[1]);
if (x < 300000 || x <= freq_start) {
chprintf(chp, "bad parameter\r\n");
return;
}
freq_stop = x;
}
if (argc >= 3) {
int32_t x = atoi(argv[2]);
if (x < 1 || x > 1601) {
chprintf(chp, "bad parameter\r\n");
return;
}
sweep_points = x;
}
2016-10-04 01:16:01 +02:00
set_frequencies();
set_sweep(freq_start, freq_stop);
2016-09-24 11:51:32 +02:00
}
static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[])
{
int i;
2016-09-28 15:48:53 +02:00
(void)chp;
(void)argc;
(void)argv;
2016-09-28 02:35:20 +02:00
pause_sweep();
2016-09-26 17:06:00 +02:00
#if 0
for (i = 0; i < 100; i++) {
palClearPad(GPIOC, GPIOC_LED);
set_frequency(10000000);
palSetPad(GPIOC, GPIOC_LED);
chThdSleepMilliseconds(50);
palClearPad(GPIOC, GPIOC_LED);
2016-09-24 03:25:13 +02:00
set_frequency(90000000);
palSetPad(GPIOC, GPIOC_LED);
chThdSleepMilliseconds(50);
}
2016-09-26 17:06:00 +02:00
#endif
#if 1
int mode = 0;
if (argc >= 1)
mode = atoi(argv[0]);
for (i = 0; i < 20; i++) {
palClearPad(GPIOC, GPIOC_LED);
ili9341_test(mode);
palSetPad(GPIOC, GPIOC_LED);
chThdSleepMilliseconds(50);
}
#endif
}
2016-09-05 00:27:44 +02:00
static void cmd_gain(BaseSequentialStream *chp, int argc, char *argv[])
{
int rvalue;
int lvalue = 0;
if (argc != 1 && argc != 2) {
chprintf(chp, "usage: gain {lgain(0-95)} [rgain(0-95)]\r\n");
return;
}
rvalue = atoi(argv[0]);
if (argc == 2)
lvalue = atoi(argv[1]);
tlv320aic3204_set_gain(lvalue, rvalue);
}
static void cmd_port(BaseSequentialStream *chp, int argc, char *argv[])
{
int port;
if (argc != 1) {
chprintf(chp, "usage: port {0:TX 1:RX}\r\n");
return;
}
port = atoi(argv[0]);
if (port)
tlv320aic3204_select_in1();
else
tlv320aic3204_select_in3(); // default
}
static void cmd_stat(BaseSequentialStream *chp, int argc, char *argv[])
{
int16_t *p = &rx_buffer[0];
int32_t acc0, acc1;
int32_t ave0, ave1;
int32_t count = AUDIO_BUFFER_LEN;
int i;
(void)argc;
(void)argv;
acc0 = acc1 = 0;
for (i = 0; i < AUDIO_BUFFER_LEN*2; i += 2) {
acc0 += p[i];
acc1 += p[i+1];
}
ave0 = acc0 / count;
ave1 = acc1 / count;
acc0 = acc1 = 0;
for (i = 0; i < AUDIO_BUFFER_LEN*2; i += 2) {
acc0 += (p[i] - ave0)*(p[i] - ave0);
acc1 += (p[i+1] - ave1)*(p[i+1] - ave1);
}
2016-09-28 15:48:53 +02:00
stat.rms[0] = sqrtf(acc0 / count);
stat.rms[1] = sqrtf(acc1 / count);
2016-09-05 00:27:44 +02:00
stat.ave[0] = ave0;
stat.ave[1] = ave1;
chprintf(chp, "average: %d %d\r\n", stat.ave[0], stat.ave[1]);
chprintf(chp, "rms: %d %d\r\n", stat.rms[0], stat.rms[1]);
chprintf(chp, "callback count: %d\r\n", stat.callback_count);
chprintf(chp, "interval cycle: %d\r\n", stat.interval_cycles);
chprintf(chp, "busy cycle: %d\r\n", stat.busy_cycles);
chprintf(chp, "load: %d\r\n", stat.busy_cycles * 100 / stat.interval_cycles);
}
#define SHELL_WA_SIZE THD_WORKING_AREA_SIZE(2048)
static const ShellCommand commands[] =
{
{ "reset", cmd_reset },
{ "freq", cmd_freq },
{ "offset", cmd_offset },
{ "time", cmd_time },
{ "dac", cmd_dac },
{ "data", cmd_data },
{ "port", cmd_port },
{ "stat", cmd_stat },
{ "gain", cmd_gain },
{ "power", cmd_power },
2016-09-19 02:31:50 +02:00
{ "gamma", cmd_gamma },
{ "scan", cmd_scan },
2016-09-24 11:51:32 +02:00
{ "sweep", cmd_sweep },
{ "test", cmd_test },
2016-09-28 01:47:46 +02:00
{ "plot", cmd_scan_lcd },
2016-09-28 02:35:20 +02:00
{ "pause", cmd_pause },
{ "resume", cmd_resume },
2016-09-05 00:27:44 +02:00
{ NULL, NULL }
};
static const ShellConfig shell_cfg1 =
{
(BaseSequentialStream *)&SDU1,
commands
};
int main(void)
{
halInit();
chSysInit();
2016-09-28 02:35:20 +02:00
chMtxObjectInit(&mutex);
2016-09-05 00:27:44 +02:00
/*
* Starting DAC1 driver, setting up the output pin as analog as suggested
* by the Reference Manual.
*/
//palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
//palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
//palSetPadMode(GPIOA, 5, PAL_MODE_INPUT);
dacStart(&DACD2, &dac1cfg1);
//palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(1) | PAL_STM32_OTYPE_OPENDRAIN);
//palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(1) | PAL_STM32_OTYPE_OPENDRAIN);
i2cStart(&I2CD1, &i2ccfg);
si5351_init();
// MCO on PA8
//palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(0));
/*
* Initializes a serial-over-USB CDC driver.
*/
sduObjectInit(&SDU1);
sduStart(&SDU1, &serusbcfg);
/*
* Activates the USB driver and then the USB bus pull-up on D+.
* Note, a delay is inserted in order to not have to disconnect the cable
* after a reset.
*/
usbDisconnectBus(serusbcfg.usbp);
chThdSleepMilliseconds(100);
usbStart(serusbcfg.usbp, &usbcfg);
usbConnectBus(serusbcfg.usbp);
2016-09-26 17:06:00 +02:00
/*
* SPI LCD Initialize
*/
ili9341_init();
2016-10-04 01:16:01 +02:00
set_sweep(freq_start, freq_stop);
redraw();
2016-09-26 17:06:00 +02:00
2016-10-04 01:16:01 +02:00
/*
*/
set_frequencies();
2016-09-05 00:27:44 +02:00
/*
* I2S Initialize
*/
tlv320aic3204_init();
i2sInit();
i2sObjectInit(&I2SD2);
i2sStart(&I2SD2, &i2sconfig);
i2sStartExchange(&I2SD2);
/*
* Shell manager initialization.
*/
shellInit();
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
2016-09-28 01:47:46 +02:00
//set_frequency(10000000);
2016-09-05 00:27:44 +02:00
while (1)
{
if (SDU1.config->usbp->state == USB_ACTIVE) {
2016-09-17 16:48:18 +02:00
//palSetPad(GPIOC, GPIOC_LED);
2016-09-05 00:27:44 +02:00
thread_t *shelltp = chThdCreateFromHeap(NULL, SHELL_WA_SIZE,
"shell", NORMALPRIO + 1,
shellThread, (void *)&shell_cfg1);
chThdWait(shelltp); /* Waiting termination. */
2016-09-17 16:48:18 +02:00
//palClearPad(GPIOC, GPIOC_LED);
2016-09-05 00:27:44 +02:00
}
chThdSleepMilliseconds(1000);
}
}