January 11, 2025

Driving an LED panel - via ARM and emio

Today is my first day with success!

I first sent a single line with RGB colors set to the three last pixels on the line -- and it worked.

Next I experiment with sending multiple lines and writing to the entire panel. It turns out that the fastest I can write lines is at about 1100 Hz, which yields a panel refresh of 34 Hz, which is quite visible and ugly. But it works.

Each call to emio_write() takes 1.5 us and it takes 521 of those to send a line. This yields the 1100 Hz rate that I measure by putting my scope on the LAT signal. The pixel clock is about 300 kHz using emio -- and not even that fast since I have to take time to write the 6 color bits during one phase of the clock.

I have read that it is possible to clock pixels into a panel of this sort at rates as high as 27 Mhz and perhaps higher. This could yield a refresh rate of 3000 Hz! We will need the FPGA for that, and will probably use a rate more like 200 Hz (though we do plan to allow for PWM to control brightness and get more colors).

Another question is whether I have the ARM core in the Zynq running at the full 600 Mhz clock rate. I am not sure and I might not. Whatever the case, I am more interested in going to the FPGA at this point than I am in pushing for more from the ARM. Using the ARM to refresh the display, even at 30 Hz, is consuming all of the CPU resources for one core.

Here is the C code to send one line:

static void
hub_line ( int addr, char colors[], int ncolors )
{
        int i;
        int color;

        // printf ( "+" );

        // turn off the line
        emio_write ( OE_HUB, 1 );

        // I am guessing that A is the lsb
        emio_write ( A_HUB, addr & 1 );
        emio_write ( B_HUB, (addr >> 1) & 1 );
        emio_write ( C_HUB, (addr >> 2) & 1 );
        emio_write ( D_HUB, (addr >> 3) & 1 );
        emio_write ( E_HUB, (addr >> 4) & 1 );

        for ( i=0; i> 1) & 1 );
            emio_write ( R1_HUB, (color >> 2) & 1 );
            emio_write ( B2_HUB, (color >> 3) & 1 );
            emio_write ( G2_HUB, (color >> 4) & 1 );
            emio_write ( R2_HUB, (color >> 5) & 1 );

            // pulse clk
            emio_write ( CLK_HUB, 1 );
            emio_write ( CLK_HUB, 0 );
        }

        // pulse lat
        emio_write ( LAT_HUB, 1 );
        emio_write ( LAT_HUB, 0 );

        // turn on the line
        emio_write ( OE_HUB, 0 );
}

Have any comments? Questions? Drop me a line!

Tom's Electronics pages / tom@mmto.org