diff --git a/scope.py b/scope.py index 9e3d019..af8ea8b 100755 --- a/scope.py +++ b/scope.py @@ -103,23 +103,30 @@ class Scope(vm.VirtualMachine): async def capture(self, channels=['A'], trigger_channel=None, trigger_level=None, trigger_type='rising', hair_trigger=False, period=1e-3, nsamples=1000, timeout=None, low=None, high=None, raw=False): channels = list(channels) - if 'A' in channels and 'B' in channels: - nsamples_multiplier = 2 - dual = True - else: - nsamples_multiplier = 1 - dual = False - ticks = int(period / nsamples / nsamples_multiplier / self.capture_clock_period) - for clock_mode in vm.ClockModes: - if clock_mode.dual == dual and ticks in range(clock_mode.clock_low, clock_mode.clock_high + 1): - break + analog_channels = [channel for channel in channels if channel in {'A', 'B'}] + logic = 'L' in channels + ticks = int(period / nsamples / self.capture_clock_period) + for capture_mode in vm.CaptureModes: + if capture_mode.analog_channels == len(analog_channels) and capture_mode.logic_channels == logic: + if ticks in range(capture_mode.clock_low, capture_mode.clock_high + 1): + clock_scale = 1 + break + elif capture_mode.clock_divide and ticks > capture_mode.clock_high: + for clock_scale in range(2, 1<<16): + test_ticks = int(period / nsamples / self.capture_clock_period / clock_scale) + if test_ticks in range(capture_mode.clock_low, capture_mode.clock_high + 1): + ticks = test_ticks + break + else: + continue + break else: raise RuntimeError(f"Unsupported clock period: {ticks}") - if clock_mode.clock_max is not None and ticks > clock_mode.clock_max: - ticks = clock_mode.clock_max - nsamples = int(round(period / ticks / nsamples_multiplier / self.capture_clock_period)) - total_samples = nsamples * nsamples_multiplier - buffer_width = self.capture_buffer_size // clock_mode.sample_width + if capture_mode.clock_max is not None and ticks > capture_mode.clock_max: + ticks = capture_mode.clock_max + nsamples = int(round(period / ticks / self.capture_clock_period / clock_scale)) + total_samples = nsamples*2 if logic else nsamples + buffer_width = self.capture_buffer_size // capture_mode.sample_width assert total_samples <= buffer_width if raw: @@ -144,6 +151,8 @@ class Scope(vm.VirtualMachine): elif trigger_channel == 'B': kitchen_sink_a = vm.KitchenSinkA.ChannelBComparatorEnable spock_option |= vm.SpockOption.TriggerSourceB + else: + raise RuntimeError(f"Cannot trigger on channel {trigger_channel}") kitchen_sink_b = vm.KitchenSinkB.AnalogFilterEnable if self._generator_running: kitchen_sink_b |= vm.KitchenSinkB.WaveformGeneratorEnable @@ -157,16 +166,21 @@ class Scope(vm.VirtualMachine): analog_enable |= 1 if 'B' in channels: analog_enable |= 2 + logic_enable = 0 + for channel in range(8): + if not ((channel == 4 and self._generator_running) or (channel == 6 and 'A' in channels) or (channel == 7 and 'B' in channels)): + logic_enable |= 1<{nsamples}h', data) - traces[channel] = [(value/65536+0.5)*value_multiplier + value_offset for value in data] + if capture_mode.sample_width == 2: + data = struct.unpack(f'>{asamples}h', data) + data = [(value/65536+0.5)*value_multiplier + value_offset for value in data] else: - traces[channel] = [(value/256)*value_multiplier + value_offset for value in data] + data = [(value/256)*value_multiplier + value_offset for value in data] + traces[channel] = {(t+dump_channel*ticks*clock_scale)*self.capture_clock_period: value + for (t, value) in zip(range(start_timestamp, timestamp, ticks*clock_scale*len(analog_channels)), data)} + + if logic: + async with self.transaction(): + await self.set_registers(SampleAddress=(address - total_samples) % buffer_width, + DumpMode=vm.DumpMode.Raw, DumpChan=128, DumpCount=nsamples, DumpRepeat=1, DumpSend=1, DumpSkip=0) + await self.issue_program_spock_registers() + await self.issue_analog_dump_binary() + data = await self._reader.readexactly(nsamples) + ts = [t*self.capture_clock_period for t in range(start_timestamp, timestamp, ticks*clock_scale)] + for i in range(8): + mask = 1<] In [5]: @@ -345,6 +376,6 @@ def generate(*args, **kwargs): if __name__ == '__main__': import sys - logging.basicConfig(level=logging.INFO, stream=sys.stderr) + logging.basicConfig(level=logging.DEBUG, stream=sys.stderr) asyncio.get_event_loop().run_until_complete(main()) diff --git a/vm.py b/vm.py index a2f4458..0742525 100644 --- a/vm.py +++ b/vm.py @@ -137,18 +137,27 @@ class KitchenSinkB(IntEnum): AnalogFilterEnable = 0x80 WaveformGeneratorEnable = 0x40 -ClockMode = namedtuple('ClockMode', ('clock_low', 'clock_high', 'clock_max', 'dual', 'sample_width', - 'TraceMode', 'BufferMode')) +CaptureMode = namedtuple('CaptureMode', ('clock_low', 'clock_high', 'clock_max', 'analog_channels', 'sample_width', + 'logic_channels', 'clock_divide', 'TraceMode', 'BufferMode')) -ClockModes = [ - ClockMode(40, 65536, None, False, 2, TraceMode.Macro, BufferMode.Macro), - ClockMode(40, 65536, None, True, 2, TraceMode.MacroChop, BufferMode.MacroChop), - ClockMode(15, 40, None, False, 1, TraceMode.Analog, BufferMode.Single), - ClockMode(13, 40, None, True, 1, TraceMode.AnalogChop, BufferMode.Chop), - ClockMode( 8, 14, None, False, 1, TraceMode.AnalogFast, BufferMode.Single), - ClockMode( 8, 40, None, True, 1, TraceMode.AnalogFastChop, BufferMode.Chop), - ClockMode( 2, 8, 5, False, 1, TraceMode.AnalogShot, BufferMode.Single), - ClockMode( 4, 8, 5, True, 1, TraceMode.AnalogShotChop, BufferMode.Chop), +CaptureModes = [ + CaptureMode(40, 65536, None, 1, 2, False, False, TraceMode.Macro, BufferMode.Macro), + CaptureMode(40, 65536, None, 2, 2, False, False, TraceMode.MacroChop, BufferMode.MacroChop), + CaptureMode(15, 40, None, 1, 1, False, True, TraceMode.Analog, BufferMode.Single), + CaptureMode(13, 40, None, 2, 1, False, True, TraceMode.AnalogChop, BufferMode.Chop), + CaptureMode( 8, 14, None, 1, 1, False, False, TraceMode.AnalogFast, BufferMode.Single), + CaptureMode( 8, 40, None, 2, 1, False, False, TraceMode.AnalogFastChop, BufferMode.Chop), + CaptureMode( 2, 7, 5, 1, 1, False, False, TraceMode.AnalogShot, BufferMode.Single), + CaptureMode( 4, 7, 5, 2, 1, False, False, TraceMode.AnalogShotChop, BufferMode.Chop), + CaptureMode( 5, 16384, None, 0, 1, True, False, TraceMode.Logic, BufferMode.Single), + CaptureMode( 4, 4, None, 0, 1, True, False, TraceMode.LogicFast, BufferMode.Single), + CaptureMode( 1, 3, None, 0, 1, True, False, TraceMode.LogicShot, BufferMode.Single), + CaptureMode(15, 40, None, 1, 1, True, True, TraceMode.Mixed, BufferMode.Dual), + CaptureMode(13, 40, None, 2, 1, True, True, TraceMode.MixedChop, BufferMode.ChopDual), + CaptureMode( 8, 14, None, 1, 1, True, False, TraceMode.MixedFast, BufferMode.Dual), + CaptureMode( 8, 40, None, 2, 1, True, False, TraceMode.MixedFastChop, BufferMode.ChopDual), + CaptureMode( 2, 7, 5, 1, 1, True, False, TraceMode.MixedShot, BufferMode.Dual), + CaptureMode( 4, 7, 5, 2, 1, True, False, TraceMode.MixedShotChop, BufferMode.ChopDual), ] def encode(value, dtype):