]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/asix-sigma/protocol.c
asix-sigma: Nit, separate declaration from assignment statements
[libsigrok.git] / src / hardware / asix-sigma / protocol.c
index f17a962332fb08ef0488e0d8c91981778fe43f73..82a0f9c20405f5946f71c08ea45aac723d256662 100644 (file)
 #include <config.h>
 #include "protocol.h"
 
-#define USB_VENDOR                     0xa600
-#define USB_PRODUCT                    0xa000
-#define USB_DESCRIPTION                        "ASIX SIGMA"
-#define USB_VENDOR_NAME                        "ASIX"
-#define USB_MODEL_NAME                 "SIGMA"
-
 /*
  * The ASIX Sigma supports arbitrary integer frequency divider in
  * the 50MHz mode. The divider is in range 1...256 , allowing for
@@ -51,7 +45,7 @@ SR_PRIV const uint64_t samplerates[] = {
        SR_MHZ(200),    /* Special FW needed */
 };
 
-SR_PRIV const int SAMPLERATES_COUNT = ARRAY_SIZE(samplerates);
+SR_PRIV const size_t samplerates_count = ARRAY_SIZE(samplerates);
 
 static const char sigma_firmware_files[][24] = {
        /* 50 MHz, supports 8 bit fractions */
@@ -105,9 +99,9 @@ SR_PRIV int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
        uint8_t buf[80];
        int idx = 0;
 
-       if ((len + 2) > sizeof(buf)) {
+       if ((2 * len + 2) > sizeof(buf)) {
                sr_err("Attempted to write %zu bytes, but buffer is too small.",
-                      len + 2);
+                      len);
                return SR_ERR_BUG;
        }
 
@@ -190,14 +184,16 @@ static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
 {
        size_t i;
        uint8_t buf[4096];
-       int idx = 0;
+       int idx;
 
        /* Send the startchunk. Index start with 1. */
-       buf[0] = startchunk >> 8;
-       buf[1] = startchunk & 0xff;
-       sigma_write_register(WRITE_MEMROW, buf, 2, devc);
+       idx = 0;
+       buf[idx++] = startchunk >> 8;
+       buf[idx++] = startchunk & 0xff;
+       sigma_write_register(WRITE_MEMROW, buf, idx, devc);
 
        /* Read the DRAM. */
+       idx = 0;
        buf[idx++] = REG_DRAM_BLOCK;
        buf[idx++] = REG_DRAM_WAIT_ACK;
 
@@ -336,7 +332,7 @@ static int sigma_fpga_init_la(struct dev_context *devc)
        /* Initialize the logic analyzer mode. */
        uint8_t logic_mode_start[] = {
                REG_ADDR_LOW  | (READ_ID & 0xf),
-               REG_ADDR_HIGH | (READ_ID >> 8),
+               REG_ADDR_HIGH | (READ_ID >> 4),
                REG_READ_ADDR,  /* Read ID register. */
 
                REG_ADDR_LOW | (WRITE_TEST & 0xf),
@@ -448,10 +444,18 @@ static int upload_firmware(struct sr_context *ctx,
        unsigned char *buf;
        unsigned char pins;
        size_t buf_size;
-       const char *firmware = sigma_firmware_files[firmware_idx];
-       struct ftdi_context *ftdic = &devc->ftdic;
+       const char *firmware;
+       struct ftdi_context *ftdic;
+
+       /* Avoid downloading the same firmware multiple times. */
+       firmware = sigma_firmware_files[firmware_idx];
+       if (devc->cur_firmware == firmware_idx) {
+               sr_info("Not uploading firmware file '%s' again.", firmware);
+               return SR_OK;
+       }
 
        /* Make sure it's an ASIX SIGMA. */
+       ftdic = &devc->ftdic;
        ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
                                 USB_DESCRIPTION, NULL);
        if (ret < 0) {
@@ -519,24 +523,54 @@ static int upload_firmware(struct sr_context *ctx,
        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.
+ *
+ * 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.
+ */
+SR_PRIV uint64_t sigma_limit_samples_to_msec(const struct dev_context *devc,
+                                            uint64_t limit_samples)
+{
+       uint64_t limit_msec;
+       uint64_t worst_cluster_time_ms;
+
+       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_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
 {
        struct dev_context *devc;
        struct drv_context *drvc;
-       unsigned int i;
+       size_t i;
        int ret;
 
        devc = sdi->priv;
        drvc = sdi->driver->context;
        ret = SR_OK;
 
-       for (i = 0; i < ARRAY_SIZE(samplerates); i++) {
+       /* Reject rates that are not in the list of supported rates. */
+       for (i = 0; i < samplerates_count; i++) {
                if (samplerates[i] == samplerate)
                        break;
        }
-       if (samplerates[i] == 0)
+       if (i >= samplerates_count || samplerates[i] == 0)
                return SR_ERR_SAMPLERATE;
 
+       /*
+        * Depending on the samplerates of 200/100/50- MHz, specific
+        * firmware is required and higher rates might limit the set
+        * of available channels.
+        */
        if (samplerate <= SR_MHZ(50)) {
                ret = upload_firmware(drvc->sr_ctx, 0, devc);
                devc->num_channels = 16;
@@ -548,6 +582,11 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
                devc->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).
+        */
        if (ret == SR_OK) {
                devc->cur_samplerate = samplerate;
                devc->period_ps = 1000000000000ULL / samplerate;
@@ -555,6 +594,18 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
                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;
 }
 
@@ -685,6 +736,73 @@ static uint16_t sigma_dram_cluster_ts(struct sigma_dram_cluster *cluster)
        return (cluster->timestamp_hi << 8) | cluster->timestamp_lo;
 }
 
+/*
+ * Return one 16bit data entity of a DRAM cluster at the specified index.
+ */
+static uint16_t sigma_dram_cluster_data(struct sigma_dram_cluster *cl, int idx)
+{
+       uint16_t sample;
+
+       sample = 0;
+       sample |= cl->samples[idx].sample_lo << 0;
+       sample |= cl->samples[idx].sample_hi << 8;
+       sample = (sample >> 8) | (sample << 8);
+       return sample;
+}
+
+/*
+ * Deinterlace sample data that was retrieved at 100MHz samplerate.
+ * One 16bit item contains two samples of 8bits each. The bits of
+ * multiple samples are interleaved.
+ */
+static uint16_t sigma_deinterlace_100mhz_data(uint16_t indata, int idx)
+{
+       uint16_t outdata;
+
+       indata >>= idx;
+       outdata = 0;
+       outdata |= (indata >> (0 * 2 - 0)) & (1 << 0);
+       outdata |= (indata >> (1 * 2 - 1)) & (1 << 1);
+       outdata |= (indata >> (2 * 2 - 2)) & (1 << 2);
+       outdata |= (indata >> (3 * 2 - 3)) & (1 << 3);
+       outdata |= (indata >> (4 * 2 - 4)) & (1 << 4);
+       outdata |= (indata >> (5 * 2 - 5)) & (1 << 5);
+       outdata |= (indata >> (6 * 2 - 6)) & (1 << 6);
+       outdata |= (indata >> (7 * 2 - 7)) & (1 << 7);
+       return outdata;
+}
+
+/*
+ * Deinterlace sample data that was retrieved at 200MHz samplerate.
+ * One 16bit item contains four samples of 4bits each. The bits of
+ * multiple samples are interleaved.
+ */
+static uint16_t sigma_deinterlace_200mhz_data(uint16_t indata, int idx)
+{
+       uint16_t outdata;
+
+       indata >>= idx;
+       outdata = 0;
+       outdata |= (indata >> (0 * 4 - 0)) & (1 << 0);
+       outdata |= (indata >> (1 * 4 - 1)) & (1 << 1);
+       outdata |= (indata >> (2 * 4 - 2)) & (1 << 2);
+       outdata |= (indata >> (3 * 4 - 3)) & (1 << 3);
+       return outdata;
+}
+
+static void store_sr_sample(uint8_t *samples, int idx, uint16_t data)
+{
+       samples[2 * idx + 0] = (data >> 0) & 0xff;
+       samples[2 * idx + 1] = (data >> 8) & 0xff;
+}
+
+/*
+ * This size translates to: event count (1K events per cluster), times
+ * the sample width (unitsize, 16bits per event), times the maximum
+ * number of samples per event.
+ */
+#define SAMPLES_BUFFER_SIZE    (1024 * 2 * 4)
+
 static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                                      unsigned int events_in_cluster,
                                      unsigned int triggered,
@@ -694,13 +812,16 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
        struct sigma_state *ss = &devc->state;
        struct sr_datafeed_packet packet;
        struct sr_datafeed_logic logic;
-       uint16_t tsdiff, ts;
-       uint8_t samples[2048];
+       uint16_t tsdiff, ts, sample, item16;
+       uint8_t samples[SAMPLES_BUFFER_SIZE];
+       uint8_t *send_ptr;
+       size_t send_count, trig_count;
        unsigned int i;
+       int j;
 
        ts = sigma_dram_cluster_ts(dram_cluster);
        tsdiff = ts - ss->lastts;
-       ss->lastts = ts;
+       ss->lastts = ts + EVENTS_PER_CLUSTER;
 
        packet.type = SR_DF_LOGIC;
        packet.payload = &logic;
@@ -718,32 +839,59 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
         * sample in the cluster happens at the time of the timestamp
         * and the remaining samples happen at timestamp +1...+6 .
         */
-       for (ts = 0; ts < tsdiff - (EVENTS_PER_CLUSTER - 1); ts++) {
+       for (ts = 0; ts < tsdiff; ts++) {
                i = ts % 1024;
-               samples[2 * i + 0] = ss->lastsample & 0xff;
-               samples[2 * i + 1] = ss->lastsample >> 8;
+               store_sr_sample(samples, i, ss->lastsample);
 
                /*
                 * If we have 1024 samples ready or we're at the
                 * end of submitting the padding samples, submit
-                * the packet to Sigrok.
+                * the packet to Sigrok. Since constant data is
+                * sent, duplication of data for rates above 50MHz
+                * is simple.
                 */
-               if ((i == 1023) || (ts == (tsdiff - EVENTS_PER_CLUSTER))) {
+               if ((i == 1023) || (ts == tsdiff - 1)) {
                        logic.length = (i + 1) * logic.unitsize;
-                       sr_session_send(sdi, &packet);
+                       for (j = 0; j < devc->samples_per_event; j++)
+                               sr_session_send(sdi, &packet);
                }
        }
 
        /*
         * Parse the samples in current cluster and prepare them
-        * to be submitted to Sigrok.
+        * to be submitted to Sigrok. Cope with memory layouts that
+        * vary with the samplerate.
         */
+       send_ptr = &samples[0];
+       send_count = 0;
+       sample = 0;
        for (i = 0; i < events_in_cluster; i++) {
-               samples[2 * i + 1] = dram_cluster->samples[i].sample_lo;
-               samples[2 * i + 0] = dram_cluster->samples[i].sample_hi;
+               item16 = sigma_dram_cluster_data(dram_cluster, i);
+               if (devc->cur_samplerate == SR_MHZ(200)) {
+                       sample = sigma_deinterlace_200mhz_data(item16, 0);
+                       store_sr_sample(samples, send_count++, sample);
+                       sample = sigma_deinterlace_200mhz_data(item16, 1);
+                       store_sr_sample(samples, send_count++, sample);
+                       sample = sigma_deinterlace_200mhz_data(item16, 2);
+                       store_sr_sample(samples, send_count++, sample);
+                       sample = sigma_deinterlace_200mhz_data(item16, 3);
+                       store_sr_sample(samples, send_count++, sample);
+               } else if (devc->cur_samplerate == SR_MHZ(100)) {
+                       sample = sigma_deinterlace_100mhz_data(item16, 0);
+                       store_sr_sample(samples, send_count++, sample);
+                       sample = sigma_deinterlace_100mhz_data(item16, 1);
+                       store_sr_sample(samples, send_count++, sample);
+               } else {
+                       sample = item16;
+                       store_sr_sample(samples, send_count++, sample);
+               }
        }
 
-       /* Send data up to trigger point (if triggered). */
+       /*
+        * If a trigger position applies, then provide the datafeed with
+        * the first part of data up to that position, then send the
+        * trigger marker.
+        */
        int trigger_offset = 0;
        if (triggered) {
                /*
@@ -756,10 +904,12 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                                        ss->lastsample, &devc->trigger);
 
                if (trigger_offset > 0) {
+                       trig_count = trigger_offset * devc->samples_per_event;
                        packet.type = SR_DF_LOGIC;
-                       logic.length = trigger_offset * logic.unitsize;
+                       logic.length = trig_count * logic.unitsize;
                        sr_session_send(sdi, &packet);
-                       events_in_cluster -= trigger_offset;
+                       send_ptr += trig_count * logic.unitsize;
+                       send_count -= trig_count;
                }
 
                /* Only send trigger if explicitly enabled. */
@@ -769,17 +919,18 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                }
        }
 
-       if (events_in_cluster > 0) {
+       /*
+        * Send the data after the trigger, or all of the received data
+        * if no trigger position applies.
+        */
+       if (send_count) {
                packet.type = SR_DF_LOGIC;
-               logic.length = events_in_cluster * logic.unitsize;
-               logic.data = samples + (trigger_offset * logic.unitsize);
+               logic.length = send_count * logic.unitsize;
+               logic.data = send_ptr;
                sr_session_send(sdi, &packet);
        }
 
-       ss->lastsample =
-               samples[2 * (events_in_cluster - 1) + 0] |
-               (samples[2 * (events_in_cluster - 1) + 1] << 8);
-
+       ss->lastsample = sample;
 }
 
 /*
@@ -797,12 +948,18 @@ static int decode_chunk_ts(struct sigma_dram_line *dram_line,
                           struct sr_dev_inst *sdi)
 {
        struct sigma_dram_cluster *dram_cluster;
-       struct dev_context *devc = sdi->priv;
-       unsigned int clusters_in_line =
-               (events_in_line + (EVENTS_PER_CLUSTER - 1)) / EVENTS_PER_CLUSTER;
+       struct dev_context *devc;
+       unsigned int clusters_in_line;
        unsigned int events_in_cluster;
        unsigned int i;
-       uint32_t trigger_cluster = ~0, triggered = 0;
+       uint32_t trigger_cluster, triggered;
+
+       devc = sdi->priv;
+       clusters_in_line = events_in_line;
+       clusters_in_line += EVENTS_PER_CLUSTER - 1;
+       clusters_in_line /= EVENTS_PER_CLUSTER;
+       trigger_cluster = ~0;
+       triggered = 0;
 
        /* Check if trigger is in this chunk. */
        if (trigger_event < (64 * 7)) {
@@ -837,17 +994,22 @@ static int decode_chunk_ts(struct sigma_dram_line *dram_line,
 
 static int download_capture(struct sr_dev_inst *sdi)
 {
-       struct dev_context *devc = sdi->priv;
        const uint32_t chunks_per_read = 32;
+
+       struct dev_context *devc;
        struct sigma_dram_line *dram_line;
        int bufsz;
        uint32_t stoppos, triggerpos;
        uint8_t modestatus;
-
        uint32_t i;
        uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
-       uint32_t dl_events_in_line = 64 * 7;
-       uint32_t trg_line = ~0, trg_event = ~0;
+       uint32_t dl_events_in_line;
+       uint32_t trg_line, trg_event;
+
+       devc = sdi->priv;
+       dl_events_in_line = 64 * 7;
+       trg_line = ~0;
+       trg_event = ~0;
 
        dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
        if (!dram_line)
@@ -931,13 +1093,13 @@ static int download_capture(struct sr_dev_inst *sdi)
  */
 static int sigma_capture_mode(struct sr_dev_inst *sdi)
 {
-       struct dev_context *devc = sdi->priv;
-
+       struct dev_context *devc;
        uint64_t running_msec;
        struct timeval tv;
-
        uint32_t stoppos, triggerpos;
 
+       devc = sdi->priv;
+
        /* Check if the selected sampling duration passed. */
        gettimeofday(&tv, 0);
        running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 +