]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/asix-sigma/protocol.c
asix-sigma: reword list of sample rates, (try to) use 1/2/5 steps
[libsigrok.git] / src / hardware / asix-sigma / protocol.c
index 7405c8fdfdd51e7b920acdc9726e07e74a22f870..80e60706085fd110bf75befda024ae5b46180118 100644 (file)
 #include "protocol.h"
 
 /*
- * The ASIX Sigma supports arbitrary integer frequency divider in
- * the 50MHz mode. The divider is in range 1...256 , allowing for
- * very precise sampling rate selection. This driver supports only
- * a subset of the sampling rates.
+ * The ASIX SIGMA hardware supports fixed 200MHz and 100MHz sample rates
+ * (by means of separate firmware images). As well as 50MHz divided by
+ * an integer divider in the 1..256 range (by the "typical" firmware).
+ * Which translates to a strict lower boundary of around 195kHz.
+ *
+ * This driver "suggests" a subset of the available rates by listing a
+ * few discrete values, while setter routines accept any user specified
+ * rate that is supported by the hardware.
  */
 SR_PRIV const uint64_t samplerates[] = {
-       SR_KHZ(200),    /* div=250 */
-       SR_KHZ(250),    /* div=200 */
-       SR_KHZ(500),    /* div=100 */
-       SR_MHZ(1),      /* div=50  */
-       SR_MHZ(5),      /* div=10  */
-       SR_MHZ(10),     /* div=5   */
-       SR_MHZ(25),     /* div=2   */
-       SR_MHZ(50),     /* div=1   */
-       SR_MHZ(100),    /* Special FW needed */
-       SR_MHZ(200),    /* Special FW needed */
+       /* 50MHz and integer divider. 1/2/5 steps (where possible). */
+       SR_KHZ(200), SR_KHZ(500),
+       SR_MHZ(1), SR_MHZ(2), SR_MHZ(5),
+       SR_MHZ(10), SR_MHZ(25), SR_MHZ(50),
+       /* 100MHz/200MHz, fixed rates in special firmware. */
+       SR_MHZ(100), SR_MHZ(200),
 };
 
 SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
 
 static const char *firmware_files[] = {
-       "asix-sigma-50.fw", /* Up to 50MHz sample rate, 8bit divider. */
-       "asix-sigma-100.fw", /* 100MHz sample rate, fixed. */
-       "asix-sigma-200.fw", /* 200MHz sample rate, fixed. */
-       "asix-sigma-50sync.fw", /* Synchronous clock from external pin. */
-       "asix-sigma-phasor.fw", /* Frequency counter. */
+       [SIGMA_FW_50MHZ] = "asix-sigma-50.fw", /* 50MHz, 8bit divider. */
+       [SIGMA_FW_100MHZ] = "asix-sigma-100.fw", /* 100MHz, fixed. */
+       [SIGMA_FW_200MHZ] = "asix-sigma-200.fw", /* 200MHz, fixed. */
+       [SIGMA_FW_SYNC] = "asix-sigma-50sync.fw", /* Sync from external pin. */
+       [SIGMA_FW_FREQ] = "asix-sigma-phasor.fw", /* Frequency counter. */
 };
 
 #define SIGMA_FIRMWARE_SIZE_LIMIT (256 * 1024)
@@ -313,10 +313,16 @@ SR_PRIV int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *
 /*
  * Initiate slave serial mode for configuration download. Which is done
  * by pulsing PROG_B and sensing INIT_B. Make sure CCLK is idle before
- * initiating the configuration download. Run a "suicide sequence" first
- * to terminate the regular FPGA operation before reconfiguration.
+ * initiating the configuration download.
+ *
+ * Run a "suicide sequence" first to terminate the regular FPGA operation
+ * before reconfiguration. The FTDI cable is single channel, and shares
+ * pins which are used for data communication in FIFO mode with pins that
+ * are used for FPGA configuration in bitbang mode. Hardware defaults for
+ * unconfigured hardware, and runtime conditions after FPGA configuration
+ * need to cooperate such that re-configuration of the FPGA can start.
  */
