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