X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fasix-sigma%2Fapi.c;h=d8f9bf27c49206bfaa2522005e5c405d3434f4a9;hb=53c8a99c41120a5359e407934ae5041a285046e1;hp=140cbd832f19db3013e2798a56df0e613c8865ba;hpb=abcd47719689178ebb5e9050eb128312b17d82fa;p=libsigrok.git diff --git a/src/hardware/asix-sigma/api.c b/src/hardware/asix-sigma/api.c index 140cbd83..d8f9bf27 100644 --- a/src/hardware/asix-sigma/api.c +++ b/src/hardware/asix-sigma/api.c @@ -24,9 +24,9 @@ #include "protocol.h" /* - * Channel numbers seem to go from 1-16, according to this image: - * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg - * (the cable has two additional GND pins, and a TI and TO pin) + * Channels are labelled 1-16, see this vendor's image of the cable: + * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg (TI/TO are + * additional trigger in/out signals). */ static const char *channel_names[] = { "1", "2", "3", "4", "5", "6", "7", "8", @@ -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, @@ -243,9 +252,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devc->capture_ratio = 50; devc->use_triggers = 0; - /* TODO Retrieve some of this state from hardware? */ - devc->firmware_idx = SIGMA_FW_NONE; - devc->samplerate = sigma_get_samplerate(sdi); + /* Get current hardware configuration (or use defaults). */ + (void)sigma_fetch_hw_config(sdi); } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); @@ -280,6 +288,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 +301,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 +335,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 +356,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 +401,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)); @@ -380,9 +422,10 @@ static int config_list(uint32_t key, GVariant **data, static int dev_acquisition_start(const struct sr_dev_inst *sdi) { struct dev_context *devc; - struct clockselect_50 clockselect; + uint16_t pindis_mask; + uint8_t async, div; int triggerpin, ret; - uint8_t triggerselect; + uint8_t trigsel2; struct triggerinout triggerinout_conf; struct triggerlut lut; uint8_t regval, trgconf_bytes[2], clock_bytes[4], *wrptr; @@ -398,7 +441,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; @@ -413,13 +462,15 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) } /* Enter trigger programming mode. */ - ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x20); + trigsel2 = TRGSEL2_RESET; + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2); if (ret != SR_OK) return ret; - triggerselect = 0; - if (devc->samplerate >= SR_MHZ(100)) { + trigsel2 = 0; + 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); if (ret != SR_OK) return ret; @@ -433,23 +484,28 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) } /* Set trigger pin and light LED on trigger. */ - triggerselect = TRGSEL2_LEDSEL1 | (triggerpin & 0x7); + trigsel2 = triggerpin & TRGSEL2_PINS_MASK; + trigsel2 |= TRGSEL2_LEDSEL1; /* Default rising edge. */ + /* TODO Documentation disagrees, bit set means _rising_ edge. */ if (devc->trigger.fallingmask) - triggerselect |= 1 << 3; + trigsel2 |= TRGSEL2_PINPOL_RISE; - } else if (devc->samplerate <= SR_MHZ(50)) { - /* All other modes. */ + } else if (devc->clock.samplerate <= SR_MHZ(50)) { + /* 50MHz firmware modes. */ + + /* Translate application specs to hardware perspective. */ ret = sigma_build_basic_trigger(devc, &lut); if (ret != SR_OK) return ret; + /* Communicate resulting register values to the device. */ ret = sigma_write_trigger_lut(devc, &lut); if (ret != SR_OK) return ret; - triggerselect = TRGSEL2_LEDSEL1 | TRGSEL2_LEDSEL0; + trigsel2 = TRGSEL2_LEDSEL1 | TRGSEL2_LEDSEL0; } /* Setup trigger in and out pins to default values. */ @@ -481,36 +537,51 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) return ret; /* Leave trigger programming mode. */ - ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, triggerselect); + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2); if (ret != SR_OK) return ret; - /* Set clock select register. */ - clockselect.async = 0; - clockselect.fraction = 1; /* Divider 1. */ - clockselect.disabled_channels = 0x0000; /* All channels enabled. */ - if (devc->samplerate == SR_MHZ(200)) { - /* Enable 4 channels. */ - clockselect.disabled_channels = 0xfff0; - } else if (devc->samplerate == SR_MHZ(100)) { - /* Enable 8 channels. */ - clockselect.disabled_channels = 0xff00; + /* + * Samplerate dependent clock and channels configuration. Some + * channels by design are not available at higher clock rates. + * Register layout differs between firmware variants (depth 1 + * with LSB channel mask above 50MHz, depth 4 with more details + * up to 50MHz). + * + * Derive a mask where bits are set for unavailable channels. + * Either send the single byte, or the full byte sequence. + */ + pindis_mask = ~((1UL << devc->num_channels) - 1); + if (devc->clock.samplerate > SR_MHZ(50)) { + ret = sigma_set_register(devc, WRITE_CLOCK_SELECT, + pindis_mask & 0xff); } else { - /* - * 50 MHz mode, or fraction thereof. The 50MHz reference - * can get divided by any integer in the range 1 to 256. - * Divider minus 1 gets written to the hardware. - * (The driver lists a discrete set of sample rates, but - * all of them fit the above description.) - */ - clockselect.fraction = SR_MHZ(50) / devc->samplerate; + wrptr = clock_bytes; + /* Select 50MHz base clock, and divider. */ + async = 0; + 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); + ret = sigma_write_register(devc, WRITE_CLOCK_SELECT, + clock_bytes, wrptr - clock_bytes); } - wrptr = clock_bytes; - write_u8_inc(&wrptr, clockselect.async); - write_u8_inc(&wrptr, clockselect.fraction - 1); - write_u16be_inc(&wrptr, clockselect.disabled_channels); - count = wrptr - clock_bytes; - ret = sigma_write_register(devc, WRITE_CLOCK_SELECT, clock_bytes, count); if (ret != SR_OK) return ret;