NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Everything Else » More GLCD questions...

October 10, 2013
by andyi
andyi's Avatar

I recently got hold of a Sainsmart 3.2" TFT LCD screen (the one with the sd card cage and touch screen). I cut down Henning Karlsen's UTFT library and converted it to C (from CPP) to run on the nerdkit 168. It's working fine in 16 bit mode, I can draw all sorts of wacky pictures but it uses all my MCU pins and now I want to use the 8 bit mode to try and make use of the SD card and/or touch screen. Trouble is I can't get it working. I have tried all sorts of configurations but no joy.

I think the code is ok and have checked all connections but I'm wondering if there is something I need to do to configure the interface for 8 bit?

I have seen 2 different circuits, one connecting the spare 8 GLCD pins (DB0-DB7) to ground and another to +5v via 4.7K resistors. Neither of these has produced results for me. Briefly my connections are:-

MCU PortD -> GLCD DB8-DB15
MCU PB0-> GLCD CS,PB3->RS, PB4->WR, PB5->RESET
GLCD RD pin is held at 3.3V
GLCD PB0-PB7 to GND

Has anyone managed to get something like this working?

October 11, 2013
by andyi
andyi's Avatar

I've had no luck answering this question (some people report that you have to move resistors or apply jumpers to unmarked points on the PCB - but my soldering skills are no where near up to scratch for smt components) and I'm also banging against the memory limit for the atmega168 anyway,so I'm going to have to break out the shiny new 328 that has just arrived and make use of the extra port and memory.

Now I'll be able to compile the full UTFT library and use the fonts as well as the graphics - at least I will when I've figured out how to use my (also shiny and new) AVR ISP mkII.

But before I leave it, here is a picture to prove the 168 can drive a glcd.

3.2 lcd

The mess of wires on the right hand side is just going to and from 20 10K resistors to drop the voltage to ~3.3V.

October 11, 2013
by andyi
andyi's Avatar

obviously I don't get another port on the 328... ... but I do on the 1284 which arrived in the same parcel!

October 12, 2013
by esoderberg
esoderberg's Avatar

Andyi,

Working GLCD code would be a nice addition to the forum here; please post when able. If you have questions IRT the AVR ISP mkII, I've been using it for the last few years with Atmel Studio 6 so I might be able to help.

Eric

October 15, 2013
by andyi
andyi's Avatar

Here is the code I used for the Sainsmart 3.2 tft with SSD1289 controller. I have stripped out everything else in case you wonder why there are so many switch statements with only one option. As I said earlier it is based on UTFT (fonts stripped out to fit on 168).

Pin defs:-

MCU       GLCD
PC0-5 -> DB0-5
PB1   -> DB6
PB2   -> DB7
PD0-7 -> DB08-15
PB0   -> CS
PB3   -> RS
PB4   -> WR
PB5   -> RESET

other GLCD pins
GND    -> 0V
VCC    -> 5V
LEDA   -> 3.3V
RD     -> 3.3V

I have used 10K resistors from the MCU to level shift down to ~3.4V (also tried level shifting ICs but they take seem to be slower)

// Sainsmart 3.2 tft lcd test script

#include <avr/pgmspace.h>
#include "../../code/libnerdkits/delay.h"
#include "lcdtest.h"
//#include <stdint.h>
//#include <math.h>

// MCU setup
void mcu_setup()
{
    // define pins
    // CS       - PB0
    // WR       - PB4
    // RS       - PB3
    // RESET    - PB5
    // RD       - tied high to 3.3v
    // ALE      - define for LATCHED 16 bit
    // SDA      - define for SERIAL
    // SCL      - define for SERIAL

    // switch off UART 
    UCSR0B=0;
    // define direction of all pins
    switch (display_transfer_mode)
    {
        case 16:
            DDRB |= 0x3F;
            DDRC |= 0x3F;
            DDRD |= 0xFF;
            break;
        // other modes not yet implemented
    }
    // set all pins low
    //PORTB &= ~(0x3F);
    //PORTC &= ~(0x3F);
    //PORTD &= 0x00;
    PORTB=0;
    PORTC=0;
    PORTD=0;
}
void initialise(byte orientation)
{
    orient=orientation;     // PORTRAIT or LANDSCAPE
    display_model=SSD1289;  // SSD1289, SSD1289_8 or SSD1289LATCHED for 3.2" or ST7735 for 1.8"

    switch (display_model)
    {
        case SSD1289:
            disp_x_size=239; 
            disp_y_size=319; 
            display_transfer_mode=16;
            break;
        //other models not implemented
    }
}

