728x90

728x90

Monday, February 23, 2026

ATMega644P SPI and MCP492X 12-bit ADC

Overview

The Microchip Technology Inc. MCP492X are 2.7 – 5.5V, low-power, low DNL, 12-Bit Digital-to-Analog Converters (DACs) with optional 2x buffered output and SPI interface. 
The MCP492X are DACs that provide high accuracy and low noise performance for industrial applications where calibration or compensation of signals (such as temperature, pressure and humidity) are required. The MCP492X are available in the extended temperature range and PDIP, SOIC, MSOP and TSSOP packages.

ATMega644P SPI and MCP492X 12-bit ADC
MCP4921 and MCP4922 DIP Chip

 This chip has a DIP version that is very user-friendly for DIY electronics prototyping. The MCP4921 has only one output DAC while the MCP4922 has two output DAC. DAC selection is set in software.

ATMega644P SPI and MCP492X 12-bit ADC 

These two versions of chip function almost the same except the number of output DAC.

ATMega644P SPI and MCP492X 12-bit ADC
PIN FUNCTION TABLE

 This 12-bit DAC yield different 4096 step. Using a typical +5.0VDC supply voltage we can double its output voltage level to 2X via its gain control bit.

ATMega644P SPI and MCP492X 12-bit ADC
Output Voltage Calculation

The SPI interface of this chip is one direction (write only). One SPI data frame is 16-bit (two byte) that contain DAC setting and 12-bit DAC value.

ATMega644P SPI and MCP492X 12-bit ADC
WRITE COMMAND REGISTER

The Chip Select (CS) is active low. So the master MCU keeps this pin low for two bytes of data transmission.

ATMega644P SPI and MCP492X 12-bit ADC
Write Command

 Using a dedicates SPI interface of an MCU offers a high speed data transmission.

ATMega644P SPI and MCP4921 Single DAC

The MCP4921 is a simple 8-bit DAC chip with single output.  Here the ATMega644P send any DAC voltage to this chip with the lowest and the highest voltage level.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 I use its 2X gain feature that give a maximum output voltage up to 10VDC from a 5.0VDC supply voltage.

  1. /*
  2. * 12-spi_mcp4921.c
  3. *
  4. * Created: 2/23/2026 2:55:53 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define BUF 14
  17. #define G1X 13
  18. #define ACTIVE 12

  19. void SPI_MasterInit(void)
  20. {
  21. /* Set MOSI and SCK output, all others input */
  22. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  23. /* Enable SPI, Master, set clock rate fck/16 */
  24. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  25. }

  26. void SPI_MasterTransmit(char cData)
  27. {
  28. /* Start transmission */
  29. SPDR = cData;
  30. /* Wait for transmission complete */
  31. while(!(SPSR & (1<<SPIF)))
  32. ;
  33. }

  34. void SPI_SlaveInit(void)
  35. {
  36. /* Set MISO output, all others input */
  37. DDR_SPI = (1<<DD_MISO);
  38. /* Enable SPI */
  39. SPCR = (1<<SPE);
  40. }
  41. char SPI_SlaveReceive(void)
  42. {
  43. /* Wait for reception complete */
  44. while(!(SPSR & (1<<SPIF)))
  45. ;
  46. /* Return Data Register */
  47. return SPDR;
  48. }

  49. void mcp4921_send(unsigned int value){
  50. unsigned int mcp4922_data,dac_12;
  51. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  52. dac_12=value;
  53. mcp4922_data|=dac_12&0x0FFF;
  54. PRT_SPI&=~(1<<DD_SS);
  55. SPI_MasterTransmit(mcp4922_data>>8);
  56. SPI_MasterTransmit(mcp4922_data&0x00FF);
  57. PRT_SPI|=(1<<DD_SS);
  58. }

  59. int main(void)
  60. {
  61. /* Replace with your application code */
  62. SPI_MasterInit();
  63. while (1)
  64. {
  65. mcp4921_send(0x0000);
  66. _delay_ms(1000);
  67. mcp4921_send(0x0FFF);
  68. _delay_ms(1000);
  69. }
  70. }




