]> sigrok.org Git - libsigrok.git/blobdiff - src/hardware/asix-sigma/protocol.c
asix-sigma: Only change number of channels after successful firmware upload
[libsigrok.git] / src / hardware / asix-sigma / protocol.c
index 82a0f9c20405f5946f71c08ea45aac723d256662..ee7ce02211e373dbc55f13d82ac3d50ca77deefc 100644 (file)
@@ -330,6 +330,7 @@ static int sigma_fpga_init_bitbang(struct dev_context *devc)
 static int sigma_fpga_init_la(struct dev_context *devc)
 {
        /* Initialize the logic analyzer mode. */
+       uint8_t mode_regval = WMR_SDRAMINIT;
        uint8_t logic_mode_start[] = {
                REG_ADDR_LOW  | (READ_ID & 0xf),
                REG_ADDR_HIGH | (READ_ID >> 4),
@@ -345,8 +346,8 @@ static int sigma_fpga_init_la(struct dev_context *devc)
                REG_READ_ADDR,  /* Read scratch register. */
 
                REG_ADDR_LOW | (WRITE_MODE & 0xf),
-               REG_DATA_LOW | 0x0,
-               REG_DATA_HIGH_WRITE | 0x8,
+               REG_DATA_LOW | (mode_regval & 0xf),
+               REG_DATA_HIGH_WRITE | (mode_regval >> 4),
        };
 
        uint8_t result[3];
@@ -461,14 +462,14 @@ static int upload_firmware(struct sr_context *ctx,
        if (ret < 0) {
                sr_err("ftdi_usb_open failed: %s",
                       ftdi_get_error_string(ftdic));
-               return 0;
+               return SR_ERR;
        }
 
        ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
        if (ret < 0) {
                sr_err("ftdi_set_bitmode failed: %s",
                       ftdi_get_error_string(ftdic));
-               return 0;
+               return SR_ERR;
        }
 
        /* Four times the speed of sigmalogan - Works well. */
@@ -476,7 +477,7 @@ static int upload_firmware(struct sr_context *ctx,
        if (ret < 0) {
                sr_err("ftdi_set_baudrate failed: %s",
                       ftdi_get_error_string(ftdic));
-               return 0;
+               return SR_ERR;
        }
 
        /* Initialize the FPGA for firmware upload. */
@@ -553,6 +554,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
        struct drv_context *drvc;
        size_t i;
        int ret;
+       int num_channels;
 
        devc = sdi->priv;
        drvc = sdi->driver->context;
@@ -571,15 +573,16 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
         * firmware is required and higher rates might limit the set
         * of available channels.
         */
+       num_channels = devc->num_channels;
        if (samplerate <= SR_MHZ(50)) {
                ret = upload_firmware(drvc->sr_ctx, 0, devc);
-               devc->num_channels = 16;
+               num_channels = 16;
        } else if (samplerate == SR_MHZ(100)) {
                ret = upload_firmware(drvc->sr_ctx, 1, devc);
-               devc->num_channels = 8;
+               num_channels = 8;
        } else if (samplerate == SR_MHZ(200)) {
                ret = upload_firmware(drvc->sr_ctx, 2, devc);
-               devc->num_channels = 4;
+               num_channels = 4;
        }
 
        /*
@@ -588,8 +591,8 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi, uint64_t sampler
         * an "event" (memory organization internal to the device).
         */
        if (ret == SR_OK) {
+               devc->num_channels = num_channels;
                devc->cur_samplerate = samplerate;
-               devc->period_ps = 1000000000000ULL / samplerate;
                devc->samples_per_event = 16 / devc->num_channels;
                devc->state.state = SIGMA_IDLE;
        }
@@ -796,6 +799,34 @@ static void store_sr_sample(uint8_t *samples, int idx, uint16_t data)
        samples[2 * idx + 1] = (data >> 8) & 0xff;
 }
 
+/*
+ * Local wrapper around sr_session_send() calls. Make sure to not send
+ * more samples to the session's datafeed than what was requested by a
+ * previously configured (optional) sample count.
+ */
+static void sigma_session_send(struct sr_dev_inst *sdi,
+                               struct sr_datafeed_packet *packet)
+{
+       struct dev_context *devc;
+       struct sr_datafeed_logic *logic;
+       uint64_t send_now;
+
+       devc = sdi->priv;
+       if (devc->limit_samples) {
+               logic = (void *)packet->payload;
+               send_now = logic->length / logic->unitsize;
+               if (devc->sent_samples + send_now > devc->limit_samples) {
+                       send_now = devc->limit_samples - devc->sent_samples;
+                       logic->length = send_now * logic->unitsize;
+               }
+               if (!send_now)
+                       return;
+               devc->sent_samples += send_now;
+       }
+
+       sr_session_send(sdi, packet);
+}
+
 /*
  * This size translates to: event count (1K events per cluster), times
  * the sample width (unitsize, 16bits per event), times the maximum
@@ -829,15 +860,9 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
        logic.data = samples;
 
        /*
-        * First of all, send Sigrok a copy of the last sample from
-        * previous cluster as many times as needed to make up for
-        * the differential characteristics of data we get from the
-        * Sigma. Sigrok needs one sample of data per period.
-        *
-        * One DRAM cluster contains a timestamp and seven samples,
-        * the units of timestamp are "devc->period_ps" , the first
-        * sample in the cluster happens at the time of the timestamp
-        * and the remaining samples happen at timestamp +1...+6 .
+        * If this cluster is not adjacent to the previously received
+        * cluster, then send the appropriate number of samples with the
+        * previous values to the sigrok session. This "decodes RLE".
         */
        for (ts = 0; ts < tsdiff; ts++) {
                i = ts % 1024;
@@ -853,7 +878,7 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                if ((i == 1023) || (ts == tsdiff - 1)) {
                        logic.length = (i + 1) * logic.unitsize;
                        for (j = 0; j < devc->samples_per_event; j++)
-                               sr_session_send(sdi, &packet);
+                               sigma_session_send(sdi, &packet);
                }
        }
 
@@ -907,7 +932,7 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                        trig_count = trigger_offset * devc->samples_per_event;
                        packet.type = SR_DF_LOGIC;
                        logic.length = trig_count * logic.unitsize;
-                       sr_session_send(sdi, &packet);
+                       sigma_session_send(sdi, &packet);
                        send_ptr += trig_count * logic.unitsize;
                        send_count -= trig_count;
                }
@@ -927,7 +952,7 @@ static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
                packet.type = SR_DF_LOGIC;
                logic.length = send_count * logic.unitsize;
                logic.data = send_ptr;
-               sr_session_send(sdi, &packet);
+               sigma_session_send(sdi, &packet);
        }
 
        ss->lastsample = sample;