void setCS()
{
    PORTB|=(1<<PB0);
}
void clearCS()
{
    PORTB&=~(1<<PB0);
}
void setWR()
{
    PORTB|=(1<<PB4);
}
void clearWR()
{
    PORTB&=~(1<<PB4);
}
void setRS()
{
    PORTB|=(1<<PB3);
}
void clearRS()
{
    PORTB&=~(1<<PB3);
}
void setRESET()
{
    PORTB|=(1<<PB5);
}
void clearRESET()
{
    PORTB&=~(1<<PB5);
}
void lcd_write_bus(char VH, char VL, byte mode)
{
    switch (mode)
    {
        case 16:
            //       16 bit
            // clear port b,c,d data bits
            PORTB &= ~(0x06);
            PORTC &= ~(0x3F);
            PORTD = VH;
            PORTC |= (VL & 0x3F);
            PORTB |= (VL>>5)&0x06;
            // pulse WR low
            clearWR();delay_us(1);setWR(); // need 10us delay for voltage level shifters - only 1 us if 10k resistors used for level shifting instead
            break;
        // no other modes implemented
    }
}

void lcd_write_com(char VL)
{
    clearRS();
    lcd_write_bus(0x00,VL,display_transfer_mode);
}

void lcd_write_data(char VH, char VL)
{
    setRS();
    lcd_write_bus(VH, VL,display_transfer_mode);
}

void lcd_write_data2(char VL)
{
    setRS();
    lcd_write_bus(0x00,VL,display_transfer_mode);
}

void lcd_write_com_data(char com1, int dat1)
{
    lcd_write_com(com1);
    lcd_write_data(dat1>>8,dat1);
}
void setcolor(byte r, byte g, byte b)
{
    fch=((r&248)|g>>5);
    fcl=((g&28)<<3|b>>3);
}
void setcolor2(word color)
{
    fch=(byte)(color>>8);
    fcl=(byte)(color&0xFF);
}
word getcolor()
{
    return (fch<<8) | fcl;
}

void setbackcolor(byte r, byte g, byte b)
{
    bch=((r&248)|g>>5);
    bcl=((g&28)<<3|b>>3);
    _transparent=false;
}
void setbackcolor2(uint32_t color)
{
    if (color==VGA_TRANSPARENT)
        _transparent=true;
    else
    {
        bch=(byte)(color>>8);
        bcl=(byte)(color & 0xFF);
        _transparent=false;
    }
}
word getbackcolor()
{
    return (bch<<8) | bcl;
}

void setxy(word x1, word y1, word x2, word y2)
{
    if (orient==LANDSCAPE)
    {
        swap(word, x1, y1);
        swap(word, x2, y2)
        y1=disp_y_size-y1;
        y2=disp_y_size-y2;
        swap(word, y1, y2)
    }
    switch(display_model)
    {
        case SSD1289: 
            lcd_write_com_data(0x44,(x2<<8)+x1);
            lcd_write_com_data(0x45,y1);
            lcd_write_com_data(0x46,y2);
            lcd_write_com_data(0x4e,x1);
            lcd_write_com_data(0x4f,y1);
            lcd_write_com(0x22);
            break;
    }
}

