Working with LCD ST7920 (graphic mode)

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I start to working with LCD ST7920

 

// define pins here
#define DATA_PORT PORTD
#define DATA_IN PIND
#define COMMAND_PORT PORTC
#define DATAPORT_DIR DDRD
#define COMMAND_DIR DDRC
#define RS 0b00000001; // PC0 binary equivalent of pin number
#define RW 0b00000010; // PC1
#define E 0b00000100; // PC2
#define RST 0b00001000; // PC3

#define delay_time 80

void highRS() {
    COMMAND_PORT |= RS;
    _delay_us(delay_time);
}

void lowRS() {
    COMMAND_PORT &= ~RS;
    _delay_us(delay_time);
}

void highRW() {
    COMMAND_PORT |= RW;
    _delay_us(delay_time);
}

void lowRW() {
    COMMAND_PORT &= ~RW;
    _delay_us(delay_time);
}

void highE() {
    COMMAND_PORT |= E;
    _delay_us(delay_time);
}

void lowE() {
    COMMAND_PORT &= ~E;
    _delay_us(delay_time);
}

void toggleE() {
    highE();
    lowE();
}

void highRST() {
    COMMAND_PORT |= RST;
    _delay_us(delay_time);
}

void lowRST() {
    COMMAND_PORT &= ~RST;
    _delay_us(delay_time);
}

// start graphic mode
void ST7920_graphicEnable(void) {
    DATAPORT_DIR = 0xff;
    _delay_ms(110);
    lowE();
    lowRS();
    lowRW();
    highRST();
    DATA_PORT = 0x30;    // set 8-bit interface
    delay_ms(110);
    toggleE();
    _delay_ms(1);
    DATA_PORT = 0x36;    //  Repeat with graphics bit set to on.
    _delay_ms(110);
    toggleE();
    DATA_PORT = 0x0c;    // display ON, cursor and blink OFF
    _delay_ms(110);
    toggleE();
    DATA_PORT = 0x01;    // clear display, reset address
    _delay_ms(110);
    toggleE();
    DATA_PORT = 0x06;    // display ON, no cursor
    _delay_ms(110);
    toggleE();
}

void ST7920_graphicFill(uint16_t value) {
    uint8_t i, j;
    for (i = 0; i < 64; i++) {
        for (j = 0; j < 8; j++) {
            ST7920_write2BytesXY(j, i, value);
        }
    }
}

void ST7920_write2BytesXY(int x, int y, uint16_t data) {
    DATAPORT_DIR = 0xff;	// set data port for output
    lowE();
    lowRS();
    lowRW();
    // convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays).
    if (y > 31) {
        y -= 32;    // because there are only 31 addressable lines in the ST7920
        x += 8;     // so we overflow x (7 visible bytes per line) to reach the bottom half
    }
    x |= 0x80;  // bit 7 signals that this is a data address write
    y |= 0x80;
    DATA_PORT = y;  // set vertical DDRAM address
    toggleE();
    DATA_PORT = x;  // set horizontal DDRAM address
    toggleE();
    highRS(); // signal for WRITE
    DATA_PORT = (data >> 8);	// set horizontal DDRAM address
    toggleE();
    DATA_PORT = data;	// set vertical DDRAM address
    toggleE();
}

uint16_t ST7920_read2Bytes(uint8_t type) {
    uint8_t i, j = 0;
    uint16_t temp;
    DATAPORT_DIR = 0x00;	// set data port for input
    DATA_PORT = 0x00;
    lowE();
    if (type == 0) {
        lowRS();
    } else {
        highRS();
    }
    highRW();
    highE();	// toggle byte in
    i = DATA_IN;	// need I read this twice?
    lowE();

    highE();
    i = DATA_IN;
    lowE();
    _delay_ms(1);
    highE();
    j = DATA_IN;
    lowE();

    temp = j;
    temp = temp | (i << 8);

    return(temp);    // return byte read
}

void ST7920_gotoXY(uint8_t x, uint8_t y) {
    DATAPORT_DIR = 0xff;	// set data port for output
    lowE();
    lowRS();
    lowRW();
    // convert coordinates to weirdly-arranged 128x64 screen (the ST7920 is mapped for 256x32 displays).
    if (y > 31) {
	y -= 32;	// because there are only 31 addressable lines in the ST7920
	x += 8;     // so we overflow x (7 visible bytes per line) to reach the bottom half
    }
    x |= 0x80;  // bit 7 signals that this is a data address write
    y |= 0x80;
    DATA_PORT = y;  // Set vertical DDRAM address
    toggleE();
    DATA_PORT = x;  // Set horizontal DDRAM address
    toggleE();
}

void ST7920_setPixel(uint8_t x, uint8_t y) {
    uint8_t x_wd, x_pixel;
    uint16_t temp;
    uint16_t dot = 0x8000;  // this will be rotated into it's correct position in the word
    x_wd = x / 16;			// find address of word with our pixel (x; 0-7)
    x_pixel = x - (x_wd * 16);  // get the modulo remainder; that's our pixel's position in the word
    ST7920_gotoXY(x_wd, y);
    temp = ST7920_read2Bytes(1);	// read word from screen at that position
    temp = (temp | (dot >> x_pixel));	// convert x_pixel into a bit position, 0-16
    ST7920_write2BytesXY(x_wd, y, temp);
}

void ST7920_clearPixel(uint8_t x, uint8_t y) {
    uint8_t x_wd, x_pixel;
    uint16_t temp;
    uint16_t dot = 0x7fff;  // this will be rotated into it's correct position in the word
    x_wd = x / 16;			// find address of word with our pixel (x; 0-7)
    x_pixel = x - (x_wd * 16);  // get the modulo remainder; that's our pixel's position in the word
    ST7920_gotoXY(x_wd, y);
    temp = ST7920_read2Bytes(1);    // read word from screen at that position
    temp = (temp & (dot >> x_pixel));   // convert x_pixel into a bit position, 0-16
    ST7920_write2BytesXY(x_wd, y, temp);
}

int main(void)
{
    DATAPORT_DIR = 0xff;		// set DATAPORT to output
    DATA_PORT = 0x00;			// set outputs to 0 initially
    COMMAND_DIR = 0x07;			// set command port to output
    COMMAND_PORT = 0x00;		// set outputs to 0 initially

    ST7920_graphicEnable();
    ST7920_graphicFill(0x0000);	

    ST7920_setPixel(0, 0);
    ST7920_setPixel(0, 63);
    ST7920_setPixel(127, 0);
    ST7920_setPixel(127, 127);

    while (1) {

	}
}

 

When I switch power OFF/ON after LCD initializing, LCD displaing not correct view. I guess something wrong with init sequence. I can't find where I am make mistake)

Last Edited: Fri. Mar 6, 2020 - 07:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No startup delay perhaps, I don't know your graphics controller, but it may need some time after power up to do it's own internal init before it can be sent commands. 

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Life is much easier with SPI interface.   Less wires.  Less bit-twiddling.

 

All the same,  the ST7920 works fine in 8-bit parallel or in 4-bit parallel mode.

But I have not got the stamina to study your code.

 

David.