diff --git a/firmware/adc.c b/firmware/adc.c index 3e883e5d8..a27a3df37 100644 --- a/firmware/adc.c +++ b/firmware/adc.c @@ -140,12 +140,10 @@ bool iobuf_set_alert(uint8_t mask, if(!adc_reg_write(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) return false; - - return true; } } - return false; + return true; } bool iobuf_get_alert(uint8_t selector, @@ -160,7 +158,7 @@ bool iobuf_get_alert(uint8_t selector, if(!adc_reg_read(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) return false; - if(!(control_byte & ADC081_BIT_ALERT_PIN_EN)) { + if(control_byte == 0) { *low_millivolts = 0; *high_millivolts = MAX_VOLTAGE; return true; @@ -193,22 +191,24 @@ bool iobuf_poll_alert(__xdata uint8_t *mask, bool clear) { return false; if(status_byte) { + __pdata uint8_t control_byte = 0; *mask |= buffer->selector; + if(!adc_reg_read(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) + return false; + if(clear) { - // Actually clear alert + // Clear actual alert and re-arm the alert pin if(!adc_reg_write(buffer->address, ADC081_REG_ALERT_STATUS, &status_byte, 1)) return false; + control_byte |= ADC081_BIT_ALERT_PIN_EN; } else { - // Only clear alert pin status - __pdata uint8_t control_byte = 0; - if(!adc_reg_read(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) - return false; - + // Only disarm the alert pin (so that alerts from other ADCs can be detected) control_byte &= ~ADC081_BIT_ALERT_PIN_EN; - if(!adc_reg_write(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) - return false; } + + if(!adc_reg_write(buffer->address, ADC081_REG_CONFIGURATION, &control_byte, 1)) + return false; } } diff --git a/software/glasgow/cli.py b/software/glasgow/cli.py index d8e924aa8..d67ad132b 100644 --- a/software/glasgow/cli.py +++ b/software/glasgow/cli.py @@ -1,5 +1,6 @@ import os import argparse +import time from fx2 import FX2DeviceError @@ -13,6 +14,21 @@ def get_argparser(): subparsers = parser.add_subparsers(dest="action", metavar="COMMAND") subparsers.required = True + p_voltage = subparsers.add_parser( + "voltage", help="query or set I/O port voltage") + p_voltage.add_argument( + "ports", metavar="PORTS", type=str, nargs='?', default="AB", + help="I/O port set (one or more of: A B, default: all)") + p_voltage.add_argument( + "voltage", metavar="VOLTS", type=float, nargs='?', default=None, + help="I/O port voltage (range: 1.8-5.0)") + p_voltage.add_argument( + "--tolerance", metavar="PCT", type=float, default=10.0, + help="raise alert if measured voltage deviates by more than ±PCT%%") + p_voltage.add_argument( + "--no-alert", dest="set_alert", default=True, action="store_false", + help="do not raise an alert if Vsense is out of range of Vio") + p_download = subparsers.add_parser( "download", help="volatile download bitstream to FPGA") p_download.add_argument( @@ -40,18 +56,45 @@ def main(): try: firmware_file = os.path.join(os.path.dirname(__file__), "glasgow.ihex") device = GlasgowDevice(firmware_file) - except (FX2DeviceError, GlasgowDeviceError) as e: - raise SystemExit(e) - if args.action == "download": - device.download_bitstream(args.bitstream.read()) - if args.action == "test": - if args.mode == "toggle-io": - device.download_bitstream(TestToggleIO().get_bitstream(debug=True)) - device.set_voltage("AB", 3.3) - if args.mode == "expose-i2c": - device.download_bitstream(TestExposeI2C().get_bitstream(debug=True)) - device.set_voltage("A", 3.3) + if args.action == "voltage": + if args.voltage is not None: + device.reset_alert(args.ports) + device.poll_alert() # clear any remaining alerts + device.set_voltage(args.ports, args.voltage) + if args.set_alert and args.voltage != 0.0: + time.sleep(0.050) # let the output capacitor discharge a bit + tolerance = args.tolerance / 100 + low_volts = args.voltage * (1 - tolerance) + high_volts = args.voltage * (1 + tolerance) + device.set_alert(args.ports, low_volts, high_volts) + + print("Port\tVio\tVsense\tRange") + alerts = device.poll_alert() + for port in args.ports: + vio = device.get_voltage(port) + vsense = device.measure_voltage(port) + alert = device.get_alert(port) + if port in alerts: + notice = " (ALERT)" + else: + notice = "" + print("{}\t{:.2}\t{:.3}\t{:.2}-{:.2}{}" + .format(port, vio, vsense, alert[0], alert[1], notice)) + + if args.action == "download": + device.download_bitstream(args.bitstream.read()) + + if args.action == "test": + if args.mode == "toggle-io": + device.download_bitstream(TestToggleIO().get_bitstream(debug=True)) + device.set_voltage("AB", 3.3) + if args.mode == "expose-i2c": + device.download_bitstream(TestExposeI2C().get_bitstream(debug=True)) + device.set_voltage("A", 3.3) + + except FX2DeviceError as e: + raise SystemExit(e) if __name__ == "__main__": diff --git a/software/glasgow/device.py b/software/glasgow/device.py index 3fd489fca..160b54f40 100644 --- a/software/glasgow/device.py +++ b/software/glasgow/device.py @@ -166,7 +166,7 @@ def measure_voltage(self, spec): except usb1.USBErrorPipe: raise GlasgowDeviceError("Cannot measure port {} sense voltage".format(spec)) - def set_alert(self, spec, low_volts=0.0, high_volts=5.5): + def set_alert(self, spec, low_volts, high_volts): low_millivolts = round(low_volts * 1000) high_millivolts = round(high_volts * 1000) self.control_write(usb1.REQUEST_TYPE_VENDOR, REQ_ALERT_VOLT, @@ -178,6 +178,9 @@ def set_alert(self, spec, low_volts=0.0, high_volts=5.5): .format(spec or "(none)", float(low_volts), float(high_volts))) + def reset_alert(self, spec): + self.set_alert(spec, 0.0, 5.5) + def get_alert(self, spec): try: low_millivolts, high_millivolts = struct.unpack("