void _fast_fill_16(int ch, int cl, long pix)
{
    long blocks;

    PORTD = ch;
    PORTB &= ~(0x06);
    PORTB |= ((cl>>5)&0x06);
    PORTC &= ~(0x3F);
    PORTC |= (cl & 0x3F);

    blocks = pix/16;
    int i;
    for (i=0; i<blocks; i++)
    {
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
        clearWR();delay_us(1);setWR();
    }
    if ((pix % 16) != 0)
        for (i=0; i<(pix % 16)+1; i++)
        {
            clearWR();delay_us(1);setWR();
        }
}

void clrxy()
{
    if (orient==PORTRAIT)
        setxy(0,0,disp_x_size,disp_y_size);
    else
        setxy(0,0,disp_y_size,disp_x_size);
}
void clrscr()
{
    clearCS();
    clrxy();
    setRS();
    _fast_fill_16(0,0,((disp_x_size+1)*(disp_y_size+1)));
    setCS();
}

void setpixel(word color)
{
    lcd_write_data((color>>8),(color&0xFF));    // rrrrrggggggbbbbb
}

void drawpixel(int x, int y)
{
    clearCS();
    setxy(x, y, x, y);
    setpixel((fch<<8)|fcl);
    setCS();
    clrxy();
}

void fillscr(word color)
{
    char ch, cl;

    ch=(byte)(color>>8);
    cl=(byte)(color & 0xFF);

    clearCS();
    clrxy();
    setRS();
    _fast_fill_16(ch,cl,((disp_x_size+1)*(disp_y_size+1)));
    setCS();
}

void fillscr2(byte r, byte g, byte b)
{
    word color = ((r&248)<<8 | (g&252)<<3 | (b&248)>>3);
    fillscr(color);
}

void drawhline(int x, int y, int l)
{
    if (l<0)
    {
        l = -l;
        x -= l;
    }
    clearCS();
    setxy(x, y, x+l, y);
    setRS();
    _fast_fill_16(fch,fcl,l);

    setCS();
    clrxy();
}

void drawvline(int x, int y, int l)
{
    if (l<0)
    {
        l = -l;
        y -= l;
    }
    clearCS();
    setxy(x, y, x, y+l);
    setRS();
    _fast_fill_16(fch,fcl,l);

    setCS();
    clrxy();
}

void drawline(int x1, int y1, int x2, int y2)
{
    if (y1==y2)
        drawhline(x1, y1, x2-x1);
    else if (x1==x2)
        drawvline(x1, y1, y2-y1);
    else
    {
        unsigned int    dx = (x2 > x1 ? x2 - x1 : x1 - x2);
        short           xstep =  x2 > x1 ? 1 : -1;
        unsigned int    dy = (y2 > y1 ? y2 - y1 : y1 - y2);
        short           ystep =  y2 > y1 ? 1 : -1;
        int             col = x1, row = y1;

        clearCS();
        if (dx < dy)
        {
            int t = - (dy >> 1);
            while (true)
            {
                setxy (col, row, col, row);
                lcd_write_data (fch, fcl);
                if (row == y2)
                    return;
                row += ystep;
                t += dx;
                if (t >= 0)
                {
                    col += xstep;
                    t   -= dy;
                }
            } 
        }
        else
        {
            int t = - (dx >> 1);
            while (true)
            {
                setxy (col, row, col, row);
                lcd_write_data (fch, fcl);
                if (col == x2)
                    return;
                col += xstep;
                t += dy;
                if (t >= 0)
                {
                    row += ystep;
                    t   -= dx;
                }
            } 
        }
        setCS();
    }
    clrxy();
}

