Merge pull request #546 from dominicgs/operacake_gpio
HackRF Opera Cake - GPIO test mode
This commit is contained in:
@ -21,7 +21,13 @@
|
||||
|
||||
#include "operacake.h"
|
||||
#include "hackrf_core.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_lpc.h"
|
||||
#include <libopencm3/lpc43xx/scu.h>
|
||||
|
||||
/*
|
||||
* I2C Mode
|
||||
*/
|
||||
#define OPERACAKE_PIN_OE(x) (x<<7)
|
||||
#define OPERACAKE_PIN_U2CTRL1(x) (x<<6)
|
||||
#define OPERACAKE_PIN_U2CTRL0(x) (x<<5)
|
||||
@ -44,7 +50,7 @@
|
||||
#define OPERACAKE_SAMESIDE OPERACAKE_PIN_U1CTRL(1)
|
||||
#define OPERACAKE_CROSSOVER OPERACAKE_PIN_U1CTRL(0)
|
||||
#define OPERACAKE_EN_LEDS (OPERACAKE_PIN_LEDEN2(1) | OPERACAKE_PIN_LEDEN2(0))
|
||||
#define OPERACAKE_GPIO_EN OPERACAKE_PIN_OE(0)
|
||||
#define OPERACAKE_GPIO_ENABLE OPERACAKE_PIN_OE(0)
|
||||
#define OPERACAKE_GPIO_DISABLE OPERACAKE_PIN_OE(1)
|
||||
|
||||
#define OPERACAKE_REG_INPUT 0x00
|
||||
@ -56,6 +62,10 @@
|
||||
| OPERACAKE_PORT_A1 | OPERACAKE_PORT_B1 \
|
||||
| OPERACAKE_EN_LEDS)
|
||||
#define OPERACAKE_CONFIG_ALL_OUTPUT (0x00)
|
||||
// Leave LED bits as outputs
|
||||
#define OPERACAKE_CONFIG_GPIO_INPUTS (0x7C)
|
||||
|
||||
#define OPERACAKE_POLARITY_NORMAL (0x00)
|
||||
|
||||
#define OPERACAKE_DEFAULT_ADDRESS 0x18
|
||||
|
||||
@ -145,6 +155,9 @@ uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opera Glasses
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t freq_min;
|
||||
uint16_t freq_max;
|
||||
@ -194,3 +207,82 @@ uint8_t operacake_set_range(uint32_t freq_mhz) {
|
||||
current_range = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPIO
|
||||
*/
|
||||
uint16_t gpio_test(uint8_t address)
|
||||
{
|
||||
uint8_t i, reg, bit_mask, gpio_mask = 0x1F;
|
||||
uint16_t result = 0;
|
||||
operacake_init();
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_8, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_12, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_13, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_14, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
scu_pinmux(SCU_PINMUX_GPIO3_15, SCU_GPIO_FAST | SCU_CONF_FUNCTION0);
|
||||
|
||||
static struct gpio_t gpio_pins[] = {
|
||||
GPIO(3, 8), // u1ctrl IO2
|
||||
GPIO(3, 14), // u3ctrl0 IO3
|
||||
GPIO(3, 15), // u3ctrl1 IO4
|
||||
GPIO(3, 12), // u2ctrl0 IO5
|
||||
GPIO(3, 13) // u2ctrl1 IO6
|
||||
};
|
||||
// Setup I2C to put it in GPIO mode
|
||||
reg = (OPERACAKE_GPIO_ENABLE | OPERACAKE_EN_LEDS);
|
||||
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT, reg);
|
||||
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG,
|
||||
OPERACAKE_CONFIG_GPIO_INPUTS);
|
||||
operacake_write_reg(oc_bus, address, OPERACAKE_REG_POLARITY,
|
||||
OPERACAKE_POLARITY_NORMAL);
|
||||
// clear state
|
||||
for(i=0; i<5; i++) {
|
||||
gpio_output(&gpio_pins[i]);
|
||||
gpio_write(&gpio_pins[i], 0);
|
||||
}
|
||||
// Test each pin separately
|
||||
for(i=0; i<5; i++) {
|
||||
// Set pin high
|
||||
gpio_write(&gpio_pins[i], 1);
|
||||
// check input
|
||||
reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT);
|
||||
reg >>= 2;
|
||||
reg &= gpio_mask;
|
||||
bit_mask = 1 << i;
|
||||
result <<= 1;
|
||||
if(!(reg & bit_mask)) {
|
||||
// Is the correct bit set?
|
||||
result |= 1;
|
||||
}
|
||||
result <<= 1;
|
||||
if(reg & ~bit_mask) {
|
||||
// Are any other bits set?
|
||||
result |= 1;
|
||||
}
|
||||
result <<= 1;
|
||||
// set pin low
|
||||
gpio_write(&gpio_pins[i], 0);
|
||||
// check input
|
||||
reg = operacake_read_reg(oc_bus, address, OPERACAKE_REG_INPUT);
|
||||
reg >>= 2;
|
||||
reg &= gpio_mask;
|
||||
bit_mask = 1 << i;
|
||||
if(reg & bit_mask) {
|
||||
// Is the correct bit clear?
|
||||
result |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
for(i=0; i<5; i++) {
|
||||
gpio_input(&gpio_pins[i]);
|
||||
}
|
||||
|
||||
// Put it back in to I2C mode and set default pins
|
||||
operacake_write_reg(oc_bus, address, OPERACAKE_REG_CONFIG,
|
||||
OPERACAKE_CONFIG_ALL_OUTPUT);
|
||||
operacake_write_reg(oc_bus, address, OPERACAKE_REG_OUTPUT,
|
||||
OPERACAKE_DEFAULT_OUTPUT);
|
||||
return result;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ uint8_t operacake_init(void);
|
||||
uint8_t operacake_set_ports(uint8_t address, uint8_t PA, uint8_t PB);
|
||||
uint8_t operacake_add_range(uint16_t freq_min, uint16_t freq_max, uint8_t port);
|
||||
uint8_t operacake_set_range(uint32_t freq_mhz);
|
||||
uint16_t gpio_test(uint8_t address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ static const usb_request_handler_fn vendor_request_handler[] = {
|
||||
usb_vendor_request_operacake_set_ranges,
|
||||
usb_vendor_request_set_clkout_enable,
|
||||
usb_vendor_request_spiflash_status,
|
||||
usb_vendor_request_spiflash_clear_status
|
||||
usb_vendor_request_spiflash_clear_status,
|
||||
usb_vendor_request_operacake_gpio_test
|
||||
};
|
||||
|
||||
static const uint32_t vendor_request_handler_count =
|
||||
|
@ -74,3 +74,18 @@ usb_request_status_t usb_vendor_request_operacake_set_ranges(
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
||||
usb_request_status_t usb_vendor_request_operacake_gpio_test(
|
||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage)
|
||||
{
|
||||
uint16_t test_result;
|
||||
uint8_t address = endpoint->setup.value & 0xFF;
|
||||
if (stage == USB_TRANSFER_STAGE_SETUP) {
|
||||
test_result = gpio_test(address);
|
||||
endpoint->buffer[0] = test_result & 0xff;
|
||||
endpoint->buffer[1] = test_result >> 8;
|
||||
usb_transfer_schedule_block(endpoint->in, &endpoint->buffer, 2, NULL, NULL);
|
||||
usb_transfer_schedule_ack(endpoint->out);
|
||||
}
|
||||
return USB_REQUEST_STATUS_OK;
|
||||
}
|
||||
|
@ -34,4 +34,7 @@ usb_request_status_t usb_vendor_request_operacake_set_ports(
|
||||
usb_request_status_t usb_vendor_request_operacake_set_ranges(
|
||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
|
||||
usb_request_status_t usb_vendor_request_operacake_gpio_test(
|
||||
usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage);
|
||||
|
||||
#endif /* end of include guard: __USB_API_OPERACAKE_H__ */
|
||||
|
@ -36,6 +36,9 @@ typedef int bool;
|
||||
#define FREQ_MAX_MHZ (7250) /* 7250 MHz */
|
||||
#define MAX_FREQ_RANGES 8
|
||||
|
||||
#define INVALID_ADDRESS 0xFF
|
||||
#define INVALID_PORT 0xFF
|
||||
|
||||
static void usage() {
|
||||
printf("\nUsage:\n");
|
||||
printf("\t-h, --help: this help\n");
|
||||
@ -45,12 +48,14 @@ static void usage() {
|
||||
printf("\t-b <n>: set port B connection\n");
|
||||
printf("\t-f <min:max:port>: automatically assign <port> for range <min:max> in MHz\n");
|
||||
printf("\t-l, --list: list available operacake boards\n");
|
||||
printf("\t-g, --gpio_test: test GPIO functionality of an opera cake\n");
|
||||
}
|
||||
|
||||
static struct option long_options[] = {
|
||||
{ "device", no_argument, 0, 'd' },
|
||||
{ "address", no_argument, 0, 'o' },
|
||||
{ "list", no_argument, 0, 'l' },
|
||||
{ "gpio_test", no_argument, 0, 'g' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 },
|
||||
};
|
||||
@ -135,11 +140,12 @@ int parse_range(char* s, hackrf_oc_range* range) {
|
||||
int main(int argc, char** argv) {
|
||||
int opt;
|
||||
const char* serial_number = NULL;
|
||||
uint8_t operacake_address = 0;
|
||||
uint8_t port_a = 0;
|
||||
uint8_t port_b = 0;
|
||||
uint8_t operacake_address = INVALID_ADDRESS;
|
||||
uint8_t port_a = INVALID_PORT;
|
||||
uint8_t port_b = INVALID_PORT;
|
||||
bool set_ports = false;
|
||||
bool list = false;
|
||||
bool gpio_test = false;
|
||||
uint8_t operacakes[8];
|
||||
uint8_t operacake_count = 0;
|
||||
int i = 0;
|
||||
@ -154,7 +160,7 @@ int main(int argc, char** argv) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:h?", long_options, &option_index)) != EOF ) {
|
||||
while( (opt = getopt_long(argc, argv, "d:o:a:b:lf:hg?", long_options, &option_index)) != EOF ) {
|
||||
switch( opt ) {
|
||||
case 'd':
|
||||
serial_number = optarg;
|
||||
@ -162,7 +168,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
case 'o':
|
||||
operacake_address = atoi(optarg);
|
||||
set_ports = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
@ -200,6 +205,7 @@ int main(int argc, char** argv) {
|
||||
fprintf(stderr, "failed to parse port\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
set_ports = true;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
@ -208,11 +214,17 @@ int main(int argc, char** argv) {
|
||||
fprintf(stderr, "failed to parse port\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
set_ports = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
list = true;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
gpio_test = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case '?':
|
||||
usage();
|
||||
@ -225,8 +237,14 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!(list || set_ports || range_idx)) {
|
||||
fprintf(stderr, "Specify either list or address option.\n");
|
||||
if(!(list || set_ports || range_idx || gpio_test)) {
|
||||
fprintf(stderr, "Specify either list, address, or GPIO test option.\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if((set_ports || gpio_test) && (operacake_address == INVALID_ADDRESS)) {
|
||||
fprintf(stderr, "An address is required.\n");
|
||||
usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@ -257,7 +275,69 @@ int main(int argc, char** argv) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(gpio_test) {
|
||||
uint16_t test_result;
|
||||
uint8_t reg, mask = 0x7;
|
||||
result = hackrf_operacake_gpio_test(device, operacake_address, &test_result);
|
||||
if (result != HACKRF_SUCCESS) {
|
||||
fprintf(stderr, "hackrf_operacake_gpio_test() failed: %s (%d)\n",
|
||||
hackrf_error_name(result), result);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(test_result) {
|
||||
fprintf(stderr, "GPIO test failed\n");
|
||||
fprintf(stderr, "Pin\tHigh\tShorts\tLow\n");
|
||||
reg = test_result & mask;
|
||||
fprintf(stderr, "u2ctrl1\t%d\t%d\t%d\n",
|
||||
(reg>>2) & 1,
|
||||
(reg>>1) & 1,
|
||||
reg & 1);
|
||||
test_result >>= 3;
|
||||
reg = test_result & mask;
|
||||
fprintf(stderr, "u2ctrl0\t%d\t%d\t%d\n",
|
||||
(reg>>2) & 1,
|
||||
(reg>>1) & 1,
|
||||
reg & 1);
|
||||
test_result >>= 3;
|
||||
reg = test_result & mask;
|
||||
fprintf(stderr, "u3ctrl1\t%d\t%d\t%d\n",
|
||||
(reg>>2) & 1,
|
||||
(reg>>1) & 1,
|
||||
reg & 1);
|
||||
test_result >>= 3;
|
||||
reg = test_result & mask;
|
||||
fprintf(stderr, "u3ctrl0\t%d\t%d\t%d\n",
|
||||
(reg>>2) & 1,
|
||||
(reg>>1) & 1,
|
||||
reg & 1);
|
||||
test_result >>= 3;
|
||||
reg = test_result & mask;
|
||||
fprintf(stderr, "u1ctrl \t%d\t%d\t%d\n",
|
||||
(reg>>2) & 1,
|
||||
(reg>>1) & 1,
|
||||
reg & 1);
|
||||
} else {
|
||||
fprintf(stderr, "GPIO test passed\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(set_ports) {
|
||||
// Set other port to "don't care" if not set
|
||||
if(port_a == INVALID_PORT) {
|
||||
if(port_b >= 4) {
|
||||
port_a = 0;
|
||||
} else {
|
||||
port_a = 4;
|
||||
}
|
||||
}
|
||||
if(port_b == INVALID_PORT) {
|
||||
if(port_a >= 4) {
|
||||
port_b = 0;
|
||||
} else {
|
||||
port_b = 4;
|
||||
}
|
||||
}
|
||||
if(((port_a<=3) && (port_b<=3)) || ((port_a>=4) && (port_b>=4))) {
|
||||
fprintf(stderr, "Port A and B cannot be connected to the same side\n");
|
||||
return EXIT_FAILURE;
|
||||
|
@ -83,6 +83,7 @@ typedef enum {
|
||||
HACKRF_VENDOR_REQUEST_CLKOUT_ENABLE = 32,
|
||||
HACKRF_VENDOR_REQUEST_SPIFLASH_STATUS = 33,
|
||||
HACKRF_VENDOR_REQUEST_SPIFLASH_CLEAR_STATUS = 34,
|
||||
HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST = 35,
|
||||
} hackrf_vendor_request;
|
||||
|
||||
#define USB_CONFIG_STANDARD 0x1
|
||||
@ -2080,6 +2081,30 @@ int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device, const uint8_t address,
|
||||
uint16_t* test_result)
|
||||
{
|
||||
USB_API_REQUIRED(device, 0x0103)
|
||||
int result;
|
||||
result = libusb_control_transfer(
|
||||
device->usb_device,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
|
||||
HACKRF_VENDOR_REQUEST_OPERACAKE_GPIO_TEST,
|
||||
address,
|
||||
0,
|
||||
(unsigned char*)test_result,
|
||||
2,
|
||||
0
|
||||
);
|
||||
|
||||
if (result < 1) {
|
||||
last_libusb_error = result;
|
||||
return HACKRF_ERROR_LIBUSB;
|
||||
} else {
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
@ -251,6 +251,10 @@ extern ADDAPI int ADDCALL hackrf_set_operacake_ranges(hackrf_device* device,
|
||||
|
||||
extern ADDAPI int ADDCALL hackrf_set_clkout_enable(hackrf_device* device, const uint8_t value);
|
||||
|
||||
extern ADDAPI int ADDCALL hackrf_operacake_gpio_test(hackrf_device* device,
|
||||
uint8_t address,
|
||||
uint16_t* test_result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user