Add support for mcupro Logic16, a Saleae Logic16 clone.
From sigrok's point of view, this analyzer has two differences: * It does not require uploading the firmware. * It returns garbage in some registers used for sanity checks. Saleae's software ignores that garbage; sigrok only does if it specifically detects the mcupro clone.
This commit is contained in:
parent
f88c73732c
commit
6f479a0a72
|
@ -292,8 +292,8 @@ static int prime_fpga(const struct sr_dev_inst *sdi)
|
||||||
if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK)
|
if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (version != 0x10) {
|
if (version != 0x10 && version != 0x40 && version != 0x41) {
|
||||||
sr_err("Invalid FPGA bitstream version: 0x%02x != 0x10.", version);
|
sr_err("Unsupported FPGA version: 0x%02x.", version);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,53 +337,55 @@ static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
|
||||||
if (devc->cur_voltage_range == vrange)
|
if (devc->cur_voltage_range == vrange)
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
|
|
||||||
switch (vrange) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL) {
|
||||||
case VOLTAGE_RANGE_18_33_V:
|
switch (vrange) {
|
||||||
filename = FPGA_FIRMWARE_18;
|
case VOLTAGE_RANGE_18_33_V:
|
||||||
break;
|
filename = FPGA_FIRMWARE_18;
|
||||||
case VOLTAGE_RANGE_5_V:
|
|
||||||
filename = FPGA_FIRMWARE_33;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sr_err("Unsupported voltage range.");
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sr_info("Uploading FPGA bitstream at %s.", filename);
|
|
||||||
if ((fw = g_fopen(filename, "rb")) == NULL) {
|
|
||||||
sr_err("Unable to open bitstream file %s for reading: %s.",
|
|
||||||
filename, strerror(errno));
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf[0] = COMMAND_FPGA_UPLOAD_INIT;
|
|
||||||
if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) {
|
|
||||||
fclose(fw);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
chunksize = fread(buf, 1, sizeof(buf), fw);
|
|
||||||
if (chunksize == 0)
|
|
||||||
break;
|
break;
|
||||||
|
case VOLTAGE_RANGE_5_V:
|
||||||
for (offset = 0; offset < chunksize; offset += 62) {
|
filename = FPGA_FIRMWARE_33;
|
||||||
len = (offset + 62 > chunksize ?
|
break;
|
||||||
chunksize - offset : 62);
|
default:
|
||||||
command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA;
|
sr_err("Unsupported voltage range.");
|
||||||
command[1] = len;
|
return SR_ERR;
|
||||||
memcpy(command + 2, buf + offset, len);
|
|
||||||
ret = do_ep1_command(sdi, command, len + 2, NULL, 0);
|
|
||||||
if (ret != SR_OK) {
|
|
||||||
fclose(fw);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sr_info("Uploaded %d bytes.", chunksize);
|
sr_info("Uploading FPGA bitstream at %s.", filename);
|
||||||
|
if ((fw = g_fopen(filename, "rb")) == NULL) {
|
||||||
|
sr_err("Unable to open bitstream file %s for reading: %s.",
|
||||||
|
filename, strerror(errno));
|
||||||
|
return SR_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = COMMAND_FPGA_UPLOAD_INIT;
|
||||||
|
if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) {
|
||||||
|
fclose(fw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
chunksize = fread(buf, 1, sizeof(buf), fw);
|
||||||
|
if (chunksize == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (offset = 0; offset < chunksize; offset += 62) {
|
||||||
|
len = (offset + 62 > chunksize ?
|
||||||
|
chunksize - offset : 62);
|
||||||
|
command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA;
|
||||||
|
command[1] = len;
|
||||||
|
memcpy(command + 2, buf + offset, len);
|
||||||
|
ret = do_ep1_command(sdi, command, len + 2, NULL, 0);
|
||||||
|
if (ret != SR_OK) {
|
||||||
|
fclose(fw);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_info("Uploaded %d bytes.", chunksize);
|
||||||
|
}
|
||||||
|
fclose(fw);
|
||||||
|
sr_info("FPGA bitstream upload done.");
|
||||||
}
|
}
|
||||||
fclose(fw);
|
|
||||||
sr_info("FPGA bitstream upload done.");
|
|
||||||
|
|
||||||
if ((ret = prime_fpga(sdi)) != SR_OK)
|
if ((ret = prime_fpga(sdi)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -467,7 +469,7 @@ SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
|
||||||
/* Ignore FIFO overflow on previous capture */
|
/* Ignore FIFO overflow on previous capture */
|
||||||
reg1 &= ~0x20;
|
reg1 &= ~0x20;
|
||||||
|
|
||||||
if (reg1 != 0x08) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL && reg1 != 0x08) {
|
||||||
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1);
|
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +498,7 @@ SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
|
||||||
if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK)
|
if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (reg1 != 0x48) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL && reg1 != 0x48) {
|
||||||
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1);
|
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
@ -504,7 +506,7 @@ SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
|
||||||
if ((ret = read_fpga_register(sdi, 10, ®10)) != SR_OK)
|
if ((ret = read_fpga_register(sdi, 10, ®10)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (reg10 != clock_select) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL && reg10 != clock_select) {
|
||||||
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.",
|
sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.",
|
||||||
reg10, clock_select);
|
reg10, clock_select);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
@ -533,6 +535,9 @@ SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t reg1, reg8, reg9;
|
uint8_t reg1, reg8, reg9;
|
||||||
|
struct dev_context *devc;
|
||||||
|
|
||||||
|
devc = sdi->priv;
|
||||||
|
|
||||||
if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
|
if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -543,7 +548,7 @@ SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
|
||||||
if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK)
|
if ((ret = read_fpga_register(sdi, 1, ®1)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((reg1 & ~0x20) != 0x08) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL && (reg1 & ~0x20) != 0x08) {
|
||||||
sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1 & ~0x20);
|
sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1 & ~0x20);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
@ -554,7 +559,7 @@ SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
|
||||||
if ((ret = read_fpga_register(sdi, 9, ®9)) != SR_OK)
|
if ((ret = read_fpga_register(sdi, 9, ®9)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (reg1 & 0x20) {
|
if (devc->fpga_variant == FPGA_VARIANT_ORIGINAL && reg1 & 0x20) {
|
||||||
sr_warn("FIFO overflow, capture data may be truncated.");
|
sr_warn("FIFO overflow, capture data may be truncated.");
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
}
|
}
|
||||||
|
@ -564,6 +569,7 @@ SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
|
||||||
|
|
||||||
SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
|
SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
|
||||||
{
|
{
|
||||||
|
uint8_t version;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -577,6 +583,17 @@ SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
|
||||||
if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK)
|
if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
/* mcupro Saleae16 has firmware pre-stored in FPGA.
|
||||||
|
So, we can query it right away. */
|
||||||
|
if (read_fpga_register(sdi, 0, &version) == SR_OK &&
|
||||||
|
(version == 0x40 || version == 0x41)) {
|
||||||
|
sr_info("mcupro Saleae16 detected.");
|
||||||
|
devc->fpga_variant = FPGA_VARIANT_MCUPRO;
|
||||||
|
} else {
|
||||||
|
sr_info("Original Saleae Logic16 detected.");
|
||||||
|
devc->fpga_variant = FPGA_VARIANT_ORIGINAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
|
ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
|
||||||
if (ret != SR_OK)
|
if (ret != SR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -35,8 +35,16 @@ enum voltage_range {
|
||||||
VOLTAGE_RANGE_5_V, /* 5V logic */
|
VOLTAGE_RANGE_5_V, /* 5V logic */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum fpga_variant {
|
||||||
|
FPGA_VARIANT_ORIGINAL,
|
||||||
|
FPGA_VARIANT_MCUPRO /* mcupro clone v4.6 with Actel FPGA */
|
||||||
|
};
|
||||||
|
|
||||||
/** Private, per-device-instance driver context. */
|
/** Private, per-device-instance driver context. */
|
||||||
struct dev_context {
|
struct dev_context {
|
||||||
|
/** Distinguishing between original Logic16 and clones */
|
||||||
|
enum fpga_variant fpga_variant;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we can't keep track of a Logic16 device after upgrading
|
* Since we can't keep track of a Logic16 device after upgrading
|
||||||
* the firmware (it renumerates into a different device address
|
* the firmware (it renumerates into a different device address
|
||||||
|
|
Loading…
Reference in New Issue