void drawcircle(int x, int y, int radius)
{
    int f = 1 - radius;
    int ddF_x = 1;
    int ddF_y = -2 * radius;
    int x1 = 0;
    int y1 = radius;

    clearCS();
    setxy(x, y + radius, x, y + radius);
    lcd_write_data(fch,fcl);
    setxy(x, y - radius, x, y - radius);
    lcd_write_data(fch,fcl);
    setxy(x + radius, y, x + radius, y);
    lcd_write_data(fch,fcl);
    setxy(x - radius, y, x - radius, y);
    lcd_write_data(fch,fcl);

    while(x1 < y1)
    {
        if(f >= 0) 
        {
            y1--;
            ddF_y += 2;
            f += ddF_y;
        }
        x1++;
        ddF_x += 2;
        f += ddF_x;    
        setxy(x + x1, y + y1, x + x1, y + y1);
        lcd_write_data(fch,fcl);
        setxy(x - x1, y + y1, x - x1, y + y1);
        lcd_write_data(fch,fcl);
        setxy(x + x1, y - y1, x + x1, y - y1);
        lcd_write_data(fch,fcl);
        setxy(x - x1, y - y1, x - x1, y - y1);
        lcd_write_data(fch,fcl);
        setxy(x + y1, y + x1, x + y1, y + x1);
        lcd_write_data(fch,fcl);
        setxy(x - y1, y + x1, x - y1, y + x1);
        lcd_write_data(fch,fcl);
        setxy(x + y1, y - x1, x + y1, y - x1);
        lcd_write_data(fch,fcl);
        setxy(x - y1, y - x1, x - y1, y - x1);
        lcd_write_data(fch,fcl);
    }
    setCS();
    clrxy();
}

void fillcircle(int x, int y, int radius)
{
    int y1;
    int x1;
    for(y1=-radius; y1<=0; y1++) 
        for(x1=-radius; x1<=0; x1++)
            if(x1*x1+y1*y1 <= radius*radius) 
            {
                drawhline(x+x1, y+y1, 2*(-x1));
                drawhline(x+x1, y-y1, 2*(-x1));
                break;
            }
}
void drawrect(int x1, int y1, int x2, int y2)
{
    if (x1>x2)
    {
        swap(int, x1, x2);
    }
    if (y1>y2)
    {
        swap(int, y1, y2);
    }

    drawhline(x1, y1, x2-x1);
    drawhline(x1, y2, x2-x1);
    drawvline(x1, y1, y2-y1);
    drawvline(x2, y1, y2-y1);
}

void drawroundrect(int x1, int y1, int x2, int y2)
{
    if (x1>x2)
    {
        swap(int, x1, x2);
    }
    if (y1>y2)
    {
        swap(int, y1, y2);
    }
    if ((x2-x1)>4 && (y2-y1)>4)
    {
        drawpixel(x1+1,y1+1);
        drawpixel(x2-1,y1+1);
        drawpixel(x1+1,y2-1);
        drawpixel(x2-1,y2-1);
        drawhline(x1+2, y1, x2-x1-4);
        drawhline(x1+2, y2, x2-x1-4);
        drawvline(x1, y1+2, y2-y1-4);
        drawvline(x2, y1+2, y2-y1-4);
    }
}

void fillrect(int x1, int y1, int x2, int y2)
{
    if (x1>x2)
    {
        swap(int, x1, x2);
    }
    if (y1>y2)
    {
        swap(int, y1, y2);
    }
    clearCS();
    setxy(x1, y1, x2, y2);
    setRS();
    _fast_fill_16(fch,fcl,(((long)(x2-x1)+1)*((long)(y2-y1)+1)));
    setCS();
}

void fillroundrect(int x1, int y1, int x2, int y2)
{
    if (x1>x2)
    {
        swap(int, x1, x2);
    }
    if (y1>y2)
    {
        swap(int, y1, y2);
    }

    if ((x2-x1)>4 && (y2-y1)>4)
    {
        int i;
        for (i=0; i<((y2-y1)/2)+1; i++)
        {
            switch(i)
            {
            case 0:
                drawhline(x1+2, y1+i, x2-x1-4);
                drawhline(x1+2, y2-i, x2-x1-4);
                break;
            case 1:
                drawhline(x1+1, y1+i, x2-x1-2);
                drawhline(x1+1, y2-i, x2-x1-2);
                break;
            default:
                drawhline(x1, y1+i, x2-x1);
                drawhline(x1, y2-i, x2-x1);
            }
        }
    }
}
// lcd on
void lcdon()
{
    clearCS();
    setCS();
}

