kopia lustrzana https://github.com/kamocat/uSDX
Minimized code in main ino
rodzic
0f42a423b2
commit
d007e5c1e7
168
code/code.ino
168
code/code.ino
|
@ -54,6 +54,10 @@
|
|||
#include "radio/fm.h"
|
||||
#include "radio/cat.h"
|
||||
#include "radio/rx.h"
|
||||
#include "radio/common2.h"
|
||||
#include "radio/calibration.h"
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
//FUSES = { .low = 0xFF, .high = 0xD6, .extended = 0xFD }; // Fuse settings should be these at programming.
|
||||
|
||||
|
@ -65,170 +69,6 @@ ISR(TIMER2_COMPA_vect) // Timer2 COMPA interrupt
|
|||
#endif
|
||||
}
|
||||
|
||||
void dummy()
|
||||
{
|
||||
}
|
||||
|
||||
enum dsp_cap_t { ANALOG, DSP, SDR };
|
||||
uint8_t dsp_cap = 0;
|
||||
uint8_t ssb_cap = 0;
|
||||
|
||||
uint16_t analogSampleMic()
|
||||
{
|
||||
uint16_t adc;
|
||||
noInterrupts();
|
||||
if(dsp_cap == SDR) digitalWrite(RX, LOW); // disable RF input, only for SDR mod
|
||||
//si5351.SendRegister(SI_CLK_OE, 0b11111111); // CLK2_EN=0, CLK1_EN,CLK0_EN=0
|
||||
ADMUX = admux[2]; // set MUX for next conversion
|
||||
ADCSRA |= (1 << ADSC); // start next ADC conversion
|
||||
for(;!(ADCSRA & (1 << ADIF));); // wait until ADC conversion is completed
|
||||
if(dsp_cap == SDR) digitalWrite(RX, HIGH); // enable RF input, only for SDR mod
|
||||
//si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
adc = ADC;
|
||||
interrupts();
|
||||
return adc;
|
||||
}
|
||||
|
||||
volatile bool change = true;
|
||||
volatile int32_t freq = 7074000;
|
||||
|
||||
int8_t smode = 1;
|
||||
|
||||
float dbm_max;
|
||||
float smeter(float ref = 5) //= 10*log(8000/2400)=5 ref to 2.4kHz BW. plus some other calibration factor
|
||||
{
|
||||
if(smode == 0){ // none, no s-meter
|
||||
return 0;
|
||||
}
|
||||
float rms = _absavg256 / 256.0; //sqrt(256.0);
|
||||
//if(dsp_cap == SDR) rms = (float)rms * 1.1 * (float)(1 << att2) / (1024.0 * (float)R * 4.0 * 100.0 * 40.0); // 2 rx gain stages: rmsV = ADC value * AREF / [ADC DR * processing gain * receiver gain * audio gain]
|
||||
if(dsp_cap == SDR) rms = (float)rms * 1.1 * (float)(1 << att2) / (1024.0 * (float)R * 4.0 * 820.0 * 3.0/*??*/); // 1 rx gain stage: rmsV = ADC value * AREF / [ADC DR * processing gain * receiver gain * audio gain]
|
||||
else rms = (float)rms * 5.0 * (float)(1 << att2) / (1024.0 * (float)R * 2.0 * 100.0 * 120.0 / 1.750);
|
||||
float dbm = (10.0 * log10((rms * rms) / 50.0) + 30.0) - ref; //from rmsV to dBm at 50R
|
||||
dbm_max = max(dbm_max, dbm);
|
||||
static uint8_t cnt;
|
||||
cnt++;
|
||||
if((cnt % 8) == 0){
|
||||
if(smode == 1){ // dBm meter
|
||||
lcd.noCursor(); lcd.setCursor(9, 0); lcd.print((int16_t)dbm_max); lcd.print(F("dBm "));
|
||||
}
|
||||
if(smode == 2){ // S-meter
|
||||
uint8_t s = (dbm_max < -63) ? ((dbm_max - -127) / 6) : (uint8_t)(dbm_max - -63 + 10) % 10; // dBm to S
|
||||
lcd.noCursor(); lcd.setCursor(14, 0); if(s < 10){ lcd.print('S'); } lcd.print(s);
|
||||
}
|
||||
dbm_max = -174.0 + 34.0;
|
||||
}
|
||||
if(smode == 3){ // S-bar
|
||||
int8_t s = (dbm < -63) ? ((dbm - -127) / 6) : (uint8_t)(dbm - -63 + 10) % 10; // dBm to S
|
||||
lcd.noCursor(); lcd.setCursor(12, 0);
|
||||
char tmp[5];
|
||||
for(uint8_t i = 0; i != 4; i++){ tmp[i] = max(2, min(5, s + 1)); s = s - 3; } tmp[4] = 0;
|
||||
lcd.print(tmp);
|
||||
}
|
||||
return dbm;
|
||||
}
|
||||
|
||||
void start_rx()
|
||||
{
|
||||
_init = 1;
|
||||
rx_state = 0;
|
||||
func_ptr = sdr_rx; //enable RX DSP/SDR
|
||||
adc_start(2, true, F_ADC_CONV); admux[2] = ADMUX;
|
||||
if(dsp_cap == SDR){
|
||||
adc_start(0, !(att == 1)/*true*/, F_ADC_CONV); admux[0] = ADMUX;
|
||||
adc_start(1, !(att == 1)/*true*/, F_ADC_CONV); admux[1] = ADMUX;
|
||||
} else { // ANALOG, DSP
|
||||
adc_start(0, false, F_ADC_CONV); admux[0] = ADMUX; admux[1] = ADMUX;
|
||||
}
|
||||
timer1_start(F_SAMP_PWM);
|
||||
timer2_start(F_SAMP_RX);
|
||||
TCCR1A &= ~(1 << COM1B1); digitalWrite(KEY_OUT, LOW); // disable KEY_OUT PWM
|
||||
}
|
||||
|
||||
void switch_rxtx(uint8_t tx_enable){
|
||||
tx = tx_enable;
|
||||
TIMSK2 &= ~(1 << OCIE2A); // disable timer compare interrupt
|
||||
//delay(1);
|
||||
noInterrupts();
|
||||
if(tx_enable){
|
||||
switch(mode){
|
||||
case USB:
|
||||
case LSB: func_ptr = dsp_tx; break;
|
||||
case CW: func_ptr = dsp_tx_cw; break;
|
||||
case AM: func_ptr = dsp_tx_am; break;
|
||||
case FM: func_ptr = dsp_tx_fm; break;
|
||||
}
|
||||
} else func_ptr = sdr_rx;
|
||||
if((!dsp_cap) && (!tx_enable) && vox) func_ptr = dummy; //hack: for SSB mode, disable dsp_rx during vox mode enabled as it slows down the vox loop too much!
|
||||
interrupts();
|
||||
if(tx_enable) ADMUX = admux[2];
|
||||
else _init = 1;
|
||||
rx_state = 0;
|
||||
if(tx_enable){
|
||||
digitalWrite(RX, LOW); // TX (disable RX)
|
||||
#ifdef NTX
|
||||
digitalWrite(NTX, LOW); // TX (enable TX)
|
||||
#endif
|
||||
lcd.setCursor(15, 1); lcd.print("T");
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111011); // CLK2_EN=1, CLK1_EN,CLK0_EN=0
|
||||
//if(!mox) TCCR1A &= ~(1 << COM1A1); // disable SIDETONE, prevent interference during TX
|
||||
OCR1AL = 0; // make sure SIDETONE is set to 0%
|
||||
TCCR1A |= (1 << COM1B1); // enable KEY_OUT PWM
|
||||
} else {
|
||||
//TCCR1A |= (1 << COM1A1); // enable SIDETONE
|
||||
TCCR1A &= ~(1 << COM1B1); digitalWrite(KEY_OUT, LOW); // disable KEY_OUT PWM, prevents interference during RX
|
||||
OCR1BL = 0; // make sure PWM (KEY_OUT) is set to 0%
|
||||
digitalWrite(RX, !(att == 2)); // RX (enable RX when attenuator not on)
|
||||
#ifdef NTX
|
||||
digitalWrite(NTX, HIGH); // RX (disable TX)
|
||||
#endif
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
lcd.setCursor(15, 1); lcd.print((vox) ? "V" : "R");
|
||||
}
|
||||
OCR2A = (((float)F_CPU / (float)64) / (float)((tx_enable) ? F_SAMP_TX : F_SAMP_RX) + 0.5) - 1;
|
||||
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt TIMER2_COMPA_vect
|
||||
}
|
||||
|
||||
#ifdef QCX
|
||||
#define CAL_IQ 1
|
||||
#ifdef CAL_IQ
|
||||
int16_t cal_iq_dummy = 0;
|
||||
// RX I/Q calibration procedure: terminate with 50 ohm, enable CW filter, adjust R27, R24, R17 subsequently to its minimum side-band rejection value in dB
|
||||
void calibrate_iq()
|
||||
{
|
||||
smode = 1;
|
||||
lcd.setCursor(0, 0); lcd.print(blanks); lcd.print(blanks);
|
||||
digitalWrite(SIG_OUT, true); // loopback on
|
||||
si5351.freq(freq, 0, 90); // RX in USB
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111000); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
float dbc;
|
||||
si5351.freq_calc_fast(+700); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-700); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("I-Q bal. 700Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
si5351.freq_calc_fast(+600); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-600); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("Phase Lo 600Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
si5351.freq_calc_fast(+800); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-800); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("Phase Hi 800Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
|
||||
lcd.setCursor(9, 0); lcd.print(blanks); // cleanup dbmeter
|
||||
digitalWrite(SIG_OUT, false); // loopback off
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
change = true; //restore original frequency setting
|
||||
}
|
||||
#endif
|
||||
#endif //QCX
|
||||
|
||||
|
||||
#include "ui.h" // Need to seperate this out
|
||||
|
||||
void setup()
|
||||
{
|
||||
digitalWrite(KEY_OUT, LOW); // for safety: to prevent exploding PA MOSFETs, in case there was something still biasing them.
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#ifdef QCX
|
||||
#define CAL_IQ 1
|
||||
#ifdef CAL_IQ
|
||||
int16_t cal_iq_dummy = 0;
|
||||
// RX I/Q calibration procedure: terminate with 50 ohm, enable CW filter, adjust R27, R24, R17 subsequently to its minimum side-band rejection value in dB
|
||||
void calibrate_iq()
|
||||
{
|
||||
smode = 1;
|
||||
lcd.setCursor(0, 0); lcd.print(blanks); lcd.print(blanks);
|
||||
digitalWrite(SIG_OUT, true); // loopback on
|
||||
si5351.freq(freq, 0, 90); // RX in USB
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111000); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
float dbc;
|
||||
si5351.freq_calc_fast(+700); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-700); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("I-Q bal. 700Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
si5351.freq_calc_fast(+600); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-600); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("Phase Lo 600Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
si5351.freq_calc_fast(+800); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
dbc = smeter();
|
||||
si5351.freq_calc_fast(-800); si5351.SendPLLBRegisterBulk(); delay(100);
|
||||
lcd.setCursor(0, 1); lcd.print("Phase Hi 800Hz"); lcd.print(blanks);
|
||||
for(; !digitalRead(BUTTONS);){ wdt_reset(); smeter(dbc); } for(; digitalRead(BUTTONS);) wdt_reset();
|
||||
|
||||
lcd.setCursor(9, 0); lcd.print(blanks); // cleanup dbmeter
|
||||
digitalWrite(SIG_OUT, false); // loopback off
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
change = true; //restore original frequency setting
|
||||
}
|
||||
#endif
|
||||
#endif //QCX
|
|
@ -0,0 +1,124 @@
|
|||
enum dsp_cap_t { ANALOG, DSP, SDR };
|
||||
uint8_t dsp_cap = 0;
|
||||
uint8_t ssb_cap = 0;
|
||||
|
||||
void dummy()
|
||||
{
|
||||
}
|
||||
|
||||
void start_rx()
|
||||
{
|
||||
_init = 1;
|
||||
rx_state = 0;
|
||||
func_ptr = sdr_rx; //enable RX DSP/SDR
|
||||
adc_start(2, true, F_ADC_CONV); admux[2] = ADMUX;
|
||||
if(dsp_cap == SDR){
|
||||
adc_start(0, !(att == 1)/*true*/, F_ADC_CONV); admux[0] = ADMUX;
|
||||
adc_start(1, !(att == 1)/*true*/, F_ADC_CONV); admux[1] = ADMUX;
|
||||
} else { // ANALOG, DSP
|
||||
adc_start(0, false, F_ADC_CONV); admux[0] = ADMUX; admux[1] = ADMUX;
|
||||
}
|
||||
timer1_start(F_SAMP_PWM);
|
||||
timer2_start(F_SAMP_RX);
|
||||
TCCR1A &= ~(1 << COM1B1); digitalWrite(KEY_OUT, LOW); // disable KEY_OUT PWM
|
||||
}
|
||||
|
||||
uint16_t analogSampleMic()
|
||||
{
|
||||
uint16_t adc;
|
||||
noInterrupts();
|
||||
if(dsp_cap == SDR) digitalWrite(RX, LOW); // disable RF input, only for SDR mod
|
||||
//si5351.SendRegister(SI_CLK_OE, 0b11111111); // CLK2_EN=0, CLK1_EN,CLK0_EN=0
|
||||
ADMUX = admux[2]; // set MUX for next conversion
|
||||
ADCSRA |= (1 << ADSC); // start next ADC conversion
|
||||
for(;!(ADCSRA & (1 << ADIF));); // wait until ADC conversion is completed
|
||||
if(dsp_cap == SDR) digitalWrite(RX, HIGH); // enable RF input, only for SDR mod
|
||||
//si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
adc = ADC;
|
||||
interrupts();
|
||||
return adc;
|
||||
}
|
||||
|
||||
|
||||
void switch_rxtx(uint8_t tx_enable){
|
||||
tx = tx_enable;
|
||||
TIMSK2 &= ~(1 << OCIE2A); // disable timer compare interrupt
|
||||
//delay(1);
|
||||
noInterrupts();
|
||||
if(tx_enable){
|
||||
switch(mode){
|
||||
case USB:
|
||||
case LSB: func_ptr = dsp_tx; break;
|
||||
case CW: func_ptr = dsp_tx_cw; break;
|
||||
case AM: func_ptr = dsp_tx_am; break;
|
||||
case FM: func_ptr = dsp_tx_fm; break;
|
||||
}
|
||||
} else func_ptr = sdr_rx;
|
||||
if((!dsp_cap) && (!tx_enable) && vox) func_ptr = dummy; //hack: for SSB mode, disable dsp_rx during vox mode enabled as it slows down the vox loop too much!
|
||||
interrupts();
|
||||
if(tx_enable) ADMUX = admux[2];
|
||||
else _init = 1;
|
||||
rx_state = 0;
|
||||
if(tx_enable){
|
||||
digitalWrite(RX, LOW); // TX (disable RX)
|
||||
#ifdef NTX
|
||||
digitalWrite(NTX, LOW); // TX (enable TX)
|
||||
#endif
|
||||
lcd.setCursor(15, 1); lcd.print("T");
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111011); // CLK2_EN=1, CLK1_EN,CLK0_EN=0
|
||||
//if(!mox) TCCR1A &= ~(1 << COM1A1); // disable SIDETONE, prevent interference during TX
|
||||
OCR1AL = 0; // make sure SIDETONE is set to 0%
|
||||
TCCR1A |= (1 << COM1B1); // enable KEY_OUT PWM
|
||||
} else {
|
||||
//TCCR1A |= (1 << COM1A1); // enable SIDETONE
|
||||
TCCR1A &= ~(1 << COM1B1); digitalWrite(KEY_OUT, LOW); // disable KEY_OUT PWM, prevents interference during RX
|
||||
OCR1BL = 0; // make sure PWM (KEY_OUT) is set to 0%
|
||||
digitalWrite(RX, !(att == 2)); // RX (enable RX when attenuator not on)
|
||||
#ifdef NTX
|
||||
digitalWrite(NTX, HIGH); // RX (disable TX)
|
||||
#endif
|
||||
si5351.SendRegister(SI_CLK_OE, 0b11111100); // CLK2_EN=0, CLK1_EN,CLK0_EN=1
|
||||
lcd.setCursor(15, 1); lcd.print((vox) ? "V" : "R");
|
||||
}
|
||||
OCR2A = (((float)F_CPU / (float)64) / (float)((tx_enable) ? F_SAMP_TX : F_SAMP_RX) + 0.5) - 1;
|
||||
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt TIMER2_COMPA_vect
|
||||
}
|
||||
|
||||
volatile bool change = true;
|
||||
volatile int32_t freq = 7074000;
|
||||
|
||||
int8_t smode = 1;
|
||||
|
||||
float dbm_max;
|
||||
float smeter(float ref = 5) //= 10*log(8000/2400)=5 ref to 2.4kHz BW. plus some other calibration factor
|
||||
{
|
||||
if(smode == 0){ // none, no s-meter
|
||||
return 0;
|
||||
}
|
||||
float rms = _absavg256 / 256.0; //sqrt(256.0);
|
||||
//if(dsp_cap == SDR) rms = (float)rms * 1.1 * (float)(1 << att2) / (1024.0 * (float)R * 4.0 * 100.0 * 40.0); // 2 rx gain stages: rmsV = ADC value * AREF / [ADC DR * processing gain * receiver gain * audio gain]
|
||||
if(dsp_cap == SDR) rms = (float)rms * 1.1 * (float)(1 << att2) / (1024.0 * (float)R * 4.0 * 820.0 * 3.0/*??*/); // 1 rx gain stage: rmsV = ADC value * AREF / [ADC DR * processing gain * receiver gain * audio gain]
|
||||
else rms = (float)rms * 5.0 * (float)(1 << att2) / (1024.0 * (float)R * 2.0 * 100.0 * 120.0 / 1.750);
|
||||
float dbm = (10.0 * log10((rms * rms) / 50.0) + 30.0) - ref; //from rmsV to dBm at 50R
|
||||
dbm_max = max(dbm_max, dbm);
|
||||
static uint8_t cnt;
|
||||
cnt++;
|
||||
if((cnt % 8) == 0){
|
||||
if(smode == 1){ // dBm meter
|
||||
lcd.noCursor(); lcd.setCursor(9, 0); lcd.print((int16_t)dbm_max); lcd.print(F("dBm "));
|
||||
}
|
||||
if(smode == 2){ // S-meter
|
||||
uint8_t s = (dbm_max < -63) ? ((dbm_max - -127) / 6) : (uint8_t)(dbm_max - -63 + 10) % 10; // dBm to S
|
||||
lcd.noCursor(); lcd.setCursor(14, 0); if(s < 10){ lcd.print('S'); } lcd.print(s);
|
||||
}
|
||||
dbm_max = -174.0 + 34.0;
|
||||
}
|
||||
if(smode == 3){ // S-bar
|
||||
int8_t s = (dbm < -63) ? ((dbm - -127) / 6) : (uint8_t)(dbm - -63 + 10) % 10; // dBm to S
|
||||
lcd.noCursor(); lcd.setCursor(12, 0);
|
||||
char tmp[5];
|
||||
for(uint8_t i = 0; i != 4; i++){ tmp[i] = max(2, min(5, s + 1)); s = s - 3; } tmp[4] = 0;
|
||||
lcd.print(tmp);
|
||||
}
|
||||
return dbm;
|
||||
}
|
Ładowanie…
Reference in New Issue