aboutsummaryrefslogtreecommitdiffstats
path: root/ni845x_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ni845x_spi.c')
-rw-r--r--ni845x_spi.c269
1 files changed, 131 insertions, 138 deletions
diff --git a/ni845x_spi.c b/ni845x_spi.c
index 7b2bea3e..253025f0 100644
--- a/ni845x_spi.c
+++ b/ni845x_spi.c
@@ -40,8 +40,6 @@ enum voltage_coerce_mode {
USE_HIGHER
};
-static const struct spi_master spi_programmer_ni845x;
-
static unsigned char CS_number; // use chip select 0 as default
static enum USB845x_type device_pid = Unknown_NI845X_Device;
@@ -50,10 +48,6 @@ static NiHandle configuration_handle;
static uint16_t io_voltage_in_mV;
static bool ignore_io_voltage_limits;
-static int ni845x_spi_shutdown(void *data);
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle);
-static void ni845x_spi_print_available_devices(void);
-
// USB-8452 supported voltages, keep this array in ascending order!
static const uint8_t usb8452_io_voltages_in_100mV[5] = {
kNi845x12Volts,
@@ -129,8 +123,30 @@ static void ni845x_report_warning(const char *const func, const int32 err)
}
/**
+ * @brief ni845x_spi_open_resource
+ * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
+ * @param opened_handle the opened handle from the ni845xOpen
+ * @return the 0 on successful competition, negative error code on failure positive code on warning
+ */
+static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle)
+{
+ // NI-845x driver loads the FPGA bitfile at the first time
+ // which can take couple seconds
+ if (device_pid == USB8452)
+ msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
+
+ int32 tmp = ni845xOpen(resource_handle, opened_handle);
+
+ if (tmp < 0)
+ ni845x_report_error("ni845xOpen", tmp);
+ else if (tmp > 0)
+ ni845x_report_warning("ni845xOpen", tmp);
+ return tmp;
+}
+
+/**
* @param serial a null terminated string containing the serial number of the specific device or NULL
- * @return the 0 on successful completition, negative error code on failure
+ * @return the 0 on successful completion, negative error code on failure
*/
static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
{
@@ -145,7 +161,7 @@ static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
tmp = ni845xFindDevice(resource_name, &device_find_handle, &found_devices_count);
if (tmp != 0) {
- // supress warning if no device found
+ // suppress warning if no device found
if (tmp != NI845x_FIND_DEVICE_NO_DEVICE_FOUND)
ni845x_report_error("ni845xFindDevice", tmp);
return -1;
@@ -194,33 +210,11 @@ _close_ret:
}
/**
- * @brief ni845x_spi_open_resource
- * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
- * @param opened_handle the opened handle from the ni845xOpen
- * @return the 0 on successful competition, negative error code on failure positive code on warning
- */
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle)
-{
- // NI-845x driver loads the FPGA bitfile at the first time
- // which can take couple seconds
- if (device_pid == USB8452)
- msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
-
- int32 tmp = ni845xOpen(resource_handle, opened_handle);
-
- if (tmp < 0)
- ni845x_report_error("ni845xOpen", tmp);
- else if (tmp > 0)
- ni845x_report_warning("ni845xOpen", tmp);
- return tmp;
-}
-
-/**
* @brief usb8452_spi_set_io_voltage sets the IO voltage for the USB-8452 devices
* @param requested_io_voltage_mV the desired IO voltage in mVolts
* @param set_io_voltage_mV the IO voltage which was set in mVolts
* @param coerce_mode if set to USE_LOWER the closest supported IO voltage which is lower or equal to
- * the requested_io_voltage_mV will be selected. Otherwise the next closest supported voltage will be choosen
+ * the requested_io_voltage_mV will be selected. Otherwise the next closest supported voltage will be chosen
* which is higher or equal to the requested_io_voltage_mV.
* @return 0 on success, negative on error, positive on warning
*/
@@ -346,7 +340,7 @@ static void ni845x_spi_print_available_devices(void)
tmp = ni845xFindDevice(resource_handle, &device_find_handle, &found_devices_count);
if (tmp != 0) {
- // supress warning if no device found
+ // suppress warning if no device found
if (tmp != NI845x_FIND_DEVICE_NO_DEVICE_FOUND)
ni845x_report_error("ni845xFindDevice", tmp);
return;
@@ -389,103 +383,6 @@ static void ni845x_spi_print_available_devices(void)
ni845x_report_error("ni845xCloseFindDeviceHandle", tmp);
}
-int ni845x_spi_init(void)
-{
- char *speed_str = NULL;
- char *CS_str = NULL;
- char *voltage = NULL;
- char *endptr = NULL;
- int requested_io_voltage_mV = 1200; // default the IO voltage to 1.2V
- int spi_speed_KHz = 1000; // selecting 1 MHz SCK is a good bet
- char *serial_number = NULL; // by default open the first connected device
- char *ignore_io_voltage_limits_str = NULL;
- int32 tmp = 0;
-
- // read the cs parameter (which Chip select should we use)
- CS_str = extract_programmer_param("cs");
- if (CS_str) {
- CS_number = CS_str[0] - '0';
- free(CS_str);
- if (strlen(CS_str) > 1 || CS_number < 0 || 7 < CS_number) {
- msg_perr("Only CS 0-7 supported\n");
- return 1;
- }
- }
-
- voltage = extract_programmer_param("voltage");
- if (voltage != NULL) {
- requested_io_voltage_mV = parse_voltage(voltage);
- free(voltage);
- if (requested_io_voltage_mV < 0)
- return 1;
- }
-
- serial_number = extract_programmer_param("serial");
-
- speed_str = extract_programmer_param("spispeed");
- if (speed_str) {
- spi_speed_KHz = strtoul(speed_str, &endptr, 0);
- if (*endptr) {
- msg_perr("The spispeed parameter passed with invalid format: %s\n",
- speed_str);
- msg_perr("Please pass the parameter with a simple number in kHz\n");
- return 1;
- }
- free(speed_str);
- }
-
- ignore_io_voltage_limits = false;
- ignore_io_voltage_limits_str = extract_programmer_param("ignore_io_voltage_limits");
- if (ignore_io_voltage_limits_str
- && strcmp(ignore_io_voltage_limits_str, "yes") == 0) {
- ignore_io_voltage_limits = true;
- }
-
- if (ni845x_spi_open(serial_number, &device_handle)) {
- if (serial_number) {
- msg_pinfo("Could not find any connected NI USB-8451/8452 with serialnumber: %s!\n",
- serial_number);
- ni845x_spi_print_available_devices();
- msg_pinfo("Check the S/N field on the bottom of the device,\n"
- "or use 'lsusb -v -d 3923:7166 | grep Serial' for USB-8451\n"
- "or 'lsusb -v -d 3923:7514 | grep Serial' for USB-8452\n");
- free(serial_number);
- } else {
- msg_pinfo("Could not find any connected NI USB-845x device!\n");
- }
- return 1;
- }
- free(serial_number);
-
- // open the SPI config handle
- tmp = ni845xSpiConfigurationOpen(&configuration_handle);
- if (tmp != 0) {
- ni845x_report_error("ni845xSpiConfigurationOpen", tmp);
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- if (usb8452_spi_set_io_voltage(requested_io_voltage_mV, &io_voltage_in_mV, USE_LOWER) < 0) {
- ni845x_spi_shutdown(NULL);
- return 1; // no alert here usb8452_spi_set_io_voltage already printed that
- }
-
- if (ni845x_spi_set_speed(spi_speed_KHz)) {
- msg_perr("Unable to set SPI speed\n");
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- if (register_shutdown(ni845x_spi_shutdown, NULL)) {
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- register_spi_master(&spi_programmer_ni845x);
-
- return 0;
-}
-
static int ni845x_spi_shutdown(void *data)
{
int32 ret = 0;
@@ -583,7 +480,7 @@ static int ni845x_spi_io_voltage_check(const struct flashctx *flash)
return 0;
}
-static int ni845x_spi_transmit(struct flashctx *flash,
+static int ni845x_spi_transmit(const struct flashctx *flash,
unsigned int write_cnt,
unsigned int read_cnt,
const unsigned char *write_arr,
@@ -620,7 +517,7 @@ static int ni845x_spi_transmit(struct flashctx *flash,
if (read_cnt != 0 && read_arr != NULL) {
if ((read_cnt + write_cnt) != read_size) {
- msg_perr("%s: expected and returned read count mismatch: %u expected, %ld recieved\n",
+ msg_perr("%s: expected and returned read count mismatch: %u expected, %ld received\n",
__func__, read_cnt, read_size);
free(transfer_buffer);
return -1;
@@ -632,11 +529,107 @@ static int ni845x_spi_transmit(struct flashctx *flash,
}
static const struct spi_master spi_programmer_ni845x = {
- .max_data_read = MAX_DATA_READ_UNLIMITED,
- .max_data_write = MAX_DATA_WRITE_UNLIMITED,
- .command = ni845x_spi_transmit,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+ .command = ni845x_spi_transmit,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = ni845x_spi_shutdown,
+};
+
+static int ni845x_spi_init(const struct programmer_cfg *cfg)
+{
+ char *speed_str = NULL;
+ char *CS_str = NULL;
+ char *voltage = NULL;
+ char *endptr = NULL;
+ int requested_io_voltage_mV = 1200; // default the IO voltage to 1.2V
+ int spi_speed_KHz = 1000; // selecting 1 MHz SCK is a good bet
+ char *serial_number = NULL; // by default open the first connected device
+ char *ignore_io_voltage_limits_str = NULL;
+ int32 tmp = 0;
+
+ // read the cs parameter (which Chip select should we use)
+ CS_str = extract_programmer_param_str(cfg, "cs");
+ if (CS_str) {
+ CS_number = CS_str[0] - '0';
+ free(CS_str);
+ if (strlen(CS_str) > 1 || CS_number < 0 || 7 < CS_number) {
+ msg_perr("Only CS 0-7 supported\n");
+ return 1;
+ }
+ }
+
+ voltage = extract_programmer_param_str(cfg, "voltage");
+ if (voltage != NULL) {
+ requested_io_voltage_mV = parse_voltage(voltage);
+ free(voltage);
+ if (requested_io_voltage_mV < 0)
+ return 1;
+ }
+
+ serial_number = extract_programmer_param_str(cfg, "serial");
+
+ speed_str = extract_programmer_param_str(cfg, "spispeed");
+ if (speed_str) {
+ spi_speed_KHz = strtoul(speed_str, &endptr, 0);
+ if (*endptr) {
+ msg_perr("The spispeed parameter passed with invalid format: %s\n",
+ speed_str);
+ msg_perr("Please pass the parameter with a simple number in kHz\n");
+ return 1;
+ }
+ free(speed_str);
+ }
+
+ ignore_io_voltage_limits = false;
+ ignore_io_voltage_limits_str = extract_programmer_param_str(cfg, "ignore_io_voltage_limits");
+ if (ignore_io_voltage_limits_str
+ && strcmp(ignore_io_voltage_limits_str, "yes") == 0) {
+ ignore_io_voltage_limits = true;
+ }
+
+ if (ni845x_spi_open(serial_number, &device_handle)) {
+ if (serial_number) {
+ msg_pinfo("Could not find any connected NI USB-8451/8452 with serialnumber: %s!\n",
+ serial_number);
+ ni845x_spi_print_available_devices();
+ msg_pinfo("Check the S/N field on the bottom of the device,\n"
+ "or use 'lsusb -v -d 3923:7166 | grep Serial' for USB-8451\n"
+ "or 'lsusb -v -d 3923:7514 | grep Serial' for USB-8452\n");
+ free(serial_number);
+ } else {
+ msg_pinfo("Could not find any connected NI USB-845x device!\n");
+ }
+ return 1;
+ }
+ free(serial_number);
+
+ // open the SPI config handle
+ tmp = ni845xSpiConfigurationOpen(&configuration_handle);
+ if (tmp != 0) {
+ ni845x_report_error("ni845xSpiConfigurationOpen", tmp);
+ ni845x_spi_shutdown(NULL);
+ return 1;
+ }
+
+ if (usb8452_spi_set_io_voltage(requested_io_voltage_mV, &io_voltage_in_mV, USE_LOWER) < 0) {
+ ni845x_spi_shutdown(NULL);
+ return 1; // no alert here usb8452_spi_set_io_voltage already printed that
+ }
+
+ if (ni845x_spi_set_speed(spi_speed_KHz)) {
+ msg_perr("Unable to set SPI speed\n");
+ ni845x_spi_shutdown(NULL);
+ return 1;
+ }
+
+ return register_spi_master(&spi_programmer_ni845x, NULL);
+}
+
+const struct programmer_entry programmer_ni845x_spi = {
+ .name = "ni845x_spi",
+ .type = OTHER, // choose other because NI-845x uses own USB implementation
+ .devs.note = "National Instruments USB-845x\n",
+ .init = ni845x_spi_init,
};