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:
@ -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();
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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__
|
||||||
|
Reference in New Issue
Block a user