X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=hardware%2Fsysclk-lwla%2Fprotocol.c;h=f1ae8b3d5d1fe1c1b146fa5d41ddb3eeb0f7ad50;hb=102f12396660e0784134bccce5cc0679db325751;hp=3618eb11030745e51da0035a8ce298e25549f9a2;hpb=8a3ddd8815aea40a2efd5987e754df1ec1322337;p=libsigrok.git diff --git a/hardware/sysclk-lwla/protocol.c b/hardware/sysclk-lwla/protocol.c index 3618eb11..f1ae8b3d 100644 --- a/hardware/sysclk-lwla/protocol.c +++ b/hardware/sysclk-lwla/protocol.c @@ -20,9 +20,6 @@ #include "protocol.h" #include -/* Bit mask covering all 34 channels. */ -#define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_PROBES) - 1) - /* Bit mask for the RLE repeat-count-follows flag. */ #define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35) @@ -32,13 +29,13 @@ /* Number of 64-bit words read from the capture status memory. */ #define CAP_STAT_LEN 5 -/* The bitstream filenames are indexed by the clock source enumeration. +/* The bitstream filenames are indexed by the clock_config enumeration. */ -static const char *const bitstream_map[] = { - FIRMWARE_DIR "/sysclk-lwla1034-off.bitstream", - FIRMWARE_DIR "/sysclk-lwla1034-int.bitstream", - FIRMWARE_DIR "/sysclk-lwla1034-extpos.bitstream", - FIRMWARE_DIR "/sysclk-lwla1034-extneg.bitstream", +static const char bitstream_map[][32] = { + "sysclk-lwla1034-off.rbf", + "sysclk-lwla1034-int.rbf", + "sysclk-lwla1034-extpos.rbf", + "sysclk-lwla1034-extneg.rbf", }; /* Submit an already filled-in USB transfer. @@ -64,11 +61,14 @@ static int submit_transfer(struct dev_context *devc, static int capture_setup(const struct sr_dev_inst *sdi) { struct dev_context *devc; + struct acquisition_state *acq; uint64_t divider_count; + uint64_t trigger_mask; uint64_t memory_limit; uint16_t command[3 + 10*4]; devc = sdi->priv; + acq = devc->acquisition; command[0] = LWLA_WORD(CMD_CAP_SETUP); command[1] = LWLA_WORD(0); /* address */ @@ -83,7 +83,7 @@ static int capture_setup(const struct sr_dev_inst *sdi) * 100 MHz. At the highest samplerate of 125 MHz the clock divider * is bypassed. */ - if (devc->samplerate > 0 && devc->samplerate < SR_MHZ(100)) + if (!acq->bypass_clockdiv && devc->samplerate > 0) divider_count = SR_MHZ(100) / devc->samplerate - 1; else divider_count = 0; @@ -103,10 +103,18 @@ static int capture_setup(const struct sr_dev_inst *sdi) command[17] = LWLA_WORD_2(devc->trigger_edge_mask); command[18] = LWLA_WORD_3(devc->trigger_edge_mask); - command[19] = LWLA_WORD_0(devc->trigger_mask); - command[20] = LWLA_WORD_1(devc->trigger_mask); - command[21] = LWLA_WORD_2(devc->trigger_mask); - command[22] = LWLA_WORD_3(devc->trigger_mask); + trigger_mask = devc->trigger_mask; + /* Set bits to select external TRG input edge. */ + if (devc->cfg_trigger_source == TRIGGER_EXT_TRG) + switch (devc->cfg_trigger_slope) { + case EDGE_POSITIVE: trigger_mask |= (uint64_t)1 << 35; break; + case EDGE_NEGATIVE: trigger_mask |= (uint64_t)1 << 34; break; + } + + command[19] = LWLA_WORD_0(trigger_mask); + command[20] = LWLA_WORD_1(trigger_mask); + command[21] = LWLA_WORD_2(trigger_mask); + command[22] = LWLA_WORD_3(trigger_mask); /* Set the capture memory full threshold. This is slightly less * than the actual maximum, most likely in order to compensate for @@ -229,16 +237,15 @@ static void issue_read_start(const struct sr_dev_inst *sdi) acq->sample = 0; acq->run_len = 0; - acq->captured_samples = 0; - acq->transferred_samples = 0; + acq->samples_done = 0; /* For some reason, the start address is 4 rather than 0. */ acq->mem_addr_done = 4; acq->mem_addr_next = 4; acq->mem_addr_stop = acq->mem_addr_fill; - /* Byte offset into the packet output buffer. */ - acq->out_offset = 0; + /* Sample position in the packet output buffer. */ + acq->out_index = 0; regvals = devc->reg_write_seq; @@ -258,6 +265,10 @@ static void issue_read_start(const struct sr_dev_inst *sdi) devc->state = STATE_READ_PREPARE; } +/* Issue a command as an asynchronous USB transfer which returns the device + * to normal state after a read operation. Sets a new device context state + * on success. + */ static void issue_read_end(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -285,10 +296,9 @@ static void process_capture_length(const struct sr_dev_inst *sdi) devc->transfer_error = TRUE; return; } - acq->mem_addr_fill = LWLA_READ32(acq->xfer_buf_in); + acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); - sr_dbg("%lu words in capture buffer.", - (unsigned long)acq->mem_addr_fill); + sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill); if (acq->mem_addr_fill > 0 && sdi->status == SR_ST_ACTIVE) issue_read_start(sdi); @@ -342,9 +352,10 @@ static void issue_stop_capture(const struct sr_dev_inst *sdi) static void process_capture_status(const struct sr_dev_inst *sdi) { uint64_t duration; - uint64_t timescale; struct dev_context *devc; struct acquisition_state *acq; + unsigned int mem_fill; + unsigned int flags; devc = sdi->priv; acq = devc->acquisition; @@ -360,22 +371,32 @@ static void process_capture_status(const struct sr_dev_inst *sdi) * in the FPGA. These fields are definitely less than 64 bit wide * internally, and the unused bits occasionally even contain garbage. */ - acq->mem_addr_fill = LWLA_READ32(&acq->xfer_buf_in[0]); - duration = LWLA_READ32(&acq->xfer_buf_in[8]); - acq->capture_flags = LWLA_READ32(&acq->xfer_buf_in[16]) - & STATUS_FLAG_MASK; - - /* The 125 MHz setting is special, and uses the same timebase - * for the duration field as the 100 MHz setting. + mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]); + duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]); + flags = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK; + + /* The LWLA1034 runs at 125 MHz if the clock divider is bypassed. + * However, the time base used for the duration is apparently not + * adjusted for this "boost" mode. Whereas normally the duration + * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed. + * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle + * counter period is the same as at the 100 MHz setting. */ - timescale = MIN(devc->samplerate, SR_MHZ(100)); - acq->captured_samples = (duration * timescale) / 1000; + if (acq->bypass_clockdiv) + acq->duration_now = duration * 4 / 5; + else + acq->duration_now = duration; + + sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.", + mem_fill, acq->duration_now, flags); + + if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED)) + sr_info("Capture triggered."); - sr_spew("Captured %lu words, %" PRIu64 " samples, flags 0x%02X", - (unsigned long)acq->mem_addr_fill, - acq->captured_samples, acq->capture_flags); + acq->capture_flags = flags; - if (acq->captured_samples >= devc->limit_samples) { + if (acq->duration_now >= acq->duration_max) { + sr_dbg("Time limit reached, stopping capture."); issue_stop_capture(sdi); return; } @@ -425,49 +446,6 @@ static void request_read_mem(const struct sr_dev_inst *sdi) } } -/* Send a packet of logic samples to the session bus. The payload is taken - * from the acquisition state. The return value indicates whether to stop - * reading more samples. - */ -static gboolean send_logic_packet(const struct sr_dev_inst *sdi) -{ - uint64_t samples; - struct dev_context *devc; - struct acquisition_state *acq; - struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - int last; - - devc = sdi->priv; - acq = devc->acquisition; - - if (acq->transferred_samples >= devc->limit_samples) - return TRUE; - - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.unitsize = UNIT_SIZE; - logic.data = acq->out_packet; - logic.length = acq->out_offset; - - samples = acq->out_offset / UNIT_SIZE; - last = FALSE; - - /* Cut the packet short if necessary. */ - if (acq->transferred_samples + samples >= devc->limit_samples) { - samples = devc->limit_samples - acq->transferred_samples; - logic.length = samples * UNIT_SIZE; - last = TRUE; - } - acq->transferred_samples += samples; - acq->out_offset = 0; - - /* Send off logic datafeed packet. */ - sr_session_send(sdi, &packet); - - return last; -} - /* Demangle and decompress incoming sample data from the capture buffer. * The data chunk is taken from the acquisition state, and is expected to * contain a multiple of 8 device words. @@ -478,15 +456,19 @@ static gboolean send_logic_packet(const struct sr_dev_inst *sdi) static int process_sample_data(const struct sr_dev_inst *sdi) { uint64_t sample; - uint64_t run_len; uint64_t high_nibbles; uint64_t word; struct dev_context *devc; struct acquisition_state *acq; uint8_t *out_p; - uint16_t *slice; + uint32_t *slice; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; size_t expect_len; size_t actual_len; + size_t out_max_samples; + size_t out_run_samples; + size_t ri; size_t in_words_left; size_t si; @@ -494,54 +476,76 @@ static int process_sample_data(const struct sr_dev_inst *sdi) acq = devc->acquisition; if (acq->mem_addr_done >= acq->mem_addr_stop - || acq->transferred_samples >= devc->limit_samples) + || acq->samples_done >= acq->samples_max) return SR_OK; in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done, READ_CHUNK_LEN); - expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint16_t); + expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t); actual_len = acq->xfer_in->actual_length; if (actual_len != expect_len) { - sr_err("Received size %lu does not match expected size %lu.", - (unsigned long)actual_len, (unsigned long)expect_len); + sr_err("Received size %zu does not match expected size %zu.", + actual_len, expect_len); devc->transfer_error = TRUE; return SR_ERR; } acq->mem_addr_done += in_words_left; + + /* Prepare session packet. */ + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.unitsize = UNIT_SIZE; + logic.data = acq->out_packet; + slice = acq->xfer_buf_in; si = 0; /* word index within slice */ for (;;) { - sample = acq->sample; + /* Calculate number of samples to write into packet. */ + out_max_samples = MIN(acq->samples_max - acq->samples_done, + PACKET_LENGTH - acq->out_index); + out_run_samples = MIN(acq->run_len, out_max_samples); + /* Expand run-length samples into session packet. */ - for (run_len = acq->run_len; run_len > 0; --run_len) { - out_p = &acq->out_packet[acq->out_offset]; + sample = acq->sample; + out_p = &acq->out_packet[acq->out_index * UNIT_SIZE]; + + for (ri = 0; ri < out_run_samples; ++ri) { out_p[0] = sample & 0xFF; out_p[1] = (sample >> 8) & 0xFF; out_p[2] = (sample >> 16) & 0xFF; out_p[3] = (sample >> 24) & 0xFF; out_p[4] = (sample >> 32) & 0xFF; - acq->out_offset += UNIT_SIZE; - - /* Send out packet if it is full. */ - if (acq->out_offset > PACKET_SIZE - UNIT_SIZE) - if (send_logic_packet(sdi)) - return SR_OK; /* sample limit reached */ + out_p += UNIT_SIZE; + } + acq->run_len -= out_run_samples; + acq->out_index += out_run_samples; + acq->samples_done += out_run_samples; + + /* Packet full or sample count limit reached? */ + if (out_run_samples == out_max_samples) { + logic.length = acq->out_index * UNIT_SIZE; + sr_session_send(sdi, &packet); + acq->out_index = 0; + + if (acq->samples_done >= acq->samples_max) + return SR_OK; /* sample limit reached */ + if (acq->run_len > 0) + continue; /* need another packet */ } - acq->run_len = 0; if (in_words_left == 0) break; /* done with current chunk */ /* Now work on the current slice. */ - high_nibbles = LWLA_READ32(&slice[8 * 2]); - word = LWLA_READ32(&slice[si * 2]); + high_nibbles = LWLA_TO_UINT32(slice[8]); + word = LWLA_TO_UINT32(slice[si]); word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32); if (acq->rle == RLE_STATE_DATA) { acq->sample = word & ALL_CHANNELS_MASK; - acq->run_len = ((word >> NUM_PROBES) & 1) + 1; + acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1; if (word & RLE_FLAG_LEN_FOLLOWS) acq->rle = RLE_STATE_LEN; } else { @@ -550,17 +554,18 @@ static int process_sample_data(const struct sr_dev_inst *sdi) } /* Move to next word. */ - if (++si >= 8) { - si = 0; - slice += 9 * 2; - } + si = (si + 1) % 8; + if (si == 0) + slice += 9; --in_words_left; } - /* Send out partially filled packet if it is the last one. */ - if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_offset > 0) - send_logic_packet(sdi); - + /* Send out partially filled packet if this was the last chunk. */ + if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) { + logic.length = acq->out_index * UNIT_SIZE; + sr_session_send(sdi, &packet); + acq->out_index = 0; + } return SR_OK; } @@ -582,7 +587,7 @@ static void end_acquisition(struct sr_dev_inst *sdi) devc->state = STATE_IDLE; /* Remove USB file descriptors from polling. */ - usb_source_remove(drvc->sr_ctx); + usb_source_remove(sdi->session, drvc->sr_ctx); packet.type = SR_DF_END; sr_session_send(sdi, &packet); @@ -675,7 +680,7 @@ static void receive_transfer_in(struct libusb_transfer *transfer) case STATE_READ_RESPONSE: if (process_sample_data(sdi) == SR_OK && acq->mem_addr_next < acq->mem_addr_stop - && acq->transferred_samples < devc->limit_samples) + && acq->samples_done < acq->samples_max) request_read_mem(sdi); else issue_read_end(sdi); @@ -697,14 +702,10 @@ SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi) devc = sdi->priv; - /* Select internal clock if it hasn't been set yet */ - if (devc->selected_clock_source == CLOCK_SOURCE_NONE) - devc->selected_clock_source = CLOCK_SOURCE_INT; - /* Force reload of bitstream */ - devc->cur_clock_source = CLOCK_SOURCE_NONE; + devc->cur_clock_config = CONF_CLOCK_NONE; - ret = lwla_set_clock_source(sdi); + ret = lwla_set_clock_config(sdi); if (ret != SR_OK) return ret; @@ -716,49 +717,102 @@ SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi) ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL1, &value); if (ret != SR_OK) return ret; - sr_info("Received test word 0x%08X back.", value); + sr_dbg("Received test word 0x%08X back.", value); if (value != 0x12345678) return SR_ERR; ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL4, &value); if (ret != SR_OK) return ret; - sr_info("Received test word 0x%08X back.", value); + sr_dbg("Received test word 0x%08X back.", value); if (value != 0x12345678) return SR_ERR; ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL3, &value); if (ret != SR_OK) return ret; - sr_info("Received test word 0x%08X back.", value); + sr_dbg("Received test word 0x%08X back.", value); if (value != 0x87654321) return SR_ERR; return ret; } -/* Select the LWLA clock source. If the clock source changed from the - * previous setting, this will download a new bitstream to the FPGA. +SR_PRIV int lwla_convert_trigger(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + struct sr_trigger *trigger; + struct sr_trigger_stage *stage; + struct sr_trigger_match *match; + const GSList *l, *m; + uint64_t channel_index; + + devc = sdi->priv; + + devc->trigger_mask = 0; + devc->trigger_values = 0; + devc->trigger_edge_mask = 0; + + if (!(trigger = sr_session_trigger_get(sdi->session))) + return SR_OK; + + if (g_slist_length(trigger->stages) > 1) { + sr_err("This device only supports 1 trigger stage."); + return SR_ERR; + } + + for (l = trigger->stages; l; l = l->next) { + stage = l->data; + for (m = stage->matches; m; m = m->next) { + match = m->data; + if (!match->channel->enabled) + /* Ignore disabled channels with a trigger. */ + continue; + channel_index = 1 << match->channel->index; + devc->trigger_mask |= channel_index; + switch (match->match) { + case SR_TRIGGER_ONE: + devc->trigger_values |= channel_index; + break; + case SR_TRIGGER_RISING: + devc->trigger_values |= channel_index; + /* Fall through for edge mask. */ + case SR_TRIGGER_FALLING: + devc->trigger_edge_mask |= channel_index; + break; + } + } + } + + return SR_OK; +} + +/* Select the LWLA clock configuration. If the clock source changed from + * the previous setting, this will download a new bitstream to the FPGA. */ -SR_PRIV int lwla_set_clock_source(const struct sr_dev_inst *sdi) +SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi) { struct dev_context *devc; int ret; - enum clock_source selected; + enum clock_config choice; devc = sdi->priv; - selected = devc->selected_clock_source; - if (devc->cur_clock_source != selected) { - devc->cur_clock_source = CLOCK_SOURCE_NONE; + if (sdi->status == SR_ST_INACTIVE) + choice = CONF_CLOCK_NONE; + else if (devc->cfg_clock_source == CLOCK_INTERNAL) + choice = CONF_CLOCK_INT; + else if (devc->cfg_clock_edge == EDGE_POSITIVE) + choice = CONF_CLOCK_EXT_RISE; + else + choice = CONF_CLOCK_EXT_FALL; - if (selected >= 0 && selected < G_N_ELEMENTS(bitstream_map)) { - ret = lwla_send_bitstream(sdi->conn, - bitstream_map[selected]); - if (ret == SR_OK) - devc->cur_clock_source = selected; - return ret; - } + if (choice != devc->cur_clock_config) { + devc->cur_clock_config = CONF_CLOCK_NONE; + ret = lwla_send_bitstream(sdi->conn, bitstream_map[choice]); + if (ret == SR_OK) + devc->cur_clock_config = choice; + return ret; } return SR_OK; } @@ -769,11 +823,51 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct sr_usb_dev_inst *usb; + struct acquisition_state *acq; struct regval_pair regvals[7]; int ret; devc = sdi->priv; usb = sdi->conn; + acq = devc->acquisition; + + if (devc->limit_msec > 0) { + acq->duration_max = devc->limit_msec; + sr_info("Acquisition time limit %" PRIu64 " ms.", + devc->limit_msec); + } else + acq->duration_max = MAX_LIMIT_MSEC; + + if (devc->limit_samples > 0) { + acq->samples_max = devc->limit_samples; + sr_info("Acquisition sample count limit %" PRIu64 ".", + devc->limit_samples); + } else + acq->samples_max = MAX_LIMIT_SAMPLES; + + if (devc->cfg_clock_source == CLOCK_INTERNAL) { + sr_info("Internal clock, samplerate %" PRIu64 ".", + devc->samplerate); + if (devc->samplerate == 0) + return SR_ERR_BUG; + /* At 125 MHz, the clock divider is bypassed. */ + acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100)); + + /* If only one of the limits is set, derive the other one. */ + if (devc->limit_msec == 0 && devc->limit_samples > 0) + acq->duration_max = devc->limit_samples + * 1000 / devc->samplerate + 1; + else if (devc->limit_samples == 0 && devc->limit_msec > 0) + acq->samples_max = devc->limit_msec + * devc->samplerate / 1000; + } else { + acq->bypass_clockdiv = TRUE; + + if (devc->cfg_clock_edge == EDGE_NEGATIVE) + sr_info("External clock, falling edge."); + else + sr_info("External clock, rising edge."); + } regvals[0].reg = REG_MEM_CTRL2; regvals[0].val = 2; @@ -794,7 +888,7 @@ SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi) regvals[5].val = 0; regvals[6].reg = REG_DIV_BYPASS; - regvals[6].val = (devc->samplerate > SR_MHZ(100)) ? 1 : 0; + regvals[6].val = acq->bypass_clockdiv; ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals)); if (ret != SR_OK) @@ -818,6 +912,10 @@ SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi) usb = sdi->conn; acq = devc->acquisition; + acq->duration_now = 0; + acq->mem_addr_fill = 0; + acq->capture_flags = 0; + libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND, (unsigned char *)acq->xfer_buf_out, 0, &receive_transfer_out,