From: Gerhard Sittig Date: Sat, 16 May 2020 17:37:52 +0000 (+0200) Subject: asix-sigma: add support for external clock X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=2d8a50897614e097cffa36dd7a3acd7d9032a9a1;p=libsigrok.git asix-sigma: add support for external clock The 50MHz netlist supports the use of an external clock. Any of the 16 channels can use any of its edges to have another sample taken from all the other pins. It's nice that the hardware does track timestamps, which results in an exact reproduction of the input signals' timing with 20ns resolution, although the clock is externally provided and need not have a fixed rate. --- diff --git a/src/hardware/asix-sigma/api.c b/src/hardware/asix-sigma/api.c index b66957b4..bbeb59e0 100644 --- a/src/hardware/asix-sigma/api.c +++ b/src/hardware/asix-sigma/api.c @@ -46,12 +46,21 @@ static const uint32_t devopts[] = { SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, SR_CONF_CONN | SR_CONF_GET, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, + SR_CONF_EXTERNAL_CLOCK_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, #if ASIX_SIGMA_WITH_TRIGGER SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, #endif }; +static const char *ext_clock_edges[] = { + [SIGMA_CLOCK_EDGE_RISING] = "rising", + [SIGMA_CLOCK_EDGE_FALLING] = "falling", + [SIGMA_CLOCK_EDGE_EITHER] = "either", +}; + #if ASIX_SIGMA_WITH_TRIGGER static const int32_t trigger_matches[] = { SR_TRIGGER_ZERO, @@ -245,7 +254,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) /* TODO Retrieve some of this state from hardware? */ devc->firmware_idx = SIGMA_FW_NONE; - devc->samplerate = sigma_get_samplerate(sdi); + devc->clock.samplerate = sigma_get_samplerate(sdi); } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); @@ -280,6 +289,7 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; + const char *clock_text; (void)cg; @@ -292,7 +302,18 @@ static int config_get(uint32_t key, GVariant **data, *data = g_variant_new_string(sdi->connection_id); break; case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(devc->samplerate); + *data = g_variant_new_uint64(devc->clock.samplerate); + break; + case SR_CONF_EXTERNAL_CLOCK: + *data = g_variant_new_boolean(devc->clock.use_ext_clock); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + clock_text = channel_names[devc->clock.clock_pin]; + *data = g_variant_new_string(clock_text); + break; + case SR_CONF_CLOCK_EDGE: + clock_text = ext_clock_edges[devc->clock.clock_edge]; + *data = g_variant_new_string(clock_text); break; case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_SAMPLES: @@ -315,6 +336,7 @@ static int config_set(uint32_t key, GVariant *data, struct dev_context *devc; int ret; uint64_t want_rate, have_rate; + int idx; (void)cg; @@ -335,7 +357,22 @@ static int config_set(uint32_t key, GVariant *data, g_free(text_want); g_free(text_have); } - devc->samplerate = have_rate; + devc->clock.samplerate = have_rate; + break; + case SR_CONF_EXTERNAL_CLOCK: + devc->clock.use_ext_clock = g_variant_get_boolean(data); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + idx = std_str_idx(data, ARRAY_AND_SIZE(channel_names)); + if (idx < 0) + return SR_ERR_ARG; + devc->clock.clock_pin = idx; + break; + case SR_CONF_CLOCK_EDGE: + idx = std_str_idx(data, ARRAY_AND_SIZE(ext_clock_edges)); + if (idx < 0) + return SR_ERR_ARG; + devc->clock.clock_edge = idx; break; case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_SAMPLES: @@ -365,6 +402,12 @@ static int config_list(uint32_t key, GVariant **data, case SR_CONF_SAMPLERATE: *data = sigma_get_samplerates_list(); break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + *data = g_variant_new_strv(ARRAY_AND_SIZE(channel_names)); + break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_strv(ARRAY_AND_SIZE(ext_clock_edges)); + break; #if ASIX_SIGMA_WITH_TRIGGER case SR_CONF_TRIGGER_MATCH: *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); @@ -399,7 +442,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) * * Determine an acquisition timeout from optionally configured * sample count or time limits. Which depends on the samplerate. + * Force 50MHz samplerate when external clock is in use. */ + if (devc->clock.use_ext_clock) { + if (devc->clock.samplerate != SR_MHZ(50)) + sr_info("External clock, forcing 50MHz samplerate."); + devc->clock.samplerate = SR_MHZ(50); + } ret = sigma_set_samplerate(sdi); if (ret != SR_OK) return ret; @@ -420,7 +469,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return ret; trigsel2 = 0; - if (devc->samplerate >= SR_MHZ(100)) { + if (devc->clock.samplerate >= SR_MHZ(100)) { /* 100 and 200 MHz mode. */ /* TODO Decipher the 0x81 magic number's purpose. */ ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x81); @@ -444,7 +493,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) if (devc->trigger.fallingmask) trigsel2 |= TRGSEL2_PINPOL_RISE; - } else if (devc->samplerate <= SR_MHZ(50)) { + } else if (devc->clock.samplerate <= SR_MHZ(50)) { /* 50MHz firmware modes. */ /* Translate application specs to hardware perspective. */ @@ -504,21 +553,30 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) * Either send the single byte, or the full byte sequence. */ pindis_mask = ~((1UL << devc->num_channels) - 1); - if (devc->samplerate > SR_MHZ(50)) { + if (devc->clock.samplerate > SR_MHZ(50)) { ret = sigma_set_register(devc, WRITE_CLOCK_SELECT, pindis_mask & 0xff); } else { wrptr = clock_bytes; /* Select 50MHz base clock, and divider. */ async = 0; - div = SR_MHZ(50) / devc->samplerate - 1; - /* - * TODO Optionally use external clock. - * async[0] = 1 to enable external clock - * div[5] = 1 to select falling edge - * div[4] = 1 to select rising edge - * div[3:0] = 1..16 to select clock pin - */ + div = SR_MHZ(50) / devc->clock.samplerate - 1; + if (devc->clock.use_ext_clock) { + async = CLKSEL_CLKSEL8; + div = devc->clock.clock_pin + 1; + switch (devc->clock.clock_edge) { + case SIGMA_CLOCK_EDGE_RISING: + div |= CLKSEL_RISING; + break; + case SIGMA_CLOCK_EDGE_FALLING: + div |= CLKSEL_FALLING; + break; + case SIGMA_CLOCK_EDGE_EITHER: + div |= CLKSEL_RISING; + div |= CLKSEL_FALLING; + break; + } + } write_u8_inc(&wrptr, async); write_u8_inc(&wrptr, div); write_u16be_inc(&wrptr, pindis_mask); diff --git a/src/hardware/asix-sigma/protocol.c b/src/hardware/asix-sigma/protocol.c index 9b61fd56..dd74ec98 100644 --- a/src/hardware/asix-sigma/protocol.c +++ b/src/hardware/asix-sigma/protocol.c @@ -943,7 +943,7 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) g_variant_unref(data); count_msecs = 0; if (user_count) - count_msecs = 1000 * user_count / devc->samplerate + 1; + count_msecs = 1000 * user_count / devc->clock.samplerate + 1; /* Get time limit, which is in msecs. */ ret = sr_sw_limits_config_get(&devc->cfg_limits, @@ -963,7 +963,7 @@ SR_PRIV int sigma_set_acquire_timeout(struct dev_context *devc) return SR_OK; /* Add some slack, and use that timeout for acquisition. */ - worst_cluster_time_ms = 1000 * 65536 / devc->samplerate; + worst_cluster_time_ms = 1000 * 65536 / devc->clock.samplerate; acquire_msecs += 2 * worst_cluster_time_ms; data = g_variant_new_uint64(acquire_msecs); ret = sr_sw_limits_config_set(&devc->acq_limits, @@ -1033,7 +1033,7 @@ SR_PRIV int sigma_set_samplerate(const struct sr_dev_inst *sdi) drvc = sdi->driver->context; /* Accept any caller specified rate which the hardware supports. */ - ret = sigma_normalize_samplerate(devc->samplerate, &samplerate); + ret = sigma_normalize_samplerate(devc->clock.samplerate, &samplerate); if (ret != SR_OK) return ret; @@ -1257,7 +1257,7 @@ SR_PRIV int sigma_convert_trigger(const struct sr_dev_inst *sdi) if (!match->channel->enabled) continue; channelbit = 1 << match->channel->index; - if (devc->samplerate >= SR_MHZ(100)) { + if (devc->clock.samplerate >= SR_MHZ(100)) { /* Fast trigger support. */ if (trigger_set) { sr_err("100/200MHz modes limited to single trigger pin."); @@ -1481,7 +1481,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->samplerate == SR_MHZ(200)) { + if (devc->clock.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); @@ -1490,7 +1490,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->samplerate == SR_MHZ(100)) { + } else if (devc->clock.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); @@ -1529,7 +1529,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->samplerate <= SR_MHZ(50)) { + if (devc->clock.samplerate <= SR_MHZ(50)) { trigger_event -= MIN(EVENTS_PER_CLUSTER - 1, trigger_event); } diff --git a/src/hardware/asix-sigma/protocol.h b/src/hardware/asix-sigma/protocol.h index 1311c935..406f9e4d 100644 --- a/src/hardware/asix-sigma/protocol.h +++ b/src/hardware/asix-sigma/protocol.h @@ -129,6 +129,11 @@ enum sigma_read_register { #define BIT_MASK(l) ((1UL << (l)) - 1) +#define CLKSEL_CLKSEL8 (1 << 0) +#define CLKSEL_PINMASK BIT_MASK(4) +#define CLKSEL_RISING (1 << 4) +#define CLKSEL_FALLING (1 << 5) + #define TRGSEL_SELINC_MASK BIT_MASK(2) #define TRGSEL_SELINC_SHIFT 0 #define TRGSEL_SELRES_MASK BIT_MASK(2) @@ -341,6 +346,12 @@ enum sigma_firmware_idx { SIGMA_FW_FREQ, }; +enum ext_clock_edge_t { + SIGMA_CLOCK_EDGE_RISING, + SIGMA_CLOCK_EDGE_FALLING, + SIGMA_CLOCK_EDGE_EITHER, +}; + struct submit_buffer; struct dev_context { @@ -354,7 +365,12 @@ struct dev_context { struct ftdi_context ctx; gboolean is_open, must_close; } ftdi; - uint64_t samplerate; + struct { + uint64_t samplerate; + gboolean use_ext_clock; + size_t clock_pin; + enum ext_clock_edge_t clock_edge; + } clock; struct sr_sw_limits cfg_limits; /* Configured limits (user specified). */ struct sr_sw_limits acq_limits; /* Acquisition limits (internal use). */ struct sr_sw_limits feed_limits; /* Datafeed limits (internal use). */