diff --git a/firmware/common/Makefile_inc.mk b/firmware/common/Makefile_inc.mk index 8917beda..fc22f2b9 100644 --- a/firmware/common/Makefile_inc.mk +++ b/firmware/common/Makefile_inc.mk @@ -54,8 +54,8 @@ CFLAGS += -std=gnu99 -Os -g3 -Wall -Wextra -I$(LIBOPENCM3)/include -I../common \ -fno-common -mcpu=cortex-m4 -mthumb -MD \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ $(HACKRF_OPTS) -LDFLAGS += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu \ - -L../common \ +LDFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \ + -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu -L../common \ -L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \ -T$(LDSCRIPT) -nostartfiles \ -Wl,--gc-sections -Xlinker -Map=$(BINARY).map diff --git a/firmware/common/hackrf_core.c b/firmware/common/hackrf_core.c index 7246d222..ef8d118d 100644 --- a/firmware/common/hackrf_core.c +++ b/firmware/common/hackrf_core.c @@ -39,59 +39,90 @@ void delay(uint32_t duration) __asm__("nop"); } -bool set_fracrate(const float freq) { +/* GCD algo from wikipedia */ +/* http://en.wikipedia.org/wiki/Greatest_common_divisor */ +static uint32_t +gcd(uint32_t u, uint32_t v) +{ + int s; - uint32_t MSx_P1,MSx_P2,MSx_P3; - uint32_t b,c; - float div = (800/freq); - uint32_t a = (uint32_t)div; - float x = div-a; + if (!u || !v) + return u | v; - if(a != div){ - uint32_t j=0,k=1,l=1,m=1; - - si5351c_set_int_mode(0, 0); - - while (k <= 0xFFFF && m <= 0xFFFF){ - float n = (float)(j+l)/(k+m); - if( x == n){ - if(k + m <= 0xFFFF){ - b=j+l; c=k+m; - break; - } else if(m > k){ - b=l; c=m; - break; - } else { - b=j; c=k; - break; - } - } - else if(x > n){ - j+=l; k+=m; - } - else{ - l+=j; m+=k; - } - } - if (k > 0xFFFF){ - b=l; c=m; - } - else{ - b=j; c=k; - } - } else { - if(a & 0x1) // odd integer, needs frac mode - si5351c_set_int_mode(0, 0); - else - si5351c_set_int_mode(0, 1); - b=0; c=1; + 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; + + /* Find best config */ + a = (VCO_FREQ * rate_denom) / rate_num; + + rem = (VCO_FREQ * rate_denom) - (a * rate_num); + + 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; + } + } + + /* Can we enable integer mode ? */ + if (a & 0x1 || b) + si5351c_set_int_mode(0, 0); + else + si5351c_set_int_mode(0, 1); + + /* Final MS values */ MSx_P1 = 128*a + (128 * b/c) - 512; - MSx_P2 = (128*b)%c; + MSx_P2 = (128*b) % c; MSx_P3 = c; - /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ si5351c_configure_multisynth(0, MSx_P1, MSx_P2, MSx_P3, 1); @@ -105,10 +136,8 @@ bool set_fracrate(const float freq) { //si5351c_configure_multisynth(3, p1, 0, 1, 0); // no clk out return true; - } - bool sample_rate_set(const uint32_t sample_rate_hz) { #ifdef JELLYBEAN /* Due to design issues, Jellybean/Lemondrop frequency plan is limited. diff --git a/firmware/common/hackrf_core.h b/firmware/common/hackrf_core.h index d32f27e4..5752da00 100644 --- a/firmware/common/hackrf_core.h +++ b/firmware/common/hackrf_core.h @@ -259,7 +259,7 @@ void pin_setup(void); void enable_1v8_power(void); -bool set_fracrate(const float sampling_rate_mhz); +bool sample_rate_frac_set(uint32_t rate_num, uint32_t rate_denom); bool sample_rate_set(const uint32_t sampling_rate_hz); bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index e42fbb9e..83524804 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -68,7 +68,8 @@ typedef struct { set_freq_params_t set_freq_params; typedef struct { - float freq_mhz; + uint32_t freq_hz; + uint32_t divider; } set_sample_r_params_t; set_sample_r_params_t set_sample_r_params; @@ -425,22 +426,6 @@ usb_request_status_t usb_vendor_request_read_si5351c( } } -usb_request_status_t usb_vendor_request_set_sample_rate( - usb_endpoint_t* const endpoint, - const usb_transfer_stage_t stage -) { - if( stage == USB_TRANSFER_STAGE_SETUP ) { - const uint32_t sample_rate = (endpoint->setup.index << 16) | endpoint->setup.value; - if( sample_rate_set(sample_rate) ) { - usb_endpoint_schedule_ack(endpoint->in); - return USB_REQUEST_STATUS_OK; - } - return USB_REQUEST_STATUS_STALL; - } else { - return USB_REQUEST_STATUS_OK; - } -} - usb_request_status_t usb_vendor_request_set_baseband_filter_bandwidth( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage @@ -702,7 +687,7 @@ usb_request_status_t usb_vendor_request_set_freq( } } -usb_request_status_t usb_vendor_request_set_fracrate( +usb_request_status_t usb_vendor_request_set_sample_rate_frac( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) { @@ -712,7 +697,7 @@ usb_request_status_t usb_vendor_request_set_fracrate( return USB_REQUEST_STATUS_OK; } else if (stage == USB_TRANSFER_STAGE_DATA) { - if( set_fracrate(set_sample_r_params.freq_mhz*2) ) + if( sample_rate_frac_set(set_sample_r_params.freq_hz * 2, set_sample_r_params.divider ) ) { usb_endpoint_schedule_ack(endpoint->in); return USB_REQUEST_STATUS_OK; @@ -834,7 +819,7 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_max2837, usb_vendor_request_write_si5351c, usb_vendor_request_read_si5351c, - usb_vendor_request_set_sample_rate, + usb_vendor_request_set_sample_rate_frac, usb_vendor_request_set_baseband_filter_bandwidth, usb_vendor_request_write_rffc5071, usb_vendor_request_read_rffc5071, @@ -850,7 +835,6 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_set_lna_gain, usb_vendor_request_set_vga_gain, usb_vendor_request_set_txvga_gain, - usb_vendor_request_set_fracrate }; static const uint32_t vendor_request_handler_count = diff --git a/host/hackrf-tools/src/hackrf_si5351c.c b/host/hackrf-tools/src/hackrf_si5351c.c index 0a447d45..666ac7e4 100644 --- a/host/hackrf-tools/src/hackrf_si5351c.c +++ b/host/hackrf-tools/src/hackrf_si5351c.c @@ -121,17 +121,17 @@ int dump_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number) } p1 = - (parameters[2] & 0x03 << 16) + ((parameters[2] & 0x03) << 16) | (parameters[3] << 8) | parameters[4] ; p2 = - (parameters[5] & 0x0F << 16) + ((parameters[5] & 0x0F) << 16) | (parameters[6] << 8) | parameters[7] ; p3 = - (parameters[5] & 0xF0 << 12) + ((parameters[5] & 0xF0) << 12) | (parameters[0] << 8) | parameters[1] ; @@ -143,7 +143,7 @@ int dump_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number) printf("\tp2 = %u\n", p2); printf("\tp3 = %u\n", p3); if(p3) - printf("\tOutput (800Mhz PLL): %#.10f Mhz\n", (800 / (float)((p1*p3 + p2 + 512*p3)/(128*p3))) / div_lut[r_div] ); + printf("\tOutput (800Mhz PLL): %#.10f Mhz\n", ((double)800 / (double)(((double)p1*p3 + p2 + 512*p3)/(double)(128*p3))) / div_lut[r_div] ); } else { // MS6 and 7 are integer only unsigned int parms; @@ -157,7 +157,7 @@ int dump_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number) } } - r_div = (ms_number == 6) ? parameters[2] & 0x7 : parameters[2] & 0x70 >> 4 ; + r_div = (ms_number == 6) ? parameters[2] & 0x7 : (parameters[2] & 0x70) >> 4 ; parms = (ms_number == 6) ? parameters[0] : parameters[1]; printf("\tp1_int = %u\n", parms); if(parms) diff --git a/host/hackrf-tools/src/hackrf_transfer.c b/host/hackrf-tools/src/hackrf_transfer.c index 3423c8f0..98de34be 100644 --- a/host/hackrf-tools/src/hackrf_transfer.c +++ b/host/hackrf-tools/src/hackrf_transfer.c @@ -591,7 +591,7 @@ int main(int argc, char** argv) { signal(SIGABRT, &sigint_callback_handler); #endif printf("call hackrf_sample_rate_set(%u Hz/%.03f MHz)\n", sample_rate_hz,((float)sample_rate_hz/(float)FREQ_ONE_MHZ)); - result = hackrf_sample_rate_set(device, sample_rate_hz); + result = hackrf_set_sample_rate_manual(device, sample_rate_hz, 1); if( result != HACKRF_SUCCESS ) { printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result); usage(); @@ -600,7 +600,7 @@ int main(int argc, char** argv) { printf("call hackrf_baseband_filter_bandwidth_set(%d Hz/%.03f MHz)\n", baseband_filter_bw_hz, ((float)baseband_filter_bw_hz/(float)FREQ_ONE_MHZ)); - result = hackrf_baseband_filter_bandwidth_set(device, baseband_filter_bw_hz); + result = hackrf_set_baseband_filter_bandwidth(device, baseband_filter_bw_hz); if( result != HACKRF_SUCCESS ) { printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); usage(); diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 49a89fc9..06a3a62f 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -64,7 +64,6 @@ typedef enum { HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19, HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20, HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21, - HACKRF_VENDOR_REQUEST_SET_FRACRATE = 22, } hackrf_vendor_request; typedef enum { @@ -473,29 +472,7 @@ int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number } } -int ADDCALL hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz) -{ - int result; - result = libusb_control_transfer( - device->usb_device, - LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET, - sampling_rate_hz & 0xffff, - sampling_rate_hz >> 16, - NULL, - 0, - 0 - ); - - if( result != 0 ) - { - return HACKRF_ERROR_LIBUSB; - } else { - return HACKRF_SUCCESS; - } -} - -int ADDCALL hackrf_baseband_filter_bandwidth_set(hackrf_device* device, const uint32_t bandwidth_hz) +int ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_hz) { int result; result = libusb_control_transfer( @@ -764,23 +741,26 @@ int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz) typedef struct { - float freq_mhz; + uint32_t freq_hz; + uint32_t divider; } set_fracrate_params_t; -int ADDCALL hackrf_set_fracrate(hackrf_device* device, const float freq_mhz) +int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, + const uint32_t freq_hz, uint32_t divider) { set_fracrate_params_t set_fracrate_params; uint8_t length; int result; - - set_fracrate_params.freq_mhz = TO_LE(freq_mhz); + + set_fracrate_params.freq_hz = TO_LE(freq_hz); + set_fracrate_params.divider = TO_LE(divider); length = sizeof(set_fracrate_params_t); result = libusb_control_transfer( device->usb_device, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - HACKRF_VENDOR_REQUEST_SET_FRACRATE, + HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET, 0, 0, (unsigned char*)&set_fracrate_params, @@ -796,6 +776,41 @@ int ADDCALL hackrf_set_fracrate(hackrf_device* device, const float freq_mhz) } } +int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq) +{ + const int MAX_N = 32; + uint32_t freq_hz, divider; + double freq_frac = 1.0 + freq - (int)freq; + uint64_t v, a, m; + int i, e; + + v = *((uint64_t*)&freq); + e = (v >> 52) - 1023; + + m = ((1ULL << 52) - 1); + + v = *((uint64_t*)&freq_frac); + v &= m; + + m &= ~((1 << (e+4)) - 1); + + a = 0; + + for (i=1; i 10Mhz or as plain old 10000000hz (double) + preferred rates are 8, 10, 12.5, 16, 20Mhz due to less jitter */ +extern ADDAPI int ADDCALL hackrf_set_sample_rate_manual(hackrf_device* device, const uint32_t freq_hz, const uint32_t divider); +extern ADDAPI int ADDCALL hackrf_set_sample_rate(hackrf_device* device, const double freq_hz); /* external amp, bool on/off */ extern ADDAPI int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value);