Our earlier blogs on DMD discussed the Dot Matrix Display internals and interfacing techniques. In this blog, we will focus on the developing display firmware for a DMD panel.

Driving DMDs

As we have seen, the DMD panel comprises of a matrix of LEDs. Each LED needs one bit of information to store its state. So effectively the DMD data to be displayed can be represented as a consecutive memory. Of the many mechanism available, a simple array will be the easiest representation. Thus to represent pixels in a 16×32 DMD panel, the following ‘C’ statement can be used.

Unsigned char buffer_data [16][4];

Since each byte has 8 bits, we are representing a 32 pixel row with 4 bytes. Now that the memory for display data is allocated, we need to transfer the same to the DMD panel. There are many ways to achieve the same like using simple bit banging mechanism or dedicated peripherals – if available. As seen earlier, using the SPI is the simplest and easiest method. Since most of the microcontrollers, even very low end MCUs, has SPI master port available, this solution is applicable across platforms.

By design, the data pushed in to the DMD panel is displayed only in every fourth row that too in certain order. It is necessary to select the line set based on the Demultiplexer input. For a 16×32 DMD panel, we will have to drive Demux inputs in four possible combinations – 00, 01, 10 and 11.

16X32 DMD panel

Demux inputs – possible combinations

Since only one fourth of the data is going to be displayed at any given time in the DMD, it is essential that the display is refreshed fast enough for the human eye to detect the difference. Assuming a minimum of 20 frames per second, we need to drive it four times more speed for each line set. So for 16×32 lines, we need to drive the SPI at atleast a frequency of 16x32x20 i.e. around 10 KHz. Apart of this, we need to switch the Demux pins once every 16×8 pixels i.e. around 12.8 ms.

One way of achieving this is using a timer in combination with SPI. Typical steps involved in using SPI for driving DMD is given below

  • Initialize the Pins and Port functionality enabling SPI operation for DS/OE pins and GPIO output for Latch pin and Demux pins.
  • Initialize the SPI controller at least 20 times the number of pixels.
  • Initialize a variable to indicate the current line set.
  • Use a timer or task to perform the following operations once, every quarter of the total transfer time.
    • Switch the Demux pin to point to the current line set
    • Configure the SPI controller to transfer the current set of line data (each separated by one fourth of the buffer size).
    • Increment the line set pointer to point to the next set. Fall back to 0 after 3.
    • Wait for the SPI transfer to complete before starting the next cycle.

With the above mechanism it is possible to seamlessly display the data in DMD with SPI controller.

Buffer Manipulation

But major discrepancy is not covered in the above description. As mentioned earlier, the data shifted in to the DMD is displayed in a certain manner typically as depicted below.

It is possible to store the data in the above format. Or for ease of manipulation, we can go for a double buffer approach. One buffer (buffer_data) will hold data in a format easy to manipulate and another buffer (back_buffer) in a format shifted in to the DMD. A simple routing can be used to copy data from the first buffer to the next, typically as follow.

The memory allocation for back_buffer is represented as,

Unsigned char back_buffer [4][16];

//for four bytes of data

for(index = 0;index < 4; index ++)

{

pos = 0;

//when single DMD panel (16×32) NUM_PANELS is one and so on.

for(col = 0; col < 4 * NUM_PANELS; col ++)

{

offset = 15 – index;

//four different set of rows given in Demux table

for(row = 0; row < 4; row ++)

{

back_buffer[index][pos]  = ~buffer_data[offset][col];

offset = offset – 4;

pos ++;

}

}

}

Thus with the above double buffering scheme the complexities of shifting is abstracted and user can simply manipulate the buffer directly. For example to draw a simple pattern of ‘T’ in the first 8×8 pixels, following statement can be used:

Buffer_data [0][0] = 0x1F;

Buffer_data [1][0] = 0x04;

Buffer_data [2][0] = 0x04;

Buffer_data [3][0] = 0x04;

Buffer_data [4][0] = 0x04;

Buffer_data [5][0] = 0x04;

Buffer_data [6][0] = 0x04;

Upon calling the transfer routine, this information is transferred suitably to back_buffer. The timer/task will feed this data to DMD via SPI effectively displaying the ‘T’ symbol.

With an understanding of software control of DMD, we will look into advance concepts of font rendering and scrolling in our next blog.