SumitBirla.com

Home » Writings » Gumstix/Audiostix2 interface to LCD

Gumstix/Audiostix2 interface to LCD

Posted: June 4, 2006

Gumstix is a very neat, hobbyist-friendly embedded computer which runs Linux. It is about the size of a stick of gum (hence the name) and has a strong community support system. Various breakout and add-on boards are available making the platform versatile. I had intended to use Gumstix in my CarPC project, but I ended up spending most of my time getting the LCD to interface directly with PXA LCD driver. I have listed my findings below for the benefit of others.

Audiostix2 to LQ050Q5DR01 interface

The following table shows the connections between the Audiostix2 board and the LCD. Since the Gumstix outputs a 16-bit color (RGB565) and the LCD expects 18-bit color, we simply ground the least significant bits (LSB) of red and blue. Note that the BIAS signal is not needed for this LCD and has been left open.

Audiostix2
GPSstix        Sharp LQ050Q5DR01      My understanding
--------------------------------------------------------------
LCLK            PIN_3   Hsync         signals the end of line                   
PCLK            PIN_13  CLK           pixel clock
FCLK            PIN_28  Vsync         signals the end of a frame
LDD15           PIN_29  R5            RED_4 - Most significant bit     
LDD14           PIN_27  R4            RED_3
LDD13           PIN_25  R3            RED_2
LDD12           PIN_21  R2            RED_1
LDD11           PIN_19  R1            RED_0
LDD10           PIN_8   G5            GREEN_5 - Most significant bit 
LDD9            PIN_6   G4            GREEN_4
LDD8            PIN_4   G3            GREEN_3
LDD7            PIN_37  G2            GREEN_2
LDD6            PIN_35  G1            GREEN_1
LDD5            PIN_33  G0            GREEN_0
LDD4            PIN_24  B5            BLUE_4 - Most significant bit 
LDD3            PIN_22  B4            BLUE_3
LDD2            PIN_20  B3            BLUE_2
LDD1            PIN_16  B2            BLUE_1
LDD0            PIN_14  B1            BLUE_0
BIAS            -                     Not used
-               PIN_1   GND
-               PIN_2   VCC           +3.3V
-               PIN_5   T0            Leave open (thermistor output)
-               PIN_7   T1            Leave open (thermistor output)
-               PIN_9   HVR           GND (Horiz. of vertical scan direction)
-               PIN_10  GND
-               PIN_11  GND
-               PIN_12  B0            GND (LSB of blue is unused)
-               PIN_15  GND
-               PIN_17  R0            GND (LSB of red is unused)
-               PIN_18  GND
-               PIN_23  GND
-               PIN_26  GND
-               PIN_30  TEST          Leave open
-               PIN_31  GND
-               PIN_32  TEST          Leave open
-               PIN_34  TEST          Leave open
-               PIN_36  TEST          Leave open
-               PIN_38  ENAB          GND (signal to settle horiz.)
-               PIN_39  VCC           +3.3V
-               PIN_40  GND

PXA Register Setup for LQ050Q5DR01

LCD Controller Control Register 0 (7-23)
LCCR0                    0x003008f9  00000000 00110000 00001000 11111001
LCCR0_ENB                         1  LCD controller enable
LCCR0_CMS                         0  LCD monochrome operation enable
LCCR0_SDS                         0  LCD dual panel display enable
LCCR0_LDM                         1  LCD disable done IRQ disable
LCCR0_SFM                         1  LCD start of frame IRQ disable
LCCR0_IUM                         1  LCD fifo underrun error IRQ disable
LCCR0_EFM                         1  LCD end of frame IRQ disable
LCCR0_PAS                         1  LCD active display enable
LCCR0_DPD                         0  LCD send 8 pixel on L_DD[7:0] at each clock
LCCR0_DIS                         0  LCD controller disable
LCCR0_QDM                         1  LCD quick disable IRQ disable
LCCR0_PDD                         0  LCD palette DMA request delay
LCCR0_BM                          1  LCD branch start IRQ disable
LCCR0_OUM                         1  LCD fifo underrun IRQ disable

LCD Controller Control Register 1 (7-26)
LCCR1                    0x46ff2d3f  01000110 11111111 00101101 00111111
LCCR1_PPL                       319  LCD pixels per line (+1)
LCCR1_HSW                        11  LCD horizontal sync pulse width (+1)
LCCR1_ELW                       255  LCD end of line pixel clock wait count (+1)
LCCR1_BLW                        70  LCD beginning of line pixel clock wait count (+1)

LCD Controller Control Register 2 (7-28)
LCCR2                    0x0500fcef  00000101 00000000 11111100 11101111
LCCR2_LPP                       239  LCD lines per panel (+1)
LCCR2_VSW                        63  LCD vertical sync pulse width (+1)
LCCR2_EFW                         0  LCD end of frame line clock wait count (+1)
LCCR2_BFW                         5  LCD beginning of frame line clock wait count (+1)

