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.
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_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
};
#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,
#if ASIX_SIGMA_WITH_TRIGGER
static const int32_t trigger_matches[] = {
SR_TRIGGER_ZERO,
/* TODO Retrieve some of this state from hardware? */
devc->firmware_idx = SIGMA_FW_NONE;
/* 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);
}
libusb_free_device_list(devlist, 1);
g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
{
struct dev_context *devc;
+ const char *clock_text;
*data = g_variant_new_string(sdi->connection_id);
break;
case SR_CONF_SAMPLERATE:
*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:
break;
case SR_CONF_LIMIT_MSEC:
case SR_CONF_LIMIT_SAMPLES:
struct dev_context *devc;
int ret;
uint64_t want_rate, have_rate;
struct dev_context *devc;
int ret;
uint64_t want_rate, have_rate;
g_free(text_want);
g_free(text_have);
}
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:
break;
case SR_CONF_LIMIT_MSEC:
case SR_CONF_LIMIT_SAMPLES:
case SR_CONF_SAMPLERATE:
*data = sigma_get_samplerates_list();
break;
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));
#if ASIX_SIGMA_WITH_TRIGGER
case SR_CONF_TRIGGER_MATCH:
*data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches));
*
* Determine an acquisition timeout from optionally configured
* sample count or time limits. Which depends on the samplerate.
*
* 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;
ret = sigma_set_samplerate(sdi);
if (ret != SR_OK)
return ret;
return ret;
trigsel2 = 0;
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);
/* 100 and 200 MHz mode. */
/* TODO Decipher the 0x81 magic number's purpose. */
ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x81);
if (devc->trigger.fallingmask)
trigsel2 |= TRGSEL2_PINPOL_RISE;
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. */
/* 50MHz firmware modes. */
/* Translate application specs to hardware perspective. */
* Either send the single byte, or the full byte sequence.
*/
pindis_mask = ~((1UL << devc->num_channels) - 1);
* 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;
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);
write_u8_inc(&wrptr, async);
write_u8_inc(&wrptr, div);
write_u16be_inc(&wrptr, pindis_mask);
g_variant_unref(data);
count_msecs = 0;
if (user_count)
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,
/* Get time limit, which is in msecs. */
ret = sr_sw_limits_config_get(&devc->cfg_limits,
return SR_OK;
/* Add some slack, and use that timeout for acquisition. */
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,
acquire_msecs += 2 * worst_cluster_time_ms;
data = g_variant_new_uint64(acquire_msecs);
ret = sr_sw_limits_config_set(&devc->acq_limits,
drvc = sdi->driver->context;
/* Accept any caller specified rate which the hardware supports. */
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;
if (ret != SR_OK)
return ret;
if (!match->channel->enabled)
continue;
channelbit = 1 << match->channel->index;
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.");
/* Fast trigger support. */
if (trigger_set) {
sr_err("100/200MHz modes limited to single trigger pin.");
sample = 0;
for (i = 0; i < events_in_cluster; i++) {
item16 = sigma_dram_cluster_data(dram_cluster, i);
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);
sample = sigma_deinterlace_200mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 1);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_200mhz_data(item16, 3);
check_and_submit_sample(devc, sample, 1, triggered);
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);
sample = sigma_deinterlace_100mhz_data(item16, 0);
check_and_submit_sample(devc, sample, 1, triggered);
sample = sigma_deinterlace_100mhz_data(item16, 1);
/* Check if trigger is in this chunk. */
if (trigger_event < EVENTS_PER_ROW) {
/* 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);
}
trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
trigger_event);
}
#define BIT_MASK(l) ((1UL << (l)) - 1)
#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)
#define TRGSEL_SELINC_MASK BIT_MASK(2)
#define TRGSEL_SELINC_SHIFT 0
#define TRGSEL_SELRES_MASK BIT_MASK(2)
+enum ext_clock_edge_t {
+ SIGMA_CLOCK_EDGE_RISING,
+ SIGMA_CLOCK_EDGE_FALLING,
+ SIGMA_CLOCK_EDGE_EITHER,
+};
+
struct submit_buffer;
struct dev_context {
struct submit_buffer;
struct dev_context {
struct ftdi_context ctx;
gboolean is_open, must_close;
} ftdi;
struct ftdi_context ctx;
gboolean is_open, must_close;
} ftdi;
+ 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). */
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). */