Skip to content

Commit 9714777

Browse files
committed
Merge branch 'rp2_hstx' into release/v1.27.0
2 parents 78ff170 + 74ee1eb commit 9714777

File tree

7 files changed

+670
-0
lines changed

7 files changed

+670
-0
lines changed

docs/library/rp2.HSTX.rst

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
.. currentmodule:: rp2
2+
.. _rp2.HSTX:
3+
4+
class HSTX -- access to the RP2350's HSTX controller
5+
====================================================
6+
7+
The :class:`HSTX` class offers access to the RP2350's High-speed Serial Transmit (HSTX) peripheral, which can output data through up to 8 GPIO pins (only GPIO 12 through 19) at up to 150MHz, and is double-data rate (DDR) capable. This enables the HSTX to theoretically stream data up to 2.4Gbps, provided its FIFO buffer can be kept filled (it's typically necessary to use the DMA controller to achieve this). The HSTX also features a command expander, which can manipulate the data stream (the RP2350 currently only implements a TMDS encoder) and repeat data. For full details of the RP2350's HSTX system, see section 12.11 of the `RP2350 Datasheet <https://datasheets.raspberrypi.org/rp2350/rp2350-datasheet.pdf>`_.
8+
9+
Examples
10+
--------
11+
12+
A simple use of the HSTX peripheral is to blink a pair of LEDs. This can be accomplished with the following complete example::
13+
14+
import rp2
15+
import time
16+
from machine import Pin
17+
18+
# Get the singleton HSTX object.
19+
hstx = rp2.HSTX()
20+
21+
# Set GPIO pins 12 and 13 to the HSTX alternate function.
22+
pin_12 = Pin(12, mode=Pin.ALT, alt=Pin.ALT_HSTX)
23+
pin_13 = Pin(13, mode=Pin.ALT, alt=Pin.ALT_HSTX)
24+
25+
# Configure pin 12 to output bit 0 of data in the HSTX FIFO for both the first
26+
# and second (positive and negative) phases of the HSTX clock cycle, and pin 13
27+
# to output the same but inverted value.
28+
hstx.bit(pin_12, hstx.pack_bit(sel_p=0, sel_n=0))
29+
hstx.bit(pin_13, hstx.pack_bit(sel_p=0, sel_n=0, inv=1))
30+
31+
# Set up the CSR register to enable HSTX with no shifting.
32+
csr = hstx.pack_csr(
33+
shift = 0,
34+
enable = 1
35+
)
36+
hstx.csr(csr)
37+
38+
# Data can be manually pushed into the FIFO, though a DMA channel should be used
39+
# for real applications.
40+
while True:
41+
hstx.fifo_put(1)
42+
time.sleep(1)
43+
hstx.fifo_put(0)
44+
time.sleep(1)
45+
46+
It's usually more practical to use a DMA channel to feed data to the HSTX FIFO. To support this, the HSTX class supports the buffer protocol (write-only), and can be used like so::
47+
48+
import rp2
49+
import array
50+
51+
# Get the singleton HSTX object. Configuration of the HSTX is omitted from this
52+
# example for brevity.
53+
hstx = rp2.HSTX()
54+
55+
# Data to send to the HSTX FIFO.
56+
data = array.array("I", [0x01234567, 0x89ABCDEF])
57+
58+
# Data request (DREQ) signal number for the HSTX FIFO.
59+
DREQ_HSTX = 52
60+
61+
# Set up a DMA channel to feed data to the HSTX FIFO.
62+
dma = rp2.DMA()
63+
dma_ctrl = dma.pack_ctrl(
64+
inc_write = False, # Keep writing to the same HSTX FIFO address.
65+
dreq_sel = DREQ_HSTX # Pace DMA transfers by the HSTX data request signal.
66+
)
67+
dma.config(
68+
read = data,
69+
write = hstx,
70+
count = len(data),
71+
ctrl = dma_ctrl,
72+
trigger = True
73+
)
74+
75+
The command expander can be used with the TMDS encoder for driving DVI displays (HDMI displays also support this signal). The example below demonstrates the HSTX configuration, but is not a complete implementation. Special timing signals are required in addition to needing a complete frame buffer, so those are omitted here for simplicity::
76+
77+
import rp2
78+
from machine import Pin
79+
80+
# Define the GPIO pins used for each TMDS lane.
81+
pin_clk_p = 14
82+
pin_clk_n = 15
83+
pin_d0_p = 18
84+
pin_d0_n = 19
85+
pin_d1_p = 16
86+
pin_d1_n = 17
87+
pin_d2_p = 12
88+
pin_d2_n = 13
89+
90+
# Get the singleton HSTX object.
91+
hstx = rp2.HSTX()
92+
93+
# Configure the command expander's shift register. This simple example does not
94+
# actually perform any shifting, but it's possible to pack multiple pixels per
95+
# 32-bit data word, then shift the words to align the bits for the TMDS encoder
96+
# by changing the `enc_n_shifts` and `enc_shift` fields.
97+
expand_shift = hstx.pack_expand_shift(
98+
enc_n_shifts = 1,
99+
enc_shift = 0,
100+
raw_n_shifts = 1,
101+
raw_shift = 0
102+
)
103+
hstx.expand_shift(expand_shift)
104+
105+
# Configure the TMDS encoder to convert the data in the command expander's shift
106+
# register to TMDS format. This example demonstrates RGB565 pixel format, which
107+
# is assumed to be packed into the 32-bit data words as follows:
108+
#
109+
# (xxxxxxxx xxxxxxxx RRRRRGGG GGGBBBBB)
110+
#
111+
# There are 3 TMDS data lanes for DVI video (lane 0 carries the blue channel,
112+
# lane 1 carries green, and lane 2 carries red). For each lane, the bits for
113+
# that channel need to start at bit 7 (8th bit position), so each lane needs to
114+
# shift the register to get the MSB aligned using the `ln_rot` field (right
115+
# rotate, wraps around). Up to 8 bits can be used per channel, specified by the
116+
# `ln_nbits` field (values of 0-7 correspond to 1-8 bits).
117+
expand_tmds = hstx.pack_expand_tmds(
118+
l2_nbits = 4, # 5 bits (red)
119+
l2_rot = 8, # Shift right 8 bits to align MSB
120+
l1_nbits = 5, # 6 bits (green)
121+
l1_rot = 3, # Shift right 3 bits to align MSB
122+
l0_nbits = 4, # 5 bits (blue)
123+
l0_rot = 29, # Shift right 29 bits to align MSB (left 3 bits)
124+
)
125+
hstx.expand_tmds(expand_tmds)
126+
127+
# The TMDS encoder sends 30 bits of data per pixel (10 bits per lane) to the
128+
# 32-bit output shift register. The bits for lane 0, 1, and 2 are as follows:
129+
#
130+
# (xx 2222222222 1111111111 0000000000)
131+
#
132+
# The output shift register will be configured to shift the whole register by 2
133+
# bits every system clock cycle (DDR) for 5 cycles (10 bits total). So we'll
134+
# configure each lane's pins to output bits 10*n and 10*n+1 on the positive and
135+
# negative phases of the system clock, respectively.
136+
#
137+
# The clock lane outputs a continuous clock signal, so those GPIO pins just
138+
# follow the HSTX clock generator, which will be configured below.
139+
#
140+
# Each pair of pins is differential, so the `_n` pin is just the inverted value
141+
# of the `_p` pin.
142+
hstx.bit(pin_clk_p, hstx.pack_bit(clk=1, inv=0))
143+
hstx.bit(pin_clk_n, hstx.pack_bit(clk=1, inv=1))
144+
hstx.bit(pin_d0_p, hstx.pack_bit(sel_p= 0, sel_n= 1, inv=0))
145+
hstx.bit(pin_d0_n, hstx.pack_bit(sel_p= 0, sel_n= 1, inv=1))
146+
hstx.bit(pin_d1_p, hstx.pack_bit(sel_p=10, sel_n=11, inv=0))
147+
hstx.bit(pin_d1_n, hstx.pack_bit(sel_p=10, sel_n=11, inv=1))
148+
hstx.bit(pin_d2_p, hstx.pack_bit(sel_p=20, sel_n=21, inv=0))
149+
hstx.bit(pin_d2_n, hstx.pack_bit(sel_p=20, sel_n=21, inv=1))
150+
151+
# Set all HSTX pins (GPIO 12-19) to ALT function for HSTX output.
152+
for i in range(12, 20):
153+
Pin(i, mode=Pin.ALT, alt=Pin.ALT_HSTX)
154+
155+
# DVI requires the clock lane to cycle once per 10 data bits, meaning every 5
156+
# system clock cycles (DDR).
157+
#
158+
# The output shift register needs to shift by 2 bits every system clock cycle
159+
# for 5 cycles, so `shift` and `n_shifts` are set to 2 and 5, respectively.
160+
#
161+
# Then we enable the command expander to activate the TMDS encoder, and enable
162+
# the HSTX peripheral.
163+
csr = hstx.pack_csr(
164+
clk_div = 5,
165+
n_shifts = 5,
166+
shift = 2,
167+
expand_enable = 1,
168+
enable = 1
169+
)
170+
hstx.csr(csr)
171+
172+
Constructor
173+
-----------
174+
175+
.. class:: HSTX()
176+
177+
Gets the singleton object for accessing the HSTX peripheral.
178+
179+
Methods
180+
-------
181+
182+
.. method:: HSTX.csr([value])
183+
184+
Gets or sets the HSTX control and status register (CSR) *value*. This is an integer value that is typically packed using :meth:`HSTX.pack_csr()`.
185+
186+
.. method:: HSTX.bit(pin, [value])
187+
188+
Gets or sets the bit register *value* for the given *pin* (only GPIO 12 to 19, can be a `machine.Pin()` or integer). This is an integer value that is typically packed using :meth:`HSTX.pack_bit()`.
189+
190+
.. method:: HSTX.expand_shift([value])
191+
192+
Gets or sets the command expander's shift register *value*. This is an integer value that is typically packed using :meth:`HSTX.pack_expand_shift()`.
193+
194+
.. method:: HSTX.expand_tmds([value])
195+
196+
Gets or sets the command expander's TMDS encoder register *value*. This is an integer value that is typically packed using :meth:`HSTX.pack_expand_tmds()`.
197+
198+
.. method:: HSTX.pack_csr(**kwargs)
199+
200+
Pack the values provided in the keyword arguments into the named fields of a new control register value. Any field that is not provided will be set to a default value.
201+
202+
The keys for the keyword arguments can be any key returned by :meth:`HSTX.unpack_csr()`. The writable values are:
203+
204+
- *enable*: ``bool`` Enable the HSTX peripheral (default: ``False``).
205+
206+
- *expand_enable*: ``bool`` Enable the command expander (default: ``False``).
207+
208+
- *coupled_mode*: ``bool`` Enable the PIO-to_HSTX connection (default: ``False``).
209+
210+
- *coupled_select*: ``int`` Select which PIO instance to couple to (0-2, default: ``0``).
211+
212+
- *shift*: ``int`` Number of bits to right-rotate the output shift register by each cycle (0-31, default: ``6``).
213+
214+
- *n_shifts*: ``int`` Number of shifts to perform before reloading the shift register (0-31, with 0 meaning shift 32 times, default: ``5``).
215+
216+
- *clk_phase*: ``int`` Initial phase of the generated HSTX clock (0-15, default: ``0``).
217+
218+
- *clk_div*: ``int`` Clock perid of the generated HSTX clock, in system clock cycles (0-15, with 0 meaning *clk_div* of 16, default: ``1``).
219+
220+
.. method:: HSTX.pack_bit(**kwargs)
221+
222+
Pack the values provided in the keyword arguments into the named fields of a new control register value. Any field that is not provided will be set to a default value.
223+
224+
The keys for the keyword arguments can be any key returned by :meth:`HSTX.unpack_bit()`. The writable values are:
225+
226+
- *sel_p*: ``int`` Data bit to output for the first half (positive phase) of the HSTX clock cycle (0-31, default: ``0``).
227+
228+
- *sel_n*: ``int`` Data bit to output for the second half (negative phase) of the HSTX clock cycle (0-31, default: ``0``).
229+
230+
- *inv*: ``bool`` Invert the output value (default: ``False``).
231+
232+
- *clk*: ``bool`` Output the generated clock instead of a data bit (default: ``False``).
233+
234+
.. method:: HSTX.pack_expand_shift(**kwargs)
235+
236+
Pack the values provided in the keyword arguments into the named fields of a new control register value. Any field that is not provided will be set to a default value.
237+
238+
The keys for the keyword arguments can be any key returned by :meth:`HSTX.unpack_expand_shift()`. The writable values are:
239+
240+
- *raw_shift*: ``int`` Number of bits to right-rotate the command expander's shift register by each shift when using the raw data command (0-31, default: ``0``).
241+
242+
- *raw_n_shifts*: ``int`` Number of shifts to perform when using the raw data command before reloading the shift register (0-31, with 0 meaning shift 32 times, default: ``1``).
243+
244+
- *enc_shift*: ``int`` Number of bits to right-rotate the command expander's shift register by each shift when using an encoder (eg. TMDS) command (0-31, default: ``0``).
245+
246+
- *enc_n_shifts*: ``int`` Number of shifts to perform when using an encoder (eg. TMDS) command before reloading the shift register (0-31, with 0 meaning shift 32 times, default: ``1``).
247+
248+
.. method:: HSTX.pack_expand_tmds(**kwargs)
249+
250+
Pack the values provided in the keyword arguments into the named fields of a new control register value. Any field that is not provided will be set to a default value.
251+
252+
The keys for the keyword arguments can be any key returned by :meth:`HSTX.unpack_expand_tmds()`. The writable values are:
253+
254+
- *l0_rot*: ``int`` Number of bits to right-rotate the command expander's shift register to align the MSB for lane 0 (0-31, default: ``0``).
255+
256+
- *l0_nbits*: ``int`` Number of bits to use for lane 0 (0-7, corresponding to 1-8 bits, default: ``0``).
257+
258+
- *l1_rot*: ``int`` Number of bits to right-rotate the command expander's shift register to align the MSB for lane 1 (0-31, default: ``0``).
259+
260+
- *l1_nbits*: ``int`` Number of bits to use for lane 1 (0-7, corresponding to 1-8 bits, default: ``0``).
261+
262+
- *l2_rot*: ``int`` Number of bits to right-rotate the command expander's shift register to align the MSB for lane 2 (0-31, default: ``0``).
263+
264+
- *l2_nbits*: ``int`` Number of bits to use for lane 2 (0-7, corresponding to 1-8 bits, default: ``0``).
265+
266+
.. method:: HSTX.unpack_csr(value)
267+
268+
Unpack the control and status register (CSR) *value* into a dictionary with key/value pairs for each of the fields in the register. This method will return values for all the keys that can be passed to ``HSTX.pack_csr``.
269+
270+
.. method:: HSTX.unpack_bit(value)
271+
272+
Unpack the bit register *value* for a given pin into a dictionary with key/value pairs for each of the fields in the register. This method will return values for all the keys that can be passed to ``HSTX.pack_bit()``.
273+
274+
.. method:: HSTX.unpack_expand_shift(value)
275+
276+
Unpack the command expander's shift register *value* into a dictionary with key/value pairs for each of the fields in the register. This method will return values for all the keys that can be passed to ``HSTX.pack_expand_shift()``.
277+
278+
.. method:: HSTX.unpack_expand_tmds(value)
279+
280+
Unpack the command expander's TMDS encoder register *value* into a dictionary with key/value pairs for each of the fields in the register. This method will return values for all the keys that can be passed to ``HSTX.pack_expand_tmds()``.
281+
282+
.. method:: HSTX.fifo_put(value)
283+
284+
Push a word into the HSTX FIFO.
285+
286+
.. method:: HSTX.fifo_level()
287+
288+
Get the current number of words in the HSTX FIFO.
289+
290+
.. method:: HSTX.fifo_wof([value])
291+
292+
Get or clear the HSTX FIFO write overflow flag. If *value* is provided, the flag is cleared regardless of the value.
293+
294+
Buffer protocol
295+
---------------
296+
297+
The HSTX class supports the `buffer protocol`, allowing direct access to the HSTX FIFO, which is write-only. This is primarily in order to allow the HSTX object to be passed directly as the write parameter when configuring a `rp2.DMA()` channel.

