]> 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 1a667d48d74d44c3c341d3cc4c9620b783b087bd..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,13 +533,21 @@ 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;
        }
 
+       devc->state.state = SIGMA_CONFIG;
+
        /* Set the cable to bitbang mode. */
        ret = ftdi_set_bitmode(&devc->ftdic, BB_PINMASK, BITMODE_BITBANG);
        if (ret < 0) {
@@ -561,55 +598,140 @@ static int upload_firmware(struct sr_context *ctx,
                return ret;
 
        /* Keep track of successful firmware download completion. */
-       devc->cur_firmware = firmware_idx;
+       devc->state.state = SIGMA_IDLE;
+       devc->firmware_idx = firmware_idx;
        sr_info("Firmware uploaded.");
 
        return SR_OK;
 }
 
 /*
- * Sigma doesn't support limiting the number of samples, so we have to
- * translate the number and the samplerate to an elapsed time.
+ * The driver supports user specified time or sample count limits. The
+ * device's hardware supports neither, and hardware compression prevents
+ * reliable detection of "fill levels" (currently reached sample counts)
+ * from register values during acquisition. That's why the driver needs
+ * to apply some heuristics:
+ *
+ * - The (optional) sample count limit and the (normalized) samplerate
+ *   get mapped to an estimated duration for these samples' acquisition.
+ * - The (optional) time limit gets checked as well. The lesser of the
+ *   two limits will terminate the data acquisition phase. The exact
+ *   sample count limit gets enforced in session feed submission paths.
+ * - Some slack needs to be given to account for hardware pipelines as
+ *   well as late storage of last chunks after compression thresholds
+ *   are tripped. The resulting data set will span at least the caller
+ *   specified period of time, which shall be perfectly acceptable.
  *
- * In addition we need to ensure that the last data cluster has passed
- * the hardware pipeline, and became available to the PC side. With RLE
- * compression up to 327ms could pass before another cluster accumulates
- * at 200kHz samplerate when input pins don't change.
+ * With RLE compression active, up to 64K sample periods can pass before
+ * a cluster accumulates. Which translates to 327ms at 200kHz. Add two
+ * times that period for good measure, one is not enough to flush the
+ * hardware pipeline (observation from an earlier experiment).
  */
-SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
-                                            uint64_t limit_samples)
+SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc)
 {
-       uint64_t limit_msec;
+       int ret;
+       GVariant *data;
+       uint64_t user_count, user_msecs;
        uint64_t worst_cluster_time_ms;
+       uint64_t count_msecs, acquire_msecs;
 
-       limit_msec = limit_samples * 1000 / devc->cur_samplerate;
-       worst_cluster_time_ms = 65536 * 1000 / devc->cur_samplerate;
-       /*
-        * One cluster time is not enough to flush pipeline when sampling
-        * grounded pins with 1 sample limit at 200kHz. Hence the 2* fix.
-        */
-       return limit_msec + 2 * worst_cluster_time_ms;
+       sr_sw_limits_init(&devc->acq_limits);
+
+       /* Get sample count limit, convert to msecs. */
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_SAMPLES, &data);
+       if (ret != SR_OK)
+               return ret;
+       user_count = g_variant_get_uint64(data);
+       g_variant_unref(data);
+       count_msecs = 0;
+       if (user_count)
+               count_msecs = 1000 * user_count / devc->samplerate + 1;
+
+       /* Get time limit, which is in msecs. */
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_MSEC, &data);
+       if (ret != SR_OK)
+               return ret;
+       user_msecs = g_variant_get_uint64(data);
+       g_variant_unref(data);
+
+       /* Get the lesser of them, with both being optional. */
+       acquire_msecs = ~0ull;
+       if (user_count && count_msecs < acquire_msecs)
+               acquire_msecs = count_msecs;
+       if (user_msecs && user_msecs < acquire_msecs)
+               acquire_msecs = user_msecs;
+       if (acquire_msecs == ~0ull)
+               return SR_OK;
+
+       /* Add some slack, and use that timeout for acquisition. */
+       worst_cluster_time_ms = 1000 * 65536 / devc->samplerate;
+       acquire_msecs += 2 * worst_cluster_time_ms;
+       data = g_variant_new_uint64(acquire_msecs);
+       ret = sr_sw_limits_config_set(&devc->acq_limits,
+               SR_CONF_LIMIT_MSEC, data);
+       g_variant_unref(data);
+       if (ret != SR_OK)
+               return ret;
+
+       sr_sw_limits_acquisition_start(&devc->acq_limits);
+       return SR_OK;
 }
 
-SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+/*
+ * Check whether a caller specified samplerate matches the device's
+ * hardware constraints (can be used for acquisition). Optionally yield
+ * a value that approximates the original spec.
+ *
+ * This routine assumes that input specs are in the 200kHz to 200MHz
+ * range of supported rates, and callers typically want to normalize a
+ * given value to the hardware capabilities. Values in the 50MHz range
+ * get rounded up by default, to avoid a more expensive check for the
+ * closest match, while higher sampling rate is always desirable during
+ * measurement. Input specs which exactly match hardware capabilities
+ * remain unaffected. Because 100/200MHz rates also limit the number of
+ * available channels, they are not suggested by this routine, instead
+ * callers need to pick them consciously.
+ */
+SR_PRIV int sigma_normalize_samplerate(uint64_t want_rate, uint64_t *have_rate)
+{
+       uint64_t div, rate;
+
+       /* Accept exact matches for 100/200MHz. */
+       if (want_rate == SR_MHZ(200) || want_rate == SR_MHZ(100)) {
+               if (have_rate)
+                       *have_rate = want_rate;
+               return SR_OK;
+       }
+
+       /* Accept 200kHz to 50MHz range, and map to near value. */
+       if (want_rate >= SR_KHZ(200) && want_rate <= SR_MHZ(50)) {
+               div = SR_MHZ(50) / want_rate;
+               rate = SR_MHZ(50) / div;
+               if (have_rate)
+                       *have_rate = rate;
+               return SR_OK;
+       }
+
+       return SR_ERR_ARG;
+}
+
+SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        struct drv_context *drvc;
-       size_t i;
+       uint64_t samplerate;
        int ret;
        int num_channels;
 
        devc = sdi->priv;
        drvc = sdi->driver->context;
-       ret = SR_OK;
 
-       /* Reject rates that are not in the list of supported rates. */
-       for (i = 0; i < samplerates_count; i++) {
-               if (samplerates[i] == samplerate)
-                       break;
-       }
-       if (i >= samplerates_count || samplerates[i] == 0)
-               return SR_ERR_SAMPLERATE;
+       /* Accept any caller specified rate which the hardware supports. */
+       ret = sigma_normalize_samplerate(devc->samplerate, &samplerate);
+       if (ret != SR_OK)
+               return ret;
 
        /*
         * Depending on the samplerates of 200/100/50- MHz, specific
@@ -618,38 +740,24 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
         */
        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;
        }
 
        /*
-        * Derive the sample period from the sample rate as well as the
-        * number of samples that the device will communicate within
-        * an "event" (memory organization internal to the device).
+        * The samplerate affects the number of available logic channels
+        * as well as a sample memory layout detail (the number of samples
+        * which the device will communicate within an "event").
         */
        if (ret == SR_OK) {
                devc->num_channels = num_channels;
-               devc->cur_samplerate = samplerate;
                devc->samples_per_event = 16 / devc->num_channels;
-               devc->state.state = SIGMA_IDLE;
-       }
-
-       /*
-        * Support for "limit_samples" is implemented by stopping
-        * acquisition after a corresponding period of time.
-        * Re-calculate that period of time, in case the limit is
-        * set first and the samplerate gets (re-)configured later.
-        */
-       if (ret == SR_OK && devc->limit_samples) {
-               uint64_t msecs;
-               msecs = sigma_limit_samples_to_msec(devc, devc->limit_samples);
-               devc->limit_msec = msecs;
        }
 
        return ret;
@@ -674,7 +782,6 @@ struct submit_buffer {
        struct sr_dev_inst *sdi;
        struct sr_datafeed_packet packet;
        struct sr_datafeed_logic logic;
-       struct sr_sw_limits limit_samples;
 };
 
 static int alloc_submit_buffer(struct sr_dev_inst *sdi)
@@ -697,7 +804,7 @@ static int alloc_submit_buffer(struct sr_dev_inst *sdi)
        if (!buffer->sample_data)
                return SR_ERR_MALLOC;
        buffer->write_pointer = buffer->sample_data;
-       sr_sw_limits_init(&buffer->limit_samples);
+       sr_sw_limits_init(&devc->feed_limits);
 
        buffer->sdi = sdi;
        memset(&buffer->logic, 0, sizeof(buffer->logic));
@@ -710,26 +817,33 @@ static int alloc_submit_buffer(struct sr_dev_inst *sdi)
        return SR_OK;
 }
 
