Skip to content

Commit 79110c3

Browse files
committed
IO documentation
1 parent c120d1c commit 79110c3

10 files changed

Lines changed: 294 additions & 63 deletions

File tree

doc/api/io.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
IO
22
==
33

4+
See IOs and pin mapping diagrams `here`_.
5+
6+
.. _here: https://github.com/dspsandbox/Redpitaya-IO-Sync#ios--pin-mapping
47

58
Base IO
69
-------

doc/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Library for synchronous and deterministic control of RedPitaya's digital and ana
66
.. toctree::
77
:maxdepth: 2
88
:caption: Contents
9-
9+
1010
api/device
1111
api/sequence
1212
api/frame

driver/src/redpitaya_io_sync/io/analog.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ class AnalogOutCmd(Enum):
55
DUTY_CYCLE = 0x0
66

77
class AnalogOut(BaseIo):
8+
"""
9+
Driver class for low speed analog IOs (PWM + Low Pass Filter).
10+
"""
811
def __init__(self, addr, clk_freq):
912
super().__init__(addr, clk_freq)
1013

1114
def duty_cycle(self, val: float):
15+
"""
16+
Define scale of underlying Sigma-Delta Modulator (12-bit resolution).
17+
18+
:param val: Relative scale in range [0.0, 1.0].
19+
"""
1220
DUTY_CYCLE_MIN = 0.0
1321
DUTY_CYCLE_MAX = 1.0
1422
MODULATION_DEPTH = 12

driver/src/redpitaya_io_sync/io/base.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ def __init__(self, addr, clk_freq):
2828

2929

3030
def reset(self):
31+
"""
32+
Reset IO instruction cache and time base.
33+
"""
3134
self._tlast = 0
3235
self._tnext = 0
3336
self._tincr = 1
@@ -91,22 +94,45 @@ def _get_instruction_and_time_list(self):
9194
return instr_list, t_list
9295

9396

94-
def get_time(self):
97+
def get_time(self) -> int:
98+
"""
99+
Retrieve current IO time (in units of CLK cycles).
100+
"""
95101
return self._tnext
96102

97103
def set_time(self, val: int):
104+
"""
105+
Define new IO time (should be larger or equal than current IO time).
106+
107+
:param val: time (in units of clk cycles).
108+
109+
"""
98110
if val < self._tnext:
99111
raise Exception(f"Cannot set time to {val} because it is smaller than current time {self._tnext}.")
100112
self._tnext = np.uint64(val)
101113
def set_time_increment(self, val: int):
114+
"""
115+
Define IO instruction time increment, i.e. time between consecutive IO instructions. Default time increment after reset is 1 clk cycle.
116+
117+
:param val: time increment (in units of clk cycles).
118+
"""
102119
if val <= 0:
103120
raise Exception(f"Time increment must be a positive integer. Got {val} instead.")
104121
self._tincr = np.uint64(val)
105122

106-
def get_time_increment(self):
123+
def get_time_increment(self) -> int:
124+
"""
125+
Retrieve current IO time increment (in units of clk cycles).
126+
"""
107127
return self._tincr
108128

109129
def delay(self, val: int = 0):
130+
"""
131+
Increment current IO time by a specified delay time. Used to retard following IO instruction.
132+
133+
:param val: Delay time (in units of clk cycles).
134+
135+
"""
110136
t = self.get_time()
111137
self.set_time(t + val)
112138

driver/src/redpitaya_io_sync/io/digital.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,34 @@ class DigitalIoCmd(Enum):
66
TRISTATE = 0x1
77

88
class DigitalIo(BaseIo):
9+
"""
10+
Driver class for Digital IOs.
11+
12+
.. note::
13+
Ports configured as inputs (high-impedance via :meth:`tristate`) include internal pull-up resistors and will idle high when left undriven.
14+
"""
915
def __init__(self, addr, clk_freq):
1016
super().__init__(addr, clk_freq)
1117

1218
def output(self, val: int, mask: int = 0xffff):
13-
self._add_instruction(cmd=DigitalIoCmd.OUTPUT.value, data=((mask << 16) | val))
14-
19+
"""
20+
Set output value of masked ports (requires ports to be defined as outputs via :meth:`DigitalIo.tristate`).
21+
E.g. ``val=0b0010`` and ``mask=0b1010`` will result in port[0] -> unchanged, port[1] -> 1, port[2] -> unchanged and port[3] -> 0.
22+
23+
:param val: Output value.
24+
:param mask: Bit mask for updating digital ports.
25+
"""
26+
self._add_instruction(cmd=DigitalIoCmd.OUTPUT.value, data=((mask << 16) | val))
27+
1528
def tristate(self, val: int, mask: int = 0xffff):
29+
"""
30+
Set direction (output/tristate) of masked ports.
31+
A ``0`` bit configures the corresponding port as a driven output; a ``1`` bit puts it in high-impedance (input) mode.
32+
E.g. ``val=0b0010`` and ``mask=0b1010`` will result in port[0] -> unchanged, port[1] -> high-Z (input), port[2] -> unchanged and port[3] -> driven (output).
33+
34+
:param val: Direction value (0 = driven output, 1 = high-impedance / input).
35+
:param mask: Bit mask for updating digital ports.
36+
"""
1637
self._add_instruction(cmd=DigitalIoCmd.TRISTATE.value, data=((mask << 16) | val))
1738

1839

driver/src/redpitaya_io_sync/io/led.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,21 @@ class LedCmd(Enum):
55
OUTPUT = 0x0
66

77
class Led(BaseIo):
8+
"""
9+
Driver class for the onboard LEDs.
10+
"""
811
def __init__(self, addr, clk_freq):
912
super().__init__(addr, clk_freq)
1013

