Overview
Nokia 5510 LCD Module is 84x48 monochrome graphical LCD that use a Philip PCD8544 pixel matrix LCD controller/driver. It is very easy to use since it uses only three wires SPI interface with some additional control pin. It configuration setting is simple that is very similar to the KS0108 LCD controller except the three wires SPI interface. Using this interface is easy to connect and maintenance with a master MCU.
| DS1307 Real Time Clock Reading |
For a tutorial of using this LCD module with PIC16887 see this post since I don't show any more detail. For a simple text displaying on this graphical LCD see this post.
![]() |
| Nokia 5110 LCD Module |
Nokia 5110 LCD Module Back Side |
A master MCU just need to transmit LCD data or command to this LCD. It only contains a dozen of LCD commands for instance LCD contrast setting and LCD position. Each SPI transmissions contains only one byte of data/command with its active low chip select pin.
Text and Graphic Displaying
| Schematic and Simulation |
This simple example the ATMega644p send some text and graphic data to an SPI slave Nokia 5510 graphical LCD. This PCD8544 controller chip offers a high speed SPI data reception even in serial data mode.
Source Code "main.c":
- /*
- * spi_nokia_5510_3.c
- *
- * Created: 2/20/2026 11:05:25 AM
- * Author : Admin
- */
- #include <stdio.h>
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define DD_SS 4
- #define DD_DC 3
- #include "fonts.h"
- #include "graphic_84x48.h"
- const unsigned char lcdX = 48;
- const unsigned char lcdY = 84;
- #define selectCommand() PORTB&=~(1<<DD_DC)
- #define selectData() PORTB|=(1<<DD_DC)
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- // Nokia 5510 LCD Command
- void masterTransmit(char spiData){
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(spiData);
- PRT_SPI|=(1<<DD_SS);
- }
- void nokia5510Command(char cmd){
- selectCommand();
- masterTransmit(cmd);
- }
- void nokia5510Data(char data){
- selectData();
- masterTransmit(data);
- }
- void nokia5510Char(char _char){
- selectData();
- for(char i=0;i<5;i++) {
- masterTransmit(ASCII[_char-0x20][i]);
- }
- masterTransmit(0x00);
- selectData();
- }
- void writeText(char *txt){
- while(*txt) nokia5510Char(*txt++);
- }
- /*Set the cursor*/
- void setXy(char x,char y){
- selectCommand();
- /*x ranges from 0 to 83*/
- masterTransmit(0x80+(6*x));
- /*y ranges from 0 to 5*/
- masterTransmit(0x40+y);
- selectCommand();
- }
- void lcdClear(void){
- for (int i=0;i<lcdX*lcdY/8;i++)
- {
- selectData();
- masterTransmit(0x00);
- }
- selectData();
- }
- void nokia5510Init(void){
- SPI_MasterInit();
- DDR_SPI|=(1<<DD_DC);
- nokia5510Command(0x21); // LCD Extended Commands
- nokia5510Command(0xB5); // SET LCD CONTRAST
- nokia5510Command(0x04); // set temp coefficient 0x04
- nokia5510Command(0x14); // LCD bias
- nokia5510Command(0x20);
- nokia5510Command(0x0C); // LCD normal Mode
- }
- int main(void)
- {
- /* Replace with your application code */
- unsigned long secontCnt=0;
- char cntString[]="";
- nokia5510Init();
- lcdClear();
- setXy(0,1);
- writeText("ATMega644P SPI");
- setXy(0,2);
- writeText("NOKIA 5510 LCD");
- setXy(0,3);
- writeText("Microchip");
- setXy(0,4);
- writeText("Studio IDE");
- _delay_ms(10000);
- lcdClear();
- setXy(0,0);
- for(uint16_t i=0;i<sizeof(graphic_84x48);i++)
- nokia5510Data(graphic_84x48[i]);
- _delay_ms(10000);
- lcdClear();
- setXy(0,0);
- writeText("Started Time:");
- while (1)
- {
- sprintf(cntString,"%u",secontCnt);
- setXy(1,2);
- writeText(cntString);
- for(char i=0;i<14;i++) writeText(" ");
- setXy(1,3);
- writeText("Seconds");
- secontCnt++;
- if(secontCnt>=102) secontCnt=0;
- _delay_ms(1000);
- }
- }
Click here to download this example.
| Tested with ATMega644P |
| Tested with ATMega644P |
| Tested with ATMega644P |
Font Table Creation and ADC Reading
We can create a C font table using Mikroelectrokia GLCD Font Creator that's free to use. It just use the OS installed system font. The user just need to import those font with preferred settings, font name, size, range etc.
| Tahoma Font Extracting |
Then we need to export these data with any programming languages data type.
| Program C data table export |
In this example I use a big tahoma font table for text displaying. The MCU read an analog input value from ADC0 pin.
| ADC Reading |
C Source Code "main.c":
- /*
- * 12-spi_nokia_5510_ADC.c
- *
- * Created: 2/20/2026 9:51:04 PM
- * Author : Admin
- */
- #include <stdio.h>
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define DD_SS 4
- #define DD_DC 3
- #include "fonts.h"
- #include "graphic_84x48.h"
- #include "tahoma_15x16.h"
- const unsigned char lcdX = 48;
- const unsigned char lcdY = 84;
- #define selectCommand() PORTB&=~(1<<DD_DC)
- #define selectData() PORTB|=(1<<DD_DC)
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- // Nokia 5510 LCD Command
- void masterTransmit(char spiData){
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(spiData);
- PRT_SPI|=(1<<DD_SS);
- }
- void nokia5510Command(char cmd){
- selectCommand();
- masterTransmit(cmd);
- }
- void nokia5510Data(char data){
- selectData();
- masterTransmit(data);
- }
- void nokia5510Char(char _char){
- selectData();
- for(char i=0;i<5;i++) {
- masterTransmit(ASCII[_char-0x20][i]);
- }
- masterTransmit(0x00);
- selectData();
- }
- void writeText(char *txt){
- while(*txt) nokia5510Char(*txt++);
- }
- /*Set the cursor*/
- void setXy(char x,char y){
- selectCommand();
- /*x ranges from 0 to 83*/
- masterTransmit(0x80+(6*x));
- /*y ranges from 0 to 5*/
- masterTransmit(0x40+y);
- selectCommand();
- }
- void lcdClear(void){
- for (int i=0;i<lcdX*lcdY/8;i++)
- {
- selectData();
- masterTransmit(0x00);
- }
- selectData();
- }
- void nokia5510Init(void){
- SPI_MasterInit();
- DDR_SPI|=(1<<DD_DC);
- nokia5510Command(0x21); // LCD Extended Commands
- nokia5510Command(0xB5); // SET LCD CONTRAST
- nokia5510Command(0x04); // set temp coefficient 0x04
- nokia5510Command(0x14); // LCD bias
- nokia5510Command(0x20);
- nokia5510Command(0x0C); // LCD normal Mode
- }
- void lcd_xy(int8_t x, int8_t y){
- if(x<84) nokia5510Command(0x80+x);
- if(y<6) nokia5510Command(0x40+y);
- }
- void lcd_char_tahoma_15x16(int8_t x, int8_t y, uint8_t ch){
- uint16_t c=x*2;
- for(uint8_t i=0;i<30;i++){
- if(i%2) {lcd_xy(c/2,y+1); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
- else {lcd_xy(c/2,y); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
- c++;
- }
- }
- void lcd_text_tahoma(int8_t x, int8_t y, uint8_t *text){
- //char x_count=0;
- while(*text) {
- lcd_char_tahoma_15x16(x, y, *text++);
- x+=15;
- }
- }
- int main(void)
- {
- /* Replace with your application code */
- nokia5510Init();
- lcdClear();
-
- //setXy(0,0);
- lcd_text_tahoma(0,0,"Nokia");
- lcd_text_tahoma(0,2,"5510");
- lcd_text_tahoma(0,4,"GLCD");
- DDRB&=~(1<<0);
- ADCSRA=(1<<ADEN);
- ADMUX=0;
- char msg[4];
- _delay_ms(10000);
- lcdClear();
- while (1)
- {
- //Start the conversion
- ADCSRA|=(1<<ADSC);
- //Wait for the completion
- while((ADCSRA&(1<<ADSC))==1);
- //Read the result
- unsigned int temp =ADCL+(ADCH<<8);
- float voltage = (temp*5.0)/1023;
- lcd_text_tahoma(0,0,"ADC0:");
- sprintf(msg,"%04d",temp);
- lcd_text_tahoma(0,2,msg);
- sprintf(msg,"%0.2fV",voltage);
- lcd_text_tahoma(0,4,msg);
- _delay_ms(100);
- }
- }
AVR ATMega644P Experiment Board:
| AVR ATMega644P Experiment Board |
| AVR ATMega644P Experiment Board |
Click here to download this example.
DS1307 Real Time Clock Reading
This small display can show some readable text. So I tested it with a ds1307 real time clock chip. I use a software TWI instead of a dedicated hardware TWI.
| Real Time Clock Reading |
Source Code "main.c":
- /*
- * 12-spi_nokia_5510_RTC.c
- *
- * Created: 2/21/2026 11:46:38 AM
- * Author : Admin
- */
- #include <stdio.h>
- #include <avr/io.h>
- #include <util/delay.h>
- #define F_CPU 16000000UL
- #define DDR_SPI DDRB
- #define PRT_SPI PORTB
- #define DD_MOSI 5
- #define DD_MISO 6
- #define DD_SCK 7
- #define DD_SS 4
- #define DD_DC 3
- #include "fonts.h"
- #include "graphic_84x48.h"
- #include "tahoma_15x16.h"
- #include "twi_device.h"
- const unsigned char lcdX = 48;
- const unsigned char lcdY = 84;
- #define selectCommand() PORTB&=~(1<<DD_DC)
- #define selectData() PORTB|=(1<<DD_DC)
- void SPI_MasterInit(void)
- {
- /* Set MOSI and SCK output, all others input */
- DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
- /* Enable SPI, Master, set clock rate fck/16 */
- SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
- }
- void SPI_MasterTransmit(char cData)
- {
- /* Start transmission */
- SPDR = cData;
- /* Wait for transmission complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- }
- void SPI_SlaveInit(void)
- {
- /* Set MISO output, all others input */
- DDR_SPI = (1<<DD_MISO);
- /* Enable SPI */
- SPCR = (1<<SPE);
- }
- char SPI_SlaveReceive(void)
- {
- /* Wait for reception complete */
- while(!(SPSR & (1<<SPIF)))
- ;
- /* Return Data Register */
- return SPDR;
- }
- // Nokia 5510 LCD Command
- void masterTransmit(char spiData){
- PRT_SPI&=~(1<<DD_SS);
- SPI_MasterTransmit(spiData);
- PRT_SPI|=(1<<DD_SS);
- }
- void nokia5510Command(char cmd){
- selectCommand();
- masterTransmit(cmd);
- }
- void nokia5510Data(char data){
- selectData();
- masterTransmit(data);
- }
- void nokia5510Char(char _char){
- selectData();
- for(char i=0;i<5;i++) {
- masterTransmit(ASCII[_char-0x20][i]);
- }
- masterTransmit(0x00);
- selectData();
- }
- void writeText(char *txt){
- while(*txt) nokia5510Char(*txt++);
- }
- /*Set the cursor*/
- void setXy(char x,char y){
- selectCommand();
- /*x ranges from 0 to 83*/
- masterTransmit(0x80+(6*x));
- /*y ranges from 0 to 5*/
- masterTransmit(0x40+y);
- selectCommand();
- }
- void lcdClear(void){
- for (int i=0;i<lcdX*lcdY/8;i++)
- {
- selectData();
- masterTransmit(0x00);
- }
- selectData();
- }
- void nokia5510Init(void){
- SPI_MasterInit();
- DDR_SPI|=(1<<DD_DC);
- nokia5510Command(0x21); // LCD Extended Commands
- nokia5510Command(0xB5); // SET LCD CONTRAST
- nokia5510Command(0x04); // set temp coefficient 0x04
- nokia5510Command(0x14); // LCD bias
- nokia5510Command(0x20);
- nokia5510Command(0x0C); // LCD normal Mode
- }
- void lcd_xy(int8_t x, int8_t y){
- if(x<84) nokia5510Command(0x80+x);
- if(y<6) nokia5510Command(0x40+y);
- }
- void lcd_char_tahoma_15x16(int8_t x, int8_t y, uint8_t ch){
- uint16_t c=x*2;
- for(uint8_t i=0;i<30;i++){
- if(i%2) {lcd_xy(c/2,y+1); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
- else {lcd_xy(c/2,y); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
- c++;
- }
- }
- void lcd_text_tahoma(int8_t x, int8_t y, uint8_t *text){
- //char x_count=0;
- while(*text) {
- lcd_char_tahoma_15x16(x, y, *text++);
- x+=15;
- }
- }
- void rtc_init(void){
- char rtc[8]={0x30,0x35,0x13,0x07,0x31,0x01,0x26,1<<4};
- for (char i=0;i<8;i++)
- {
- twi_start();
- //D0 is DS1307 Write Address
- twi_write(DS1307_W);
- //Select Control Register
- twi_write(i);
- //Enable SQWE bit blinks at 1 Hz
- twi_write(rtc[i]);
- twi_stop();
- _delay_ms(10);
- }
- }
- unsigned char rtc[50], msg[20];
- void rtc_read(void){
- for(char i=0;i<50;i++){
- /*Second Register*/
- twi_start();
- twi_write(DS1307_W);
- /*Select Second register*/
- twi_write(i);
- twi_stop();
- _delay_us(100);
- twi_start();
- twi_write(DS1307_R);
- rtc[i]=twi_read();
- twi_stop();
- _delay_us(100);
- }
- }
- int main(void)
- {
- /* Replace with your application code */
- nokia5510Init();
- lcdClear();
- setXy(0,0);
- writeText("ATMega644P SPI");
- setXy(0,1);
- writeText("NOKIA 5510 LCD");
- setXy(0,2);
- writeText("DS1307 RTC");
- setXy(0,3);
- writeText("Software TWI");
- _delay_ms(10000);
- lcdClear();
- char msg[4];
- //rtc_init();
- while (1)
- {
- rtc_read();
- setXy(0,0); writeText("DS1307 Real");
- setXy(0,1); writeText("Time Clock:");
- setXy(0,2); writeText("Time:");
- sprintf(msg,"%02X:%02X:%02X",rtc[2],rtc[1],rtc[0]);
- setXy(0,3); writeText(msg);
- setXy(0,4); writeText("Date:");
- sprintf(msg,"%02X/%02X/20%02X",rtc[4],rtc[5],rtc[6]);
- setXy(0,5); writeText(msg);
- _delay_ms(100);
- }
- }
ATMega644P AVR Prototype Board:
| ATMega644P AVR Prototype Board |
| ATMega644P AVR Prototype Board |
Click here to download this example.

