o update documentation.

This commit is contained in:
Henner Zeller 2015-07-19 17:17:59 -07:00
parent 941f71e350
commit 2de9a31572

230
README.md
View file

@ -10,6 +10,8 @@ GNU General Public License Version 2.0 <http://www.gnu.org/licenses/gpl-2.0.txt>
The example code using this library is released in the public domain.
## NOTE the pinout changed on 2015-07-19 to provide more glitch-free output. If you have an existing wiring, provide -DRGB_CLASSIC_PINOUT to the compilation or consider changing the wiring as it provides a much more stable image.
Overview
--------
The 32x32 or 16x32 RGB LED matrix panels can be scored at [Sparkfun][sparkfun],
@ -72,84 +74,49 @@ e.g. using the [active adapter PCB](./adapter/).
Since we only need output pins on the RPi, we don't need to worry about level
conversion back.
For a single chain of LED-panels, we need 13 IO pins. It will work on all
Rasperry Pis, including the first board revision of the Raspberry Pi 1.
For a single chain of LED-panels, we need 13 IO pins, which fit all in the
header of the old Raspberry Pis. Newer Raspberry Pis have 40 GPIO pins which allows
us to connect three parallel chains of RGB panels.
LED-Panel to GPIO:
* GND (Ground, '-') to ground of your Raspberry Pi (Pin 25 on RPi-header)
* R1 (Red 1st bank) : GPIO 17 (Pin 11 on RPi header)
* G1 (Green 1st bank) : GPIO 18 (Pin 12 on RPi header)
* B1 (Blue 1st bank) : GPIO 22 (Pin 15 on RPi header)
* R2 (Red 2nd bank) : GPIO 23 (Pin 16 on RPi header)
* G2 (Green 2nd bank) : GPIO 24 (Pin 18 on RPi header)
* B2 (Blue 2nd bank) : GPIO 25 (Pin 22 on RPi header)
* A, B, C, D (Row address) : GPIO 7, 8, 9, 10 (Pins 26, 24, 21, 19
on RPi-header)
(Note: there is no need for `D` needed if you have a display with 16 rows
with 1:8 multiplexing)
* OE- (neg. Output enable) : GPIO 27 (Pin 13 on RPi header) **(Note, this changed from previous versions of this library)**.
On a Raspberry Pi 1 Revision 1 (really old), this is on GPIO 0, Pin 3.
* CLK (Serial clock) : GPIO 11 (Pin 23 on RPi header) **(Note, this changed from previous versions of this library)**
* STR (Strobe row data) : GPIO 4 (Pin 7 on RPi header)
Here is an illustration of the different Raspberry Pi headers for reference.
For reference, this is how the numbering on the Raspberry Pi looks like:
<a href="img/raspberry-gpio.jpg"><img src="img/raspberry-gpio.jpg" width="600px"></a>
Left: Raspberry Pi 1, on the right Raspberry Pi 1 B+ or Raspberry Pi 2.
Or check <http://elinux.org/RPi_Low-level_peripherals> for details of available
GPIOs and pin-header.
This is the same representation as in the table below, which allows nice visual inspection.
Note, each panel has an output that allows you to daisy-chain it to the next
board (see section about chaining below).
If you are using only 1 bit pwm (`-p 1` flag), then this can be a very long
chain. Though full color pwm (color images), the refresh rate goes down
considerably after 6-8 boards.
For each of the up to three chains, you have to connect GND, strobe,
clock, OE, A, B, C, D to all of these; you find the positions below (note there are more GND
pins on the Raspberry Pi, but for simplicity, they are left out; The `---` are not connected).
Then for each panel, there is a set of (R1, G1, B1, R2, G2, B2) that you have
to connect to the places marked `[1]`, `[2]` and `[3]` for chain 1, 2, and 3.
To make things quicker to see visually, I've marked each chain with a separate
icon `[1]`=:smile:, `[2]`=:boom: and `[3]`=:droplet:.
### Up to 3 Panels with newer Raspberry Pis with 40 GPIO pins! ###
If you have one of the newer plus models of the Raspberry Pi 1 or the
Raspberry Pi2, you can control **up to three chains** in parallel. This does not
cost more CPU, so is essentially coming for free (except that your code
needs to generate more pixels of course). For the same number of panels,
always prefer parallel chains before daisy chaining more panels, as it will
keep the refresh-rate higher.
Connection | Pin | Pin | Connection
----------------:|:---:|:---:|:-----------
--- | 1 | 2 | ---
:droplet:`[3] G1`| 3 | 4 | ---
:droplet:`[3] B1`| 5 | 6 | GND
strobe | 7 | 8 | `[3] R1` :droplet:
--- | 9 | 10 | ---
clock | 11 | 12 | OE
:smile: `[1] G1`| 13 | 14 | ---
A | 15 | 16 | B
--- | 17 | 18 | C
:smile: `[1] B2`| 19 | 20 | ---
:smile: `[1] G2`| 21 | 22 | D
:smile: `[1] R1`| 23 | 24 | `[1] R2` :smile:
--- | 25 | 26 | `[1] B1` :smile:
--- | 27 | 28 | ---
:boom: `[2] G1`| 29 | 30 | ---
:boom: `[2] B1`| 31 | 32 | `[2] R1` :boom:
:boom: `[2] G2`| 33 | 34 | ---
:boom: `[2] R2`| 35 | 36 | `[3] G2` :droplet:
:droplet:`[3] R2`| 37 | 38 | `[2] B2` :boom:
--- | 39 | 40 | `[3] B2` :droplet:
For multiple parallel boards to work, you have to uncomment
#DEFINES+=-DSUPPORT_MULTI_PARALLEL # remove the '#' in the begging
in [lib/Makefile](./lib/Makefile).
If you only use two panels, you will be able to use I²C and the serial line
connectors on the Raspberry Pi. With three panels, these pins will be used up
as well.
The second and third panel chain share some of the wires of the first panel:
connect **GND, A, B, C, D, OE, CLK** and **STR** to the same pins you already
connected the first panel.
Then connect the following
### Second panel ###
* R1 (Red 1st bank) : GPIO 12 (Pin 32 on RPi header)
* G1 (Green 1st bank) : GPIO 5 (Pin 29 on RPi header)
* B1 (Blue 1st bank) : GPIO 6 (Pin 31 on RPi header)
* R2 (Red 2nd bank) : GPIO 19 (Pin 35 on RPi header)
* G2 (Green 2nd bank) : GPIO 13 (Pin 33 on RPi header)
* B2 (Blue 2nd bank) : GPIO 20 (Pin 38 on RPi header)
### Third panel ###
The third panel will use some pins that are otherwise used for I²C and the
serial interface. If you don't care about these, then we can use these to
connect a third chain of panels.
* R1 (Red 1st bank) : GPIO 14, also TxD (Pin 8 on RPi header)
* G1 (Green 1st bank) : GPIO 2, also SDA (Pin 3 on RPi header)
* B1 (Blue 1st bank) : GPIO 3, also SCL (Pin 5 on RPi header)
* R2 (Red 2nd bank) : GPIO 15, also RxD (Pin 10 on RPi header)
* G2 (Green 2nd bank) : GPIO 26 (Pin 37 on RPi header)
* B2 (Blue 2nd bank) : GPIO 21 (Pin 40 on RPi header)
In the [adapter/](./adapter) directory, there are some boards that make
the wiring task simpler.
Running
-------
@ -359,6 +326,45 @@ Or, if you are lazy, just import the whole namespace:
Read the [`minimal-example.cc`](./minimal-example.cc) to get started, then
have a look into [`demo-main.cc`](./demo-main.cc).
Help, some pixels are not displayed properly
--------------------------------------------
Some panels don't handle the 3.3V logic level well, in particular with
faster Raspberry Pis Version 2. This results in artifacts like randomly
showing up pixels or parts of the panel showing 'static'.
If you encounter this, try these things
- Make sure to have as short as possible flat-cables connecting your
Raspberry Pi with the LED panel.
- Use an adapter board with a bus-driver that acts as level shifter between
3.3V and 5V. You can find [active adapter PCBs](./adapter/) in a
subdirectory of this project.
- If you can't implement the above things, or still have problems, you can
slow down the GPIO writing a bit. This will of course reduce the
frame-rate, so it comes at a cost.
For GPIO slow-down, uncomment the following line in [lib/Makefile](lib/Makefile)
#DEFINES+=-DRGB_SLOWDOWN_GPIO # remove '#' in the beginning
Then `make clean` and `make` again.
Inverted Colors ?
-----------------
There are some displays out there that use inverse logic for the colors. You
notice that your image looks like a 'negative'. In that case, uncomment the
folling `DEFINES` line in [lib/Makefile](./lib/Makefile) by removing the `#`
at the beginning of the line.
#DEFINES+=-DINVERSE_RGB_DISPLAY_COLORS # remove '#' in the beginning
Then, recompile
make clean
make
A word about power
------------------
@ -424,46 +430,6 @@ guidelines:
- If you still see noise, increase the voltage sligthly above 5V. But note,
this is typically only a symptom of too thin traces.
Help, some pixels are not displayed properly
--------------------------------------------
Some panels don't handle the 3.3V logic level well, in particular with
faster Raspberry Pis Version 2. This results in artifacts like randomly
showing up pixels or parts of the panel showing 'static'.
If you encounter this, try these things
- Make sure to have as short as possible flat-cables connecting your
Raspberry Pi with the LED panel.
- Use an adapter board with a bus-driver that acts as level shifter between
3.3V and 5V. You can find [active adapter PCBs](./adapter/) in a
subdirectory of this project. Also, Adafruit made a HAT that has level
shifters.
- If you can't implement the above things, or still have problems, you can
slow down the GPIO writing a bit. This will of course reduce the
frame-rate, so it comes at a cost.
For GPIO slow-down, uncomment the following line in [lib/Makefile](lib/Makefile)
#DEFINES+=-DRGB_SLOWDOWN_GPIO # remove '#' in the beginning
Then `make clean` and `make` again.
Inverted Colors ?
-----------------
There are some displays out there that use inverse logic for the colors. You
notice that your image looks like a 'negative'. In that case, uncomment the
folling `DEFINES` line in [lib/Makefile](./lib/Makefile) by removing the `#`
at the beginning of the line.
#DEFINES+=-DINVERSE_RGB_DISPLAY_COLORS # remove '#' in the beginning
Then, recompile
make clean
make
Technical details
-----------------
@ -499,39 +465,23 @@ areas of your picture.
(Even with realtime extensions enabled in Linux, this is still a (smaller)
problem).
The timing of the Output Enable pin has to be very accurate otherwise you'll
see brightness glitches. We are using the PWM hardware of the Raspberry Pi to
provide such accurate timing.
Limitations
-----------
If using higher resolution color (This code supports up to 24bpp @3x11 bit PWM),
you will see dynamic glitches - lines that flicker and randomly look a bit
brighter. At lower bit PWM between <= 4, this is typically not visible.
If you are using the RGB_CLASSIC_PINOUT, then we can't make use of the PWM
hardware (which only outputs to a particular pin), so you'll see random
brightness glitches. I strongly suggest to change to the now
default pinout.
This is due to the fact that we have to do the PWM ourselves and for
high-resolution PWM, the smallest time-period is around 200ns. We would need
hard real-time requirements of the operating system of << 200ns.
Even for realtime environments, that is pretty tough.
We're running this on a general purpose computer with no dedicated
realtime hardware (such as dedicated, separate realtime core(s) we could use
on the BeagleBone Black). Linux does provide some support for realtime
applications, but the latency goals here are in the tens of microseconds at
best. Even with realtime-patches applied (I tried the
[RPi wheezy image provided by Emlid][emlid-rt]), this does not make much of
a dent.
The system needs constant CPU to update the display. Using the DMA controller
was considered but after extensive experiments ( https://github.com/hzeller/rpi-gpio-dma-demo )
dropped due to its slow speed..
According to the paper [How fast is fast enough? Choosing between Xenomai and
Linux for real-time applications][rt-paper], it might pay off to move the display
update part to the kernel. Future TODO.
(One experiment already done was to use the DMA controller of the RPi to make
use of dedicated hardware. However, it turns out that the DMA controller was
slower writing data than using GPIO directly. But maybe it might be worthwile if
it turns out to have more stable realtime properties.)
There seems to be a limit in how fast the GPIO pins can be controlled.
We get about 10Mhz clock speed out of GPIO clocking. Do do things correctly,
we would have to take the time it takes to clock a row in as essentially the
lowest PWM time (~3.4µs).
However, we just ignore this 'black' time, and switch the row on and off after
the clocking with the needed time-period; that way we get down to 200ns.
There seems to be a limit in how fast the GPIO pins can be controlled, which
limits the frame-rate.
[hub75]: ./img/hub75.jpg
[hub75-arrow]: ./img/hub75-other.jpg