Repository navigation
fix(logic_analyzer): count pulses from the measured signal period #320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -713,12 +713,15 @@ def get_states(self) -> Dict[str, bool]: | |
| } | ||
|
|
||
| def count_pulses( | ||
| self, channel: str = "FRQ", interval: float = 1, block: bool = True | ||
| ) -> Union[int, None]: | ||
| self, channel: str = "FRQ", interval: float = 1, timeout: float = 1 | ||
| ) -> int: | ||
| """Count pulses on a digital input. | ||
|
|
||
| The counter is 16 bits, so it will roll over after 65535 pulses. This | ||
| method can be used at the same time as the oscilloscope. | ||
| The number of pulses is calculated from the period of the signal, which | ||
| is measured by capturing logic events. This method cannot be used at the | ||
| same time as the oscilloscope. The signal must be slow enough for the | ||
| capture to resolve the time between two events, and fast enough for two | ||
| events to be captured within the timeout. | ||
|
|
||
| Parameters | ||
| ---------- | ||
|
|
@@ -727,46 +730,43 @@ def count_pulses( | |
| interval : float, optional | ||
| Time in seconds during which to count pulses. The default value is | ||
| 1 second. | ||
| block : bool, optional | ||
| Whether to block while counting pulses or not. If False, this | ||
| method will return None, and the pulses must be manually fetched | ||
| using :meth:`fetch_pulse_count`. Additionally, the interval | ||
| argument has no meaning if block is False; the counter will keep | ||
| counting even after the interval time has expired. The default | ||
| value is True. | ||
| timeout : float, optional | ||
| Timeout in seconds before cancelling the capture. The default value | ||
| is 1 second. | ||
|
|
||
| Returns | ||
| ------- | ||
| Union[int, None] | ||
| Number of pulses counted during the interval, or None if block is | ||
| False. | ||
| int | ||
| Number of pulses counted during the interval, or 0 if the signal is | ||
| too slow, or too fast, to be measured. | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError if the interval is negative. | ||
| """ | ||
| self._reset_prescaler() | ||
| self._device.send_byte(CP.COMMON) | ||
| self._device.send_byte(CP.START_COUNTING) | ||
| self._device.send_byte(self._channels[channel].number) | ||
| self._device.get_ack() | ||
| if interval < 0: | ||
| raise ValueError("Interval cannot be negative.") | ||
|
|
||
| if block: | ||
| time.sleep(interval) | ||
| else: | ||
| return | ||
| tmp = self._channel_one_map | ||
| self._channel_one_map = channel | ||
| try: | ||
| timestamps = self.capture( | ||
| channel, 2, modes=["sixteen rising"], timeout=timeout | ||
| )[0] | ||
| finally: | ||
| self._channel_one_map = tmp | ||
|
|
||
| return self.fetch_pulse_count() | ||
| try: | ||
| # Sixteen rising edges are captured, so the time between two | ||
| # captured events covers 16 periods of the signal. | ||
| period = (timestamps[1] - timestamps[0]) * 1e-6 / 16 | ||
| except IndexError: | ||
| return 0 | ||
|
|
||
| def fetch_pulse_count(self) -> int: | ||
| """Return the number of pulses counted since calling :meth:`count_pulses`. | ||
| if period <= 0: | ||
|
Comment on lines
+762
to
+766
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Medium · Counter rollover reports zero pulses When the capture’s two sampled events straddle the 32-bit timer rollover, the capture timer wraps at 32 bits, so when the first timestamp is near its maximum and the next is after rollover, the subtraction produces a nonpositive period. Unwrap the 32-bit timestamps or compute their difference modulo 2**32 before deriving the period. Prompt for AI agentsIn `pslab/instrument/logic_analyzer.py` at lines 750-754:
**Counter rollover reports zero pulses**
When the capture’s two sampled events straddle the 32-bit timer rollover, the capture timer wraps at 32 bits, so when the first timestamp is near its maximum and the next is after rollover, the subtraction produces a nonpositive period. `count_pulses` then returns 0 for a measurable signal.
Unwrap the 32-bit timestamps or compute their difference modulo 2**32 before deriving the period. |
||
| return 0 | ||
|
|
||
| Returns | ||
| ------- | ||
| int | ||
| Number of pulses counted since calling :meth:`count_pulses`. | ||
| """ | ||
| self._device.send_byte(CP.COMMON) | ||
| self._device.send_byte(CP.FETCH_COUNT) | ||
| count = self._device.get_int() | ||
| self._device.get_ack() | ||
| return count | ||
| return int(round(interval / period)) | ||
|
sourcery-ai[bot] marked this conversation as resolved.
|
||
|
|
||
| def _reset_prescaler(self): | ||
| self._device.send_byte(CP.TIMING) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Medium · Existing pulse-count calls break
When an existing caller passes
blockor callsfetch_pulse_count(),count_pulses()no longer acceptsblock, andfetch_pulse_count()has been removed, so callers receiveTypeErrororAttributeErrorinstead of using the existing public API.Preserve compatibility for the
blockoption andfetch_pulse_count(), or provide a compatible transition for existing callers.Also at
pslab/instrument/logic_analyzer.py:757-768.Prompt for AI agents