@@ -1003,6 +1028,7 @@ static int download_capture(struct sr_dev_inst *sdi)
        uint8_t modestatus;
        uint32_t i;
        uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
+       uint32_t dl_first_line, dl_line;
        uint32_t dl_events_in_line;
        uint32_t trg_line, trg_event;
 
@@ -1017,36 +1043,58 @@ static int download_capture(struct sr_dev_inst *sdi)
 
        sr_info("Downloading sample data.");
 
-       /* Stop acquisition. */
-       sigma_set_register(WRITE_MODE, 0x11, devc);
+       /*
+        * Ask the hardware to stop data acquisition. Reception of the
+        * FORCESTOP request makes the hardware "disable RLE" (store
+        * clusters to DRAM regardless of whether pin state changes) and
+        * raise the POSTTRIGGERED flag.
+        */
+       sigma_set_register(WRITE_MODE, WMR_FORCESTOP | WMR_SDRAMWRITEEN, devc);
+       do {
+               modestatus = sigma_get_register(READ_MODE, devc);
+       } while (!(modestatus & RMR_POSTTRIGGERED));
 
        /* Set SDRAM Read Enable. */
-       sigma_set_register(WRITE_MODE, 0x02, devc);
+       sigma_set_register(WRITE_MODE, WMR_SDRAMREADEN, devc);
 
        /* Get the current position. */
        sigma_read_pos(&stoppos, &triggerpos, devc);
 
        /* Check if trigger has fired. */
        modestatus = sigma_get_register(READ_MODE, devc);