docs/library/rp2.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,5 +245,6 @@ Classes
245245

246246
rp2.DMA.rst
247247
rp2.Flash.rst
248+
rp2.HSTX.rst
248249
rp2.PIO.rst
249250
rp2.StateMachine.rst

ports/rp2/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ set(MICROPY_SOURCE_PORT
172172
mutex_extra.c
173173
pendsv.c
174174
rp2_flash.c
175+
rp2_hstx.c
175176
rp2_pio.c
176177
rp2_psram.c
177178
rp2_dma.c
@@ -199,6 +200,7 @@ set(MICROPY_SOURCE_QSTR
199200
${MICROPY_PORT_DIR}/modrp2.c
200201
${MICROPY_PORT_DIR}/modos.c
201202
${MICROPY_PORT_DIR}/rp2_flash.c
203+
${MICROPY_PORT_DIR}/rp2_hstx.c
202204
${MICROPY_PORT_DIR}/rp2_pio.c
203205
${MICROPY_PORT_DIR}/rp2_dma.c
204206
${CMAKE_BINARY_DIR}/pins_${MICROPY_BOARD}.c

ports/rp2/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ int main(int argc, char **argv) {
190190
// Initialise sub-systems.
191191
readline_init0();
192192
machine_pin_init();
193+
#ifdef PICO_RP2350
194+
rp2_hstx_init();
195+
#endif
193196
rp2_pio_init();
194197
rp2_dma_init();
195198
#if MICROPY_PY_MACHINE_I2S
@@ -256,6 +259,9 @@ int main(int argc, char **argv) {
256259
#endif
257260
rp2_dma_deinit();
258261
rp2_pio_deinit();
262+
#ifdef PICO_RP2350
263+
rp2_hstx_deinit();
264+
#endif
259265
#if MICROPY_PY_BLUETOOTH
260266
mp_bluetooth_deinit();
261267
#endif

ports/rp2/modrp2.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ static const mp_rom_map_elem_t rp2_module_globals_table[] = {
9797
{ MP_ROM_QSTR(MP_QSTR_DMA), MP_ROM_PTR(&rp2_dma_type) },
9898
{ MP_ROM_QSTR(MP_QSTR_bootsel_button), MP_ROM_PTR(&rp2_bootsel_button_obj) },
9999

100+
#ifdef PICO_RP2350
101+
{ MP_ROM_QSTR(MP_QSTR_HSTX), MP_ROM_PTR(&rp2_hstx_type) },
102+
#endif
103+
100104
#if MICROPY_PY_NETWORK_CYW43
101105
// Deprecated (use network.country instead).
102106
{ MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },

ports/rp2/modrp2.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ extern const mp_obj_type_t rp2_pio_type;
3333
extern const mp_obj_type_t rp2_state_machine_type;
3434
extern const mp_obj_type_t rp2_dma_type;
3535

36+
#ifdef PICO_RP2350
37+
extern const mp_obj_type_t rp2_hstx_type;
38+
void rp2_hstx_init(void);
39+
void rp2_hstx_deinit(void);
40+
#endif
41+
3642
void rp2_pio_init(void);
3743
void rp2_pio_deinit(void);
3844

0 commit comments

Comments
 (0)