forked from ttrftech/CentSDR
-
Notifications
You must be signed in to change notification settings - Fork 2
/
nanosdr.h
383 lines (296 loc) · 11.2 KB
/
nanosdr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*
* Copyright (c) 2016-2017, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
* All rights reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* The software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef _NANOSDR_H_
#define _NANOSDR_H_
/*
If you want to generate the quadrature LO directly from Si5351A without U2 (74LVC74APW),
enable the below SI5351_GEN_QUADRATURE_LO macro switch.
In that case you need to remove the U2 then populate the R5 and R6 with 0ohm resistor (jumper).
Si5351A only be able to generate the quadrature LO down to 3.5MHz, so below that frequency
no phase shift between I and Q LO, meaning the CW, USB and LSB mode will not work properly.
*/
//#define SI5351_GEN_QUADRATURE_LO 1
#ifdef SI5351_GEN_QUADRATURE_LO
/*
To support the quadrature LO down to 100kHz, enable the below SI5351_GEN_QUADRATURE_LO_BELOW_3500KHZ macro switch,
then modify the hardware:
- add 100ohm resistor in between PB10 (pin 21 on U5 STM32F303) and CLK0 (pin 10 on U7 Si5351A)
- add 100ohm resistor in between PB11 (pin 22 on U5 STM32F303) and CLK1 (pin 9 on U7 Si5351A)
How this work:
- Si5351A supports the Initial Phase Offset (CLKx_PHOFF) on each Output Multisynth, however it is only 7 bits so
not enough for the frequency below 4.761905MHz (Si5351A PLL is still working at 441MHz, so says below 3.5MHz)
- If you set up the R divider AFTER enabling the PLL, it starts counting at the time the Rx_DIV is set.
- That means if you keep toggling the Rx_DIV between 000b (Divided by 1) and 010b (Divided by 4) at random timing,
it eventually generates the quadrature LO.
- However you need to make sure it has correct phase, therefore connecting the CLK0 and CLK1 to GPIO pins is required
to monitor the phase difference.
- There may be a way to not using the GPIOs for detecting the phase, e.g. set up the CLK2 temporarily to the
receiving frequency + offset, then start capturing I/Q signal. By analyzing the signal, software should be able to
tell the quadrature LO has correct phase or not, if no other strong signal is blocking the CLK2 signal.
*/
//#define SI5351_GEN_QUADRATURE_LO_BELOW_3500KHZ 1
/*
If you want to try the SSB TX portion of the uSDX (https://groups.io/g/ucx) (originally QCX-SSB https://github.com/threeme3/QCX-SSB)
on CentSDR, enable the macro switch below.
Current TX implementation only supports 40m band (7.000MHz ~ 7.250MHz).
S3 (PA1 Pin11 of STM32F303 or T-IRQ on LCD connector) is a PTT control line, LOW (open, internally pull-down) is for RX mode
and put it to HIGH (3.3V VDD) for TX.
You need to have the uSDX PA circuit (EER Class-E PWM based SSB modulator) and connected to CentSDR:
- PWM signal (active low) for Amplitude portion of SSB: S4 (PB0 Pin18 of STM32F303 or T_CS on LCD connector)
- PWM signal for RF frequency and Phase portion of SSB: AUXLO thru hole next to the SMA antenna connector
Note: above signals are in 3.3V logic level, and uSDX PA requires 5V logic level so please insert some buffer between them.
(e.g. use a NAND gate in 74ACT00)
Warning: the Amplitude PWM signal is in ACTIVE LOW, so you have to negate the logic before put in the RC low pass filter
To make it complete transceiver, you also need to add RF switch (FET) to connect / disconnect the CentSDR to antenna.
You can use the PTT control line, but it is in active HIGH so you need to negate the logic before put in the gate of the
FET.
For the PA and RF-RX switch circuit, please refer to https://github.com/threeme3/QCX-SSB/blob/master/ucx.png
If you just want to hear the Phase portion of the SSB signal without constructing the uSDX PA, you can connect a short wire
at the AUXLO thru hole as antenna then listen on 40m LSB (e.g. 7.200MHz) with HF rig.
*/
//#define PORT_uSDX_TO_CentSDR 1
#endif
/*
* main.c
*/
typedef struct {
int32_t rms[2];
int16_t ave[2];
int16_t min[2];
int16_t max[2];
uint32_t callback_count;
int32_t last_counter_value;
int32_t interval_cycles;
int32_t busy_cycles;
uint16_t fps_count;
uint16_t fps;
uint16_t overflow_count;
uint16_t overflow;
uint16_t vref;
uint16_t temperature;
uint16_t battery;
} stat_t;
extern int16_t measured_power_dbm;
extern stat_t stat;
void set_agc_mode(int agcmode);
/*
* tlv320aic3204.c
*/
typedef struct {
int target_level;
int gain_hysteresis;
int attack;
int attack_scale;
int decay;
int decay_scale;
int maximum_gain;
} tlv320aic3204_agc_config_t;
extern void tlv320aic3204_init(void);
extern void tlv320aic3204_set_gain(int g1, int g2);
extern void tlv320aic3204_set_digital_gain(int g1, int g2);
extern void tlv320aic3204_set_volume(int gain);
extern void tlv320aic3204_agc_config(tlv320aic3204_agc_config_t *conf);
extern void tlv320aic3204_set_fs(int fs);
extern void tlv320aic3204_stop(void);
extern void tlv320aic3204_config_adc_filter(int enable);
extern void tlv320aic3204_config_adc_filter2(double iqbal);
extern void tlv320aic3204_set_impedance(int imp);
extern int tlv320aic3204_get_sticky_flag_register(void);
extern int8_t tlv320aic3204_get_left_agc_gain(void);
extern int8_t tlv320aic3204_get_right_agc_gain(void);
extern void tlv320aic3204_set_adc_phase_adjust(int8_t adjust);
extern void tlv320aic3204_set_adc_fine_gain_adjust(int8_t g1, int8_t g2);
extern void tlv320aic3204_beep(void);
extern void tlv320aic3204_select_in1(void);
extern void tlv320aic3204_select_in3(void);
extern uint8_t tlv320aic3204_read_register(uint8_t page, uint8_t reg);
extern void tlv320aic3204_write_register(uint8_t page, uint8_t reg, uint8_t val);
#define AIC3204_STICKY_ADC_OVERFLOW 0x0c
/*
* dsp.c
*/
// 5ms @ 48kHz
#define AUDIO_BUFFER_LEN 480
extern int16_t rx_buffer[AUDIO_BUFFER_LEN * 2];
extern int16_t tx_buffer[AUDIO_BUFFER_LEN * 2];
extern int16_t buffer[2][AUDIO_BUFFER_LEN];
extern int16_t buffer2[2][AUDIO_BUFFER_LEN];
typedef enum { B_CAPTURE, B_IF1, B_IF2, B_PLAYBACK, BUFFERS_MAX } buffer_t;
typedef struct {
enum { BT_C_INTERLEAVE, BT_IQ, BT_R_INTERLEAVE, BT_REAL } type;
int16_t length;
int16_t *buf0;
int16_t *buf1;
} buffer_ref_t;
extern const buffer_ref_t buffers_table[BUFFERS_MAX];
typedef void (*signal_process_func_t)(int16_t *src, int16_t *dst, size_t len);
extern signal_process_func_t signal_process;
void am_demod(int16_t *src, int16_t *dst, size_t len);
void cw_demod(int16_t *src, int16_t *dst, size_t len);
void lsb_demod(int16_t *src, int16_t *dst, size_t len);
void usb_demod(int16_t *src, int16_t *dst, size_t len);
void fm_demod(int16_t *src, int16_t *dst, size_t len);
void fm_demod_stereo(int16_t *src, int16_t *dst, size_t len);
void iq_demod(int16_t *src, int16_t *dst, size_t len);
void dsp_init(void);
#define FS 48000
#define AM_FREQ_OFFSET 10000
#define SSB_FREQ_OFFSET 1300
#define PHASESTEP(freq) (65536L * freq / FS)
extern int32_t center_frequency;
extern int16_t mode_freq_offset;
extern int16_t mode_freqoffset_phasestep;
extern int16_t cw_tone_phasestep;
typedef struct {
int16_t *buffer;
int16_t stride;
int16_t count;
int16_t coeff;
int32_t accumlate;
int16_t offset;
} dcrejection_t;
// state variables for stereo separation
typedef struct {
uint32_t phase_step_default;
uint32_t phase_step;
uint32_t phase_accum;
// average of correlation vector angle
int32_t sdi;
int32_t sdq;
int32_t corr;
int32_t corr_ave;
int32_t corr_std;
int16_t integrator;
} stereo_separate_state_t;
extern stereo_separate_state_t stereo_separate_state;
/*
* font: Font5x7.c numfont32x24.c numfont20x24.c icons.c
*/
extern const uint16_t x5x7_bits [];
extern const uint32_t numfont20x24[][24];
extern const uint32_t numfont32x24[][24];
extern const uint32_t icons48x20[][20*2];
#define S_PI "\034"
#define S_MICRO "\035"
#define S_OHM "\036"
#define S_DEGREE "\037"
#define S_RARROW "\033"
#define ICON_AGC_OFF 7
/*
* ili9341.c
*/
#define RGB565(b,g,r) ( (((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f) )
typedef struct {
uint16_t width;
uint16_t height;
uint16_t scaley;
uint16_t slide;
uint16_t stride;
const uint32_t *bitmap;
} font_t;
extern const font_t NF20x24;
extern const font_t NF32x24;
extern const font_t NF32x48;
extern const font_t ICON48x20;
extern uint16_t spi_buffer[];
void ili9341_init(void);
void ili9341_test(int mode);
void ili9341_bulk(int x, int y, int w, int h);
void ili9341_fill(int x, int y, int w, int h, int color);
void ili9341_draw_bitmap(int x, int y, int w, int h, uint16_t *bitmap);
void ili9341_drawchar_5x7(uint8_t ch, int x, int y, uint16_t fg, uint16_t bg);
void ili9341_drawstring_5x7(const char *str, int x, int y, uint16_t fg, uint16_t bg);
void ili9341_drawfont(uint8_t ch, const font_t *font, int x, int y, uint16_t fg, uint16_t bg);
void ili9341_drawfont_string(const char *str, const font_t *font, int x, int y, uint16_t fg, uint16_t bg);
void ili9341_set_direction(int rot180);
/*
* display.c
*/
void disp_init(void);
void disp_process(void);
void disp_fetch_samples(int bufid, int type, int16_t *buf0, int16_t *buf1, size_t len);
void disp_update(void);
void disp_update_power(void);
void disp_clear_aux(void);
void set_window_function(int wf_type);
/*
* ui.c
*/
extern void ui_init(void);
extern void ui_process(void);
typedef enum {
MOD_CW,
MOD_LSB,
MOD_USB,
MOD_AM,
MOD_FM,
MOD_FM_STEREO,
MOD_IQ,
MOD_MAX
} modulation_t;
extern void set_tune(int hz);
extern void set_modulation(modulation_t mod);
extern void recall_channel(unsigned int channel);
extern void set_fs(int fs);
typedef struct {
enum { CHANNEL, FREQ, VOLUME, MOD, AGC, RFGAIN, AGC_MAXGAIN, CWTONE, IQBAL,
SPDISP, WFDISP, MODE_MAX } mode;
int8_t volume;
uint8_t channel;
uint32_t freq;
modulation_t modulation;
int16_t rfgain;
uint8_t fs; /* 48, 96, 192 */
enum { AGC_MANUAL, AGC_SLOW, AGC_MID, AGC_FAST, AGC_MAX } agcmode;
int8_t digit; /* 0~5 */
int freq_offset;
enum { SPDISP_CAP, SPDISP_CAP2, SPDISP_IF, SPDISP_AUD, SPDISP_MODE_MAX } spdispmode;
enum { WATERFALL, WAVEFORM, WAVEFORM_MAG, WAVEFORM_MAG2, WFDISP_MODE_MAX } wfdispmode;
int16_t cw_tone_freq;
int16_t iqbal;
} uistat_t;
extern uistat_t uistat;
/*
* flash.c
*/
#define CHANNEL_MAX 100
typedef struct {
uint32_t freq;
modulation_t modulation;
} channel_t;
typedef struct {
int32_t magic;
uint16_t dac_value;
tlv320aic3204_agc_config_t agc;
channel_t channels[CHANNEL_MAX];
uistat_t uistat;
int8_t freq_inverse;
uint8_t button_polarity;
int8_t lcd_rotation;
int8_t rotary_encoder_direction;
int32_t checksum;
} config_t;
extern config_t config;
#define CONFIG_MAGIC 0x434f4e45 /* 'CONF' */
int config_save(void);
int config_recall(void);
void clear_all_config_prop_data(void);
#endif /* _NANOSDR_H_ */
/*EOF*/