-static int sigma_fpga_init_bitbang(struct dev_context *devc)
+static int sigma_fpga_init_bitbang_once(struct dev_context *devc)
 {
        uint8_t suicide[] = {
                BB_PIN_D7 | BB_PIN_D2,
@@ -348,9 +354,11 @@ static int sigma_fpga_init_bitbang(struct dev_context *devc)
        sigma_write(suicide, sizeof(suicide), devc);
        sigma_write(suicide, sizeof(suicide), devc);
        sigma_write(suicide, sizeof(suicide), devc);
+       g_usleep(10 * 1000);
 
        /* Section 2. part 2), pulse PROG. */
        sigma_write(init_array, sizeof(init_array), devc);
+       g_usleep(10 * 1000);
        ftdi_usb_purge_buffers(&devc->ftdic);
 
        /* Wait until the FPGA asserts INIT_B. */
@@ -367,6 +375,27 @@ static int sigma_fpga_init_bitbang(struct dev_context *devc)
        return SR_ERR_TIMEOUT;
 }
 
+/*
+ * This is belt and braces. Re-run the bitbang initiation sequence a few
+ * times should first attempts fail. Failure is rare but can happen (was
+ * observed during driver development).
+ */
+static int sigma_fpga_init_bitbang(struct dev_context *devc)
+{
+       size_t retries;
+       int ret;
+
+       retries = 10;
+       while (retries--) {
+               ret = sigma_fpga_init_bitbang_once(devc);
+               if (ret == SR_OK)
+                       return ret;
+               if (ret != SR_ERR_TIMEOUT)
+                       return ret;
+       }
+       return ret;
+}
+
 /*
  * Configure the FPGA for logic-analyzer mode.
  */
@@ -496,7 +525,7 @@ static int sigma_fw_2_bitbang(struct sr_context *ctx, const char *name,
 }
 
 static int upload_firmware(struct sr_context *ctx,
-               int firmware_idx, struct dev_context *devc)
+       struct dev_context *devc, enum sigma_firmware_idx firmware_idx)
 {
        int ret;
        unsigned char *buf;
@@ -504,9 +533,15 @@ static int upload_firmware(struct sr_context *ctx,
        size_t buf_size;
        const char *firmware;
 
-       /* Avoid downloading the same firmware multiple times. */
+       /* Check for valid firmware file selection. */
+       if (firmware_idx >= ARRAY_SIZE(firmware_files))
+               return SR_ERR_ARG;
        firmware = firmware_files[firmware_idx];
-       if (devc->cur_firmware == firmware_idx) {
+       if (!firmware || !*firmware)
+               return SR_ERR_ARG;
+
+       /* Avoid downloading the same firmware multiple times. */
+       if (devc->firmware_idx == firmware_idx) {
                sr_info("Not uploading firmware file '%s' again.", firmware);
                return SR_OK;
        }
@@ -564,7 +599,7 @@ static int upload_firmware(struct sr_context *ctx,
 
        /* Keep track of successful firmware download completion. */
        devc->state.state = SIGMA_IDLE;
-       devc->cur_firmware = firmware_idx;
+       devc->firmware_idx = firmware_idx;
        sr_info("Firmware uploaded.");
 
        return SR_OK;
@@ -705,13 +740,13 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi)
         */
        num_channels = devc->num_channels;
        if (samplerate <= SR_MHZ(50)) {
-               ret = upload_firmware(drvc->sr_ctx, 0, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_50MHZ);
                num_channels = 16;
        } else if (samplerate == SR_MHZ(100)) {
-               ret = upload_firmware(drvc->sr_ctx, 1, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_100MHZ);
                num_channels = 8;
        } else if (samplerate == SR_MHZ(200)) {
-               ret = upload_firmware(drvc->sr_ctx, 2, devc);
+               ret = upload_firmware(drvc->sr_ctx, devc, SIGMA_FW_200MHZ);
                num_channels = 4;
        }