|
| 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. |
0 commit comments