/* * lcd.c * * Created: Jan 2022 * Author: Arjan te Marvelde * * Driver for SSD1327 based 128x128 display. * * It is an output-only MMI, so only write is supported * * The interface functions are: * lcd_putc(int x, int y, uint8_t c, uint8_t *font); * lcd_puts(int x, int y, char *buf, uint8_t *font); * lcd_putg(int x, int y, uint8_t *bitmap); * lcd_clrscr(void); * lcd_init(void); * The parameters (x, y) determine upper left corner of object item, should be even numbers. * The font or bitmap object itself contains other parameters like (w, h) and the item data content. * (w, h) also should be even numbers. * * A font or bitmap object definition starts with: * - uint8_t item field width * - uint8_t item field height * - uint8_t first item number (e.g. character code) * - uint8_t last item number * followed by the item data, a nibble per pixel. * * Use of graphics functions requires a bitmap, where the same format as for fonts is used but there is only one character. * A predefined bitmap is for example the Udjat logo, but user defined bitmap can also be dumped on display. * For filling the bitmap dynamically, several graphics functions are provided: * * I2C write sequence: * control byte + following bytes * control byte = 0bxy000000, where * x: single (1) or multiple (0) * y: data(1) or control(0) * * Display is 128 columns wide by 128 rows high. Each (col, row) is a grey value nibble [1-15]. * The nibbles are organized in display RAM as follows: * +-----+-----+-----+-----+-----+-----+ ~ +-----+-----+ * |L 0 H 0|L 1 H 1|L 2 H 2| |L 63 H 63| * +-----+-----+-----+-----+-----+-----+ ~ +-----+-----+ * |L 64 H 64|L 65 H 65|L 66 H 66| |L 127 H 127| * +-----+-----+-----+-----+-----+-----+ ~ +-----+-----+ * / / / / / / / / / / * \ \ \ \ \ \ \ \ \ \ * +-----+-----+-----+-----+-----+-----+ ~ +-----+-----+ * |L8128 H8128|L8129 H8129|L8130 H8130| |L8191 H8191| * +-----+-----+-----+-----+-----+-----+ ~ +-----+-----+ * * * For writing Display RAM, first the conditions and start location are set (commands) then followed by a data burst. * */ #include #include #include "pico/stdlib.h" #include "hardware/i2c.h" #include "lcd.h" // Command definition D Function (reset values) // SSD1327 # // ---------------------------------------------------------------------------------------------------------------------------- #define LCD_WINCOLADDR 0x15 // 2 Sets first and last column for window (0x00, 0x3F). #define LCD_WINROWADDR 0x75 // 2 Sets first and last row for window (0x00, 0x7F). #define LCD_SCR_RIGHT 0x26 // 7 Setup right-scrolling part of display (see below) #define LCD_SCR_LEFT 0x27 // 7 Setup left-scrolling part of display #define LCD_SCR_STOP 0x2e // 0 Stop scrolling window #define LCD_SCR_START 0x2f // 0 Start scrolling window #define LCD_CONTRAST 0x81 // 1 Sets Contrast of the display (0x7F). #define LCD_REMAP 0xa0 // 1 Enables/Disables address remapping (0x00). #define LCD_DSTARTLINE 0xa1 // 1 Sets display start line (0x00). #define LCD_DOFFSET 0xa2 // 1 Sets display vertical offset (0x00). #define LCD_MODENORM 0xa4 // 0 Display in normal mode #define LCD_MODEWHITE 0xa5 // 0 Display all pixels white, greyscale=15 #define LCD_MODEBLACK 0xa6 // 0 Display all pixels black, greyscale=0 #define LCD_MODEINVERS 0xa7 // 0 Display all pixels inverted, greyscale=15-val #define LCD_MUXRATIO 0xa8 // 1 Set ratio to X+1, X>14, (0x7f) #define LCD_FASELECT 0xab // 0 Select internal Vdd regulator when 1, external when 0 (0x01) #define LCD_INACTIVE 0xae // 0 Switches display to sleep mode #define LCD_ACTIVE 0xaf // 0 Switches display on, normal mode #define LCD_PHASELEN 0xb1 // 1 High nibble phase2, low nibbel phase1 (0x74) #define LCD_NOP1 0xb2 // 0 No operation #define LCD_OSC_D_F 0xb3 // 1 Set oscillator divider (0x00) #define LCD_GPIO 0xb5 // 1 (0x02) #define LCD_PCPER2 0xb6 // 1 (0x04) #define LCD_GS_TABLE 0xb8 // 15 Pulse width for GS levels 1..15, all unequal and value rising #define LCD_GS_LINEAR 0xb9 // 0 Sets linear GS table (default) #define LCD_NOP2 0xbb // 0 No operation #define LCD_PCLEVEL 0xbc // 1 (0x05) #define LCD_CDLEVEL 0xbe // 1 (0x05) #define LCD_FBSELECT 0xd5 // 1 (0x00) #define LCD_CMDLOCK 0xfd // 1 Lock OLED command interface (0x16) or unlock (0x12) #define I2C_SSD1327 0x3c // I2C address (0x3C) #define LCD_CTRLCMD 0x00 // Control byte for burst commands #define LCD_CTRLDATA 0x40 // Control byte for burst data #define LCD_CTRLSINGLE 0x80 // OR in case of single command/data #define LCD_CTRLMULTI 0x00 // OR in case of multibyte command/data #define LCD_DELAY 1000 // Screen refresh time #define LCD_WIDTH 0x80 // Pixels #define LCD_HEIGHT 0x80 // Pixels uint8_t txdata[1+LCD_WIDTH]; // Maximum transfer size, one line of data /* * Set display active area (cursor) to (x,y) left upper corner and (width x height) size */ void lcd_cursor(uint8_t x, uint8_t y, uint8_t w, uint8_t h) { txdata[0] = LCD_CTRLCMD | LCD_CTRLMULTI; // Multiple command byte txdata[1] = LCD_WINCOLADDR; // Set window columns txdata[2] = (x/2)&0x3f; // left txdata[3] = (((x+w)/2)-1)&0x3f; // right txdata[4] = LCD_WINROWADDR; // Set window rows txdata[5] = (y)&0x7f; // top txdata[6] = (y+h-1)&0x7f; // bottom i2c_write_blocking(i2c0, I2C_SSD1327, txdata, 7, false); // Send commands } /* * Clear the display */ void lcd_clrscr(uint8_t x, uint8_t y, uint8_t w, uint8_t h) { int i; lcd_cursor(x,y,w,h); // Set window txdata[0] = LCD_CTRLDATA | LCD_CTRLMULTI; memset(&txdata[1], 0x00, w/2); // Black line for (i=0; i=font[2]) && (c<=font[3]))) // Range check character code c=0; // Not good: default on first else c-=font[2]; // Good: shift down value w=font[0]; h=font[1]; // Retrieve character width and height if (((x+w)>LCD_WIDTH)||((y+h)>LCD_HEIGHT)) return; // Out of range! lcd_cursor(x,y,w,h); // Define window txdata[0] = LCD_CTRLDATA | LCD_CTRLMULTI ; // Multiple data byte xorbyte = (invert?0xff:0x00); // Optionally set inversion srce = &font[4 + (int)c*w*h/2]; // Initialize pointers dest = &txdata[1]; for (i=0; iLCD_WIDTH)||((y+h)>LCD_HEIGHT)) return; // Out of range! lcd_cursor(x,y,w,h); // Define window for writing if (invert) xorbyte = 0xff; // Optionally set inversion txdata[0] = LCD_CTRLDATA | LCD_CTRLMULTI ; // Multiple data byte for (i=0; i