Factor out sample_rate_set() from cpu_clock_init().

Implement switching between several supported sampling rates for Jellybean and Jawbreaker.
Commit bits of the Si5351C USB request support that I apparently missed in a prior commit.
This commit is contained in:
Jared Boone
2012-10-17 16:57:26 -07:00
parent d4da08a3d7
commit 9c4a0e94b0
6 changed files with 152 additions and 23 deletions

View File

@ -36,6 +36,96 @@ void delay(uint32_t duration)
__asm__("nop"); __asm__("nop");
} }
bool sample_rate_set(const uint32_t sample_rate_hz) {
#ifdef JELLYBEAN
/* Due to design issues, Jellybean/Lemondrop frequency plan is limited.
* Long version of the story: The MAX2837 reference frequency
* originates from the same PLL as the sample clocks, and in order to
* keep the sample clocks in phase and keep jitter noise down, the MAX2837
* and sample clocks must be integer-related.
*/
uint32_t r_div_sample = 2;
uint32_t r_div_sgpio = 1;
switch( sample_rate_hz ) {
case 5000000:
r_div_sample = 3; /* 800 MHz / 20 / 8 = 5 MHz */
r_div_sgpio = 2; /* 800 MHz / 20 / 4 = 10 MHz */
break;
case 10000000:
r_div_sample = 2; /* 800 MHz / 20 / 4 = 10 MHz */
r_div_sgpio = 1; /* 800 MHz / 20 / 2 = 20 MHz */
break;
case 20000000:
r_div_sample = 1; /* 800 MHz / 20 / 2 = 20 MHz */
r_div_sgpio = 0; /* 800 MHz / 20 / 1 = 40 MHz */
break;
default:
return false;
}
/* NOTE: Because MS1, 2, 3 outputs are slaved to PLLA, the p1, p2, p3
* values are irrelevant. */
/* MS0/CLK1 is the source for the MAX5864 codec. */
si5351c_configure_multisynth(1, 4608, 0, 1, r_div_sample);
/* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */
si5351c_configure_multisynth(2, 4608, 0, 1, r_div_sample);
/* MS0/CLK3 is the source for the SGPIO clock. */
si5351c_configure_multisynth(3, 4608, 0, 1, r_div_sgpio);
return true;
#endif
#ifdef JAWBREAKER
uint32_t p1 = 4608;
switch(sample_rate_hz) {
case 5000000:
p1 = 9728; // 800MHz / 80 = 10 MHz (SGPIO), 5 MHz (codec)
break;
case 10000000:
p1 = 4608; // 800MHz / 40 = 20 MHz (SGPIO), 10 MHz (codec)
break;
case 12500000:
p1 = 3584; // 800MHz / 32 = 25 MHz (SGPIO), 12.5 MHz (codec)
break;
case 16000000:
p1 = 2688; // 800MHz / 25 = 32 MHz (SGPIO), 16 MHz (codec)
break;
case 20000000:
p1 = 2048; // 800MHz / 20 = 40 MHz (SGPIO), 20 MHz (codec)
break;
default:
return false;
}
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, p1, 0, 1, 1);
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, p1, 0, 1, 0);
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, p1, 0, 1, 0);
/* MS0/CLK3 is the source for the external clock output. */
si5351c_configure_multisynth(3, p1, 0, 1, 0);
return true;
#endif
}
/* clock startup for Jellybean with Lemondrop attached */ /* clock startup for Jellybean with Lemondrop attached */
void cpu_clock_init(void) void cpu_clock_init(void)
{ {
@ -68,15 +158,6 @@ void cpu_clock_init(void)
/* MS0/CLK0 is the source for the MAX2837 clock input. */ /* MS0/CLK0 is the source for the MAX2837 clock input. */
si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */
/* MS0/CLK1 is the source for the MAX5864 codec. */
si5351c_configure_multisynth(1, 4608, 0, 1, 2); /* 10MHz */
/* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */
si5351c_configure_multisynth(2, 4608, 0, 1, 2); /* 10MHz */
/* MS0/CLK3 is the source for the SGPIO clock. */
si5351c_configure_multisynth(3, 4608, 0, 1, 1); /* 20MHz */
/* MS4/CLK4 is the source for the LPC43xx microcontroller. */ /* MS4/CLK4 is the source for the LPC43xx microcontroller. */
si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */ si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */
@ -97,18 +178,6 @@ void cpu_clock_init(void)
* CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal) * CLK7 -> LPC4330 (but LPC4330 starts up on its own crystal)
*/ */
/* MS0/CLK0 is the source for the MAX5864/CPLD (CODEC_CLK). */
si5351c_configure_multisynth(0, 4608, 0, 1, 1); /* 10MHz */
/* MS0/CLK1 is the source for the CPLD (CODEC_X2_CLK). */
si5351c_configure_multisynth(1, 4608, 0, 1, 0); /* 20MHz */
/* MS0/CLK2 is the source for SGPIO (CODEC_X2_CLK) */
si5351c_configure_multisynth(2, 4608, 0, 1, 0); /* 20MHz */
/* MS0/CLK3 is the source for the external clock output. */
si5351c_configure_multisynth(3, 4608, 0, 1, 0); /* 20MHz */
/* MS4/CLK4 is the source for the RFFC5071 mixer. */ /* MS4/CLK4 is the source for the RFFC5071 mixer. */
si5351c_configure_multisynth(4, 1536, 0, 1, 0); /* 50MHz */ si5351c_configure_multisynth(4, 1536, 0, 1, 0); /* 50MHz */
@ -119,6 +188,9 @@ void cpu_clock_init(void)
//si5351c_configure_multisynth(7, 8021, 0, 3, 0); /* 12MHz */ //si5351c_configure_multisynth(7, 8021, 0, 3, 0); /* 12MHz */
#endif #endif
/* Set to 10 MHz, the common rate between Jellybean and Jawbreaker. */
sample_rate_set(10000000);
si5351c_configure_clock_control(); si5351c_configure_clock_control();
si5351c_enable_clock_outputs(); si5351c_enable_clock_outputs();

View File

@ -30,6 +30,7 @@ extern "C"
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
/* hardware identification number */ /* hardware identification number */
#define BOARD_ID_JELLYBEAN 0 #define BOARD_ID_JELLYBEAN 0
@ -216,6 +217,8 @@ void pin_setup(void);
void enable_1v8_power(void); void enable_1v8_power(void);
bool sample_rate_set(const uint32_t sampling_rate_hz);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -293,6 +293,22 @@ bool usb_vendor_request_read_si5351c(
} }
} }
bool 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 true;
}
return false;
} else {
return true;
}
}
void usb_vendor_request( void usb_vendor_request(
usb_endpoint_t* const endpoint, usb_endpoint_t* const endpoint,
const usb_transfer_stage_t stage const usb_transfer_stage_t stage
@ -312,6 +328,18 @@ void usb_vendor_request(
success = usb_vendor_request_read_max2837(endpoint, stage); success = usb_vendor_request_read_max2837(endpoint, stage);
break; break;
case 4:
success = usb_vendor_request_write_si5351c(endpoint, stage);
break;
case 5:
success = usb_vendor_request_read_si5351c(endpoint, stage);
break;
case 6:
success = usb_vendor_request_set_sample_rate(endpoint, stage);
break;
default: default:
break; break;
} }

View File

@ -165,6 +165,12 @@ int main(int argc, char** argv) {
signal(SIGINT, sigint_callback_handler); signal(SIGINT, sigint_callback_handler);
result = hackrf_sample_rate_set(device, 10000000);
if( result != HACKRF_SUCCESS ) {
printf("hackrf_sample_rate_set() failed: %s (%d)\n", hackrf_error_name(result), result);
return -1;
}
if( transceiver_mode == TRANSCEIVER_MODE_RX ) { if( transceiver_mode == TRANSCEIVER_MODE_RX ) {
result = hackrf_start_rx(device, rx_callback); result = hackrf_start_rx(device, rx_callback);
} else { } else {

View File

@ -34,6 +34,7 @@ typedef enum {
HACKRF_VENDOR_REQUEST_MAX2837_READ = 3, HACKRF_VENDOR_REQUEST_MAX2837_READ = 3,
HACKRF_VENDOR_REQUEST_SI5351C_WRITE = 4, HACKRF_VENDOR_REQUEST_SI5351C_WRITE = 4,
HACKRF_VENDOR_REQUEST_SI5351C_READ = 5, HACKRF_VENDOR_REQUEST_SI5351C_READ = 5,
HACKRF_VENDOR_REQUEST_SAMPLE_RATE_SET = 6,
} hackrf_vendor_request; } hackrf_vendor_request;
typedef enum { typedef enum {
@ -333,6 +334,25 @@ int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16
} }
} }
int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz) {
int 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;
}
}
static void* transfer_threadproc(void* arg) { static void* transfer_threadproc(void* arg) {
hackrf_device* device = (hackrf_device*)arg; hackrf_device* device = (hackrf_device*)arg;

View File

@ -53,8 +53,6 @@ int hackrf_exit();
int hackrf_open(hackrf_device** device); int hackrf_open(hackrf_device** device);
int hackrf_close(hackrf_device* device); int hackrf_close(hackrf_device* device);
//int hackrf_set_sampling_rate(float sampling_rate_hz);
int hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback); int hackrf_start_rx(hackrf_device* device, hackrf_sample_block_cb_fn callback);
int hackrf_stop_rx(hackrf_device* device); int hackrf_stop_rx(hackrf_device* device);
@ -69,6 +67,8 @@ int hackrf_max2837_write(hackrf_device* device, uint8_t register_number, uint16_
int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value); int hackrf_si5351c_read(hackrf_device* device, uint16_t register_number, uint16_t* value);
int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value); int hackrf_si5351c_write(hackrf_device* device, uint16_t register_number, uint16_t value);
int hackrf_sample_rate_set(hackrf_device* device, const uint32_t sampling_rate_hz);
const char* hackrf_error_name(enum hackrf_error errcode); const char* hackrf_error_name(enum hackrf_error errcode);
#endif//__HACKRF_H__ #endif//__HACKRF_H__