// LCD_Init
void lcd_init()
{
    setRESET();
    delay_ms(5);
    clearRESET();
    delay_ms(15);
    setRESET();
    delay_ms(15);

    clearCS();
    switch(display_model)
    {
        case SSD1289:
            lcd_write_com_data(0x00,0x0001);
            lcd_write_com_data(0x03,0xA8A4);
            lcd_write_com_data(0x0C,0x0000);
            lcd_write_com_data(0x0D,0x080C);
            lcd_write_com_data(0x0E,0x2B00);
            lcd_write_com_data(0x1E,0x00B7);
            lcd_write_com_data(0x01,0x2B3F);
            lcd_write_com_data(0x02,0x0600);
            lcd_write_com_data(0x10,0x0000);
            lcd_write_com_data(0x11,0x6070);
            lcd_write_com_data(0x05,0x0000);
            lcd_write_com_data(0x06,0x0000);
            lcd_write_com_data(0x16,0xEF1C);
            lcd_write_com_data(0x17,0x0003);
            lcd_write_com_data(0x07,0x0233);
            lcd_write_com_data(0x0B,0x0000);
            lcd_write_com_data(0x0F,0x0000);
            lcd_write_com_data(0x41,0x0000);
            lcd_write_com_data(0x42,0x0000);
            lcd_write_com_data(0x48,0x0000);
            lcd_write_com_data(0x49,0x013F);
            lcd_write_com_data(0x4A,0x0000);
            lcd_write_com_data(0x4B,0x0000);
            lcd_write_com_data(0x44,0xEF00);
            lcd_write_com_data(0x45,0x0000);
            lcd_write_com_data(0x46,0x013F);
            lcd_write_com_data(0x30,0x0707);
            lcd_write_com_data(0x31,0x0204);
            lcd_write_com_data(0x32,0x0204);
            lcd_write_com_data(0x33,0x0502);
            lcd_write_com_data(0x34,0x0507);
            lcd_write_com_data(0x35,0x0204);
            lcd_write_com_data(0x36,0x0204);
            lcd_write_com_data(0x37,0x0502);
            lcd_write_com_data(0x3A,0x0302);
            lcd_write_com_data(0x3B,0x0302);
            lcd_write_com_data(0x23,0x0000);
            lcd_write_com_data(0x24,0x0000);
            lcd_write_com_data(0x25,0x8000);
            lcd_write_com_data(0x4f,0x0000);
            lcd_write_com_data(0x4e,0x0000);
            lcd_write_com(0x22);
            break;
    }

    setCS();

    setcolor(255,255,255);
    setbackcolor(0,0,0);
    cfont.font=0;
    _transparent=false;
}

// Main
int main()
{
    // initialise variables
    initialise(PORTRAIT);
    // set up MCU
    mcu_setup();
    // lcd on is not strictly necessary for SSD1289
    lcdon();
    // lcd_init produces a fuzzy coloured screen if it works
    lcd_init();
    // some example drawing
    clrscr();
    fillscr(VGA_YELLOW);
    delay_ms(500);
    fillscr(VGA_BLUE);
    setcolor2(VGA_RED);
    fillcircle(100,150, 50);
    setcolor(0,255,0);
    drawcircle(100,200,50);
    drawrect(60,270,100,300);
    fillrect(120,270,180,300);
    drawroundrect(60,60,120,10);
    fillroundrect(130,60,200,10);
    setcolor2(VGA_SILVER);
    drawline(1,1,239,319);
    drawpixel(130,280);
    drawpixel(131,280);
    drawpixel(132,280);
    drawpixel(130,281);
    drawpixel(131,281);
    drawpixel(132,281);
    drawpixel(130,282);
    drawpixel(131,282);
    drawpixel(132,282);
    return 0;
}
October 15, 2013
by andyi
andyi's Avatar

and lcdtest.h...

#ifndef lcdtest_h
#define lcdtest_h

#define LEFT 0
#define RIGHT 9999
#define CENTER 9998

#define PORTRAIT 0
#define LANDSCAPE 1

