Merge pull request #76 from smunaut/pending

Final (hopefully) sample rate API + misc fixes
This commit is contained in:
Michael Ossmann
2013-06-08 17:00:56 -07:00
8 changed files with 142 additions and 111 deletions

View File

@ -54,8 +54,8 @@ CFLAGS += -std=gnu99 -Os -g3 -Wall -Wextra -I$(LIBOPENCM3)/include -I../common \
-fno-common -mcpu=cortex-m4 -mthumb -MD \ -fno-common -mcpu=cortex-m4 -mthumb -MD \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
$(HACKRF_OPTS) $(HACKRF_OPTS)
LDFLAGS += -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu \ LDFLAGS += -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-L../common \ -L$(TOOLCHAIN_DIR)/lib/armv7e-m/fpu -L../common \
-L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \ -L$(LIBOPENCM3)/lib -L$(LIBOPENCM3)/lib/lpc43xx \
-T$(LDSCRIPT) -nostartfiles \ -T$(LDSCRIPT) -nostartfiles \
-Wl,--gc-sections -Xlinker -Map=$(BINARY).map -Wl,--gc-sections -Xlinker -Map=$(BINARY).map

View File

@ -39,58 +39,89 @@ void delay(uint32_t duration)
__asm__("nop"); __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; if (!u || !v)
uint32_t b,c; return u | v;
float div = (800/freq);
uint32_t a = (uint32_t)div;
float x = div-a;
if(a != div){ for (s=0; !((u|v)&1); s++) {
uint32_t j=0,k=1,l=1,m=1; u >>= 1;
v >>= 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;
} }
MSx_P1 = 128*a + (128 * b/c) - 512; while (!(u&1))
MSx_P2 = (128*b)%c; u >>= 1;
MSx_P3 = c;
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_P3 = c;
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */ /* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, MSx_P1, MSx_P2, MSx_P3, 1); 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 //si5351c_configure_multisynth(3, p1, 0, 1, 0); // no clk out
return true; return true;
} }
bool sample_rate_set(const uint32_t sample_rate_hz) { bool sample_rate_set(const uint32_t sample_rate_hz) {
#ifdef JELLYBEAN #ifdef JELLYBEAN
/* Due to design issues, Jellybean/Lemondrop frequency plan is limited. /* Due to design issues, Jellybean/Lemondrop frequency plan is limited.

View File

@ -259,7 +259,7 @@ void pin_setup(void);
void enable_1v8_power(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 sample_rate_set(const uint32_t sampling_rate_hz);
bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz); bool baseband_filter_bandwidth_set(const uint32_t bandwidth_hz);

View File

@ -68,7 +68,8 @@ typedef struct {
set_freq_params_t set_freq_params; set_freq_params_t set_freq_params;
typedef struct { 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_t set_sample_r_params; 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_request_status_t usb_vendor_request_set_baseband_filter_bandwidth(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage 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, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage) const usb_transfer_stage_t stage)
{ {
@ -712,7 +697,7 @@ usb_request_status_t usb_vendor_request_set_fracrate(
return USB_REQUEST_STATUS_OK; return USB_REQUEST_STATUS_OK;
} else if (stage == USB_TRANSFER_STAGE_DATA) } 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); usb_endpoint_schedule_ack(endpoint->in);
return USB_REQUEST_STATUS_OK; 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_read_max2837,
usb_vendor_request_write_si5351c, usb_vendor_request_write_si5351c,
usb_vendor_request_read_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_set_baseband_filter_bandwidth,
usb_vendor_request_write_rffc5071, usb_vendor_request_write_rffc5071,
usb_vendor_request_read_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_lna_gain,
usb_vendor_request_set_vga_gain, usb_vendor_request_set_vga_gain,
usb_vendor_request_set_txvga_gain, usb_vendor_request_set_txvga_gain,
usb_vendor_request_set_fracrate
}; };
static const uint32_t vendor_request_handler_count = static const uint32_t vendor_request_handler_count =

View File

@ -121,17 +121,17 @@ int dump_multisynth_config(hackrf_device* device, const uint_fast8_t ms_number)
} }
p1 = p1 =
(parameters[2] & 0x03 << 16) ((parameters[2] & 0x03) << 16)
| (parameters[3] << 8) | (parameters[3] << 8)
| parameters[4] | parameters[4]
; ;
p2 = p2 =
(parameters[5] & 0x0F << 16) ((parameters[5] & 0x0F) << 16)
| (parameters[6] << 8) | (parameters[6] << 8)
| parameters[7] | parameters[7]
; ;
p3 = p3 =
(parameters[5] & 0xF0 << 12) ((parameters[5] & 0xF0) << 12)
| (parameters[0] << 8) | (parameters[0] << 8)
| parameters[1] | 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("\tp2 = %u\n", p2);
printf("\tp3 = %u\n", p3); printf("\tp3 = %u\n", p3);
if(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 { } else {
// MS6 and 7 are integer only // MS6 and 7 are integer only
unsigned int parms; 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]; parms = (ms_number == 6) ? parameters[0] : parameters[1];
printf("\tp1_int = %u\n", parms); printf("\tp1_int = %u\n", parms);
if(parms) if(parms)

View File

@ -591,7 +591,7 @@ int main(int argc, char** argv) {
signal(SIGABRT, &sigint_callback_handler); signal(SIGABRT, &sigint_callback_handler);
#endif #endif
printf("call hackrf_sample_rate_set(%u Hz/%.03f MHz)\n", sample_rate_hz,((float)sample_rate_hz/(float)FREQ_ONE_MHZ)); 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 ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();
@ -600,7 +600,7 @@ int main(int argc, char** argv) {
printf("call hackrf_baseband_filter_bandwidth_set(%d Hz/%.03f MHz)\n", 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)); 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 ) { if( result != HACKRF_SUCCESS ) {
printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result); printf("hackrf_baseband_filter_bandwidth_set() failed: %s (%d)\n", hackrf_error_name(result), result);
usage(); usage();

View File

@ -64,7 +64,6 @@ typedef enum {
HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19, HACKRF_VENDOR_REQUEST_SET_LNA_GAIN = 19,
HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20, HACKRF_VENDOR_REQUEST_SET_VGA_GAIN = 20,
HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21, HACKRF_VENDOR_REQUEST_SET_TXVGA_GAIN = 21,
HACKRF_VENDOR_REQUEST_SET_FRACRATE = 22,
} hackrf_vendor_request; } hackrf_vendor_request;
typedef enum { 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 ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_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 result; int result;
result = libusb_control_transfer( result = libusb_control_transfer(
@ -764,23 +741,26 @@ int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz)
typedef struct { typedef struct {
float freq_mhz; uint32_t freq_hz;
uint32_t divider;
} set_fracrate_params_t; } 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; set_fracrate_params_t set_fracrate_params;
uint8_t length; uint8_t length;
int result; 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); length = sizeof(set_fracrate_params_t);
result = libusb_control_transfer( result = libusb_control_transfer(
device->usb_device, device->usb_device,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
HACKRF_VENDOR_REQUEST_SET_FRACRATE, HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET,
0, 0,
0, 0,
(unsigned char*)&set_fracrate_params, (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<MAX_N; i++) {
a += v;
if (!(a & m) || !(~a & m))
break;
}
if (i == MAX_N)
i = 1;
freq_hz = (uint32_t)(freq * i + 0.5);
divider = i;
return hackrf_set_sample_rate_manual(device, freq_hz, divider);
}
int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value) int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value)
{ {
int result; int result;

View File

@ -112,8 +112,7 @@ extern ADDAPI int ADDCALL hackrf_max2837_write(hackrf_device* device, uint8_t re
extern ADDAPI int ADDCALL hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value); extern ADDAPI int ADDCALL hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value);
extern ADDAPI int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); extern ADDAPI int ADDCALL hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value);
extern ADDAPI int ADDCALL hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz); extern ADDAPI int ADDCALL hackrf_set_baseband_filter_bandwidth(hackrf_device* device, const uint32_t bandwidth_hz);
extern ADDAPI int ADDCALL hackrf_baseband_filter_bandwidth_set(hackrf_device* device, const uint32_t bandwidth_hz);
extern ADDAPI int ADDCALL hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value); extern ADDAPI int ADDCALL hackrf_rffc5071_read(hackrf_device* device, uint8_t register_number, uint16_t* value);
extern ADDAPI int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value); extern ADDAPI int ADDCALL hackrf_rffc5071_write(hackrf_device* device, uint8_t register_number, uint16_t value);
@ -129,7 +128,11 @@ extern ADDAPI int ADDCALL hackrf_board_id_read(hackrf_device* device, uint8_t* v
extern ADDAPI int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length); extern ADDAPI int ADDCALL hackrf_version_string_read(hackrf_device* device, char* version, uint8_t length);
extern ADDAPI int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz); extern ADDAPI int ADDCALL hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz);
extern ADDAPI int ADDCALL hackrf_set_fracrate(hackrf_device* device, const float freq_mhz);
/* currently 8-20Mhz - either as a fraction, i.e. freq 20000000hz divider 2 -> 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 */ /* external amp, bool on/off */
extern ADDAPI int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value); extern ADDAPI int ADDCALL hackrf_set_amp_enable(hackrf_device* device, const uint8_t value);