1 /* 2 * Ben NanoNote communication with the Nu Electronics "Color LCD & 3 * Joystick Shield" featuring a Nokia 6110 and the PCF8833 display 4 * controller. 5 * 6 * http://shieldlist.org/nuelectronics/colorlcd-joystick 7 * 8 * Copyright (C) 2013 Paul Boddie 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 */ 15 16 #include "pcf8833.h" 17 #include <stdio.h> 18 #include <unistd.h> 19 20 void LCD_send(lcd_sendmode mode, uint8_t data) 21 { 22 spi_begin(); 23 spi_send(data, mode); 24 spi_end(); 25 } 26 27 void LCD_send_more_data(uint8_t data) 28 { 29 spi_begin(); 30 spi_send(data, LCD_DATA); 31 spi_end(); 32 } 33 34 void spi_init() 35 { 36 OUT(LCD_CS); 37 OUT(LCD_RESET); 38 OUT(LCD_CLK); 39 OUT(LCD_SEND); 40 OUT(LCD_BACKLIGHT); 41 42 CLR(LCD_RESET); 43 CLR(LCD_BACKLIGHT); 44 } 45 46 void spi_begin() 47 { 48 CLR(LCD_CS); 49 } 50 51 void spi_end() 52 { 53 SET(LCD_CS); 54 } 55 56 /** 57 * Send the given value via MOSI/SEND. 58 */ 59 void spi_send(uint8_t v, lcd_sendmode mode) 60 { 61 uint8_t mask; 62 63 if (mode == LCD_DATA) 64 { 65 #ifdef DEBUG 66 printf("D"); 67 #endif 68 SET(LCD_SEND); 69 } 70 else 71 { 72 #ifdef DEBUG 73 printf("C"); 74 #endif 75 CLR(LCD_SEND); 76 } 77 78 SET(LCD_CLK); 79 CLR(LCD_CLK); 80 81 for (mask = 0x80; mask; mask >>= 1) 82 { 83 if (v & mask) 84 { 85 #ifdef DEBUG 86 printf("1"); 87 #endif 88 SET(LCD_SEND); 89 } 90 else 91 { 92 #ifdef DEBUG 93 printf("0"); 94 #endif 95 CLR(LCD_SEND); 96 } 97 98 SET(LCD_CLK); 99 CLR(LCD_CLK); 100 } 101 102 #ifdef DEBUG 103 printf("\n"); 104 #endif 105 } 106 107 void LCD_init() 108 { 109 /* Perform a hardware reset on the LCD. */ 110 /* CS=1, CLK=0, D/C=0 apparently superfluous */ 111 112 SET(LCD_RESET); 113 usleep(50000); 114 CLR(LCD_RESET); 115 usleep(50000); 116 SET(LCD_RESET); 117 usleep(50000); 118 119 /* CS=1, CLK=1, D/C=1, 10ms, SWRESET, 10ms apparently superfluous */ 120 121 LCD_send(LCD_COMMAND, LCD_SLEEPOUT); 122 123 /* Configure display memory access. */ 124 125 LCD_send(LCD_COMMAND, LCD_MADCTL); 126 LCD_send(LCD_DATA, LCD_MADCTL_MY_MX); 127 128 /* Contrast setting (suggested value 0x40), 10ms apparently superfluous */ 129 130 /* Switch the display on. */ 131 132 LCD_send(LCD_COMMAND, LCD_DISPON); 133 134 /* Configure the display mode/format. */ 135 /* 5 == 16bpp */ 136 137 LCD_send(LCD_COMMAND, LCD_COLMOD); 138 LCD_send(LCD_DATA, 0x05); 139 140 LCD_send(LCD_COMMAND, LCD_NOP); 141 142 /* Switch the backlight on. */ 143 144 SET(LCD_BACKLIGHT); 145 } 146 147 void LCD_off() 148 { 149 /* Switch the backlight off. */ 150 151 CLR(LCD_BACKLIGHT); 152 } 153 154 void LCD_window(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) 155 { 156 LCD_send(LCD_COMMAND, LCD_CASET); 157 LCD_send(LCD_DATA, xmin); 158 LCD_send(LCD_DATA, xmax); 159 LCD_send(LCD_COMMAND, LCD_PASET); 160 LCD_send(LCD_DATA, ymin); 161 LCD_send(LCD_DATA, ymax); 162 } 163 164 void LCD_blit_int(uint16_t colour) 165 { 166 LCD_send_more_data((colour >> 8) & 0xff); /* RGGB -> RG */ 167 LCD_send_more_data(colour & 0xff); /* RGGB -> GB */ 168 } 169 170 void LCD_area(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax, uint16_t colour) 171 { 172 uint16_t i, limit = ((xmax - xmin + 1) * (ymax - ymin + 1)) + 1; 173 174 LCD_window(xmin, ymin, xmax, ymax); 175 LCD_send(LCD_COMMAND, LCD_RAMWR); 176 177 for (i = 0; i < limit; i++) 178 { 179 LCD_blit_int(colour); 180 } 181 182 LCD_send(LCD_COMMAND, LCD_NOP); 183 } 184 185 void LCD_image(int x, int y, const uint16_t image[], uint8_t width, uint8_t height) 186 { 187 LCD_image_region(x, y, image, width, height, 0, width, 0, height); 188 } 189 190 void LCD_image_region(int x, int y, const uint16_t image[], uint8_t width, uint8_t height, uint8_t from_x, uint8_t span_x, uint8_t from_y, uint8_t span_y) 191 { 192 uint8_t xmin, ymin, xcmax, ycmax, xcmin, xc, yc; 193 uint16_t xmax, ymax, colour; 194 195 /* Find the screen ranges for blitting. */ 196 197 xmin = (x < 0) ? 0 : x; 198 ymin = (y < 0) ? 0 : y; 199 xmax = (x + span_x > SCREEN_X_MAX) ? SCREEN_X_MAX : x + span_x - 1; 200 ymax = (y + span_y > SCREEN_Y_MAX) ? SCREEN_Y_MAX : y + span_y - 1; 201 202 if ((xmin > SCREEN_X_MAX) || (ymin > SCREEN_Y_MAX) || (xmax < 0) || (ymax < 0)) 203 { 204 return; 205 } 206 207 /* Find the image ranges for reading data. */ 208 209 xcmin = (x < 0) ? -x + from_x : from_x; 210 yc = (y < 0) ? -y + from_y : from_y; 211 xcmax = from_x + ((x + span_x > SCREEN_WIDTH) ? SCREEN_WIDTH - x : span_x); 212 ycmax = from_y + ((y + span_y > SCREEN_HEIGHT) ? SCREEN_HEIGHT - y : span_y); 213 214 LCD_window(xmin, ymin, xmax, ymax); 215 LCD_send(LCD_COMMAND, LCD_RAMWR); 216 217 /* Reading from the appropriate image ranges, blit to the appropriate 218 screen ranges. */ 219 220 xc = xcmin; 221 while (yc < ycmax) 222 { 223 colour = image[yc * width + xc]; 224 LCD_blit_int(colour); 225 226 xc++; 227 if (xc == xcmax) 228 { 229 xc = xcmin; 230 yc++; 231 } 232 } 233 234 LCD_send(LCD_COMMAND, LCD_NOP); 235 } 236 237 void LCD_normal() 238 { 239 LCD_send(LCD_COMMAND, LCD_NORON); 240 } 241 242 void LCD_scroll_area(uint8_t top_fixed, uint8_t scrolling, uint8_t bottom_fixed) 243 { 244 LCD_send(LCD_COMMAND, LCD_VSCRDEF); 245 LCD_send(LCD_DATA, top_fixed); 246 LCD_send(LCD_DATA, scrolling); 247 LCD_send(LCD_DATA, bottom_fixed); 248 } 249 250 void LCD_scroll_start(uint8_t address) 251 { 252 LCD_send(LCD_COMMAND, LCD_SEP); 253 LCD_send(LCD_DATA, address); 254 } 255 256 /* vim: tabstop=4 expandtab shiftwidth=4 257 */