Driving 4 NOKIA 3310 LCD ( PCD8544) c example
-
Hi,
Final project will show a couple of temperature/humidity on each screen.
( I have 4 little ESP8266 with DHT12 and an Openhab server ).
First attempt with python and SPI ( hard and bitbanging ) is not working, I do not know why....
Second attempt with python and direct gpio access were working but very very very slow !
Final attempt coding in C and direct memory access for gpio works but it takes me times to search and find all these informations. ( example is working for gpio number < 32, other gpio have another base address ).So I think this example can perhaps be helpful for someone and can save some times !
#include <stdio.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #define GPIO_ADDR 0x10000000 // base address #define GPIO_BLOCK 0x6AC // memory block size #define RST 19 #define CE1 16 #define CE2 5 #define CE3 4 #define CE4 15 #define DC 2 #define DIN 3 #define CLK 18 unsigned int ASCII[][5] = { {0x00, 0x00, 0x00, 0x00, 0x00} // 0 ,{0x00, 0x00, 0x5f, 0x00, 0x00} // 1 ! ,{0x00, 0x07, 0x00, 0x07, 0x00} // 2 " ,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 3 # ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 4 $ ,{0x23, 0x13, 0x08, 0x64, 0x62} // 5 % ,{0x36, 0x49, 0x55, 0x22, 0x50} // 6 & ,{0x00, 0x05, 0x03, 0x00, 0x00} // 7 ' ,{0x00, 0x1c, 0x22, 0x41, 0x00} // 8 ( ,{0x00, 0x41, 0x22, 0x1c, 0x00} // 9 ) ,{0x14, 0x08, 0x3e, 0x08, 0x14} // 10 * ,{0x08, 0x08, 0x3e, 0x08, 0x08} // 11 + ,{0x00, 0x50, 0x30, 0x00, 0x00} // 12 , ,{0x08, 0x08, 0x08, 0x08, 0x08} // 13 - ,{0x00, 0x60, 0x60, 0x00, 0x00} // 14 . ,{0x20, 0x10, 0x08, 0x04, 0x02} // 15 / ,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 16 0 ,{0x00, 0x42, 0x7f, 0x40, 0x00} // 17 1 ,{0x42, 0x61, 0x51, 0x49, 0x46} // 18 2 ,{0x21, 0x41, 0x45, 0x4b, 0x31} // 19 3 ,{0x18, 0x14, 0x12, 0x7f, 0x10} // 20 4 ,{0x27, 0x45, 0x45, 0x45, 0x39} // 21 5 ,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 22 6 ,{0x01, 0x71, 0x09, 0x05, 0x03} // 23 7 ,{0x36, 0x49, 0x49, 0x49, 0x36} // 24 8 ,{0x06, 0x49, 0x49, 0x29, 0x1e} // 25 9 ,{0x00, 0x36, 0x36, 0x00, 0x00} // 26 : ,{0x00, 0x56, 0x36, 0x00, 0x00} // 27 ; ,{0x08, 0x14, 0x22, 0x41, 0x00} // 28 < ,{0x14, 0x14, 0x14, 0x14, 0x14} // 29 = ,{0x00, 0x41, 0x22, 0x14, 0x08} // 30 > ,{0x02, 0x01, 0x51, 0x09, 0x06} // 31 ? ,{0x32, 0x49, 0x79, 0x41, 0x3e} // 32 @ ,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 33 A ,{0x7f, 0x49, 0x49, 0x49, 0x36} // 34 B ,{0x3e, 0x41, 0x41, 0x41, 0x22} // 35 C ,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 36 D ,{0x7f, 0x49, 0x49, 0x49, 0x41} // 37 E ,{0x7f, 0x09, 0x09, 0x09, 0x01} // 38 F ,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 39 G ,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 40 H ,{0x00, 0x41, 0x7f, 0x41, 0x00} // 41 I ,{0x20, 0x40, 0x41, 0x3f, 0x01} // 42 J ,{0x7f, 0x08, 0x14, 0x22, 0x41} // 43 K ,{0x7f, 0x40, 0x40, 0x40, 0x40} // 44 L ,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 45 M ,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 46 N ,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 47 O ,{0x7f, 0x09, 0x09, 0x09, 0x06} // 48 P ,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 49 Q ,{0x7f, 0x09, 0x19, 0x29, 0x46} // 50 R ,{0x46, 0x49, 0x49, 0x49, 0x31} // 51 S ,{0x01, 0x01, 0x7f, 0x01, 0x01} // 52 T ,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 53 U ,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 54 V ,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 55 W ,{0x63, 0x14, 0x08, 0x14, 0x63} // 56 X ,{0x07, 0x08, 0x70, 0x08, 0x07} // 57 Y ,{0x61, 0x51, 0x49, 0x45, 0x43} // 58 Z ,{0x00, 0x7f, 0x41, 0x41, 0x00} // 59 [ ,{0x02, 0x04, 0x08, 0x10, 0x20} // 60 ¥ ,{0x00, 0x41, 0x41, 0x7f, 0x00} // 61 ] ,{0x04, 0x02, 0x01, 0x02, 0x04} // 62 ^ ,{0x40, 0x40, 0x40, 0x40, 0x40} // 63 _ ,{0x00, 0x01, 0x02, 0x04, 0x00} // 64 ` ,{0x20, 0x54, 0x54, 0x54, 0x78} // 65 a ,{0x7f, 0x48, 0x44, 0x44, 0x38} // 66 b ,{0x38, 0x44, 0x44, 0x44, 0x20} // 67 c ,{0x38, 0x44, 0x44, 0x48, 0x7f} // 68 d ,{0x38, 0x54, 0x54, 0x54, 0x18} // 69 e ,{0x08, 0x7e, 0x09, 0x01, 0x02} // 70 f ,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 71 g ,{0x7f, 0x08, 0x04, 0x04, 0x78} // 72 h ,{0x00, 0x44, 0x7d, 0x40, 0x00} // 73 i ,{0x20, 0x40, 0x44, 0x3d, 0x00} // 74 j ,{0x7f, 0x10, 0x28, 0x44, 0x00} // 75 k ,{0x00, 0x41, 0x7f, 0x40, 0x00} // 76 l ,{0x7c, 0x04, 0x18, 0x04, 0x78} // 77 m ,{0x7c, 0x08, 0x04, 0x04, 0x78} // 78 n ,{0x38, 0x44, 0x44, 0x44, 0x38} // 79 o ,{0x7c, 0x14, 0x14, 0x14, 0x08} // 80 p ,{0x08, 0x14, 0x14, 0x18, 0x7c} // 81 q ,{0x7c, 0x08, 0x04, 0x04, 0x08} // 82 r ,{0x48, 0x54, 0x54, 0x54, 0x20} // 83 s ,{0x04, 0x3f, 0x44, 0x40, 0x20} // 84 t ,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 85 u ,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 86 v ,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 87 w ,{0x44, 0x28, 0x10, 0x28, 0x44} // 88 x ,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 89 y ,{0x44, 0x64, 0x54, 0x4c, 0x44} // 90 z ,{0x00, 0x08, 0x36, 0x41, 0x00} // 91 { ,{0x00, 0x00, 0x7f, 0x00, 0x00} // 92 | ,{0x00, 0x41, 0x36, 0x08, 0x00} // 93 } ,{0x10, 0x08, 0x08, 0x10, 0x08} // 94 ← ,{0x00, 0x06, 0x09, 0x09, 0x06} // 95 → ,{0x55, 0xaa, 0x55, 0xaa, 0x55} // 96 rectangle a moitié rempli ,{0xff, 0xff, 0xe7, 0xff, 0xff} // 97 rectangle rempli ,{0xff, 0x01, 0xfd, 0x05, 0x05} // 98 coin haut gauche double ,{0x05, 0x05, 0xfd, 0x01, 0xff} // 99 coin haut droit double ,{0xff, 0x80, 0xbf, 0xa0, 0xa0} // 100 coin bas gauche double ,{0xa0, 0xa0, 0xbf, 0x80, 0xff} // 101 coin bas droit double ,{0x05, 0x05, 0x05, 0x05, 0x05} // 102 ligne haut horizontal double ,{0xa0, 0xa0, 0xa0, 0xa0, 0xa0} // 103 ligne bas horizontal double ,{0xff, 0x00, 0xff, 0x00, 0x00} // 104 ligne gauche vertical double ,{0x00, 0x00, 0xff, 0x00, 0xff} // 105 ligne droit vertical double ,{0x7e, 0xdb, 0xdf, 0xdb, 0x7e} // 106 smiley plein ,{0x66, 0xef, 0xfb, 0x7e, 0x34} // 107 piaf ,{0x00, 0x18, 0x3c, 0x18, 0x00} // 108 piece plein ,{0x00, 0x18, 0x24, 0x18, 0x00} // 109 piece vide ,{0x18, 0x24, 0x48, 0x24, 0x18} // 110 coeur vide ,{0x18, 0x3c, 0x78, 0x3c, 0x18} // 111 coeur plein ,{0x80, 0x00, 0x00, 0x00, 0x00} // 112 pixel haut gauche }; volatile unsigned long *gpioAddress; volatile unsigned char CE[4]={CE1,CE2,CE3,CE4}; int gpioSetup() { int m_mfd; if ((m_mfd = open("/dev/mem", O_RDWR)) < 0) { return -1; } gpioAddress = (unsigned long*)mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, m_mfd, GPIO_ADDR); close(m_mfd); if (gpioAddress == MAP_FAILED) { return -2; } return 0; } void gpioDirection(int gpio, int direction) { unsigned long value = *(gpioAddress + 384 + 0); // obtain current settings if (direction == 1) { value |= (1 << gpio); // set bit to 1 } else { value &= ~(1 << gpio); // clear bit } *(gpioAddress + 384 + 0) = value; } void gpioSet(int gpio, int value) { if (value == 0) { *(gpioAddress + 400 ) = (1 << gpio); } else { *(gpioAddress + 396 ) = (1 << gpio); } } int gpioRead(int gpio) { unsigned long value = *(gpioAddress + 392); return (value & (1 << gpio)); } void spi(unsigned char screen,unsigned char c) { gpioSet(CE1,1); gpioSet(CE2,1); gpioSet(CE3,1); gpioSet(CE4,1); gpioSet(CE[screen],0); for (int i=0;i<8;i++) { gpioSet(DIN,(c & (1<< (7-i)))>0); /*if ((c & (1 << (7-i))) > 0) gpioSet(DIN,1); else gpioSet(DIN,0);*/ gpioSet(CLK,0); gpioSet(CLK,1); } } void lcd_cmd(unsigned char screen,unsigned char c) { gpioSet(DC,0); spi(screen,c); } void lcd_data(unsigned char screen,unsigned char c) { gpioSet(DC,1); spi(screen,c); } void gotoXY(unsigned char screen,int x, int y) { lcd_cmd(screen,0x80|x); lcd_cmd(screen,0x40|y); } void lcd_character(unsigned char screen,unsigned char c) { lcd_data(screen,0x00); for (int i=0;i<5;i++) { lcd_data(screen,ASCII[c-0x20][i]); } lcd_data(screen,0x00); } void init_lcd(unsigned char screen) { lcd_cmd(screen,0x21); // extended mode //lcd_cmd(screen,0xB4); // contrast if (screen==3) lcd_cmd(screen,0xBA); // contrast if (screen==2) lcd_cmd(screen,0xB0); // contrast if (screen==1) lcd_cmd(screen,0xB4); // contrast if (screen==0) lcd_cmd(screen,0xB4); // contrast lcd_cmd(screen,0x05); // start position lcd_cmd(screen,0x40); // start position lcd_cmd(screen,0x14); // bias mode lcd_cmd(screen,0x20); // clear lcd_cmd(screen,0x0C); // normal mode } void lcd_clear(unsigned char screen) { lcd_cmd(screen,0x24); gotoXY(screen,0,0); for (int i=0;i<504;i++) lcd_data(screen,0x00); lcd_cmd(screen,0x20); } void setup() { gpioDirection(RST,1); gpioDirection(DC,1); gpioDirection(CE1,1); gpioDirection(CE2,1); gpioDirection(CE3,1); gpioDirection(CE4,1); gpioDirection(DIN,1); gpioDirection(CLK,1); } int main() { system("omega2-ctrl gpiomux set i2c gpio"); system("omega2-ctrl gpiomux set uart1 gpio"); printf("Hello World!\n"); printf("We're running a C program on the Omega2!\n"); printf("gpiosetup :%d \n",gpioSetup()); setup(); gpioSet(RST,0); usleep(1000); gpioSet(RST,1); init_lcd(0); init_lcd(1); init_lcd(2); init_lcd(3); lcd_clear(0); lcd_clear(1); lcd_clear(2); lcd_clear(3); for (int i=0;i<60;i++) { lcd_character(0,0x20+i); lcd_character(1,0x21+i); lcd_character(2,0x22+i); lcd_character(3,0x23+i); } return 0; }