X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fkingst-la2016%2Fprotocol.c;h=a0de3be70c0982ea5bc7525a49069dfdc13bab39;hb=b0d0131eff8bacbf69aa0da818efaa4439f19a64;hp=efd16fa9fddb1f1745ed5329ac67466e18abfaea;hpb=96dc954e1c17a34daafcccb0a6013873d7ec9ee4;p=libsigrok.git diff --git a/src/hardware/kingst-la2016/protocol.c b/src/hardware/kingst-la2016/protocol.c index efd16fa9..a0de3be7 100644 --- a/src/hardware/kingst-la2016/protocol.c +++ b/src/hardware/kingst-la2016/protocol.c @@ -55,6 +55,16 @@ * CMD_FPGA_SPI requests. The FX2 MCU transparently handles the detail * of SPI transfers encoding the read (1) or write (0) direction in the * MSB of the address field. There are some 60 byte-wide FPGA registers. + * + * Unfortunately the FPGA registers change their meaning between the + * read and write directions of access, or exclusively provide one of + * these directions and not the other. This is an arbitrary vendor's + * choice, there is nothing which the sigrok driver could do about it. + * Values written to registers typically cannot get read back, neither + * verified after writing a configuration, nor queried upon startup for + * automatic detection of the current configuration. Neither appear to + * be there echo registers for presence and communication checks, nor + * version identifying registers, as far as we know. */ #define REG_RUN 0x00 /* Read capture status, write start capture. */ #define REG_PWM_EN 0x02 /* User PWM channels on/off. */ @@ -67,8 +77,8 @@ #define REG_PWM2 0x78 /* Write config for user PWM2. */ static int ctrl_in(const struct sr_dev_inst *sdi, - uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - void *data, uint16_t wLength) + uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + void *data, uint16_t wLength) { struct sr_usb_dev_inst *usb; int ret; @@ -91,8 +101,8 @@ static int ctrl_in(const struct sr_dev_inst *sdi, } static int ctrl_out(const struct sr_dev_inst *sdi, - uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - void *data, uint16_t wLength) + uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + void *data, uint16_t wLength) { struct sr_usb_dev_inst *usb; int ret; @@ -114,22 +124,92 @@ static int ctrl_out(const struct sr_dev_inst *sdi, return SR_OK; } -static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, const char *bitstream_fname) +/* + * Check the necessity for FPGA bitstream upload, because another upload + * would take some 600ms which is undesirable after program startup. Try + * to access some FPGA registers and check the values' plausibility. The + * check should fail on the safe side, request another upload when in + * doubt. A positive response (the request to continue operation with the + * currently active bitstream) should be conservative. Accessing multiple + * registers is considered cheap compared to the cost of bitstream upload. + * + * It helps though that both the vendor software and the sigrok driver + * use the same bundle of MCU firmware and FPGA bitstream for any of the + * supported models. We don't expect to successfully communicate to the + * device yet disagree on its protocol. Ideally we would access version + * identifying registers for improved robustness, but are not aware of + * any. A bitstream reload can always be forced by a power cycle. + */ +static int check_fpga_bitstream(const struct sr_dev_inst *sdi) +{ + uint8_t init_rsp; + int ret; + uint16_t run_state; + uint8_t pwm_en; + size_t read_len; + uint8_t buff[sizeof(run_state)]; + const uint8_t *rdptr; + + sr_dbg("Checking operation of the FPGA bitstream."); + + init_rsp = 0xff; + ret = ctrl_in(sdi, CMD_FPGA_INIT, 0x00, 0, &init_rsp, sizeof(init_rsp)); + if (ret != SR_OK || init_rsp != 0) { + sr_dbg("FPGA init query failed, or unexpected response."); + return SR_ERR_IO; + } + + read_len = sizeof(run_state); + ret = ctrl_in(sdi, CMD_FPGA_SPI, REG_RUN, 0, buff, read_len); + if (ret != SR_OK) { + sr_dbg("FPGA register access failed (run state)."); + return SR_ERR_IO; + } + rdptr = buff; + run_state = read_u16le_inc(&rdptr); + sr_spew("FPGA register: run state 0x%04x.", run_state); + if (run_state && (run_state & 0x3) != 0x1) { + sr_dbg("Unexpected FPGA register content (run state)."); + return SR_ERR_DATA; + } + if (run_state && (run_state & ~0xf) != 0x85e0) { + sr_dbg("Unexpected FPGA register content (run state)."); + return SR_ERR_DATA; + } + + read_len = sizeof(pwm_en); + ret = ctrl_in(sdi, CMD_FPGA_SPI, REG_PWM_EN, 0, buff, read_len); + if (ret != SR_OK) { + sr_dbg("FPGA register access failed (PWM enable)."); + return SR_ERR_IO; + } + rdptr = buff; + pwm_en = read_u8_inc(&rdptr); + sr_spew("FPGA register: PWM enable 0x%02x.", pwm_en); + if ((pwm_en & 0x3) != 0x0) { + sr_dbg("Unexpected FPGA register content (PWM enable)."); + return SR_ERR_DATA; + } + + sr_info("Could re-use current FPGA bitstream. No upload required."); + return SR_OK; +} + +static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, + const char *bitstream_fname) { - struct dev_context *devc; struct drv_context *drvc; struct sr_usb_dev_inst *usb; struct sr_resource bitstream; + uint32_t bitstream_size; uint8_t buffer[sizeof(uint32_t)]; uint8_t *wrptr; - uint8_t cmd_resp; uint8_t block[4096]; int len, act_len; unsigned int pos; int ret; - unsigned int zero_pad_to = 0x2c000; + unsigned int zero_pad_to; - devc = sdi->priv; drvc = sdi->driver->context; usb = sdi->conn; @@ -141,14 +221,18 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, const char *bits return ret; } - devc->bitstream_size = (uint32_t)bitstream.size; + bitstream_size = (uint32_t)bitstream.size; wrptr = buffer; - write_u32le_inc(&wrptr, devc->bitstream_size); + write_u32le_inc(&wrptr, bitstream_size); if ((ret = ctrl_out(sdi, CMD_FPGA_INIT, 0x00, 0, buffer, wrptr - buffer)) != SR_OK) { sr_err("Cannot initiate FPGA bitstream upload."); sr_resource_close(drvc->sr_ctx, &bitstream); return ret; } + zero_pad_to = bitstream_size; + zero_pad_to += LA2016_EP2_PADDING - 1; + zero_pad_to /= LA2016_EP2_PADDING; + zero_pad_to *= LA2016_EP2_PADDING; pos = 0; while (1) { @@ -169,7 +253,8 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, const char *bits if (len == 0) break; - ret = libusb_bulk_transfer(usb->devhdl, 2, (unsigned char*)&block[0], len, &act_len, DEFAULT_TIMEOUT_MS); + ret = libusb_bulk_transfer(usb->devhdl, 2, + &block[0], len, &act_len, DEFAULT_TIMEOUT_MS); if (ret != 0) { sr_dbg("Cannot write FPGA bitstream, block %#x len %d: %s.", pos, (int)len, libusb_error_name(ret)); @@ -190,6 +275,14 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, const char *bits sr_info("FPGA bitstream upload (%" PRIu64 " bytes) done.", bitstream.size); + return SR_OK; +} + +static int enable_fpga_bitstream(const struct sr_dev_inst *sdi) +{ + int ret; + uint8_t cmd_resp; + if ((ret = ctrl_in(sdi, CMD_FPGA_INIT, 0x00, 0, &cmd_resp, sizeof(cmd_resp))) != SR_OK) { sr_err("Cannot read response after FPGA bitstream upload."); return ret; @@ -199,15 +292,14 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi, const char *bits cmd_resp); return SR_ERR; } - g_usleep(30000); if ((ret = ctrl_out(sdi, CMD_FPGA_ENABLE, 0x01, 0, NULL, 0)) != SR_OK) { sr_err("Cannot enable FPGA after bitstream upload."); return ret; } - g_usleep(40000); + return SR_OK; } @@ -218,15 +310,14 @@ static int set_threshold_voltage(const struct sr_dev_inst *sdi, float voltage) devc = sdi->priv; - uint16_t duty_R79,duty_R56; + uint16_t duty_R79, duty_R56; uint8_t buf[2 * sizeof(uint16_t)]; uint8_t *wrptr; /* Clamp threshold setting to valid range for LA2016. */ if (voltage > 4.0) { voltage = 4.0; - } - else if (voltage < -4.0) { + } else if (voltage < -4.0) { voltage = -4.0; } @@ -244,12 +335,10 @@ static int set_threshold_voltage(const struct sr_dev_inst *sdi, float voltage) if (voltage >= 2.9) { duty_R79 = 0; /* PWM off (0V). */ duty_R56 = (uint16_t)(302 * voltage - 363); - } - else if (voltage <= -0.4) { + } else if (voltage <= -0.4) { duty_R79 = 0x02d7; /* 72% duty cycle. */ duty_R56 = (uint16_t)(302 * voltage + 1090); - } - else { + } else { duty_R79 = 0x00f2; /* 25% duty cycle. */ duty_R56 = (uint16_t)(302 * voltage + 121); } @@ -257,8 +346,7 @@ static int set_threshold_voltage(const struct sr_dev_inst *sdi, float voltage) /* Clamp duty register values to sensible limits. */ if (duty_R56 < 10) { duty_R56 = 10; - } - else if (duty_R56 > 1100) { + } else if (duty_R56 > 1100) { duty_R56 = 1100; } @@ -303,7 +391,8 @@ static int enable_pwm(const struct sr_dev_inst *sdi, uint8_t p1, uint8_t p2) return SR_OK; } -static int set_pwm(const struct sr_dev_inst *sdi, uint8_t which, float freq, float duty) +static int set_pwm(const struct sr_dev_inst *sdi, uint8_t which, + float freq, float duty) { int CTRL_PWM[] = { REG_PWM1, REG_PWM2 }; struct dev_context *devc; @@ -561,20 +650,16 @@ static uint16_t run_state(const struct sr_dev_inst *sdi) previous_state = state; if ((state & 0x0003) == 0x01) { sr_dbg("Run state: 0x%04x (%s).", state, "idle"); - } - else if ((state & 0x000f) == 0x02) { + } else if ((state & 0x000f) == 0x02) { sr_dbg("Run state: 0x%04x (%s).", state, "pre-trigger sampling"); - } - else if ((state & 0x000f) == 0x0a) { + } else if ((state & 0x000f) == 0x0a) { sr_dbg("Run state: 0x%04x (%s).", state, "sampling, waiting for trigger"); - } - else if ((state & 0x000f) == 0x0e) { + } else if ((state & 0x000f) == 0x0e) { sr_dbg("Run state: 0x%04x (%s).", state, "post-trigger sampling"); - } - else { + } else { sr_dbg("Run state: 0x%04x.", state); } } @@ -614,10 +699,10 @@ static int get_capture_info(const struct sr_dev_inst *sdi) devc->info.write_pos = read_u32le_inc(&rdptr); sr_dbg("Capture info: n_rep_packets: 0x%08x/%d, before_trigger: 0x%08x/%d, write_pos: 0x%08x%d.", - devc->info.n_rep_packets, devc->info.n_rep_packets, - devc->info.n_rep_packets_before_trigger, - devc->info.n_rep_packets_before_trigger, - devc->info.write_pos, devc->info.write_pos); + devc->info.n_rep_packets, devc->info.n_rep_packets, + devc->info.n_rep_packets_before_trigger, + devc->info.n_rep_packets_before_trigger, + devc->info.write_pos, devc->info.write_pos); if (devc->info.n_rep_packets % 5) { sr_warn("Unexpected packets count %lu, not a multiple of 5.", @@ -627,7 +712,8 @@ static int get_capture_info(const struct sr_dev_inst *sdi) return SR_OK; } -SR_PRIV int la2016_upload_firmware(struct sr_context *sr_ctx, libusb_device *dev, uint16_t product_id) +SR_PRIV int la2016_upload_firmware(struct sr_context *sr_ctx, + libusb_device *dev, uint16_t product_id) { char fw_file[1024]; snprintf(fw_file, sizeof(fw_file) - 1, UC_FIRMWARE, product_id); @@ -710,7 +796,8 @@ static int la2016_has_triggered(const struct sr_dev_inst *sdi) return (state & 0x3) == 1; } -static int la2016_start_retrieval(const struct sr_dev_inst *sdi, libusb_transfer_cb_fn cb) +static int la2016_start_retrieval(const struct sr_dev_inst *sdi, + libusb_transfer_cb_fn cb) { struct dev_context *devc; struct sr_usb_dev_inst *usb; @@ -732,7 +819,7 @@ static int la2016_start_retrieval(const struct sr_dev_inst *sdi, libusb_transfer devc->n_reps_until_trigger = devc->info.n_rep_packets_before_trigger; sr_dbg("Want to read %u xfer-packets starting from pos %" PRIu32 ".", - devc->n_transfer_packets_to_read, devc->read_pos); + devc->n_transfer_packets_to_read, devc->read_pos); if ((ret = ctrl_out(sdi, CMD_BULK_RESET, 0x00, 0, NULL, 0)) != SR_OK) { sr_err("Cannot reset USB bulk state."); @@ -848,8 +935,8 @@ static void send_chunk(struct sr_dev_inst *sdi, devc->reading_behind_trigger = 1; do_signal_trigger = 1; sr_dbg("Trigger position after %" PRIu64 " samples, %.6fms.", - devc->total_samples, - (double)devc->total_samples / devc->cur_samplerate * 1e3); + devc->total_samples, + (double)devc->total_samples / devc->cur_samplerate * 1e3); } } } @@ -877,7 +964,7 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer) usb = sdi->conn; sr_dbg("receive_transfer(): status %s received %d bytes.", - libusb_error_name(transfer->status), transfer->actual_length); + libusb_error_name(transfer->status), transfer->actual_length); if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) { sr_err("USB bulk transfer timeout."); @@ -977,6 +1064,7 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi) uint8_t buf[8]; int16_t purchase_date_bcd[2]; uint8_t magic; + const char *bitstream_fn; int ret; devc = sdi->priv; @@ -989,8 +1077,7 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi) */ if ((ret = ctrl_in(sdi, CMD_EEPROM, 0x20, 0, purchase_date_bcd, sizeof(purchase_date_bcd))) != SR_OK) { sr_err("Cannot read purchase date in EEPROM."); - } - else { + } else { sr_dbg("Purchase date: 20%02hx-%02hx.", (purchase_date_bcd[0]) & 0xff, (purchase_date_bcd[0] >> 8) & 0xff); @@ -1046,8 +1133,7 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi) if (buf[0] == (0xff & ~buf[1])) { /* Primary copy of magic passes complement check. */ magic = buf[0]; - } - else if (buf[4] == (0x0ff & ~buf[5])) { + } else if (buf[4] == (0xff & ~buf[5])) { /* Backup copy of magic passes complement check. */ sr_dbg("Using backup copy of device type magic number."); magic = buf[4]; @@ -1058,28 +1144,40 @@ SR_PRIV int la2016_init_device(const struct sr_dev_inst *sdi) /* Select the FPGA bitstream depending on the model. */ switch (magic) { case 2: - ret = upload_fpga_bitstream(sdi, FPGA_FW_LA2016); + bitstream_fn = FPGA_FW_LA2016; devc->max_samplerate = MAX_SAMPLE_RATE_LA2016; break; case 3: - ret = upload_fpga_bitstream(sdi, FPGA_FW_LA1016); + bitstream_fn = FPGA_FW_LA1016; devc->max_samplerate = MAX_SAMPLE_RATE_LA1016; break; case 8: - ret = upload_fpga_bitstream(sdi, FPGA_FW_LA2016A); + bitstream_fn = FPGA_FW_LA2016A; devc->max_samplerate = MAX_SAMPLE_RATE_LA2016; break; case 9: - ret = upload_fpga_bitstream(sdi, FPGA_FW_LA1016A); + bitstream_fn = FPGA_FW_LA1016A; devc->max_samplerate = MAX_SAMPLE_RATE_LA1016; break; default: + bitstream_fn = NULL; + break; + } + if (!bitstream_fn || !*bitstream_fn) { sr_err("Cannot identify as one of the supported models."); return SR_ERR; } + if (check_fpga_bitstream(sdi) != SR_OK) { + ret = upload_fpga_bitstream(sdi, bitstream_fn); + if (ret != SR_OK) { + sr_err("Cannot upload FPGA bitstream."); + return ret; + } + } + ret = enable_fpga_bitstream(sdi); if (ret != SR_OK) { - sr_err("Cannot upload FPGA bitstream."); + sr_err("Cannot enable FPGA bitstream after upload."); return ret; }