#include "pcd8544.h" #include "hardware/gpio.h" #include "hardware/spi.h" #include "pico/time.h" #include #define PIN_CE 17 #define PIN_SCK 18 #define PIN_MOSI 19 #define PIN_DC 20 #define PIN_RST 21 #define LCD_SPI spi0 #define LCD_HZ 4000000 static uint8_t fb[LCD_W * LCD_H / 8]; /* PCD8544 layout: 6 banks of 8 rows, LSB at the top */ static void write(int data, const uint8_t *b, size_t n){ gpio_put(PIN_DC, data); gpio_put(PIN_CE, 0); spi_write_blocking(LCD_SPI, b, n); /* returns once the bytes are shifted out */ gpio_put(PIN_CE, 1); } static void cmd(uint8_t c){ write(0, &c, 1); } void lcd_set_vop(int vop){ cmd(0x21); /* extended instruction set */ cmd((uint8_t)(0x80 | (vop & 0x7F))); cmd(0x20); } void lcd_init(int vop){ spi_init(LCD_SPI, LCD_HZ); spi_set_format(LCD_SPI, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST); gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI); gpio_init(PIN_CE); gpio_set_dir(PIN_CE, GPIO_OUT); gpio_put(PIN_CE, 1); gpio_init(PIN_DC); gpio_set_dir(PIN_DC, GPIO_OUT); gpio_put(PIN_DC, 0); gpio_init(PIN_RST); gpio_set_dir(PIN_RST, GPIO_OUT); gpio_put(PIN_RST, 0); sleep_ms(10); gpio_put(PIN_RST, 1); sleep_ms(10); cmd(0x21); /* extended */ cmd((uint8_t)(0x80 | (vop & 0x7F)));/* Vop */ cmd(0x04); /* temperature coefficient 0 */ cmd(0x13); /* bias 1:48 */ cmd(0x20); /* basic, horizontal addressing */ cmd(0x0C); /* normal display */ lcd_clear(); lcd_flush(); } void lcd_clear(void){ memset(fb, 0, sizeof fb); } void lcd_px(int x, int y, int on){ if(x < 0 || x >= LCD_W || y < 0 || y >= LCD_H) return; if(on) fb[(y >> 3) * LCD_W + x] |= (uint8_t)(1u << (y & 7)); else fb[(y >> 3) * LCD_W + x] &= (uint8_t)~(1u << (y & 7)); } void lcd_fill(int x, int y, int w, int h, int on){ int i, j; for(j = y; j < y + h; j++) for(i = x; i < x + w; i++) lcd_px(i, j, on); } /* The 5 × 7 font from sim/app.js (FONT): five column bytes per glyph, bit 0 at the top. */ typedef struct { char c; uint8_t col[5]; } glyph_t; static const glyph_t FONT[] = { {' ',{0,0,0,0,0}},{'+',{8,8,62,8,8}},{'-',{8,8,8,8,8}},{'.',{0,96,96,0,0}},{'/',{32,16,8,4,2}},{':',{0,54,54,0,0}}, {'#',{20,127,20,127,20}},{'*',{20,8,62,8,20}},{'>',{0,65,34,20,8}},{'?',{2,1,81,9,6}},{'!',{0,0,95,0,0}}, {'0',{62,81,73,69,62}},{'1',{0,66,127,64,0}},{'2',{66,97,81,73,70}},{'3',{33,65,69,75,49}},{'4',{24,20,18,127,16}}, {'5',{39,69,69,69,57}},{'6',{60,74,73,73,48}},{'7',{1,113,9,5,3}},{'8',{54,73,73,73,54}},{'9',{6,73,73,41,30}}, {'A',{126,17,17,17,126}},{'B',{127,73,73,73,54}},{'C',{62,65,65,65,34}},{'D',{127,65,65,34,28}},{'E',{127,73,73,73,65}}, {'F',{127,9,9,9,1}},{'G',{62,65,73,73,122}},{'H',{127,8,8,8,127}},{'I',{0,65,127,65,0}},{'J',{32,64,65,63,1}}, {'K',{127,8,20,34,65}},{'L',{127,64,64,64,64}},{'M',{127,2,12,2,127}},{'N',{127,4,8,16,127}},{'O',{62,65,65,65,62}}, {'P',{127,9,9,9,6}},{'Q',{62,65,81,33,94}},{'R',{127,9,25,41,70}},{'S',{70,73,73,73,49}},{'T',{1,1,127,1,1}}, {'U',{63,64,64,64,63}},{'V',{31,32,64,32,31}},{'W',{63,64,56,64,63}},{'X',{99,20,8,20,99}},{'Y',{7,8,112,8,7}}, {'Z',{97,81,73,69,67}} }; static const glyph_t *glyph(char c){ size_t i; if(c >= 'a' && c <= 'z') c = (char)(c - 32); for(i = 0; i < sizeof FONT / sizeof FONT[0]; i++) if(FONT[i].c == c) return &FONT[i]; return glyph('?'); } void lcd_text_v(int x, int y, const char *s, int on){ for(; *s; s++, x += 6){ const glyph_t *g = glyph(*s); int col, row; for(col = 0; col < 5; col++) for(row = 0; row < 7; row++) if((g->col[col] >> row) & 1) lcd_px(x + col, y + row, on); } } void lcd_text(int x, int y, const char *s){ lcd_text_v(x, y, s, 1); } void lcd_box(int x, int y, int w, int h){ lcd_fill(x, y, w, 1, 1); lcd_fill(x, y + h - 1, w, 1, 1); lcd_fill(x, y, 1, h, 1); lcd_fill(x + w - 1, y, 1, h, 1); } void lcd_flush(void){ cmd(0x80); cmd(0x40); /* X = 0, Y = 0 */ write(1, fb, sizeof fb); }