6 years, 10 months ago.

Unable to set x,y position for Nokia 5110 LCD

I have been scratching my head since couple of days to solve a lcd display issue.

Problem-1: As I read from the datasheet of PCD8544, I can set x, y position to (0, 0) by writing command 0x80 and 0x40. However upon restart when I write these commands and then display any pattern, it seem to be displaying at different location (almost at x=73, y = 0) when I keep on writing then after it continue to write till last pixel (bottom right corner) and then rolls back to top left. If i write exactly 504 data, it covers whole LCD but the start position is not as expected (0,0). Any clue or pointer what could be going wrong? PS: If I don't write (0,0) upon restart and directly start writing data, it starts writing from the first pixel of the lcd as expected :(

Problem-2: If I want to write some data i.e. write data to first byte of first row, second byte of second row, third byte of third row and so on.... If I dont set the x,y position at start up (first set_xy_pos(0,0)) and only set the Y position within while loop.

I see that it starts to display from first pixel but does not display all the rows. It just displays 1st, 2nd and 4th rows only rest remains blank

Any clue why it does not display any data on 3rd, 5th and 6th row when I explicitly set the y position?

Problem-3: upon restart if I write data 0x01, it makes two pixel ON. MSB and LSB as if I have written 0x81, any clue?

main.c

#include <pic18f45k40.h>
#include "config.h"
//#include "switch_matrix.h"
//#include "queue.h"
#include "lcd.h"
 
#define LED1_LATBIT LATAbits.LATA1
#define LED1_PORTBIT PORTAbits.RA1
 
#define LED2_LATBIT LATAbits.LATA2
#define LED2_PORTBIT PORTAbits.RA2
 
void main(void) {
 
   OSCFRQbits.HFFRQ = 0b0011;   //8MHZ clock
 
    LATDbits.LATD2 = 1;     //LCD_POWER_ON_OFF
   
//    INTCONbits.PEIE = 1;    //peripheral interrupt enable
//    INTCONbits.GIE = 1;
   
    init_lcd_if();
 
    unsigned char y_pos = 0;
    unsigned char x_pos = 0;
   
    __delay_ms(100);
    set_xy_pos(0, 0);
 
    while (1)
    {
        //buf full, read and flush
        proc_lcd_data();
        __delay_ms(100);
 
        x_pos++;
 
        if(x_pos > 83) {
            x_pos = 0;
            y_pos++;
 
            if(y_pos > 5) {
                y_pos = 0;
            }
        }
        set_xy_pos(x_pos, y_pos);
    }
    return;
}

lcd.c

#include <pic18f45k40.h>
#include "config.h"
#include "lcd.h"
//#include "queue.h"
 
#define LCD_COMMAND LATDbits.LATD1 = 0;
#define LCD_DATA LATDbits.LATD1 = 1;
#define LCD_CS(level) LATAbits.LA5 = level;
 
#define HIGH 1
#define LOW  0
 
static void send_lcd_cmd(unsigned char cmd);
void SPI_Write(unsigned char x);
 
