[HN Gopher] A closer look at Raspberry Pi RP2040 Programmable IOs
___________________________________________________________________
A closer look at Raspberry Pi RP2040 Programmable IOs
Author : beshrkayali
Score : 74 points
Date : 2021-02-14 09:28 UTC (2 days ago)
(HTM) web link (www.cnx-software.com)
(TXT) w3m dump (www.cnx-software.com)
| pkaye wrote:
| The Cypress FX3 is another chip with programmable IO which people
| have used to make low cost logic analyzers.
| gchadwick wrote:
| I've just been getting to grips with the PIO, they are a lot of
| fun to program. Whilst the instruction set is very limited with
| only enough memory for 32 of them you can do some pretty
| sophisticated things. A key part of the flexibility is the
| ability to execute incoming data as instructions. You can stream
| in a mixture of data and instructions via the DMA, the PIO
| separates the two and uses the instructions to modify execution
| so a simple loop becomes a lot more flexible. You can easily sync
| several of them up to. The scanvideo library:
| https://github.com/raspberrypi/pico-extras/blob/master/src/c...
| which is for producing video signals (like VGA) on the fly with
| scanlines supplied by the CPU is a good example of what's
| possible. You can have multiple scanline PIO running at once,
| each decoding a compressed RLE format including transparency and
| it composes them all together on the fly.
|
| If you've ever played one of the Zachtronics games (in particular
| Shenzhen IO) it feels like the programming in one of those games.
| Tight constraints but major possibilities when you think about it
| for a while.
| MatthiasWandel wrote:
| I have been puzzling over how to program quadrature decoding with
| the PIO instructions. Not many chips have quadrature decoding
| built in.
| [deleted]
| yetihehe wrote:
| If you want to do it in pio, one of solutions would be some
| elaborate series of jump instructions to detect what changed
| and then in which direction. Every jump string would terminate
| with instruction sending direction to queue. Otherwise you
| could just output pins on every change into some array through
| dma and read that array on main processor and calculate current
| position in batched mode.
| MatthiasWandel wrote:
| I guess the ting to do would be to somehow wait on a change
| on either line. Could be done with a wait on just one line if
| I only want half counts instead of quarter counts
| yetihehe wrote:
| Or just continuously poll input pins and compare with
| scratch register. When anything changes, execute check
| logic. Probably best one is just waiting on pin changes and
| sending them to main processor for handling. I have
| multiple quadrature decoder in plans, but nothing started
| yet and this is approach I will be taking if no one makes
| anything better until then. When you check 16 pins for
| changes, you can easily handle 8 decoders with just one PIO
| state machine and some cunning decoding logic. I wouldn't
| be surprised, if someone implements quadrature decoding
| with hardware interpolator. It's one nice piece of
| hardware. You can do single cycle 2d texture mapping or
| rotozooming with that thing.
| dragontamer wrote:
| Quadrature decoding is just 4-state (aka: 2-bit) gray-code
| decoding.
|
| 0 -> 1 -> 2 -> 3 -> 0 -> 1 -> 2 -> 3... is counting up.
| Formally: newstate - oldstate == 1.
|
| 0 -> 3 -> 2 -> 1 -> 0 -> ... is counting down. Formally:
| newstate - oldstate == 3.
|
| 0 -> 2 is ambiguous. Carry on the "same direction as the last
| time". Formally: newstate - oldstate == 2.
|
| 0 -> 0 is standing still, no movement. newstate - oldstate == 0
|
| -------
|
| Except of course: 0, 1, 2, 3 are gray coded, not normal binary
| coded.
|
| * 0 == 00
|
| * 1 == 01
|
| * 2 == 11
|
| * 3 == 10
|
| Anyway, convert the 00 / 01 / 11 / 10 raw hardware bit-stream
| into the above numbers (0, 1, 2, 3). Then it becomes VERY easy.
| MatthiasWandel wrote:
| The question was not how quadrature encoding works, but how
| to implement it with the limited PIO instructions
| dragontamer wrote:
| Hmmm.
|
| Any I/O is basically compression. So lets think about what
| we're actually outputting. We're converting a raw bitstream
| from two GPIO pins paired (Ex: 00, 01, 01, 01, 11, 11, 10,
| 00, 01, 11), into a singular message: such as +6.
|
| There are two applications of a quadrature encoder that I
| can think of.
|
| 1. Virtual Pot -- Converting the messages into a kind of
| "-100 to +100 slider", such as a volume control knob. In
| this case, you want a regular update schedule at human-
| interface speeds (~1000 updates / second or slower).
|
| 2. Rotational Velocity sensor -- Converting the messages
| into a speed. You're willing to batch the bitstream up as
| slowly as possible, maybe waiting for a rollover event
| (+128 or -128). And you just interrupt on those overflows.
|
| -------
|
| Since the input format is already set, we now think about
| the output format: how to represent +6 and or -12?
|
| Based on the PIO instruction set, it seems like +6 and -12
| probably would be easiest as two separate registers in two
| different state-machines.
|
| Every time an "increment" is detected, the FIFO-associated
| with +1 gets a +1 bit added to it. Every time a "decrement"
| is detected, the 2nd FIFO associated with -1 gets a +1 bit
| added to it.
|
| ----
|
| In pseudocode: IncrementSide(){
| currentState = 00; // default while(1){
| nextState = in(GPIO0) | in(GPIO1);
| if(currentState == 00 and nextState == 01){
| push 1; } if(currentState
| == 01 and nextState == 11){ push 1;
| } if(currentState == 11 and nextState ==
| 10){ push 1; }
| if(currentState == 10 and nextState == 00){
| push 1; } currentState =
| nextState; } }
|
| "nextState" and "currentState" probably is just the X and Y
| registers of the PIO state machines. The above is "very
| pseudocode" as I don't really understand PIO yet.
|
| I'm saying "push 1", but "push 1 into the OSR". It looks
| like the OSR has some kind of auto-push mechanism, but if
| that doesn't work then a manual-push might be needed in the
| code proper. Hard to say from the docs alone.
|
| DecrementSide would be just the inverted if-statements:
| if(currentState == 00 and nextState == 11){
| push 1; // Decrement side checking for a decrement
| }
|
| --------
|
| This above methodology would only work for #2 ("velocity"),
| and fails for #1 ("positional"), because the increment-side
| and decrement-side would be updating at varying rates.
|
| I probably can make a positional-decoder instead of a
| velocity one using similar principles. Or maybe by somehow
| ensuring that the +1 and -1 messages go into the same FIFO
| to be picked up by the host CPU.
|
| The idea is route "0" messages to /dev/null, compressing
| the input stream. The host still sees the important +1 and
| -1 messages. The exact mechanism for that is up for debate,
| but the simple if-else state machine above seems to
| accomplish that to a limited extent.
|
| ------
|
| EDIT: Hmmm, maybe a singular FIFO can be done if we have
| push1 and push0 for the two kinds of messages: 1
| representing +1 and 0 representing -1.
|
| Anyway, my point is that there's lots of solutions here. It
| doesn't seem very difficult to me conceptually. Just a lot
| of experimentation needed to know exactly how those 9
| instructions work and the exact mechanisms of the ISR / OSR
| / X reg / Y reg.
| tekromancr wrote:
| Don't you need more states, or an invalid state state to
| account for bounces?
| dragontamer wrote:
| Due to the grey-code methodology, a bounce will be
| interpreted as a "+1" followed by a "-1". (or
| alternatively: a -1 followed by a +1) in all situations.
|
| Ex: 00 -> 10 -> 00 is interpreted as 0 -> 3 -> 0, or -1
| transition then a +1 transition.
|
| 01 -> 11 -> 01 is interpreted as 1 -> 2 -> 1, or +1
| followed by a -1 transition.
|
| All possible combinations of bounces (00 -> 01 -> 00, 00 ->
| 10 -> 00, 01 -> 11 -> 01, 01 -> 00 -> 01, etc. etc.) have
| this +1 / -1 or -1/+1 property.
| mmastrac wrote:
| Funny enough, this popped up when I was googling RPI PIO just
| now:
|
| https://twitter.com/ZodiusInfuser/status/1357067388928335873
| IshKebab wrote:
| Quadrature decoding is extremely common in microcontrollers,
| though the peripheral may not be called a quadrature decoder.
| Normally they just make the counter peripheral flexible enough
| to do it.
|
| Example for the ESP32: https://github.com/espressif/esp-
| idf/tree/73db142/examples/p...
|
| I would not be surprised if you don't need PIO for this on this
| chip.
| sfrigon wrote:
| What stops major SoC designers to come up with a standard
| "programmable IOs" interface for all their IOs, a little bit like
| these PIOs, instead of shipping hundreds of flavors of the same
| CPU with different IO options? I guess it's more expensive to
| design & manufacture a truly general purpose IO, but doesn't the
| cost of warehouse and the risk of not having a market for that
| specific SoC outweigh the initial cost? It would also lower the
| number of pins on the SoC. e.g. You only want HDMI & SATA, here's
| the VHDL for it, you can even individually select the pins you
| want to use.
| dragontamer wrote:
| > You only want HDMI & SATA
|
| SATA is a 6Gbps port, while HDMI is a 10Gbps port.
|
| The PIO ports discussed here are on the order of 100kHz,
| roughly 1-million times slower than HDMI, and 600,000 times
| slower than SATA.
| peterburkimsher wrote:
| It actually is possible to get HDMI on the RP2040, if you're
| willing to have lower resolution.
|
| https://hackaday.com/2021/02/12/bitbanged-dvi-on-a-
| raspberry...
| sfrigon wrote:
| Wow that's nice.
|
| Even though I did not intend to say we should have SATA and
| HDMI on the RP2040 itself (I didn't know if it was
| possible), it still proves that having realtime control on
| the IOs opens the door for way more functionalities than
| SPI/I2C/UART specific ports. All of it using the same SoC
| and potentially less pins.
|
| Having the same level of control on any device would be
| beneficial in my opinion.
| sfrigon wrote:
| Right, but I didn't mean for this specific device. I meant
| for higher end SoCs, as in the RaspberryPi4/BeagleBone Black
| or even higher end SoCs. The RP2040 could be used as an
| inspiration to provide the same level of freedom to other
| SoCs.
| sfrigon wrote:
| Well actually, it would be nice to replace any specific
| interface with a generic FPGA-like interface. But of course
| what you can implement with it would be limited to the
| speed of the CPU / peripheral.
| dragontamer wrote:
| My overall point is that GHz-speed decoding in a flexible
| manner seems... difficult... to say the least.
|
| Your discussion point of "here's a VHDL block" seems to
| understand the general issue. You need a non-trivial amount
| of FPGA-magic (LUTs) to implement logic and routing at
| those speeds. SATA has some kind of error-correction code
| if I remember correctly... so its not exactly easy to parse
| those messages.
| sfrigon wrote:
| I absolutely agree that this would be non-trivial and a
| lot of magic is required to make it happen. But it would
| need to be done only once, after that it can be shared to
| all the users, a little bit like a GPU firmware/driver.
|
| I am just surprised that this is not more widespread
| among major players as a way to reduce costs and increase
| flexibility. Though I'm pretty sure I'm overlooking the
| core of the issue here haha
| mbreese wrote:
| I think one major factor is that it would increase unit
| costs in many cases. We are talking cheap chips that are
| sold in high volume. So any small increase in cost gets
| multiplied quickly. Combine that with competition (your
| competitor provides a less flexible chip, but it is $0.20
| cheaper and has the IO ports you need), and you can see
| why we have the mess we do.
|
| I think I'm many cases the flexibility is great during
| the prototype phase. But those are used at lower volume.
| When you move to production, you'd want to have the
| cheapest BOM as possible.
| magicalhippo wrote:
| > The PIO ports discussed here are on the order of 100kHz
|
| That's not what the datasheet[1] says:
|
| _When outputting DPI, PIO can sustain 360 Mb /s during the
| active scanline period when running from a 48 MHz system
| clock. In this example, one state machine is handling
| frame/scanline timing and generating the pixel clock, while
| another is handling the pixel data, and unpacking run-length-
| encoded scanlines._
|
| Still not SATA speeds though.
|
| [1]: https://datasheets.raspberrypi.org/rp2040/rp2040-datashe
| et.p...
| gchadwick wrote:
| > HDMI is a 10Gbps port.
|
| > The PIO ports discussed here are on the order of 100kHz
|
| PIO runs at the system clock, 125 MHz by default, overclocks
| of over 400 MHz have been reported stable. A single PIO can
| clock out 32 bits every cycle (with a DMA and a memory system
| that can feed this), giving you a total of 4 Gbps.
|
| Running at full throttle like that, especially for a decent
| length of time is tricky if you want to actually do anything
| other than blast out bits but 16 or 8 bits per cycle is a lot
| more straight forward, so 2 or 1 Gbps.
|
| DVI output has already been demonstrated, running two
| displays at 480p: https://github.com/Wren6991/picodvi
|
| The DVI is maybe more of a party trick than something you'd
| do in production hardware but it does demonstrate how capable
| the PIO can be. You could happily implement the same concept
| in a more performant device and reach 10 Gbps or more in a
| reasonable way.
| fpgaminer wrote:
| I was skeptical at first, but read the github and yeah, not
| only does it work, it passes eye mask tests. Crazy.
| monocasa wrote:
| You sort of have that with generic SERDES blocks.
| petra wrote:
| What stops them? Mostly business considerations.
|
| The differentiate their price according to features and so they
| extract more money. And by writing your code to specific
| peripherials, it's harder to switch to another mcu.
|
| And they have large libraries of proven hardware peripherials
| and code which make it harder for competitors to enter. Why
| would they want to compete with open-source pio libraries?
|
| The raspberry pi foundation doesn't care about all that. So
| they created this chip.
___________________________________________________________________
(page generated 2021-02-16 23:01 UTC)