//*********************************
// COLORS
//*********************************
// VGA color palette
#define VGA_BLACK       0x0000
#define VGA_WHITE       0xFFFF
#define VGA_RED         0xF800
#define VGA_GREEN       0x0400
#define VGA_BLUE        0x001F
#define VGA_SILVER      0xC618
#define VGA_GRAY        0x8410
#define VGA_MAROON      0x8000
#define VGA_YELLOW      0xFFE0
#define VGA_OLIVE       0x8400
#define VGA_LIME        0x07E0
#define VGA_AQUA        0x07FF
#define VGA_TEAL        0x0410
#define VGA_NAVY        0x0010
#define VGA_FUCHSIA     0xF81F
#define VGA_PURPLE      0x8010
#define VGA_TRANSPARENT 0xFFFFFFFF

#define SERIAL_4PIN     4
#define SERIAL_5PIN     5
#define LATCHED_16      17

#define SSD1289         2
#define ST7735          9
#define SSD1289LATCHED  16
#define SSD1289_8       19

typedef uint8_t byte;
typedef uint8_t boolean;
#define false 0
#define true 1
typedef unsigned int word;
#define swap(type, i, j) {type t = i; i = j; j = t;}
#define fontbyte(x) pgm_read_byte(&cfont.font[x])  
#define fontdatatype uint8_t

#define regtype volatile uint8_t
#define regsize uint8_t
#define bitmapdatatype unsigned int*

typedef struct
{
    uint8_t* font;
    uint8_t x_size;
    uint8_t y_size;
    uint8_t offset;
    uint8_t numchars;
} _current_font;

byte fch, fcl, bch, bcl;
byte orient;
long disp_x_size, disp_y_size;
byte display_model, display_transfer_mode, display_serial_mode;
_current_font cfont;
boolean _transparent;

#endif
October 22, 2013
by JimFrederickson
JimFrederickson's Avatar

Hello Andy,

How was it to order from Sainsmart?

I have looked at them and they have alot of items have some pretty fantastic prices.
(It seems ALOT of documentation is kind of "DIY", and I have seen several forum posts
with what seem to be "minor product defects".)

Did they ship promptly?
Did you have any issues with the order and/or payment for the order?

Regarding the display that you have, is it fairly bright and clear?

Thanks,
James...

October 23, 2013
by andyi
andyi's Avatar

Hi James, I had no problems with the ordering or payment process. I paid using paypal on the sainsmart website and received my 2 screens about 2 or 3 weeks later (can't remember exactly) here in the UK. One of them has stopped working - it worked ok initially but now doesn't initialise. The other is working fine, but at £10 ($15) each I'm not too worried.

I will try and post a clearer photo of the screen with some graphics, so you can judge the clarity and sharpness for yourself, tomorrow when I have a bit more time.

I have managed to get the display and touchpanel working well and can draw on the screen with my finger. Next to get the SD card reader going. I am still using the nerdkit atmega168 with an octal latch to free up 8 pins for the serial comms to touchpanel and sd card - i am hoping to use the same SPI for both (with different CS pins).

Andy.

November 01, 2013
by andyi
andyi's Avatar

Hi James,

Only just got time to get back to you. I'm afraid the photos aren't great but you can see that the display is fairly sharp (to my untrained eye at least) and the touch panel working. The touch writing shows a lot of scatter but i haven't implemented any sort of debouncing in code - it is just sampling once every 200us. I managed to get the touch panel to work fine with SPI at cpu@14Mhz / 64. Had some problem with the SD card though - I can get it to initialise using SPI but everything else is very hit and miss (mostly miss) - but I put that down to my code. It seems that SD card code has to be very resiliant and able to rerun commands that fail until they succeed or timeout.

"touch writing"

"close up"

Andy.

November 01, 2013
by esoderberg
esoderberg's Avatar

Nice work.

Post a Reply

Please log in to post a reply.

Did you know that you can use a transistor to interface between different voltage levels of digital logic? Learn more...