-       if (modestatus & 0x20) {
+       if (modestatus & RMR_TRIGGERED) {
                trg_line = triggerpos >> 9;
                trg_event = triggerpos & 0x1ff;
        }
 
+       devc->sent_samples = 0;
+
        /*
-        * Determine how many 1024b "DRAM lines" do we need to read from the
-        * Sigma so we have a complete set of samples. Note that the last
-        * line can be only partial, containing less than 64 clusters.
+        * Determine how many "DRAM lines" of 1024 bytes each we need to
+        * retrieve from the Sigma hardware, so that we have a complete
+        * set of samples. Note that the last line need not contain 64
+        * clusters, it might be partially filled only.
+        *
+        * When RMR_ROUND is set, the circular buffer in DRAM has wrapped
+        * around. Since the status of the very next line is uncertain in
+        * that case, we skip it and start reading from the next line. The
+        * circular buffer has 32K lines (0x8000).
         */
        dl_lines_total = (stoppos >> 9) + 1;
-
+       if (modestatus & RMR_ROUND) {
+               dl_first_line = dl_lines_total + 1;
+               dl_lines_total = 0x8000 - 2;
+       } else {
+               dl_first_line = 0;
+       }
        dl_lines_done = 0;
-
        while (dl_lines_total > dl_lines_done) {
                /* We can download only up-to 32 DRAM lines in one go! */
-               dl_lines_curr = MIN(chunks_per_read, dl_lines_total);
+               dl_lines_curr = MIN(chunks_per_read, dl_lines_total - dl_lines_done);
 
-               bufsz = sigma_read_dram(dl_lines_done, dl_lines_curr,
+               dl_line = dl_first_line + dl_lines_done;
+               dl_line %= 0x8000;
+               bufsz = sigma_read_dram(dl_line, dl_lines_curr,
                                        (uint8_t *)dram_line, devc);
                /* TODO: Check bufsz. For now, just avoid compiler warnings. */
                (void)bufsz;
@@ -1085,34 +1133,27 @@ static int download_capture(struct sr_dev_inst *sdi)
 }
 
 /*
- * Handle the Sigma when in CAPTURE mode. This function checks:
- * - Sampling time ended
- * - DRAM capacity overflow
- * This function triggers download of the samples from Sigma
- * in case either of the above conditions is true.
+ * Periodically check the Sigma status when in CAPTURE mode. This routine
+ * checks whether the configured sample count or sample time have passed,
+ * and will stop acquisition and download the acquired samples.
  */
 static int sigma_capture_mode(struct sr_dev_inst *sdi)
 {
        struct dev_context *devc;
        uint64_t running_msec;
-       struct timeval tv;
-       uint32_t stoppos, triggerpos;
+       uint64_t current_time;
 
        devc = sdi->priv;
 
-       /* Check if the selected sampling duration passed. */
-       gettimeofday(&tv, 0);
-       running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 +
-                      (tv.tv_usec - devc->start_tv.tv_usec) / 1000;
+       /*
+        * 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)
                return download_capture(sdi);
 
-       /* Get the position in DRAM to which the FPGA is writing now. */
-       sigma_read_pos(&stoppos, &triggerpos, devc);
-       /* Test if DRAM is full and if so, download the data. */
-       if ((stoppos >> 9) == 32767)
-               return download_capture(sdi);
-
        return TRUE;
 }