-static int setup_submit_buffer(struct dev_context *devc)
+static int setup_submit_limit(struct dev_context *devc)
 {
-       struct submit_buffer *buffer;
+       struct sr_sw_limits *limits;
        int ret;
        GVariant *data;
        uint64_t total;
 
-       buffer = devc->buffer;
+       limits = &devc->feed_limits;
+
+       ret = sr_sw_limits_config_get(&devc->cfg_limits,
+               SR_CONF_LIMIT_SAMPLES, &data);
+       if (ret != SR_OK)
+               return ret;
+       total = g_variant_get_uint64(data);
+       g_variant_unref(data);
 
-       total = devc->limit_samples;
+       sr_sw_limits_init(limits);
        if (total) {
                data = g_variant_new_uint64(total);
-               ret = sr_sw_limits_config_set(&buffer->limit_samples,
+               ret = sr_sw_limits_config_set(limits,
                        SR_CONF_LIMIT_SAMPLES, data);
                g_variant_unref(data);
                if (ret != SR_OK)
                        return ret;
        }
 
-       sr_sw_limits_acquisition_start(&buffer->limit_samples);
+       sr_sw_limits_acquisition_start(limits);
 
        return SR_OK;
 }
@@ -778,10 +892,12 @@ static int addto_submit_buffer(struct dev_context *devc,
        uint16_t sample, size_t count)
 {
        struct submit_buffer *buffer;
+       struct sr_sw_limits *limits;
        int ret;
 
        buffer = devc->buffer;
-       if (sr_sw_limits_check(&buffer->limit_samples))
+       limits = &devc->feed_limits;
+       if (sr_sw_limits_check(limits))
                count = 0;
 
        /*
@@ -798,8 +914,8 @@ static int addto_submit_buffer(struct dev_context *devc,
                        if (ret != SR_OK)
                                return ret;
                }
-               sr_sw_limits_update_samples_read(&buffer->limit_samples, 1);
-               if (sr_sw_limits_check(&buffer->limit_samples))
+               sr_sw_limits_update_samples_read(limits, 1);
+               if (sr_sw_limits_check(limits))
                        break;
        }
 
@@ -837,7 +953,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi)
                                /* Ignore disabled channels with a trigger. */
                                continue;
                        channelbit = 1 << (match->channel->index);
-                       if (devc->cur_samplerate >= SR_MHZ(100)) {
+                       if (devc->samplerate >= SR_MHZ(100)) {
                                /* Fast trigger support. */
                                if (trigger_set) {
                                        sr_err("Only a single pin trigger is "
@@ -1066,7 +1182,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc,
        sample = 0;
        for (i = 0; i < events_in_cluster; i++) {
                item16 = sigma_dram_cluster_data(dram_cluster, i);
-               if (devc->cur_samplerate == SR_MHZ(200)) {
+               if (devc->samplerate == SR_MHZ(200)) {
                        sample = sigma_deinterlace_200mhz_data(item16, 0);
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_200mhz_data(item16, 1);
@@ -1075,7 +1191,7 @@ static void sigma_decode_dram_cluster(struct dev_context *devc,
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_200mhz_data(item16, 3);
                        check_and_submit_sample(devc, sample, 1, triggered);
-               } else if (devc->cur_samplerate == SR_MHZ(100)) {
+               } else if (devc->samplerate == SR_MHZ(100)) {
                        sample = sigma_deinterlace_100mhz_data(item16, 0);
                        check_and_submit_sample(devc, sample, 1, triggered);
                        sample = sigma_deinterlace_100mhz_data(item16, 1);
@@ -1114,7 +1230,7 @@ static int decode_chunk_ts(struct dev_context *devc,
 
        /* Check if trigger is in this chunk. */
        if (trigger_event < EVENTS_PER_ROW) {
-               if (devc->cur_samplerate <= SR_MHZ(50)) {
+               if (devc->samplerate <= SR_MHZ(50)) {
                        trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
                                             trigger_event);
                }
@@ -1196,8 +1312,6 @@ static int download_capture(struct sr_dev_inst *sdi)
                trg_event = triggerpos & 0x1ff;
        }
 
-       devc->sent_samples = 0;
-
        /*
         * Determine how many "DRAM lines" of 1024 bytes each we need to
         * retrieve from the Sigma hardware, so that we have a complete
@@ -1220,7 +1334,7 @@ static int download_capture(struct sr_dev_inst *sdi)
        ret = alloc_submit_buffer(sdi);
        if (ret != SR_OK)
                return FALSE;
-       ret = setup_submit_buffer(devc);
+       ret = setup_submit_limit(devc);
        if (ret != SR_OK)
                return FALSE;
        dl_lines_done = 0;
@@ -1278,18 +1392,9 @@ static int download_capture(struct sr_dev_inst *sdi)
 static int sigma_capture_mode(struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
-       uint64_t running_msec;
-       uint64_t current_time;
 
        devc = sdi->priv;
-
-       /*
-        * Check if the selected sampling duration passed. Sample count
-        * limits are covered by this enforced timeout as well.
-        */
-       current_time = g_get_monotonic_time();
-       running_msec = (current_time - devc->start_time) / 1000;
-       if (running_msec >= devc->limit_msec)
+       if (sr_sw_limits_check(&devc->acq_limits))
                return download_capture(sdi);
 
        return TRUE;