void init_lcd_if(void)
{
    ANSELDbits.ANSELD1 = 0;     //MODE Select, 0:Cmd, 1:Data
    TRISDbits.TRISD1 = 0;
   
    ANSELDbits.ANSELD2 = 0;     //LCD_ON_OFF
    TRISDbits.TRISD2 = 0;
   
    ANSELDbits.ANSELD3 = 0;     //RESET, Active low
    TRISDbits.TRISD3 = 0;
//   LATDbits.LATD3 = 1;
 
    ANSELCbits.ANSELC3 = 0;     //CLK
    TRISCbits.TRISC3 = 0;
   
    ANSELCbits.ANSELC5 = 0;     //MOSI
    TRISCbits.TRISC5 = 0;
   
    ANSELAbits.ANSELA5 = 0;     //CS, Active low
    TRISAbits.TRISA5 = 0;
   
    //MOSI
    RC5PPS = 0b10000;
    //CLK
    RC3PPS = 0b01111;
   
    //config SPI registers
   
    SSP1STATbits.SMP = 1;
    SSP1CON1bits.WCOL = 0;  //no collision
    SSP1CON1bits.SSPOV = 0; //no overflow
   
    SSP1CON1bits.CKP = 0;   //idle state for the clock is a low level
//    SSP1CON1bits.SSPM = 0b0010;  //clock = FOSC/64
    SSP1CON1bits.SSPM = 0b0001;  //clock = FOSC/16
//    SSP1CON1bits.SSPM = 0b0000;  //clock = FOSC/4
   
    SSP1CON3bits.PCIE = 1;
 
 
    SSP1CON1bits.SSPEN = 1;
   
//    PIE3bits.SSP1IE = 1;       //SPI int enabled
    SSP1BUF = 0x00;
//    SPI_Write(0x00);
    //SS bit always on, SP_DEBUG
    LCD_CS(HIGH);
    __delay_ms(10);
    LCD_CS(LOW);        //Keep the CS enabled always
   
    LATDbits.LATD3 = 0;     //LCD_RESET
    __delay_ms(100);
    LATDbits.LATD3 = 1;     //LCD_RESET
   
    PIR3bits.SSP1IF=0;
 
    SPI_Write(0x00);
   
    LCD_COMMAND;
 
    send_lcd_cmd(0x21);
    send_lcd_cmd(0x13);
    send_lcd_cmd(0x07);
    send_lcd_cmd(0x80);
    send_lcd_cmd(0x20);
    send_lcd_cmd(0x0C);     //Normal mode
   
    clear_lcd_disp();
}
 
static void send_lcd_cmd(unsigned char cmd)
{
    LCD_CS(LOW);
    LCD_COMMAND;
    SPI_Write(cmd);
    LCD_CS(HIGH);  
}
 
void send_lcd_data(unsigned char data)
{
    LCD_CS(LOW);
    LCD_DATA;
    SPI_Write(data);
    LCD_CS(HIGH);
}
 
void set_display_off()
{
    send_lcd_cmd(0x08);     //Normal mode
}
 
void set_display_on()
{
    send_lcd_cmd(0x0C);     //Normal mode
}
void clear_lcd_disp(void)
{
    LCD_DATA;
    LCD_CS(LOW);
    for(int i = 0; i < 504; i++) {
        SPI_Write(0x00);
    }
    LCD_CS(HIGH);
}
 
void proc_lcd_data(void)
{
    LCD_CS(LOW);
    LCD_DATA;
    SPI_Write(0xFC);
    LCD_CS(HIGH);
}
 
void set_xy_pos(unsigned char x, unsigned char y)
{
//    send_lcd_cmd(0x40 | y);
//    send_lcd_cmd(0x80 | x);
}
 
void SPI_Write(unsigned char x)
{
    unsigned char data_flush;
    SSP1BUF=x;                /* Copy data in SSBUF to transmit */
    while(!PIR3bits.SSP1IF);    /* Wait for complete 1 byte transmission */
    PIR3bits.SSP1IF=0;        /* Clear SSPIF flag */
    data_flush=SSP1BUF;        /* Flush the data */
}

main.c

#ifndef LCD_H
#define    LCD_H
 
#ifdef    __cplusplus
extern "C" {
#endif
 
    typedef enum LCD_STATE
    {
        LCD_INIT = 0,
        LCD_IDLE,
        LCD_DATA_WRITE,
        LCD_CMD_WRITE,
    };
 
   
    void init_lcd_if(void);
    void clear_lcd_disp(void);
    void write_lcd_cmd(void);
    void send_lcd_data(unsigned char data);
    void set_display_off();
    void set_display_on();
    void set_xy_pos(unsigned char x, unsigned char y);
   
    void proc_lcd_data(void);
 
 
 
#ifdef    __cplusplus
}
#endif

1 Answer

5 years, 7 months ago.

Hi, I was confronted to the same problem of fancy positionning, I would suggest :

void PositionXY(char X, char Y)

{

CS = 1; chip deselect

SendCommand(0x80 + X); /* X position */

SendCommand(0x40 + Y); /* Y position */

CS = 0;/* chip select*/

DC = 1;/* mode data*/

}

Best Regards F. D.