mirror of
https://github.com/greatscottgadgets/hackrf.git
synced 2026-03-13 10:49:35 +01:00
Merge pull request #1688 from greatscottgadgets/radio-config-rate
This commit is contained in:
34
firmware/common/fixed_point.h
Normal file
34
firmware/common/fixed_point.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2026 Great Scott Gadgets <info@greatscottgadgets.com>
|
||||
*
|
||||
* This file is part of HackRF.
|
||||
*
|
||||
* This program 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 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __FIXED_POINT_H__
|
||||
#define __FIXED_POINT_H__
|
||||
|
||||
/* 40.24 fixed-point */
|
||||
typedef uint64_t fp_40_24_t;
|
||||
|
||||
/* one million in 40.24 fixed-point */
|
||||
#define FP_ONE_MHZ ((1000ULL * 1000ULL) << 24)
|
||||
|
||||
/* one in 40.24 fixed-point */
|
||||
#define FP_ONE_HZ (1 << 24)
|
||||
|
||||
#endif /*__FIXED_POINT_H__*/
|
||||
@@ -190,7 +190,7 @@ bool fpga_if_xcvr_selftest(void)
|
||||
max2831_set_frequency(&max283x, 2500000000);
|
||||
|
||||
// Capture 1: 4 Msps, tone at 0.5 MHz, narrowband filter OFF
|
||||
sample_rate_frac_set(4000000, 1);
|
||||
sample_rate_set(4ULL * FP_ONE_MHZ, true);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
timeout = true;
|
||||
@@ -213,7 +213,7 @@ bool fpga_if_xcvr_selftest(void)
|
||||
|
||||
// Capture 3: 20 Msps, tone at 5 MHz, narrowband filter OFF
|
||||
fpga_set_tx_nco_pstep(&fpga, 255);
|
||||
sample_rate_frac_set(20000000, 1);
|
||||
sample_rate_set(20ULL * FP_ONE_MHZ, true);
|
||||
narrowband_filter_set(0);
|
||||
delay_us_at_mhz(1000, 204);
|
||||
if (rx_samples(num_samples, 2000000) == -1) {
|
||||
@@ -236,7 +236,7 @@ bool fpga_if_xcvr_selftest(void)
|
||||
&selftest.xcvr_measurements[3]);
|
||||
|
||||
// Restore default settings.
|
||||
sample_rate_set(10000000);
|
||||
sample_rate_set(10ULL * FP_ONE_MHZ, true);
|
||||
rf_path_set_direction(&rf_path, RF_PATH_DIRECTION_OFF);
|
||||
narrowband_filter_set(0);
|
||||
fpga_init(&fpga);
|
||||
|
||||
@@ -351,7 +351,9 @@ fpga_driver_t fpga = {
|
||||
};
|
||||
#endif
|
||||
|
||||
radio_t radio;
|
||||
radio_t radio = {
|
||||
.sample_rate_cb = sample_rate_set,
|
||||
};
|
||||
|
||||
rf_path_t rf_path = {
|
||||
.switchctrl = 0,
|
||||
@@ -409,53 +411,26 @@ jtag_t jtag_cpld = {
|
||||
.gpio = &jtag_gpio_cpld,
|
||||
};
|
||||
|
||||
/* GCD algo from wikipedia */
|
||||
/* http://en.wikipedia.org/wiki/Greatest_common_divisor */
|
||||
static uint32_t gcd(uint32_t u, uint32_t v)
|
||||
/*
|
||||
* Configure clock generator to produce sample clock in units of 1/(2**24) Hz.
|
||||
* Can be called with program=false for a dry run that returns the resultant
|
||||
* frequency without actually configuring the clock generator.
|
||||
*
|
||||
* The clock generator output frequency is:
|
||||
*
|
||||
* fs = 128 * vco / (512 + p1 + p2/p3))
|
||||
*
|
||||
* where p1, p2, and p3 are register values.
|
||||
*
|
||||
* For more information see:
|
||||
* https://www.pa3fwm.nl/technotes/tn42a-si5351-programming.html
|
||||
*/
|
||||
fp_40_24_t sample_rate_set(const fp_40_24_t sample_rate, const bool program)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (!u || !v) {
|
||||
return u | v;
|
||||
}
|
||||
|
||||
for (s = 0; !((u | v) & 1); s++) {
|
||||
u >>= 1;
|
||||
v >>= 1;
|
||||
}
|
||||
|
||||
while (!(u & 1)) {
|
||||
u >>= 1;
|
||||
}
|
||||
|
||||
do {
|
||||
while (!(v & 1)) {
|
||||
v >>= 1;
|
||||
}
|
||||
|
||||
if (u > v) {
|
||||
uint32_t t;
|
||||
t = v;
|
||||
v = u;
|
||||
u = t;
|
||||
}
|
||||
|
||||
v = v - u;
|
||||
} while (v);
|
||||
|
||||
return u << s;
|
||||
}
|
||||
|
||||
bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
|
||||
{
|
||||
const uint64_t VCO_FREQ = 800 * 1000 * 1000; /* 800 MHz */
|
||||
uint32_t MSx_P1, MSx_P2, MSx_P3;
|
||||
uint32_t a, b, c;
|
||||
uint32_t rem;
|
||||
|
||||
/* Round to the nearest Hz for display. */
|
||||
uint32_t rate_hz = (rate_num + (rate_denom >> 1)) / rate_denom;
|
||||
hackrf_ui()->set_sample_rate(rate_hz);
|
||||
const fp_40_24_t vco = 800 * FP_ONE_MHZ;
|
||||
uint64_t p1, p2, p3;
|
||||
uint64_t n, d, q;
|
||||
fp_40_24_t remainder, resultant_rate;
|
||||
|
||||
/*
|
||||
* First double the sample rate so that we can produce a clock at twice
|
||||
@@ -463,36 +438,72 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
|
||||
* and it is divided by two in an output divider to produce the actual
|
||||
* AFE clock.
|
||||
*/
|
||||
rate_num *= 2;
|
||||
fp_40_24_t rate = sample_rate * 2;
|
||||
|
||||
/* Find best config */
|
||||
a = (VCO_FREQ * rate_denom) / rate_num;
|
||||
p1 = ((128 * vco) / rate) - 512;
|
||||
if (vco % rate) {
|
||||
/*
|
||||
* Compute numerator (p2) for denominator (p3) matching
|
||||
* fixed-point type.
|
||||
*/
|
||||
n = (128 * vco) - (rate * (p1 + 512));
|
||||
d = rate / FP_ONE_HZ;
|
||||
n += (d / 2);
|
||||
p2 = n / d;
|
||||
p3 = 1 << 24;
|
||||
|
||||
rem = (VCO_FREQ * rate_denom) - (a * rate_num);
|
||||
/* Reduce fraction. p3 is 1<<24, so gcd(p2, p3) is a power of 2 */
|
||||
unsigned int shift = p2 ? __builtin_ctz(p2) : 24;
|
||||
p2 >>= shift;
|
||||
p3 >>= shift;
|
||||
|
||||
if (!rem) {
|
||||
/* Integer mode */
|
||||
b = 0;
|
||||
c = 1;
|
||||
} else {
|
||||
/* Fractional */
|
||||
uint32_t g = gcd(rem, rate_num);
|
||||
rem /= g;
|
||||
rate_num /= g;
|
||||
|
||||
if (rate_num < (1 << 20)) {
|
||||
/* Perfect match */
|
||||
b = rem;
|
||||
c = rate_num;
|
||||
} else {
|
||||
/* Approximate */
|
||||
c = (1 << 20) - 1;
|
||||
b = ((uint64_t) c * (uint64_t) rem) / rate_num;
|
||||
|
||||
g = gcd(b, c);
|
||||
b /= g;
|
||||
c /= g;
|
||||
/* Convert fraction to valid denominator. */
|
||||
const uint64_t p3_max = 0xfffff;
|
||||
if (p3 > p3_max) {
|
||||
p2 *= p3_max;
|
||||
p2 += (p3 / 2);
|
||||
p2 /= p3;
|
||||
p3 = p3_max;
|
||||
}
|
||||
|
||||
/* Roll over to next p1 to enable integer mode. */
|
||||
if (p2 >= p3) {
|
||||
p1++;
|
||||
p2 = 0;
|
||||
}
|
||||
} else {
|
||||
p2 = 0;
|
||||
}
|
||||
|
||||
/* Maximum: (128 * 2048) - 512 */
|
||||
if (p1 > 0x3fe00) {
|
||||
p1 = 0x3fe00;
|
||||
p2 = 0;
|
||||
}
|
||||
|
||||
if (p2 == 0) {
|
||||
/* Use unity denominator for integer mode. */
|
||||
p3 = 1;
|
||||
n = (vco * 128);
|
||||
d = (p1 + 512);
|
||||
n += (d / 2);
|
||||
resultant_rate = n / d;
|
||||
} else {
|
||||
const uint64_t vco_hz = vco / FP_ONE_HZ;
|
||||
n = p3 * vco_hz * 128;
|
||||
d = p3 * (p1 + 512) + p2;
|
||||
const uint64_t rate_hz = n / d;
|
||||
remainder = (n - (d * rate_hz)) * FP_ONE_HZ;
|
||||
remainder += (d / 2);
|
||||
q = remainder / d;
|
||||
resultant_rate = (rate_hz * FP_ONE_HZ) + q;
|
||||
}
|
||||
|
||||
/* Return MCU sample rate, not AFE clock rate. */
|
||||
resultant_rate = (resultant_rate + 1) / 2;
|
||||
|
||||
if (!program) {
|
||||
return resultant_rate;
|
||||
}
|
||||
|
||||
bool streaming = sgpio_cpld_stream_is_enabled(&sgpio_config);
|
||||
@@ -501,103 +512,13 @@ bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom)
|
||||
sgpio_cpld_stream_disable(&sgpio_config);
|
||||
}
|
||||
|
||||
/* Can we enable integer mode ? */
|
||||
if (a & 0x1 || b) {
|
||||
/* Integer mode can be enabled if p1 is even and p2 is zero. */
|
||||
if (p1 & 0x1 || p2) {
|
||||
si5351c_set_int_mode(&clock_gen, 0, 0);
|
||||
} else {
|
||||
si5351c_set_int_mode(&clock_gen, 0, 1);
|
||||
}
|
||||
|
||||
/* Final MS values */
|
||||
MSx_P1 = 128 * a + (128 * b / c) - 512;
|
||||
MSx_P2 = (128 * b) % c;
|
||||
MSx_P3 = c;
|
||||
|
||||
#ifndef PRALINE
|
||||
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
|
||||
/*
|
||||
* On HackRF One r9 all sample clocks are externally derived
|
||||
* from MS1/CLK1 operating at twice the sample rate.
|
||||
*/
|
||||
si5351c_configure_multisynth(&clock_gen, 1, MSx_P1, MSx_P2, MSx_P3, 0);
|
||||
} else {
|
||||
/*
|
||||
* On other platforms the clock generator produces three
|
||||
* different sample clocks, all derived from multisynth 0.
|
||||
*/
|
||||
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
|
||||
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
|
||||
|
||||
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
|
||||
si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter
|
||||
|
||||
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
|
||||
si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter
|
||||
}
|
||||
#else
|
||||
/* MS0/CLK0 is the source for the MAX5864/FPGA (AFE_CLK). */
|
||||
si5351c_configure_multisynth(&clock_gen, 0, MSx_P1, MSx_P2, MSx_P3, 1);
|
||||
#endif
|
||||
|
||||
if (streaming) {
|
||||
sgpio_cpld_stream_enable(&sgpio_config);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sample_rate_set(const uint32_t sample_rate_hz)
|
||||
{
|
||||
uint32_t p1 = 4608;
|
||||
uint32_t p2 = 0;
|
||||
uint32_t p3 = 0;
|
||||
|
||||
switch (sample_rate_hz) {
|
||||
case 8000000:
|
||||
p1 = SI_INTDIV(50); // 800MHz / 50 = 16 MHz (SGPIO), 8 MHz (codec)
|
||||
break;
|
||||
|
||||
case 9216000:
|
||||
// 43.40277777777778: a = 43; b = 29; c = 72
|
||||
p1 = 5043;
|
||||
p2 = 40;
|
||||
p3 = 72;
|
||||
break;
|
||||
|
||||
case 10000000:
|
||||
p1 = SI_INTDIV(40); // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec)
|
||||
break;
|
||||
|
||||
case 12288000:
|
||||
// 32.552083333333336: a = 32; b = 159; c = 288
|
||||
p1 = 3654;
|
||||
p2 = 192;
|
||||
p3 = 288;
|
||||
break;
|
||||
|
||||
case 12500000:
|
||||
p1 = SI_INTDIV(32); // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec)
|
||||
break;
|
||||
|
||||
case 16000000:
|
||||
p1 = SI_INTDIV(25); // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec)
|
||||
break;
|
||||
|
||||
case 18432000:
|
||||
// 21.70138888889: a = 21; b = 101; c = 144
|
||||
p1 = 2265;
|
||||
p2 = 112;
|
||||
p3 = 144;
|
||||
break;
|
||||
|
||||
case 20000000:
|
||||
p1 = SI_INTDIV(20); // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec)
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PRALINE
|
||||
if (detected_platform() == BOARD_ID_HACKRF1_R9) {
|
||||
/*
|
||||
@@ -614,32 +535,21 @@ bool sample_rate_set(const uint32_t sample_rate_hz)
|
||||
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
|
||||
|
||||
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
|
||||
si5351c_configure_multisynth(
|
||||
&clock_gen,
|
||||
1,
|
||||
p1,
|
||||
0,
|
||||
1,
|
||||
0); //p1 doesn't matter
|
||||
si5351c_configure_multisynth(&clock_gen, 1, 0, 0, 0, 0); //p1 doesn't matter
|
||||
|
||||
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
|
||||
si5351c_configure_multisynth(
|
||||
&clock_gen,
|
||||
2,
|
||||
p1,
|
||||
0,
|
||||
1,
|
||||
0); //p1 doesn't matter
|
||||
si5351c_configure_multisynth(&clock_gen, 2, 0, 0, 0, 0); //p1 doesn't matter
|
||||
}
|
||||
#else
|
||||
/* MS0/CLK0 is the source for the MAX5864/FPGA (AFE_CLK). */
|
||||
si5351c_configure_multisynth(&clock_gen, 0, p1, p2, p3, 1);
|
||||
|
||||
/* MS0/CLK1 is the source for SCT_CLK (CODEC_X2_CLK). */
|
||||
si5351c_configure_multisynth(&clock_gen, 1, p1, p2, p3, 0);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
if (streaming) {
|
||||
sgpio_cpld_stream_enable(&sgpio_config);
|
||||
}
|
||||
|
||||
return resultant_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -926,7 +836,7 @@ void clock_gen_init(void)
|
||||
/* MS7/CLK7 is unused. */
|
||||
|
||||
/* Set to 10 MHz, the common rate between Jawbreaker and HackRF One. */
|
||||
sample_rate_set(10000000);
|
||||
sample_rate_set(10ULL * FP_ONE_MHZ, true);
|
||||
|
||||
si5351c_set_clock_source(&clock_gen, PLL_SOURCE_XTAL);
|
||||
// soft reset
|
||||
|
||||
@@ -45,6 +45,7 @@ extern "C" {
|
||||
#include "cpld_jtag.h"
|
||||
#include "ice40_spi.h"
|
||||
#include "fpga.h"
|
||||
#include "fixed_point.h"
|
||||
|
||||
/*
|
||||
* SCU PinMux
|
||||
@@ -435,8 +436,7 @@ void enable_1v8_power(void);
|
||||
void disable_1v8_power(void);
|
||||
#endif
|
||||
|
||||
bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom);
|
||||
bool sample_rate_set(const uint32_t sampling_rate_hz);
|
||||
fp_40_24_t sample_rate_set(const fp_40_24_t sample_rate, const bool program);
|
||||
|
||||
clock_source_t activate_best_clock_source(void);
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ void max2831_set_mode(max2831_driver_t* const drv, const max2831_mode_t new_mode
|
||||
}
|
||||
|
||||
drv->set_mode(drv, new_mode);
|
||||
max2831_set_lpf_bandwidth(drv, drv->desired_lpf_bw);
|
||||
max2831_set_lpf_bandwidth(drv, new_mode, drv->desired_lpf_bw);
|
||||
}
|
||||
|
||||
max2831_mode_t max2831_mode(max2831_driver_t* const drv)
|
||||
@@ -304,13 +304,13 @@ static const max2831_ft_fine_t max2831_tx_ft_fine[] = {
|
||||
//clang-format on
|
||||
|
||||
|
||||
uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const uint32_t bandwidth_hz) {
|
||||
uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const max2831_mode_t mode, const uint32_t bandwidth_hz) {
|
||||
const max2831_ft_t* coarse;
|
||||
const max2831_ft_fine_t* fine;
|
||||
|
||||
drv->desired_lpf_bw = bandwidth_hz;
|
||||
|
||||
if (drv->mode == MAX2831_MODE_RX) {
|
||||
if (mode == MAX2831_MODE_RX) {
|
||||
coarse = max2831_rx_ft;
|
||||
fine = max2831_rx_ft_fine;
|
||||
} else {
|
||||
@@ -343,7 +343,7 @@ uint32_t max2831_set_lpf_bandwidth(max2831_driver_t* const drv, const uint32_t b
|
||||
|
||||
/* Program found settings. */
|
||||
set_MAX2831_LPF_COARSE(drv, coarse->ft);
|
||||
if (drv->mode == MAX2831_MODE_RX) {
|
||||
if (mode == MAX2831_MODE_RX) {
|
||||
set_MAX2831_RX_LPF_FINE_ADJ(drv, f->ft_fine);
|
||||
} else {
|
||||
set_MAX2831_TX_LPF_FINE_ADJ(drv, f->ft_fine);
|
||||
|
||||
@@ -93,6 +93,7 @@ extern void max2831_stop(max2831_driver_t* const drv);
|
||||
extern void max2831_set_frequency(max2831_driver_t* const drv, uint32_t freq);
|
||||
uint32_t max2831_set_lpf_bandwidth(
|
||||
max2831_driver_t* const drv,
|
||||
const max2831_mode_t mode,
|
||||
const uint32_t bandwidth_hz);
|
||||
bool max2831_set_lna_gain(max2831_driver_t* const drv, const uint32_t gain_db);
|
||||
bool max2831_set_vga_gain(max2831_driver_t* const drv, const uint32_t gain_db);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "fpga.h"
|
||||
#include "platform_detect.h"
|
||||
#include "radio.h"
|
||||
#include "fixed_point.h"
|
||||
#include "hackrf_ui.h"
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
@@ -118,46 +120,6 @@ static bool radio_update_direction(radio_t* const radio, uint64_t* bank)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert sample rate in units of 1/(2**24) Hz to fraction.
|
||||
*/
|
||||
static inline uint64_t frac_sample_rate(const uint64_t rate)
|
||||
{
|
||||
uint64_t num = rate;
|
||||
uint64_t denom = 1 << 24;
|
||||
while ((num & 1) == 0) {
|
||||
num >>= 1;
|
||||
denom >>= 1;
|
||||
if (denom == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (denom << 32) | (num & 0xffffffff);
|
||||
}
|
||||
|
||||
static inline uint32_t numerator(const uint64_t frac)
|
||||
{
|
||||
return frac & 0xffffffff;
|
||||
}
|
||||
|
||||
static inline uint32_t denominator(const uint64_t frac)
|
||||
{
|
||||
return frac >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert fractional sample rate to units of 1/(2**24) Hz.
|
||||
*/
|
||||
static inline uint64_t round_sample_rate(const uint64_t frac)
|
||||
{
|
||||
uint64_t num = (uint64_t) numerator(frac) << 24;
|
||||
uint32_t denom = denominator(frac);
|
||||
if (denom == 0) {
|
||||
denom = 1;
|
||||
}
|
||||
return (num + (denom >> 1)) / denom;
|
||||
}
|
||||
|
||||
#define MAX_AFE_RATE_HZ (40000000UL)
|
||||
|
||||
static inline uint8_t compute_resample_log(
|
||||
@@ -182,57 +144,55 @@ static inline uint8_t compute_resample_log(
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MIN_MCU_RATE (200000ULL << 24)
|
||||
#define MAX_MCU_RATE (21800000ULL << 24)
|
||||
#define DEFAULT_MCU_RATE (10000000ULL << 24)
|
||||
#define MIN_MCU_RATE (200000ULL * FP_ONE_HZ)
|
||||
#define MAX_MCU_RATE (21800000ULL * FP_ONE_HZ)
|
||||
#define DEFAULT_MCU_RATE (10000000ULL * FP_ONE_HZ)
|
||||
|
||||
static uint64_t applied_afe_rate = RADIO_UNSET;
|
||||
static fp_40_24_t applied_afe_rate = RADIO_UNSET;
|
||||
|
||||
static bool radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
|
||||
{
|
||||
uint64_t rate, frac, previous_n;
|
||||
fp_40_24_t rate, afe_rate;
|
||||
uint64_t previous_n;
|
||||
uint8_t n = 0;
|
||||
bool new_afe_rate = false;
|
||||
bool new_rate = false;
|
||||
bool new_n = false;
|
||||
|
||||
const uint64_t requested_frac = bank[RADIO_SAMPLE_RATE_FRAC];
|
||||
const uint64_t requested_rate = bank[RADIO_SAMPLE_RATE];
|
||||
const uint64_t requested_n = bank[RADIO_RESAMPLE_RX];
|
||||
|
||||
if (requested_rate != RADIO_UNSET) {
|
||||
rate = MIN(requested_rate, MAX_MCU_RATE);
|
||||
rate = MAX(rate, MIN_MCU_RATE);
|
||||
frac = frac_sample_rate(rate);
|
||||
} else if (requested_frac != RADIO_UNSET) {
|
||||
frac = requested_frac;
|
||||
if (round_sample_rate(frac) > MAX_MCU_RATE) {
|
||||
frac = frac_sample_rate(MAX_MCU_RATE);
|
||||
}
|
||||
if (round_sample_rate(frac) < MIN_MCU_RATE) {
|
||||
frac = frac_sample_rate(MIN_MCU_RATE);
|
||||
}
|
||||
rate = round_sample_rate(frac);
|
||||
} else {
|
||||
rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE];
|
||||
if (rate == RADIO_UNSET) {
|
||||
rate = DEFAULT_MCU_RATE;
|
||||
}
|
||||
frac = RADIO_UNSET;
|
||||
}
|
||||
|
||||
const uint64_t previous_opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE];
|
||||
uint64_t opmode = bank[RADIO_OPMODE];
|
||||
if (opmode == RADIO_UNSET) {
|
||||
opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE];
|
||||
opmode = previous_opmode;
|
||||
}
|
||||
switch (previous_opmode) {
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
case TRANSCEIVER_MODE_SS:
|
||||
previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX];
|
||||
break;
|
||||
default:
|
||||
previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX];
|
||||
}
|
||||
switch (opmode) {
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
case TRANSCEIVER_MODE_SS:
|
||||
previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX];
|
||||
if (n != previous_n) {
|
||||
if (n != radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX]) {
|
||||
#ifdef PRALINE
|
||||
fpga_set_tx_interpolation_ratio(&fpga, n);
|
||||
#endif
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_TX] = n;
|
||||
new_rate = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -240,38 +200,44 @@ static bool radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
|
||||
* Resampling is enabled only in RX mode to work around a
|
||||
* spectrum inversion bug with TX interpolation.
|
||||
*/
|
||||
n = compute_resample_log(rate >> 24, requested_n);
|
||||
previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX];
|
||||
if (n != previous_n) {
|
||||
n = compute_resample_log(rate / FP_ONE_HZ, requested_n);
|
||||
if (n != radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX]) {
|
||||
#ifdef PRALINE
|
||||
fpga_set_rx_decimation_ratio(&fpga, n);
|
||||
#endif
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX] = n;
|
||||
new_rate = true;
|
||||
}
|
||||
}
|
||||
new_n = (n != previous_n);
|
||||
|
||||
if (radio->sample_rate_cb) {
|
||||
afe_rate = rate << n;
|
||||
afe_rate = radio->sample_rate_cb(afe_rate, false);
|
||||
new_afe_rate = (afe_rate != applied_afe_rate);
|
||||
if (new_afe_rate) {
|
||||
afe_rate = radio->sample_rate_cb(afe_rate, true);
|
||||
applied_afe_rate = afe_rate;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
rate = afe_rate >> n;
|
||||
new_rate = (rate != radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]);
|
||||
if (new_rate) {
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] = rate;
|
||||
if (rate != RADIO_UNSET) {
|
||||
/* Round to the nearest Hz for display. */
|
||||
const uint32_t rate_hz = (rate + (FP_ONE_HZ >> 1)) / FP_ONE_HZ;
|
||||
hackrf_ui()->set_sample_rate(rate_hz);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t afe_rate = rate << n;
|
||||
uint64_t previous_afe_rate = RADIO_UNSET;
|
||||
if (previous_n != RADIO_UNSET) {
|
||||
previous_afe_rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]
|
||||
<< previous_n;
|
||||
}
|
||||
|
||||
if (afe_rate != previous_afe_rate) {
|
||||
sample_rate_frac_set(numerator(frac) << n, denominator(frac));
|
||||
applied_afe_rate = afe_rate;
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE_FRAC] = frac;
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] = rate;
|
||||
new_rate = true;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
return (new_afe_rate || new_rate || new_n);
|
||||
}
|
||||
|
||||
#define DEFAULT_RF (2450000000ULL << 24)
|
||||
#define DEFAULT_RF (2450ULL * FP_ONE_MHZ)
|
||||
|
||||
static uint64_t applied_offset = RADIO_UNSET;
|
||||
static fp_40_24_t applied_offset = RADIO_UNSET;
|
||||
|
||||
#ifdef PRALINE
|
||||
static const tune_config_t* select_tune_config(uint64_t opmode)
|
||||
@@ -312,8 +278,8 @@ static bool radio_update_frequency(radio_t* const radio, uint64_t* bank)
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_IMAGE_REJECT]);
|
||||
if (new_if || new_lo || new_img_reject) {
|
||||
set_freq_explicit(
|
||||
requested_if >> 24,
|
||||
requested_lo >> 24,
|
||||
requested_if / FP_ONE_HZ,
|
||||
requested_lo / FP_ONE_HZ,
|
||||
requested_img_reject);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_IF] =
|
||||
requested_if;
|
||||
@@ -348,7 +314,7 @@ static bool radio_update_frequency(radio_t* const radio, uint64_t* bank)
|
||||
|
||||
bool new_rf =
|
||||
(radio->config[RADIO_BANK_APPLIED][RADIO_FREQUENCY_RF] != requested_rf);
|
||||
uint64_t requested_rf_hz = requested_rf >> 24;
|
||||
uint64_t requested_rf_hz = requested_rf / FP_ONE_HZ;
|
||||
#ifdef PRALINE
|
||||
if (applied_afe_rate == RADIO_UNSET) {
|
||||
return false;
|
||||
@@ -376,10 +342,10 @@ static bool radio_update_frequency(radio_t* const radio, uint64_t* bank)
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_ROTATION] =
|
||||
tune_config->shift << 6;
|
||||
}
|
||||
uint64_t offset = applied_afe_rate / 4;
|
||||
fp_40_24_t offset = applied_afe_rate / 4;
|
||||
bool new_offset = (applied_offset != offset);
|
||||
if (new_rotation || new_offset || new_config || new_rf) {
|
||||
tuning_set_frequency(tune_config, requested_rf_hz, offset >> 24);
|
||||
tuning_set_frequency(tune_config, requested_rf_hz, offset / FP_ONE_HZ);
|
||||
applied_offset = offset;
|
||||
}
|
||||
#else
|
||||
@@ -394,89 +360,68 @@ static bool radio_update_frequency(radio_t* const radio, uint64_t* bank)
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t auto_bandwidth(radio_t* const radio, uint64_t opmode)
|
||||
static uint32_t auto_bandwidth(radio_t* const radio)
|
||||
{
|
||||
uint64_t rotation = radio->config[RADIO_BANK_APPLIED][RADIO_ROTATION];
|
||||
|
||||
uint32_t sample_rate_hz = DEFAULT_MCU_RATE >> 24;
|
||||
uint32_t sample_rate_hz = DEFAULT_MCU_RATE / FP_ONE_HZ;
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] != RADIO_UNSET) {
|
||||
sample_rate_hz =
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] >> 24;
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE] / FP_ONE_HZ;
|
||||
}
|
||||
|
||||
uint32_t offset_hz = 0;
|
||||
if ((rotation != 0) && (rotation != RADIO_UNSET) &&
|
||||
(applied_offset != RADIO_UNSET)) {
|
||||
offset_hz = applied_offset >> 24;
|
||||
offset_hz = applied_offset / FP_ONE_HZ;
|
||||
}
|
||||
|
||||
const uint32_t bb_bandwidth = (sample_rate_hz * 3) / 4;
|
||||
const uint32_t lpf_bandwidth = bb_bandwidth + offset_hz * 2;
|
||||
|
||||
switch (opmode) {
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
case TRANSCEIVER_MODE_SS:
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_TX] = bb_bandwidth;
|
||||
break;
|
||||
default:
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_RX] = bb_bandwidth;
|
||||
}
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_TX] = bb_bandwidth;
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_BB_BANDWIDTH_RX] = bb_bandwidth;
|
||||
|
||||
return lpf_bandwidth;
|
||||
}
|
||||
|
||||
static bool radio_update_bandwidth(radio_t* const radio, uint64_t* bank)
|
||||
{
|
||||
bool new_bw = false;
|
||||
uint64_t opmode = bank[RADIO_OPMODE];
|
||||
if (opmode == RADIO_UNSET) {
|
||||
opmode = radio->config[RADIO_BANK_APPLIED][RADIO_OPMODE];
|
||||
}
|
||||
|
||||
#ifdef PRALINE
|
||||
/* Praline legacy mode always sets baseband bandwidth automatically. */
|
||||
(void) bank;
|
||||
uint32_t lpf_bandwidth = auto_bandwidth(radio, opmode);
|
||||
uint32_t lpf_bandwidth = auto_bandwidth(radio);
|
||||
|
||||
switch (opmode) {
|
||||
case TRANSCEIVER_MODE_TX:
|
||||
case TRANSCEIVER_MODE_SS:
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] !=
|
||||
lpf_bandwidth) {
|
||||
max2831_set_lpf_bandwidth(&max283x, lpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] =
|
||||
lpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] !=
|
||||
lpf_bandwidth) {
|
||||
max2831_set_lpf_bandwidth(&max283x, lpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] =
|
||||
lpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
bool narrow_lpf_enable = false;
|
||||
bool applied_narrow_lpf_enable =
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF];
|
||||
if (lpf_bandwidth <= 1750000) {
|
||||
narrow_lpf_enable = true;
|
||||
}
|
||||
if (applied_narrow_lpf_enable != narrow_lpf_enable) {
|
||||
narrowband_filter_set(narrow_lpf_enable);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF] =
|
||||
narrow_lpf_enable;
|
||||
new_bw = true;
|
||||
}
|
||||
/* Always set HPF bandwidth to 30 kHz for now. */
|
||||
const max2831_rx_hpf_freq_t hpf_bandwidth = MAX2831_RX_HPF_30_KHZ;
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] !=
|
||||
hpf_bandwidth) {
|
||||
max2831_set_rx_hpf_frequency(&max283x, hpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] =
|
||||
hpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] != lpf_bandwidth) {
|
||||
max2831_set_lpf_bandwidth(&max283x, MAX2831_MODE_TX, lpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] = lpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] != lpf_bandwidth) {
|
||||
max2831_set_lpf_bandwidth(&max283x, MAX2831_MODE_RX, lpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_LPF] = lpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
bool narrow_lpf_enable = false;
|
||||
bool applied_narrow_lpf_enable =
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF];
|
||||
if (lpf_bandwidth <= 1750000) {
|
||||
narrow_lpf_enable = true;
|
||||
}
|
||||
if (applied_narrow_lpf_enable != narrow_lpf_enable) {
|
||||
narrowband_filter_set(narrow_lpf_enable);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_RX_NARROW_LPF] =
|
||||
narrow_lpf_enable;
|
||||
new_bw = true;
|
||||
}
|
||||
/* Always set HPF bandwidth to 30 kHz for now. */
|
||||
const max2831_rx_hpf_freq_t hpf_bandwidth = MAX2831_RX_HPF_30_KHZ;
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] != hpf_bandwidth) {
|
||||
max2831_set_rx_hpf_frequency(&max283x, hpf_bandwidth);
|
||||
radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_RX_HPF] = hpf_bandwidth;
|
||||
new_bw = true;
|
||||
}
|
||||
#else
|
||||
uint64_t lpf_bandwidth;
|
||||
@@ -494,7 +439,7 @@ static bool radio_update_bandwidth(radio_t* const radio, uint64_t* bank)
|
||||
lpf_bandwidth = radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF];
|
||||
}
|
||||
if (lpf_bandwidth == RADIO_UNSET) {
|
||||
lpf_bandwidth = auto_bandwidth(radio, opmode);
|
||||
lpf_bandwidth = auto_bandwidth(radio);
|
||||
}
|
||||
|
||||
if (radio->config[RADIO_BANK_APPLIED][RADIO_XCVR_TX_LPF] != lpf_bandwidth) {
|
||||
@@ -710,8 +655,8 @@ bool radio_update(radio_t* const radio)
|
||||
bool dc = false;
|
||||
|
||||
if ((dirty &
|
||||
((1 << RADIO_SAMPLE_RATE) | (1 << RADIO_SAMPLE_RATE_FRAC) |
|
||||
(1 << RADIO_RESAMPLE_TX) | (1 << RADIO_RESAMPLE_RX))) ||
|
||||
((1 << RADIO_SAMPLE_RATE) | (1 << RADIO_RESAMPLE_TX) |
|
||||
(1 << RADIO_RESAMPLE_RX))) ||
|
||||
((detected_platform() == BOARD_ID_PRALINE) &&
|
||||
(dirty & (1 << RADIO_OPMODE)))) {
|
||||
rate = radio_update_sample_rate(radio, &tmp_bank[0]);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "fixed_point.h"
|
||||
|
||||
typedef enum {
|
||||
RADIO_OK = 1,
|
||||
RADIO_ERR_INVALID_PARAM = -2,
|
||||
@@ -106,88 +108,82 @@ typedef enum {
|
||||
* Sample rate (as seen by MCU/host) in 1/(2**24) Hz.
|
||||
*/
|
||||
RADIO_SAMPLE_RATE = 6,
|
||||
/**
|
||||
* Sample rate (as seen by MCU/host) in fractional format. The
|
||||
* numerator is stored in the low 32 bits. The denominator is stored in
|
||||
* the high 32 bits.
|
||||
*/
|
||||
RADIO_SAMPLE_RATE_FRAC = 7,
|
||||
/**
|
||||
* Base two logarithm of TX decimation ratio (0 means a ratio of 1).
|
||||
*/
|
||||
RADIO_RESAMPLE_TX = 8,
|
||||
RADIO_RESAMPLE_TX = 7,
|
||||
/**
|
||||
* Base two logarithm of RX decimation ratio (0 means a ratio of 1).
|
||||
*/
|
||||
RADIO_RESAMPLE_RX = 9,
|
||||
RADIO_RESAMPLE_RX = 8,
|
||||
/**
|
||||
* TX RF amplifier enable of type bool.
|
||||
*/
|
||||
RADIO_GAIN_TX_RF = 10,
|
||||
RADIO_GAIN_TX_RF = 9,
|
||||
/**
|
||||
* TX IF amplifier gain in dB.
|
||||
*/
|
||||
RADIO_GAIN_TX_IF = 11,
|
||||
RADIO_GAIN_TX_IF = 10,
|
||||
/**
|
||||
* RX RF amplifier enable of type bool.
|
||||
*/
|
||||
RADIO_GAIN_RX_RF = 12,
|
||||
RADIO_GAIN_RX_RF = 11,
|
||||
/**
|
||||
* RX IF amplifier gain in dB.
|
||||
*/
|
||||
RADIO_GAIN_RX_IF = 13,
|
||||
RADIO_GAIN_RX_IF = 12,
|
||||
/**
|
||||
* RX baseband amplifier gain in dB.
|
||||
*/
|
||||
RADIO_GAIN_RX_BB = 14,
|
||||
RADIO_GAIN_RX_BB = 13,
|
||||
/**
|
||||
* TX baseband bandwidth in Hz. This controls analog baseband filter
|
||||
* settings but is specified as the desired bandwidth centered in
|
||||
* digital baseband as seen by the MCU/host.
|
||||
*/
|
||||
RADIO_BB_BANDWIDTH_TX = 15,
|
||||
RADIO_BB_BANDWIDTH_TX = 14,
|
||||
/**
|
||||
* RX baseband bandwidth in Hz. This controls analog baseband filter
|
||||
* settings but is specified as the desired bandwidth centered in
|
||||
* digital baseband as seen by the MCU/host.
|
||||
*/
|
||||
RADIO_BB_BANDWIDTH_RX = 16,
|
||||
RADIO_BB_BANDWIDTH_RX = 15,
|
||||
/**
|
||||
* Quadrature transceiver TX baseband LPF bandwidth in Hz. If no
|
||||
* rotation is performed, this is set to match RADIO_BB_BANDWIDTH.
|
||||
* Currently unused.
|
||||
*/
|
||||
RADIO_XCVR_TX_LPF = 17,
|
||||
RADIO_XCVR_TX_LPF = 16,
|
||||
/**
|
||||
* Quadrature transceiver RX baseband LPF bandwidth in Hz. If no
|
||||
* rotation is performed, this is set to match RADIO_BB_BANDWIDTH.
|
||||
* Currently unused.
|
||||
*/
|
||||
RADIO_XCVR_RX_LPF = 18,
|
||||
RADIO_XCVR_RX_LPF = 17,
|
||||
/**
|
||||
* Quadrature transceiver RX baseband HPF bandwidth in Hz. Currently
|
||||
* unused.
|
||||
*/
|
||||
RADIO_XCVR_RX_HPF = 19,
|
||||
RADIO_XCVR_RX_HPF = 18,
|
||||
/**
|
||||
* Narrowband RX analog baseband LPF enable of type bool. Currently unused.
|
||||
*/
|
||||
RADIO_RX_NARROW_LPF = 20,
|
||||
RADIO_RX_NARROW_LPF = 19,
|
||||
/**
|
||||
* RF port bias tee enable of type bool.
|
||||
*/
|
||||
RADIO_BIAS_TEE = 21,
|
||||
RADIO_BIAS_TEE = 20,
|
||||
/**
|
||||
* Trigger input enable of type bool.
|
||||
*/
|
||||
RADIO_TRIGGER = 22,
|
||||
RADIO_TRIGGER = 21,
|
||||
/**
|
||||
* DC block enable of type bool.
|
||||
*/
|
||||
RADIO_DC_BLOCK = 23,
|
||||
RADIO_DC_BLOCK = 22,
|
||||
} radio_register_t;
|
||||
|
||||
#define RADIO_NUM_REGS (24)
|
||||
#define RADIO_NUM_REGS (23)
|
||||
#define RADIO_UNSET (0xffffffffffffffff)
|
||||
|
||||
/**
|
||||
@@ -211,10 +207,20 @@ typedef enum {
|
||||
|
||||
#define RADIO_NUM_BANKS (5)
|
||||
|
||||
/**
|
||||
* A callback function must be provided that configures clock generation to
|
||||
* produce the requested sample clock frequency. The function must return the
|
||||
* configured sample rate. A boolean program argument may be set to false to
|
||||
* execute a dry run, returning the sample rate without configuring clock
|
||||
* generation.
|
||||
*/
|
||||
typedef fp_40_24_t (*sample_rate_fn)(const fp_40_24_t sample_rate, const bool program);
|
||||
|
||||
typedef struct radio_t {
|
||||
radio_config_mode_t config_mode;
|
||||
uint64_t config[RADIO_NUM_BANKS][RADIO_NUM_REGS];
|
||||
volatile uint32_t regs_dirty;
|
||||
sample_rate_fn sample_rate_cb;
|
||||
} radio_t;
|
||||
|
||||
void radio_init(radio_t* const radio);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "tuning.h"
|
||||
#include "usb_endpoint.h"
|
||||
#include "streaming.h"
|
||||
#include "fixed_point.h"
|
||||
|
||||
#include <libopencm3/lpc43xx/m4/nvic.h>
|
||||
|
||||
@@ -98,7 +99,7 @@ usb_request_status_t usb_vendor_request_init_sweep(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
RADIO_FREQUENCY_RF,
|
||||
(sweep_freq + offset) << 24);
|
||||
(sweep_freq + offset) * FP_ONE_HZ);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
nvic_enable_irq(NVIC_USB0_IRQ);
|
||||
radio_update(&radio);
|
||||
@@ -228,7 +229,7 @@ void sweep_mode(uint32_t seq)
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
RADIO_FREQUENCY_RF,
|
||||
(sweep_freq + offset) << 24);
|
||||
(sweep_freq + offset) * FP_ONE_HZ);
|
||||
nvic_enable_irq(NVIC_USB0_IRQ);
|
||||
blocks_queued = 0;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "usb.h"
|
||||
#include "usb_queue.h"
|
||||
#include "platform_detect.h"
|
||||
#include "fixed_point.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -108,7 +109,11 @@ usb_request_status_t usb_vendor_request_set_freq(
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
const uint64_t freq =
|
||||
set_freq_params.freq_mhz * 1000000ULL + set_freq_params.freq_hz;
|
||||
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_FREQUENCY_RF, freq << 24);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
RADIO_FREQUENCY_RF,
|
||||
freq * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
@@ -145,12 +150,12 @@ usb_request_status_t usb_vendor_request_set_freq_explicit(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
RADIO_FREQUENCY_IF,
|
||||
explicit_params.if_freq_hz << 24);
|
||||
explicit_params.if_freq_hz * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
RADIO_FREQUENCY_LO,
|
||||
explicit_params.lo_freq_hz << 24);
|
||||
explicit_params.lo_freq_hz * FP_ONE_HZ);
|
||||
radio_reg_write(
|
||||
&radio,
|
||||
RADIO_BANK_ACTIVE,
|
||||
@@ -161,6 +166,18 @@ usb_request_status_t usb_vendor_request_set_freq_explicit(
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert fractional sample rate to units of 1/(2**24) Hz.
|
||||
*/
|
||||
static inline fp_40_24_t round_sample_rate(uint64_t num, uint32_t denom)
|
||||
{
|
||||
num *= FP_ONE_HZ;
|
||||
if (denom == 0) {
|
||||
denom = 1;
|
||||
}
|
||||
return (num + (denom >> 1)) / denom;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_set_sample_rate_frac(
|
||||
usb_endpoint_t* const endpoint,
|
||||
const usb_transfer_stage_t stage)
|
||||
@@ -174,9 +191,9 @@ usb_request_status_t usb_vendor_request_set_sample_rate_frac(
|
||||
NULL);
|
||||
} else if (stage == USB_TRANSFER_STAGE_DATA) {
|
||||
uint32_t numerator = set_sample_r_params.freq_hz;
|
||||
uint64_t denominator = set_sample_r_params.divider;
|
||||
uint64_t value = (denominator << 32) | numerator;
|
||||
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_SAMPLE_RATE_FRAC, value);
|
||||
uint32_t denominator = set_sample_r_params.divider;
|
||||
uint64_t value = round_sample_rate(numerator, denominator);
|
||||
radio_reg_write(&radio, RADIO_BANK_ACTIVE, RADIO_SAMPLE_RATE, value);
|
||||
usb_transfer_schedule_ack(endpoint->in);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
|
||||
@@ -501,7 +501,7 @@ int radio_read_register(
|
||||
return result;
|
||||
}
|
||||
|
||||
#define RADIO_NUM_REGS (24)
|
||||
#define RADIO_NUM_REGS (23)
|
||||
|
||||
int radio_read_registers(hackrf_device* device, const uint8_t bank)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user