Add 40.24 fixed-point type

This commit is contained in:
Michael Ossmann
2026-03-01 09:59:19 -05:00
parent 30229730b4
commit bb670f9af7
4 changed files with 69 additions and 27 deletions

View 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__*/

View File

@@ -27,6 +27,7 @@
#include "fpga.h"
#include "platform_detect.h"
#include "radio.h"
#include "fixed_point.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
@@ -121,10 +122,10 @@ static bool radio_update_direction(radio_t* const radio, uint64_t* bank)
/*
* Convert sample rate in units of 1/(2**24) Hz to fraction.
*/
static inline uint64_t frac_sample_rate(const uint64_t rate)
static inline uint64_t frac_sample_rate(const fp_40_24_t rate)
{
uint64_t num = rate;
uint64_t denom = 1 << 24;
uint64_t denom = FP_ONE_HZ;
while ((num & 1) == 0) {
num >>= 1;
denom >>= 1;
@@ -148,9 +149,9 @@ static inline uint32_t denominator(const uint64_t frac)
/*
* Convert fractional sample rate to units of 1/(2**24) Hz.
*/
static inline uint64_t round_sample_rate(const uint64_t frac)
static inline fp_40_24_t round_sample_rate(const uint64_t frac)
{
uint64_t num = (uint64_t) numerator(frac) << 24;
uint64_t num = (uint64_t) numerator(frac) * FP_ONE_HZ;
uint32_t denom = denominator(frac);
if (denom == 0) {
denom = 1;
@@ -182,15 +183,16 @@ 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;
uint64_t frac, previous_n;
uint8_t n = 0;
bool new_rate = false;
@@ -240,7 +242,7 @@ 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);
n = compute_resample_log(rate / FP_ONE_HZ, requested_n);
previous_n = radio->config[RADIO_BANK_APPLIED][RADIO_RESAMPLE_RX];
if (n != previous_n) {
#ifdef PRALINE
@@ -251,8 +253,8 @@ static bool radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
}
}
uint64_t afe_rate = rate << n;
uint64_t previous_afe_rate = RADIO_UNSET;
fp_40_24_t afe_rate = rate << n;
fp_40_24_t previous_afe_rate = RADIO_UNSET;
if (previous_n != RADIO_UNSET) {
previous_afe_rate = radio->config[RADIO_BANK_APPLIED][RADIO_SAMPLE_RATE]
<< previous_n;
@@ -269,9 +271,9 @@ static bool radio_update_sample_rate(radio_t* const radio, uint64_t* bank)
return new_rate;
}
#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 +314,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 +350,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 +378,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
@@ -398,16 +400,16 @@ 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;

View File

@@ -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;
}

View File

@@ -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,