diff --git a/firmware/hackrf_usb/hackrf_usb.c b/firmware/hackrf_usb/hackrf_usb.c index a8adf401..f7d4597b 100644 --- a/firmware/hackrf_usb/hackrf_usb.c +++ b/firmware/hackrf_usb/hackrf_usb.c @@ -150,6 +150,7 @@ static usb_request_handler_fn vendor_request_handler[] = { #endif usb_vendor_request_read_selftest, usb_vendor_request_adc_read, + usb_vendor_request_test_rtc_osc, }; static const uint32_t vendor_request_handler_count = diff --git a/firmware/hackrf_usb/usb_api_selftest.c b/firmware/hackrf_usb/usb_api_selftest.c index 29cbc8a1..56932794 100644 --- a/firmware/hackrf_usb/usb_api_selftest.c +++ b/firmware/hackrf_usb/usb_api_selftest.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "usb_api_selftest.h" #include "selftest.h" #include "platform_detect.h" @@ -122,3 +124,61 @@ usb_request_status_t usb_vendor_request_read_selftest( return USB_REQUEST_STATUS_OK; } } + +usb_request_status_t usb_vendor_request_test_rtc_osc( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage) +{ + uint16_t count; + if (stage == USB_TRANSFER_STAGE_SETUP) { + enum { + START_32KHZ_OSCILLATOR, + START_FREQ_MONITOR, + READ_FREQ_MONITOR, + STOP_32KHZ_OSCILLATOR, + } step = endpoint->setup.index; + + switch (step) { + case START_32KHZ_OSCILLATOR: + // Enable 32kHz oscillator + CREG_CREG0 &= ~(CREG_CREG0_PD32KHZ | CREG_CREG0_RESET32KHZ); + CREG_CREG0 |= CREG_CREG0_EN32KHZ; + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + case START_FREQ_MONITOR: + // Start counting cycles with frequency monitor + CGU_FREQ_MON = CGU_FREQ_MON_RCNT(511) | + CGU_FREQ_MON_CLK_SEL(CGU_SRC_32K); + CGU_FREQ_MON |= CGU_FREQ_MON_MEAS_MASK; + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + case READ_FREQ_MONITOR: + if (~(CGU_FREQ_MON & CGU_FREQ_MON_MEAS_MASK)) { + // Measurement completed. + count = (CGU_FREQ_MON & CGU_FREQ_MON_FCNT_MASK) >> + CGU_FREQ_MON_FCNT_SHIFT; + } else { + // Measurement failed to complete. + count = 0; + } + usb_transfer_schedule_block( + endpoint->in, + &count, + sizeof(count), + NULL, + NULL); + usb_transfer_schedule_ack(endpoint->out); + return USB_REQUEST_STATUS_OK; + case STOP_32KHZ_OSCILLATOR: + // Disable 32kHz oscillator + CREG_CREG0 &= ~CREG_CREG0_EN32KHZ; + CREG_CREG0 |= (CREG_CREG0_PD32KHZ | CREG_CREG0_RESET32KHZ); + usb_transfer_schedule_ack(endpoint->in); + return USB_REQUEST_STATUS_OK; + default: + return USB_REQUEST_STATUS_STALL; + } + } else { + return USB_REQUEST_STATUS_OK; + } +} diff --git a/firmware/hackrf_usb/usb_api_selftest.h b/firmware/hackrf_usb/usb_api_selftest.h index a2f38816..453d0362 100644 --- a/firmware/hackrf_usb/usb_api_selftest.h +++ b/firmware/hackrf_usb/usb_api_selftest.h @@ -29,4 +29,8 @@ usb_request_status_t usb_vendor_request_read_selftest( usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage); +usb_request_status_t usb_vendor_request_test_rtc_osc( + usb_endpoint_t* const endpoint, + const usb_transfer_stage_t stage); + #endif // __USB_API_SELFTEST_H diff --git a/host/hackrf-tools/src/hackrf_debug.c b/host/hackrf-tools/src/hackrf_debug.c index b1977f8d..7f6a7293 100644 --- a/host/hackrf-tools/src/hackrf_debug.c +++ b/host/hackrf-tools/src/hackrf_debug.c @@ -609,6 +609,7 @@ static struct option long_options[] = { {"ui", required_argument, 0, 'u'}, {"leds", required_argument, 0, 'l'}, {"selftest", no_argument, 0, 't'}, + {"rtc-osc", no_argument, 0, 'o'}, {"adc", required_argument, 0, 'a'}, {0, 0, 0, 0}, }; @@ -647,6 +648,7 @@ int main(int argc, char** argv) bool set_narrowband = false; bool set_fpga_bitstream = false; bool read_selftest = false; + bool test_rtc_osc = false; bool read_adc = false; int result = hackrf_init(); @@ -660,7 +662,7 @@ int main(int argc, char** argv) while ((opt = getopt_long( argc, argv, - "n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:ta:", + "n:rw:d:cmsfg1:2:C:N:P:ST:R:h?u:l:ta:o", long_options, &option_index)) != EOF) { switch (opt) { @@ -767,6 +769,9 @@ int main(int argc, char** argv) case 't': read_selftest = true; break; + case 'o': + test_rtc_osc = true; + break; case 'a': read_adc = true; @@ -812,7 +817,8 @@ int main(int argc, char** argv) if (!(write || read || dump_config || dump_state || set_tx_limit || set_rx_limit || set_ui || set_leds || set_p1 || set_p2 || set_clkin || - set_narrowband || set_fpga_bitstream || read_selftest || read_adc)) { + set_narrowband || set_fpga_bitstream || read_selftest || test_rtc_osc || + read_adc)) { fprintf(stderr, "Specify read, write, or config option.\n"); usage(); return EXIT_FAILURE; @@ -820,7 +826,8 @@ int main(int argc, char** argv) if (part == PART_NONE && !set_ui && !dump_state && !set_tx_limit && !set_rx_limit && !set_leds && !set_p1 && !set_p2 && !set_clkin && - !set_narrowband && !set_fpga_bitstream && !read_selftest && !read_adc) { + !set_narrowband && !set_fpga_bitstream && !read_selftest && !test_rtc_osc && + !read_adc) { fprintf(stderr, "Specify a part to read, write, or print config from.\n"); usage(); return EXIT_FAILURE; @@ -973,6 +980,18 @@ int main(int argc, char** argv) printf("%s", selftest.msg); } + if (test_rtc_osc) { + bool pass; + result = hackrf_test_rtc_osc(device, &pass); + if (result != HACKRF_SUCCESS) { + printf("hackrf_test_rtc_osc() failed: %s (%d)\n", + hackrf_error_name(result), + result); + return EXIT_FAILURE; + } + printf("RTC test result: %s\n", pass ? "PASS" : "FAIL"); + } + if (read_adc) { uint16_t value; result = hackrf_read_adc(device, adc_channel, &value); diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 77f055a5..ff0ee32e 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -110,6 +110,7 @@ typedef enum { HACKRF_VENDOR_REQUEST_CLKIN_CTRL = 55, HACKRF_VENDOR_REQUEST_READ_SELFTEST = 56, HACKRF_VENDOR_REQUEST_READ_ADC = 57, + HACKRF_VENDOR_REQUEST_TEST_RTC_OSC = 58, } hackrf_vendor_request; #define USB_CONFIG_STANDARD 0x1 @@ -1245,6 +1246,110 @@ int ADDCALL hackrf_read_selftest(hackrf_device* device, hackrf_selftest* selftes } } +int ADDCALL hackrf_test_rtc_osc(hackrf_device* device, bool* pass) +{ + USB_API_REQUIRED(device, 0x0109); + + int result; + + enum { + START_32KHZ_OSCILLATOR, + START_FREQ_MONITOR, + READ_FREQ_MONITOR, + STOP_32KHZ_OSCILLATOR, + } step; + + // Enable 32kHz oscillator + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_TEST_RTC_OSC, + 0, + START_32KHZ_OSCILLATOR, + NULL, + 0, + 1000); + + if (result < 0) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } + +// Wait 1s for oscillator startup +#ifdef _WIN32 + Sleep(1000); +#else + usleep(1000000); +#endif + + // Start frequency monitor + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_TEST_RTC_OSC, + 0, + START_FREQ_MONITOR, + NULL, + 0, + 1000); + + if (result < 0) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } + +// Wait for frequency monitor result +#ifdef _WIN32 + Sleep(1); +#else + usleep(1000); +#endif + + // Read frequency monitor result + uint16_t count = 0; + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_TEST_RTC_OSC, + 0, + READ_FREQ_MONITOR, + (unsigned char*) &count, + sizeof(count), + 1000); + + if (result < sizeof(count)) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } + + if (count == 1) { + // Disable 32kHz oscillator + result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_TEST_RTC_OSC, + 0, + STOP_32KHZ_OSCILLATOR, + NULL, + 0, + 1000); + + if (result < 0) { + last_libusb_error = result; + return HACKRF_ERROR_LIBUSB; + } + + *pass = true; + } else { + *pass = false; + } + + return HACKRF_SUCCESS; +} + int ADDCALL hackrf_read_adc(hackrf_device* device, uint8_t adc_channel, uint16_t* value) { USB_API_REQUIRED(device, 0x0109); diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index 10c51ee4..ba70ec78 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -1354,6 +1354,16 @@ extern ADDAPI int ADDCALL hackrf_read_selftest( hackrf_device* device, hackrf_selftest* value); +/** + * Test the RTC oscillator on the device + * + * @param[in] device device to query + * @param[out] pass RTC oscillator test result + * @return @ref HACKRF_SUCCESS on success or @ref hackrf_error variant + * @ingroup debug + */ +extern ADDAPI int ADDCALL hackrf_test_rtc_osc(hackrf_device* device, bool* pass); + /** * Read a value from an ADC channel *