In Part 1 we used an infinite loop to draw images on the RGB matrix. The time between drawing one pair of lines and the next was filled by spinning, which is rarely a good option. Instead of spinning, we can use a timer interrupt to draw each pair of lines at regular intervals, saving on power and allowing the CPU either to sleep or to do something else while it is not drawing.
The code for Part 2 uses the Raspberry Pi’s system timer, which works at a frequency of 1MHz, to generate a timer interrupt every 100us (the value can, of course, be modified as necessary). Note that the system timer is a separate module from the architecture-defined counter on the ARM core, and is owned by the Video Core. Also note that, while the documentation specifies that the system timer generates interrupt 1, on the Raspberry Pi 4 this is actually interrupt 97, as the Video Core peripheral IRQs feed into the GIC starting at ID 96.
After mapping the system timer registers and registering an interrupt handler the initial expiration time is programmed into the timer to 100us into the future. The timer interrupt service routine performs the following actions:
- Set the address lines to the current row number. The row number is kept as a static variable in the scope of the ISR.
- Advances the row number.
- Draws the two lines with the data matching the new row number, as described in Part 1.
- Programs the timer to 100us in the future.
Setting the address lines to the current row number before advancing it is a trick picked up from the reference library. It allows us to eliminate spinning for the time required between drawing a line and setting the row address, taking advantage of the fact that the same image is drawn over and over at the current refresh rate.
Since the main loop is no longer responsible for drawing the images it just sleeps for 1 second, before copying the next image into the buffer used by the ISR to draw the pixels.
The code for Part 2 is available here.