LCD Controller Control Register 3 (7-31)
LCCR3                    0x04300007  00000100 00110000 00000000 00000111
LCCR3_PCD                         7  LCD pixel clock divisor (+1)
LCCR3_ACB                         0  LCD AC bias pin frequency (+1)
LCCR3_API                         0  LCD AC bias pin transitions per interrupt
LCCR3_VSP                         1  LCD L_FCLK vertical sync polarity active low
LCCR3_HSP                         1  LCD L_LCLK horizontal sync polarity active low
LCCR3_PCP                         0  LCD data sampled on falling edge of L_PCLK
LCCR3_OEP                         0  LCD L_BIAS output enable active low
LCCR3_BPP                        16  LCD bits per pixel
LCCR3_DPC                         0  LCD double pixel clock rate at L_PCLK

Sample Framebuffer Code

The C code below can be used to check the dimensions & depth of your framebuffer device. Additionally, it prints a couple of tests patterns to screen. If you happen to have a 16-bit display and have downloaded the following raw image, then you will also see a picture being printed to screen.

/images/taj.raw
Gumstix connected to LCD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

#define RGB565(r,g,b) (((r >> 3) & 31) << 11) | (((g >> 2) & 63) << 5) | ((b >> 3) & 31)

/* structures for retrieving framebuffer information */
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;

/* size of video memory in bytes */
long int screensize;

/* pointer to memory mapped framebuffer */
char *fbp;


/*
 * Function to set a pixel in framebuffer with the specified
 * (r,g,b). Works only with 32bpp and 16bpp modes.
 */
void set_pixel(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
    long int location;
    location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                       (y+vinfo.yoffset) * finfo.line_length;

    if ( vinfo.bits_per_pixel == 32 ) {
        *(fbp + location) = b;
        *(fbp + location + 1) = g;
        *(fbp + location + 2) = r;
        *(fbp + location + 3) = 0;
    } else  { //assume 16bpp
        *((unsigned short int*)(fbp + location)) = RGB565(r,g,b);
    }
}


/*
 * Program entry point. Opens /dev/fb0 and prints two patterns
 * to it.
 */
int main()
{
    int fd, fbfd, x, y;
    unsigned char r, g, b;

    /* Open the file for reading and writing */
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) {
        perror("/dev/fb0");
        exit(1);
    }

    /* Get fixed screen information */
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
        perror("FBIOGET_FSCREENINFO");
        exit(2);
    }

    /*  Get variable screen information */
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
        perror("FBIOGET_VSCREENINFO");;
        exit(3);
    }

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );

    /* Figure out the size of the video memory in bytes */
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    /* Map the device to memory */
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                       fbfd, 0);
    if ((int)fbp == -1) {
        perror("mmap()");
        exit(4);
    }

    printf("Turning screen red...\n");
    for ( y = 20; y < vinfo.yres-20; y++ )
        for ( x = 20; x < vinfo.xres-20; x++ )
            set_pixel(x, y, 255, 0, 0);

    sleep(2);
    printf("Turning screen green...\n");
    for ( y = 20; y < vinfo.yres-20; y++ )
        for ( x = 20; x < vinfo.xres-20; x++ )
            set_pixel(x, y, 0, 255, 0);

    sleep(2);
    printf("Turning screen blue...\n");
    for ( y = 20; y < vinfo.yres-20; y++ )
        for ( x = 20; x < vinfo.xres-20; x++ )
            set_pixel(x, y, 0, 0, 255);

    /* PATTERN #1: something funky */
    sleep(2);
    printf("Printing pattern #1...\n");

    for ( y = 0; y < vinfo.yres; y++ )
        for ( x = 0; x < vinfo.xres; x++ )
            set_pixel(x, y, 31-(y-100)/16, (x-100)/6, 10);

    sleep(2);

    /* Blank the screen */
    memset(fbp, '\0', screensize);

    /* PATTERN #2: vertical and horizontal lines at 1/3 and 2/3 */
    printf("Printing pattern #2...\n");
      for ( y = 0; y < vinfo.yres; y++ ) {
        set_pixel(2*vinfo.xres/3, y, 255, 255, 255);
        set_pixel(vinfo.xres/3, y, 255, 255, 255);
      }

    for ( x = 0; x < vinfo.xres; x++ ) {
        set_pixel(x, 2*vinfo.yres/3, 255, 255, 255);
        set_pixel(x, vinfo.yres/3, 255, 255, 255);
    }

    sleep(2);

    printf("Printing pictures...\n");
    fd = open("taj.raw", O_RDONLY);

    if (fd == -1)
        perror("taj.raw");
    else
    {
        for ( y = 0; y < 213; y++ )
            for ( x = 0; x < 320; x++ )
            {
                read(fd, &r, 1);
                read(fd, &g, 1);
                read(fd, &b, 1);
                set_pixel(x, y, r, g, b);
            }

        close(fd);
    }

    printf("Done\n");
    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}