The 12-bit DAC data is masked with the MCP4921 control bits.

Now let create a sine wave output using a DAC data table. This output sine wave doesn't have zero cross.

ATMega644P SPI and MCP492X 12-bit ADC
Sine Wave Generating

 

ATMega644P SPI and MCP492X 12-bit ADC
Output DAC Signal

Its frequency is around 120Hz.

  1. /*
  2. * sine_wave.c
  3. *
  4. * Created: 2/23/2026 7:41:55 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define BUF 14
  17. #define G1X 13
  18. #define ACTIVE 12

  19. static unsigned int sine_table[50] =
  20. {
  21. 512, 576, 639, 700, 759, 813, 862, 907, 944, 975,
  22. 999, 1015, 1023, 1023, 1015, 999, 975, 944, 907, 862,
  23. 813, 759, 700, 639, 576, 512, 448, 385, 324, 265,
  24. 211, 162, 117, 80, 49, 25, 9, 1, 1, 9,
  25. 25, 49, 80, 117, 162, 211, 265, 324, 385, 448
  26. };

  27. void SPI_MasterInit(void)
  28. {
  29. /* Set MOSI and SCK output, all others input */
  30. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  31. /* Enable SPI, Master, set clock rate fck/16 */
  32. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  33. }

  34. void SPI_MasterTransmit(char cData)
  35. {
  36. /* Start transmission */
  37. SPDR = cData;
  38. /* Wait for transmission complete */
  39. while(!(SPSR & (1<<SPIF)))
  40. ;
  41. }

  42. void SPI_SlaveInit(void)
  43. {
  44. /* Set MISO output, all others input */
  45. DDR_SPI = (1<<DD_MISO);
  46. /* Enable SPI */
  47. SPCR = (1<<SPE);
  48. }
  49. char SPI_SlaveReceive(void)
  50. {
  51. /* Wait for reception complete */
  52. while(!(SPSR & (1<<SPIF)))
  53. ;
  54. /* Return Data Register */
  55. return SPDR;
  56. }

  57. void mcp4921_send(unsigned int value){
  58. unsigned int mcp4922_data,dac_12;
  59. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  60. dac_12=value;
  61. mcp4922_data|=dac_12&0x0FFF;
  62. PRT_SPI&=~(1<<DD_SS);
  63. SPI_MasterTransmit(mcp4922_data>>8);
  64. SPI_MasterTransmit(mcp4922_data&0x00FF);
  65. PRT_SPI|=(1<<DD_SS);
  66. }

  67. int main(void)
  68. {
  69. /* Replace with your application code */
  70. SPI_MasterInit();
  71. char i=0;
  72. while (1)
  73. {
  74. mcp4921_send(4*sine_table[i]);
  75. //_delay_ms(10);
  76. i++;
  77. if(i>49) i=0;
  78. }
  79. }





ATMega644P SPI and MCP4921 Single DAC

