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). */