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 43 void spi_begin() 44 { 45 CLR(LCD_CS); 46 } 47 48 void spi_end() 49 { 50 SET(LCD_CS); 51 } 52 53 /** 54 * Send the given value via MOSI/SEND. 55 */ 56 void spi_send(uint8_t v, lcd_sendmode mode) 57 { 58 uint8_t mask; 59 60 if (mode == LCD_DATA) 61 { 62 #ifdef DEBUG 63 printf("D"); 64 #endif 65 SET(LCD_SEND); 66 } 67 else 68 { 69 #ifdef DEBUG 70 printf("C"); 71 #endif 72 CLR(LCD_SEND); 73 } 74 75 SET(LCD_CLK); 76 CLR(LCD_CLK); 77 78 for (mask = 0x80; mask; mask >>= 1) 79 { 80 if (v & mask) 81 { 82 #ifdef DEBUG 83 printf("1"); 84 #endif 85 SET(LCD_SEND); 86 } 87 else 88 { 89 #ifdef DEBUG 90 printf("0"); 91 #endif 92 CLR(LCD_SEND); 93 } 94 95 SET(LCD_CLK); 96 CLR(LCD_CLK); 97 } 98 99 #ifdef DEBUG 100 printf("\n"); 101 #endif 102 } 103 104 void LCD_init(void) 105 { 106 /* Perform a hardware reset on the LCD. */ 107 /* CS=1, CLK=0, D/C=0 apparently superfluous */ 108 109 SET(LCD_RESET); 110 usleep(50000); 111 CLR(LCD_RESET); 112 usleep(50000); 113 SET(LCD_RESET); 114 usleep(50000); 115 116 /* CS=1, CLK=1, D/C=1, 10ms, SWRESET, 10ms apparently superfluous */ 117 118 LCD_send(LCD_COMMAND, LCD_SLEEPOUT); 119 120 /* Configure display memory access. */ 121 122 LCD_send(LCD_COMMAND, LCD_MADCTL); 123 LCD_send(LCD_DATA, LCD_MADCTL_MY_MX); 124 125 /* Contrast setting (suggested value 0x40), 10ms apparently superfluous */ 126 127 /* Switch the display on. */ 128 129 LCD_send(LCD_COMMAND, LCD_DISPON); 130 131 /* Configure the display mode/format. */ 132 /* 5 == 16bpp */ 133 134 LCD_send(LCD_COMMAND, LCD_COLMOD); 135 LCD_send(LCD_DATA, 0x05); 136 137 LCD_send(LCD_COMMAND, LCD_NOP); 138 139 /* Switch the backlight on. */ 140 141 SET(LCD_BACKLIGHT); 142 } 143 144 void LCD_window(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) 145 { 146 LCD_send(LCD_COMMAND, LCD_CASET); 147 LCD_send(LCD_DATA, xmin); 148 LCD_send(LCD_DATA, xmax); 149 LCD_send(LCD_COMMAND, LCD_PASET); 150 LCD_send(LCD_DATA, ymin); 151 LCD_send(LCD_DATA, ymax); 152 } 153 154 void LCD_blit_int(uint16_t colour) 155 { 156 LCD_send_more_data((colour >> 8) & 0xff); /* RGGB -> RG */ 157 LCD_send_more_data(colour & 0xff); /* RGGB -> GB */ 158 } 159 160 void LCD_area(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax, uint16_t colour) 161 { 162 uint16_t i, limit = ((xmax - xmin + 1) * (ymax - ymin + 1)) + 1; 163 164 LCD_window(xmin, ymin, xmax, ymax); 165 LCD_send(LCD_COMMAND, LCD_RAMWR); 166 167 for (i = 0; i < limit; i++) 168 { 169 LCD_blit_int(colour); 170 } 171 172 LCD_send(LCD_COMMAND, LCD_NOP); 173 } 174 175 void LCD_image(int x, int y, uint16_t image[], uint8_t width, uint8_t height) 176 { 177 LCD_image_region(x, y, image, width, height, 0, width, 0, height); 178 } 179 180 void LCD_image_region(int x, int y, 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) 181 { 182 uint8_t xmin, ymin, xcmax, ycmax, xcmin, xc, yc; 183 uint16_t xmax, ymax, colour; 184 185 /* Find the screen ranges for blitting. */ 186 187 xmin = (x < 0) ? 0 : x; 188 ymin = (y < 0) ? 0 : y; 189 xmax = (x + span_x > SCREEN_X_MAX) ? SCREEN_X_MAX : x + span_x - 1; 190 ymax = (y + span_y > SCREEN_Y_MAX) ? SCREEN_Y_MAX : y + span_y - 1; 191 192 if ((xmin > SCREEN_X_MAX) || (ymin > SCREEN_Y_MAX) || (xmax < 0) || (ymax < 0)) 193 { 194 return; 195 } 196 197 /* Find the image ranges for reading data. */ 198 199 xcmin = (x < 0) ? -x + from_x : from_x; 200 yc = (y < 0) ? -y + from_y : from_y; 201 xcmax = from_x + ((x + span_x > SCREEN_WIDTH) ? SCREEN_WIDTH - x : span_x); 202 ycmax = from_y + ((y + span_y > SCREEN_HEIGHT) ? SCREEN_HEIGHT - y : span_y); 203 204 LCD_window(xmin, ymin, xmax, ymax); 205 LCD_send(LCD_COMMAND, LCD_RAMWR); 206 207 /* Reading from the appropriate image ranges, blit to the appropriate 208 screen ranges. */ 209 210 xc = xcmin; 211 while (yc < ycmax) 212 { 213 colour = image[yc * width + xc]; 214 LCD_blit_int(colour); 215 216 xc++; 217 if (xc == xcmax) 218 { 219 xc = xcmin; 220 yc++; 221 } 222 } 223 224 LCD_send(LCD_COMMAND, LCD_NOP); 225 } 226 227 void LCD_normal(void) 228 { 229 LCD_send(LCD_COMMAND, LCD_NORON); 230 } 231 232 void LCD_scroll_area(uint8_t top_fixed, uint8_t scrolling, uint8_t bottom_fixed) 233 { 234 LCD_send(LCD_COMMAND, LCD_VSCRDEF); 235 LCD_send(LCD_DATA, top_fixed); 236 LCD_send(LCD_DATA, scrolling); 237 LCD_send(LCD_DATA, bottom_fixed); 238 } 239 240 void LCD_scroll_start(uint8_t address) 241 { 242 LCD_send(LCD_COMMAND, LCD_SEP); 243 LCD_send(LCD_DATA, address); 244 } 245 246 /* vim: tabstop=4 expandtab shiftwidth=4 247 */