The MCP4922 has two output DAC but doubled in footprint. However these two chips are identical in functions. This example show how to write DAC values to this chip.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 The master MCU just send the DAC values once and it keep in the buffer of the MCP4922 (buffer enabled).

  1. /*
  2. * 12-spi_mcp4922.c
  3. *
  4. * Created: 2/22/2026 8:01:15 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define DAC_B 15
  17. #define BUF 14
  18. #define G1X 13
  19. #define ACTIVE 12

  20. void SPI_MasterInit(void)
  21. {
  22. /* Set MOSI and SCK output, all others input */
  23. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  24. /* Enable SPI, Master, set clock rate fck/16 */
  25. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  26. }

  27. void SPI_MasterTransmit(char cData)
  28. {
  29. /* Start transmission */
  30. SPDR = cData;
  31. /* Wait for transmission complete */
  32. while(!(SPSR & (1<<SPIF)))
  33. ;
  34. }

  35. void SPI_SlaveInit(void)
  36. {
  37. /* Set MISO output, all others input */
  38. DDR_SPI = (1<<DD_MISO);
  39. /* Enable SPI */
  40. SPCR = (1<<SPE);
  41. }
  42. char SPI_SlaveReceive(void)
  43. {
  44. /* Wait for reception complete */
  45. while(!(SPSR & (1<<SPIF)))
  46. ;
  47. /* Return Data Register */
  48. return SPDR;
  49. }

  50. int main(void)
  51. {
  52. /* Replace with your application code */
  53. SPI_MasterInit();
  54. unsigned int mcp4922_data,dac_12;
  55. mcp4922_data=(1<<DAC_B)|(1<<BUF)|(1<<ACTIVE);
  56. dac_12=3000;
  57. mcp4922_data|=dac_12&0x0FFF;
  58. PRT_SPI&=~(1<<DD_SS);
  59. SPI_MasterTransmit(mcp4922_data>>8);
  60. SPI_MasterTransmit(mcp4922_data&0x00FF);
  61. PRT_SPI|=(1<<DD_SS);
  62. mcp4922_data=(1<<BUF)|(1<<ACTIVE);
  63. dac_12=2048;
  64. mcp4922_data|=dac_12&0x0FFF;
  65. PRT_SPI&=~(1<<DD_SS);
  66. SPI_MasterTransmit(mcp4922_data>>8);
  67. SPI_MasterTransmit(mcp4922_data&0x00FF);
  68. PRT_SPI|=(1<<DD_SS);
  69. while (1)
  70. {
  71. }
  72. }


Now I added one ADC input to adjust the output DAC values.