1114
def output(self, val: int, mask: int = 0xffff):
12-
self._add_instruction(cmd=LedCmd.OUTPUT.value, data=((mask << 16) | val))
15+
"""
16+
Set the on/off state of masked LEDs.
17+
E.g. ``val=0b0010`` and ``mask=0b1010`` will result in LED[0] -> unchanged, LED[1] -> on, LED[2] -> unchanged and LED[3] -> off.
18+
19+
:param val: LED state value (1 = on, 0 = off).
20+
:param mask: Bit mask for selecting which LEDs to update.
21+
"""
22+
self._add_instruction(cmd=LedCmd.OUTPUT.value, data=((mask << 16) | val))
1323

1424

1525

driver/src/redpitaya_io_sync/io/rf.py

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,99 @@ class RfCmd(Enum):
1212

1313

1414
class RfBase(BaseIo):
15+
"""
16+
Base driver class for RF IOs (DDS-based signal generation).
17+
18+
Wraps a direct digital synthesizer (DDS) core and provides control over
19+
frequency, phase, and amplitude. The ``update`` flag on each method controls
20+
whether the new value is applied immediately (``True``) or staged for a later
21+
atomic update (``False``), which allows frequency, phase, and amplitude to be
22+
changed simultaneously.
23+
"""
1524
def __init__(self, addr, clk_freq):
1625
super().__init__(addr, clk_freq)
1726

18-
def frequency(self, val: int, update: bool = True):
27+
def frequency(self, val: float, update: bool = True):
28+
"""
29+
Set the output frequency.
30+
31+
The valid range is ``[-clk_freq/2, clk_freq/2]`` (i.e. ±62.5 MHz for a 125 MHz clock).
32+
33+
:param val: Frequency in Hz.
34+
:param update: If ``True``, apply the new value immediately. Set to ``False`` to stage
35+
the change and apply it atomically together with other staged parameters.
36+
"""
1937
FREQ_MIN = -self._clk_freq / 2
2038
FREQ_MAX = self._clk_freq / 2
2139
if (val < FREQ_MIN) or (val > FREQ_MAX):
2240
raise Exception(f"Frequency value {val} is out of range [{FREQ_MIN}, {FREQ_MAX}].")
23-
cmd = RfCmd.FREQ.value
24-
if update:
41+
cmd = RfCmd.FREQ.value
42+
if update:
2543
cmd |= RfCmd.UPDATE.value
26-
data = int(val / self._clk_freq * ((1 << 32) - 1))
44+
data = int(val / self._clk_freq * ((1 << 32) - 1))
2745
self._add_instruction(cmd=cmd, data=data)
2846

29-
def phase(self, val: int, update: bool = True):
30-
cmd = RfCmd.PHASE.value
31-
if update:
47+
def phase(self, val: float, update: bool = True):
48+
"""
49+
Set the output phase.
50+
51+
The value is taken modulo 360°, so any value outside ``[0°, 360°)`` wraps around.
52+
53+
:param val: Phase in degrees.
54+
:param update: If ``True``, apply the new value immediately. Set to ``False`` to stage
55+
the change and apply it atomically together with other staged parameters.
56+
"""
57+
cmd = RfCmd.PHASE.value
58+
if update:
3259
cmd |= RfCmd.UPDATE.value
33-
data = int((val % 360) / 360 * ((1 << 32) - 1))
34-
self._add_instruction(cmd=cmd, data=data)
35-
36-
def amplitude(self, val: int, update: bool = True):
60+
data = int((val % 360) / 360 * ((1 << 32) - 1))
61+
self._add_instruction(cmd=cmd, data=data)
62+
63+
def amplitude(self, val: float, update: bool = True):
64+
"""
65+
Set the output amplitude.
66+
67+
The valid range is ``[-1, 1]``, where ``±1`` corresponds to full-scale output.
68+
69+
:param val: Amplitude as a normalized value in ``[-1, 1]``.
70+
:param update: If ``True``, apply the new value immediately. Set to ``False`` to stage
71+
the change and apply it atomically together with other staged parameters.
72+
"""
3773
AMPL_MIN = -1
3874
AMPL_MAX = 1
3975
if (val < AMPL_MIN) or (val > AMPL_MAX):
4076
raise Exception(f"Amplitude value {val} is out of range [{AMPL_MIN}, {AMPL_MAX}].")
41-
4277
cmd = RfCmd.AMPL.value
43-
if update:
78+
if update:
4479
cmd |= RfCmd.UPDATE.value
45-
data = int(val * ((1 << 15) - 1))
80+
data = int(val * ((1 << 15) - 1))
4681
self._add_instruction(cmd=cmd, data=data)
4782

4883
def phase_reset(self, update: bool = True):
49-
data = 1
50-
cmd = RfCmd.PHASE_RST.value
51-
if update:
84+
"""
85+
Reset the DDS phase accumulator to zero.
86+
87+
:param update: If ``True``, apply immediately. Set to ``False`` to stage the reset
88+
and apply it atomically together with other staged parameters.
89+
"""
90+
cmd = RfCmd.PHASE_RST.value
91+
if update:
5292
cmd |= RfCmd.UPDATE.value
53-
self._add_instruction(cmd=cmd, data=data)
93+
self._add_instruction(cmd=cmd, data=1)
5494

5595

5696
class RfOut(RfBase):
97+
"""
98+
Driver class for RF output channels.
99+
"""
57100
def __init__(self, addr, clk_freq):
58101
super().__init__(addr, clk_freq)
59-
102+
103+
60104
class RfIn(RfBase):
105+
"""
106+
Driver class for RF input channels (TODO: missing FPGA backend).
107+
"""
61108
def __init__(self, addr, clk_freq):
62109
super().__init__(addr, clk_freq)
63110

0 commit comments

Comments
 (0)