]> sigrok.org Git - libsigrok.git/commitdiff
asix-sigma: add support for external clock
authorGerhard Sittig <redacted>
Sat, 16 May 2020 17:37:52 +0000 (19:37 +0200)
committerGerhard Sittig <redacted>
Fri, 29 May 2020 06:06:18 +0000 (08:06 +0200)
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.

src/hardware/asix-sigma/api.c
src/hardware/asix-sigma/protocol.c
src/hardware/asix-sigma/protocol.h

index b66957b477c3d8b9b6c5215a917454b2f519f196..bbeb59e0d04a3fa134a046e0d026fef8314b850a 100644 (file)
@@ -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);
index 9b61fd56a0a61702370aca0a6495a8522ff5aaa7..dd74ec98cc156a07af0532a6a49ef1cb0a3a8165 100644 (file)
@@ -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);
                }
index 1311c935d10b32f2b4e23e826c686124e97b3f82..406f9e4d140817bba31fd196ddf2cf9cf8b46e3e 100644 (file)
@@ -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). */