ATMega644P SPI and MCP492X 12-bit ADC
Schematic

 

  1. /*
  2. * adc_dac.c
  3. *
  4. * Created: 2/23/2026 9:54:28 PM
  5. * Author : Admin
  6. */

  7. #include <avr/io.h>
  8. #include <util/delay.h>
  9. #define F_CPU 16000000UL

  10. #define DDR_SPI DDRB
  11. #define PRT_SPI PORTB

  12. #define DD_SS 4
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7

  16. #define DAC_B 15
  17. #define BUF 14
  18. #define G1X 13
  19. #define ACTIVE 12

  20. void SPI_MasterInit(void)
  21. {
  22. /* Set MOSI and SCK output, all others input */
  23. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  24. /* Enable SPI, Master, set clock rate fck/16 */
  25. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  26. }

  27. void SPI_MasterTransmit(char cData)
  28. {
  29. /* Start transmission */
  30. SPDR = cData;
  31. /* Wait for transmission complete */
  32. while(!(SPSR & (1<<SPIF)))
  33. ;
  34. }

  35. void SPI_SlaveInit(void)
  36. {
  37. /* Set MISO output, all others input */
  38. DDR_SPI = (1<<DD_MISO);
  39. /* Enable SPI */
  40. SPCR = (1<<SPE);
  41. }
  42. char SPI_SlaveReceive(void)
  43. {
  44. /* Wait for reception complete */
  45. while(!(SPSR & (1<<SPIF)))
  46. ;
  47. /* Return Data Register */
  48. return SPDR;
  49. }

  50. void dac_write(char dac, char gain, unsigned int dac_value){
  51. unsigned int mcp4922_data,dac_12,temp;
  52. if(gain==2) temp=0;
  53. else temp=1;
  54. if((dac=='B')||(dac==2)||(dac=='b')||(dac=='2'))
  55. mcp4922_data=(1<<DAC_B)|(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  56. else if(dac=='A'||(dac==1)|(dac=='a')||(dac=='1'))
  57. mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  58. else
  59. mcp4922_data=(1<<BUF)|(temp<<G1X)|(1<<ACTIVE);
  60. mcp4922_data|=dac_value&0x0FFF;
  61. PRT_SPI&=~(1<<DD_SS);
  62. SPI_MasterTransmit(mcp4922_data>>8);
  63. SPI_MasterTransmit(mcp4922_data&0x00FF);
  64. PRT_SPI|=(1<<DD_SS);
  65. }

  66. int main(void)
  67. {
  68. /* Replace with your application code */
  69. SPI_MasterInit();
  70. DDRB=0xFF;
  71. //PA0 or ADC0 as an analog input
  72. DDRA=0;
  73. //Turn on the ADC module
  74. ADCSRA=(1<<ADEN);
  75. uint16_t temp;
  76. ADMUX=0;
  77. dac_write(1, 2, 0x0FF);
  78. dac_write(2, 1, 0x0FFF);
  79. _delay_ms(5000);
  80. while (1)
  81. {
  82. //Start the conversion
  83. ADCSRA|=(1<<ADSC);
  84. //Wait for the completion
  85. while((ADCSRA&(1<<ADSC))==1);
  86. //Read the result
  87. temp=ADCL+(ADCH<<8);
  88. dac_write('A',2,temp*4);
  89. dac_write('B',2,0x0FFF-(temp*4));
  90. _delay_ms(100);
  91. }
  92. }





 

 

 

 

 

 


 

 

 

Friday, February 20, 2026

ATMega644P SPI Nokia 5510 Graphical LCD

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. 

ATMega644P SPI Nokia 5510 Graphical LCD
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.

PIC16F887 SPI and Nokia 5110 LCD XC8 Example
Nokia 5110 LCD Module

PIC16F887 SPI and Nokia 5110 LCD XC8 Example

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 

ATMega644P SPI Nokia 5510 Graphical LCD
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":

  1. /*
  2. * spi_nokia_5510_3.c
  3. *
  4. * Created: 2/20/2026 11:05:25 AM
  5. * Author : Admin
  6. */

  7. #include <stdio.h>
  8. #include <avr/io.h>
  9. #include <util/delay.h>
  10. #define F_CPU 16000000UL

  11. #define DDR_SPI DDRB
  12. #define PRT_SPI PORTB
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7
  16. #define DD_SS 4
  17. #define DD_DC 3

  18. #include "fonts.h"
  19. #include "graphic_84x48.h"

  20. const unsigned char lcdX = 48;
  21. const unsigned char lcdY = 84;

  22. #define selectCommand() PORTB&=~(1<<DD_DC)
  23. #define selectData() PORTB|=(1<<DD_DC)

  24. void SPI_MasterInit(void)
  25. {
  26. /* Set MOSI and SCK output, all others input */
  27. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  28. /* Enable SPI, Master, set clock rate fck/16 */
  29. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  30. }

  31. void SPI_MasterTransmit(char cData)
  32. {
  33. /* Start transmission */
  34. SPDR = cData;
  35. /* Wait for transmission complete */
  36. while(!(SPSR & (1<<SPIF)))
  37. ;
  38. }

  39. void SPI_SlaveInit(void)
  40. {
  41. /* Set MISO output, all others input */
  42. DDR_SPI = (1<<DD_MISO);
  43. /* Enable SPI */
  44. SPCR = (1<<SPE);
  45. }

  46. char SPI_SlaveReceive(void)
  47. {
  48. /* Wait for reception complete */
  49. while(!(SPSR & (1<<SPIF)))
  50. ;
  51. /* Return Data Register */
  52. return SPDR;
  53. }

  54. // Nokia 5510 LCD Command

  55. void masterTransmit(char spiData){
  56. PRT_SPI&=~(1<<DD_SS);
  57. SPI_MasterTransmit(spiData);
  58. PRT_SPI|=(1<<DD_SS);
  59. }

  60. void nokia5510Command(char cmd){
  61. selectCommand();
  62. masterTransmit(cmd);
  63. }

  64. void nokia5510Data(char data){
  65. selectData();
  66. masterTransmit(data);
  67. }

  68. void nokia5510Char(char _char){
  69. selectData();
  70. for(char i=0;i<5;i++) {
  71. masterTransmit(ASCII[_char-0x20][i]);
  72. }
  73. masterTransmit(0x00);
  74. selectData();
  75. }

  76. void writeText(char *txt){
  77. while(*txt) nokia5510Char(*txt++);
  78. }

  79. /*Set the cursor*/
  80. void setXy(char x,char y){
  81. selectCommand();
  82. /*x ranges from 0 to 83*/
  83. masterTransmit(0x80+(6*x));
  84. /*y ranges from 0 to 5*/
  85. masterTransmit(0x40+y);
  86. selectCommand();
  87. }

  88. void lcdClear(void){
  89. for (int i=0;i<lcdX*lcdY/8;i++)
  90. {
  91. selectData();
  92. masterTransmit(0x00);
  93. }
  94. selectData();
  95. }

  96. void nokia5510Init(void){
  97. SPI_MasterInit();
  98. DDR_SPI|=(1<<DD_DC);
  99. nokia5510Command(0x21); // LCD Extended Commands
  100. nokia5510Command(0xB5); // SET LCD CONTRAST
  101. nokia5510Command(0x04); // set temp coefficient 0x04
  102. nokia5510Command(0x14); // LCD bias
  103. nokia5510Command(0x20);
  104. nokia5510Command(0x0C); // LCD normal Mode
  105. }

  106. int main(void)
  107. {
  108. /* Replace with your application code */
  109. unsigned long secontCnt=0;
  110. char cntString[]="";
  111. nokia5510Init();
  112. lcdClear();
  113. setXy(0,1);
  114. writeText("ATMega644P SPI");
  115. setXy(0,2);
  116. writeText("NOKIA 5510 LCD");
  117. setXy(0,3);
  118. writeText("Microchip");
  119. setXy(0,4);
  120. writeText("Studio IDE");
  121. _delay_ms(10000);
  122. lcdClear();
  123. setXy(0,0);
  124. for(uint16_t i=0;i<sizeof(graphic_84x48);i++)
  125. nokia5510Data(graphic_84x48[i]);
  126. _delay_ms(10000);
  127. lcdClear();
  128. setXy(0,0);
  129. writeText("Started Time:");
  130. while (1)
  131. {
  132. sprintf(cntString,"%u",secontCnt);
  133. setXy(1,2);
  134. writeText(cntString);
  135. for(char i=0;i<14;i++) writeText(" ");
  136. setXy(1,3);
  137. writeText("Seconds");
  138. secontCnt++;
  139. if(secontCnt>=102) secontCnt=0;
  140. _delay_ms(1000);
  141. }
  142. }


Click here to download this example. 

ATMega644P SPI Nokia 5510 Graphical LCD
Tested with ATMega644P

 

ATMega644P SPI Nokia 5510 Graphical LCD
Tested with ATMega644P

 

ATMega644P SPI Nokia 5510 Graphical LCD
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.

ATMega644P SPI Nokia 5510 Graphical LCD
Tahoma Font Extracting

 Then we need to export these data with any programming languages data type.

ATMega644P SPI Nokia 5510 Graphical LCD
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.

ATMega644P SPI Nokia 5510 Graphical LCD
ADC Reading

Don't forget this setting in Microchip Studio IDE to be able to use the floating point data in sprintf() function.

ATMega644P SPI Nokia 5510 Graphical LCD 


ATMega644P SPI Nokia 5510 Graphical LCD

The linking flag is "-lprintf_flt". 

C Source Code "main.c":

  1. /*
  2. * 12-spi_nokia_5510_ADC.c
  3. *
  4. * Created: 2/20/2026 9:51:04 PM
  5. * Author : Admin
  6. */

  7. #include <stdio.h>
  8. #include <avr/io.h>
  9. #include <util/delay.h>
  10. #define F_CPU 16000000UL

  11. #define DDR_SPI DDRB
  12. #define PRT_SPI PORTB
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7
  16. #define DD_SS 4
  17. #define DD_DC 3

  18. #include "fonts.h"
  19. #include "graphic_84x48.h"
  20. #include "tahoma_15x16.h"

  21. const unsigned char lcdX = 48;
  22. const unsigned char lcdY = 84;

  23. #define selectCommand() PORTB&=~(1<<DD_DC)
  24. #define selectData() PORTB|=(1<<DD_DC)

  25. void SPI_MasterInit(void)
  26. {
  27. /* Set MOSI and SCK output, all others input */
  28. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  29. /* Enable SPI, Master, set clock rate fck/16 */
  30. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  31. }

  32. void SPI_MasterTransmit(char cData)
  33. {
  34. /* Start transmission */
  35. SPDR = cData;
  36. /* Wait for transmission complete */
  37. while(!(SPSR & (1<<SPIF)))
  38. ;
  39. }

  40. void SPI_SlaveInit(void)
  41. {
  42. /* Set MISO output, all others input */
  43. DDR_SPI = (1<<DD_MISO);
  44. /* Enable SPI */
  45. SPCR = (1<<SPE);
  46. }

  47. char SPI_SlaveReceive(void)
  48. {
  49. /* Wait for reception complete */
  50. while(!(SPSR & (1<<SPIF)))
  51. ;
  52. /* Return Data Register */
  53. return SPDR;
  54. }

  55. // Nokia 5510 LCD Command

  56. void masterTransmit(char spiData){
  57. PRT_SPI&=~(1<<DD_SS);
  58. SPI_MasterTransmit(spiData);
  59. PRT_SPI|=(1<<DD_SS);
  60. }

  61. void nokia5510Command(char cmd){
  62. selectCommand();
  63. masterTransmit(cmd);
  64. }

  65. void nokia5510Data(char data){
  66. selectData();
  67. masterTransmit(data);
  68. }

  69. void nokia5510Char(char _char){
  70. selectData();
  71. for(char i=0;i<5;i++) {
  72. masterTransmit(ASCII[_char-0x20][i]);
  73. }
  74. masterTransmit(0x00);
  75. selectData();
  76. }

  77. void writeText(char *txt){
  78. while(*txt) nokia5510Char(*txt++);
  79. }

  80. /*Set the cursor*/
  81. void setXy(char x,char y){
  82. selectCommand();
  83. /*x ranges from 0 to 83*/
  84. masterTransmit(0x80+(6*x));
  85. /*y ranges from 0 to 5*/
  86. masterTransmit(0x40+y);
  87. selectCommand();
  88. }

  89. void lcdClear(void){
  90. for (int i=0;i<lcdX*lcdY/8;i++)
  91. {
  92. selectData();
  93. masterTransmit(0x00);
  94. }
  95. selectData();
  96. }

  97. void nokia5510Init(void){
  98. SPI_MasterInit();
  99. DDR_SPI|=(1<<DD_DC);
  100. nokia5510Command(0x21); // LCD Extended Commands
  101. nokia5510Command(0xB5); // SET LCD CONTRAST
  102. nokia5510Command(0x04); // set temp coefficient 0x04
  103. nokia5510Command(0x14); // LCD bias
  104. nokia5510Command(0x20);
  105. nokia5510Command(0x0C); // LCD normal Mode
  106. }

  107. void lcd_xy(int8_t x, int8_t y){
  108. if(x<84) nokia5510Command(0x80+x);
  109. if(y<6) nokia5510Command(0x40+y);
  110. }

  111. void lcd_char_tahoma_15x16(int8_t x, int8_t y, uint8_t ch){
  112. uint16_t c=x*2;
  113. for(uint8_t i=0;i<30;i++){
  114. if(i%2) {lcd_xy(c/2,y+1); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
  115. else {lcd_xy(c/2,y); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
  116. c++;
  117. }
  118. }

  119. void lcd_text_tahoma(int8_t x, int8_t y, uint8_t *text){
  120. //char x_count=0;
  121. while(*text) {
  122. lcd_char_tahoma_15x16(x, y, *text++);
  123. x+=15;
  124. }
  125. }

  126. int main(void)
  127. {
  128. /* Replace with your application code */
  129. nokia5510Init();
  130. lcdClear();
  131. //setXy(0,0);
  132. lcd_text_tahoma(0,0,"Nokia");
  133. lcd_text_tahoma(0,2,"5510");
  134. lcd_text_tahoma(0,4,"GLCD");
  135. DDRB&=~(1<<0);
  136. ADCSRA=(1<<ADEN);
  137. ADMUX=0;
  138. char msg[4];
  139. _delay_ms(10000);
  140. lcdClear();
  141. while (1)
  142. {
  143. //Start the conversion
  144. ADCSRA|=(1<<ADSC);
  145. //Wait for the completion
  146. while((ADCSRA&(1<<ADSC))==1);
  147. //Read the result
  148. unsigned int temp =ADCL+(ADCH<<8);
  149. float voltage = (temp*5.0)/1023;
  150. lcd_text_tahoma(0,0,"ADC0:");
  151. sprintf(msg,"%04d",temp);
  152. lcd_text_tahoma(0,2,msg);
  153. sprintf(msg,"%0.2fV",voltage);
  154. lcd_text_tahoma(0,4,msg);
  155. _delay_ms(100);
  156. }
  157. }





AVR ATMega644P Experiment Board:

ATMega644P SPI Nokia 5510 Graphical LCD
AVR ATMega644P Experiment Board

 

ATMega644P SPI Nokia 5510 Graphical LCD
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. 

ATMega644P SPI Nokia 5510 Graphical LCD
Real Time Clock Reading

 Source Code "main.c":

 

  1. /*
  2. * 12-spi_nokia_5510_RTC.c
  3. *
  4. * Created: 2/21/2026 11:46:38 AM
  5. * Author : Admin
  6. */

  7. #include <stdio.h>
  8. #include <avr/io.h>
  9. #include <util/delay.h>
  10. #define F_CPU 16000000UL

  11. #define DDR_SPI DDRB
  12. #define PRT_SPI PORTB
  13. #define DD_MOSI 5
  14. #define DD_MISO 6
  15. #define DD_SCK 7
  16. #define DD_SS 4
  17. #define DD_DC 3

  18. #include "fonts.h"
  19. #include "graphic_84x48.h"
  20. #include "tahoma_15x16.h"
  21. #include "twi_device.h"

  22. const unsigned char lcdX = 48;
  23. const unsigned char lcdY = 84;

  24. #define selectCommand() PORTB&=~(1<<DD_DC)
  25. #define selectData() PORTB|=(1<<DD_DC)

  26. void SPI_MasterInit(void)
  27. {
  28. /* Set MOSI and SCK output, all others input */
  29. DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
  30. /* Enable SPI, Master, set clock rate fck/16 */
  31. SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
  32. }

  33. void SPI_MasterTransmit(char cData)
  34. {
  35. /* Start transmission */
  36. SPDR = cData;
  37. /* Wait for transmission complete */
  38. while(!(SPSR & (1<<SPIF)))
  39. ;
  40. }

  41. void SPI_SlaveInit(void)
  42. {
  43. /* Set MISO output, all others input */
  44. DDR_SPI = (1<<DD_MISO);
  45. /* Enable SPI */
  46. SPCR = (1<<SPE);
  47. }

  48. char SPI_SlaveReceive(void)
  49. {
  50. /* Wait for reception complete */
  51. while(!(SPSR & (1<<SPIF)))
  52. ;
  53. /* Return Data Register */
  54. return SPDR;
  55. }

  56. // Nokia 5510 LCD Command

  57. void masterTransmit(char spiData){
  58. PRT_SPI&=~(1<<DD_SS);
  59. SPI_MasterTransmit(spiData);
  60. PRT_SPI|=(1<<DD_SS);
  61. }

  62. void nokia5510Command(char cmd){
  63. selectCommand();
  64. masterTransmit(cmd);
  65. }

  66. void nokia5510Data(char data){
  67. selectData();
  68. masterTransmit(data);
  69. }

  70. void nokia5510Char(char _char){
  71. selectData();
  72. for(char i=0;i<5;i++) {
  73. masterTransmit(ASCII[_char-0x20][i]);
  74. }
  75. masterTransmit(0x00);
  76. selectData();
  77. }

  78. void writeText(char *txt){
  79. while(*txt) nokia5510Char(*txt++);
  80. }

  81. /*Set the cursor*/
  82. void setXy(char x,char y){
  83. selectCommand();
  84. /*x ranges from 0 to 83*/
  85. masterTransmit(0x80+(6*x));
  86. /*y ranges from 0 to 5*/
  87. masterTransmit(0x40+y);
  88. selectCommand();
  89. }

  90. void lcdClear(void){
  91. for (int i=0;i<lcdX*lcdY/8;i++)
  92. {
  93. selectData();
  94. masterTransmit(0x00);
  95. }
  96. selectData();
  97. }

  98. void nokia5510Init(void){
  99. SPI_MasterInit();
  100. DDR_SPI|=(1<<DD_DC);
  101. nokia5510Command(0x21); // LCD Extended Commands
  102. nokia5510Command(0xB5); // SET LCD CONTRAST
  103. nokia5510Command(0x04); // set temp coefficient 0x04
  104. nokia5510Command(0x14); // LCD bias
  105. nokia5510Command(0x20);
  106. nokia5510Command(0x0C); // LCD normal Mode
  107. }

  108. void lcd_xy(int8_t x, int8_t y){
  109. if(x<84) nokia5510Command(0x80+x);
  110. if(y<6) nokia5510Command(0x40+y);
  111. }

  112. void lcd_char_tahoma_15x16(int8_t x, int8_t y, uint8_t ch){
  113. uint16_t c=x*2;
  114. for(uint8_t i=0;i<30;i++){
  115. if(i%2) {lcd_xy(c/2,y+1); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
  116. else {lcd_xy(c/2,y); nokia5510Data(Tahoma15x16[ch-0x20][i]);}
  117. c++;
  118. }
  119. }

  120. void lcd_text_tahoma(int8_t x, int8_t y, uint8_t *text){
  121. //char x_count=0;
  122. while(*text) {
  123. lcd_char_tahoma_15x16(x, y, *text++);
  124. x+=15;
  125. }
  126. }

  127. void rtc_init(void){
  128. char rtc[8]={0x30,0x35,0x13,0x07,0x31,0x01,0x26,1<<4};
  129. for (char i=0;i<8;i++)
  130. {
  131. twi_start();
  132. //D0 is DS1307 Write Address
  133. twi_write(DS1307_W);
  134. //Select Control Register
  135. twi_write(i);
  136. //Enable SQWE bit blinks at 1 Hz
  137. twi_write(rtc[i]);
  138. twi_stop();
  139. _delay_ms(10);
  140. }
  141. }

  142. unsigned char rtc[50], msg[20];

  143. void rtc_read(void){
  144. for(char i=0;i<50;i++){
  145. /*Second Register*/
  146. twi_start();
  147. twi_write(DS1307_W);
  148. /*Select Second register*/
  149. twi_write(i);
  150. twi_stop();
  151. _delay_us(100);
  152. twi_start();
  153. twi_write(DS1307_R);
  154. rtc[i]=twi_read();
  155. twi_stop();
  156. _delay_us(100);
  157. }
  158. }

  159. int main(void)
  160. {
  161. /* Replace with your application code */
  162. nokia5510Init();
  163. lcdClear();
  164. setXy(0,0);
  165. writeText("ATMega644P SPI");
  166. setXy(0,1);
  167. writeText("NOKIA 5510 LCD");
  168. setXy(0,2);
  169. writeText("DS1307 RTC");
  170. setXy(0,3);
  171. writeText("Software TWI");
  172. _delay_ms(10000);
  173. lcdClear();
  174. char msg[4];
  175. //rtc_init();
  176. while (1)
  177. {
  178. rtc_read();
  179. setXy(0,0); writeText("DS1307 Real");
  180. setXy(0,1); writeText("Time Clock:");
  181. setXy(0,2); writeText("Time:");
  182. sprintf(msg,"%02X:%02X:%02X",rtc[2],rtc[1],rtc[0]);
  183. setXy(0,3); writeText(msg);
  184. setXy(0,4); writeText("Date:");
  185. sprintf(msg,"%02X/%02X/20%02X",rtc[4],rtc[5],rtc[6]);
  186. setXy(0,5); writeText(msg);
  187. _delay_ms(100);
  188. }
  189. }







ATMega644P AVR  Prototype Board: 

ATMega644P SPI Nokia 5510 Graphical LCD
ATMega644P AVR  Prototype Board

 

ATMega644P SPI Nokia 5510 Graphical LCD
ATMega644P AVR  Prototype Board

 

Click here to download this example

 

320x50

Search This Blog

tyro-728x90