µGFX library fork

gdisp_lld_Nokia6610GE8.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * This file is subject to the terms of the GFX License. If a copy of
  3. * the license was not distributed with this file, you can obtain one at:
  4. *
  5. * http://ugfx.org/license.html
  6. */
  7. #include "gfx.h"
  8. #if GFX_USE_GDISP
  9. /*
  10. * This is for the EPSON (GE8) controller driving a Nokia6610 color LCD display.
  11. * Note that there is also a PHILIPS (GE12) controller for the same display that this code
  12. * does not support.
  13. *
  14. * The controller drives a 132x132 display but a 1 pixel surround is not visible
  15. * which gives a visible area of 130x130.
  16. *
  17. * This controller does not support reading back over the SPI interface.
  18. * Additionally, the Olimex board doesn't even connect the pin.
  19. *
  20. * The hardware is capable of doing full width vertical scrolls aligned
  21. * on a 4 line boundary however that is not sufficient to support general vertical scrolling.
  22. * We also can't manually do read/modify scrolling because we can't read in SPI mode.
  23. *
  24. * The controller has some quirkyness when operating in other than rotation 0 mode.
  25. * When any direction is decremented it starts at location 0 rather than the end of
  26. * the area. Whilst this can be handled when we know the specific operation (pixel, fill, blit)
  27. * it cannot be handled in a generic stream operation. So, when orientation support is turned
  28. * on (and needed) we use complex operation specific routines instead of simple streaming
  29. * routines. This has a (small) performance penalty and a significant code size penalty so
  30. * don't turn on orientation support unless you really need it.
  31. *
  32. * Some of the more modern controllers have a broken command set. If you have one of these
  33. * you will recognise it by the colors being off on anything drawn after an odd (as opposed to
  34. * even) pixel count area being drawn. If so then set GDISP_GE8_BROKEN_CONTROLLER to TRUE
  35. * on your gdisp_lld_board.h file. The price is that streaming calls that are completed
  36. * without exactly the window size write operations and where the number of write operations
  37. * is odd (rather than even), it will draw an extra pixel. If this is important to you, turn on
  38. * orientation support and the streaming operations will be emulated (as described above).
  39. */
  40. #if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT)
  41. #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
  42. #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
  43. #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
  44. COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.")
  45. #endif
  46. #undef GDISP_SCREEN_WIDTH
  47. #undef GDISP_SCREEN_HEIGHT
  48. #endif
  49. #define GDISP_DRIVER_VMT GDISPVMT_Nokia6610GE8
  50. #include "gdisp_lld_config.h"
  51. #include "../../../src/gdisp/gdisp_driver.h"
  52. #include "board_Nokia6610GE8.h"
  53. /*===========================================================================*/
  54. /* Driver local definitions. */
  55. /*===========================================================================*/
  56. #include "GE8.h"
  57. #define GDISP_SCAN_LINES 132
  58. // Set parameters if they are not already set
  59. #ifndef GDISP_GE8_BROKEN_CONTROLLER
  60. #define GDISP_GE8_BROKEN_CONTROLLER TRUE
  61. #endif
  62. #ifndef GDISP_SCREEN_HEIGHT
  63. #define GDISP_SCREEN_HEIGHT 130
  64. #endif
  65. #ifndef GDISP_SCREEN_WIDTH
  66. #define GDISP_SCREEN_WIDTH 130
  67. #endif
  68. #ifndef GDISP_RAM_X_OFFSET
  69. #define GDISP_RAM_X_OFFSET 0 /* Offset in RAM of visible area */
  70. #endif
  71. #ifndef GDISP_RAM_Y_OFFSET
  72. #define GDISP_RAM_Y_OFFSET 2 /* Offset in RAM of visible area */
  73. #endif
  74. #ifndef GDISP_SLEEP_SIZE
  75. #define GDISP_SLEEP_SIZE 32 /* Sleep mode window lines */
  76. #endif
  77. #ifndef GDISP_SLEEP_POS
  78. #define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2)
  79. #endif
  80. #ifndef GDISP_INITIAL_CONTRAST
  81. #define GDISP_INITIAL_CONTRAST 60
  82. #endif
  83. #ifndef GDISP_INITIAL_BACKLIGHT
  84. #define GDISP_INITIAL_BACKLIGHT 100
  85. #endif
  86. /*===========================================================================*/
  87. /* Driver exported variables. */
  88. /*===========================================================================*/
  89. /*===========================================================================*/
  90. /* Driver local variables. */
  91. /*===========================================================================*/
  92. #if GDISP_HARDWARE_STREAM_WRITE
  93. typedef struct dvrPriv {
  94. uint16_t savecolor;
  95. #if GDISP_GE8_BROKEN_CONTROLLER
  96. uint16_t firstcolor;
  97. #endif
  98. } dvrPriv;
  99. #define PRIV ((dvrPriv *)g->priv)
  100. #endif
  101. #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0)
  102. #define GDISP_FLG_RUNBYTE (GDISP_FLG_DRIVER<<1)
  103. /*===========================================================================*/
  104. /* Driver local functions. */
  105. /*===========================================================================*/
  106. // Some macros just to make reading the code easier
  107. #define delayms(ms) gfxSleepMilliseconds(ms)
  108. #define write_data2(g, d1, d2) { write_data(g, d1); write_data(g, d2); }
  109. #define write_data3(g, d1, d2, d3) { write_data(g, d1); write_data(g, d2); write_data(g, d3); }
  110. #define write_data4(g, d1, d2, d3, d4) { write_data(g, d1); write_data(g, d2); write_data(g, d3); write_data(g, d4); }
  111. #define write_cmd1(g, cmd, d1) { write_index(g, cmd); write_data(g, d1); }
  112. #define write_cmd2(g, cmd, d1, d2) { write_index(g, cmd); write_data2(g, d1, d2); }
  113. #define write_cmd3(g, cmd, d1, d2, d3) { write_index(g, cmd); write_data3(g, d1, d2, d3); }
  114. #define write_cmd4(g, cmd, d1, d2, d3, d4) { write_index(g, cmd); write_data4(g, d1, d2, d3, d4); }
  115. #if GDISP_HARDWARE_DRAWPIXEL
  116. static GFXINLINE void set_viewpoint(GDisplay* g) {
  117. #if GDISP_NOKIA_ORIENTATION && GDISP_NEED_CONTROL
  118. switch(g->g.Orientation) {
  119. default:
  120. case GDISP_ROTATE_0:
  121. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x); // Column address set
  122. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y); // Page address set
  123. break;
  124. case GDISP_ROTATE_90:
  125. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y);
  126. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x);
  127. break;
  128. case GDISP_ROTATE_180:
  129. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x);
  130. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y);
  131. break;
  132. case GDISP_ROTATE_270:
  133. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y);
  134. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x);
  135. break;
  136. }
  137. #else
  138. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x); // Column address set
  139. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y); // Page address set
  140. #endif
  141. write_index(g, RAMWR);
  142. }
  143. #endif
  144. static GFXINLINE void set_viewport(GDisplay* g) {
  145. #if GDISP_NOKIA_ORIENTATION && GDISP_NEED_CONTROL
  146. switch(g->g.Orientation) {
  147. default:
  148. case GDISP_ROTATE_0:
  149. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set
  150. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set
  151. break;
  152. case GDISP_ROTATE_90:
  153. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1);
  154. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x);
  155. break;
  156. case GDISP_ROTATE_180:
  157. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x);
  158. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y);
  159. break;
  160. case GDISP_ROTATE_270:
  161. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y);
  162. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1);
  163. break;
  164. }
  165. #else
  166. write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set
  167. write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set
  168. #endif
  169. write_index(g, RAMWR);
  170. }
  171. /*===========================================================================*/
  172. /* Driver exported functions. */
  173. /*===========================================================================*/
  174. LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
  175. #if GDISP_HARDWARE_STREAM_WRITE
  176. g->priv = gfxAlloc(sizeof(dvrPriv));
  177. #else
  178. g->priv = 0;
  179. #endif
  180. // Initialise the board interface
  181. init_board(g);
  182. // Hardware reset
  183. setpin_reset(g, TRUE);
  184. delayms(20);
  185. setpin_reset(g, FALSE);
  186. delayms(20);
  187. // Get the bus for the following initialisation commands
  188. acquire_bus(g);
  189. write_cmd4(g, DISCTL, 0x00, GDISP_SCAN_LINES/4-1, 0x0A, 0x00); // Display control - How the controller drives the LCD
  190. // P1: 0x00 = 2 divisions, switching period=8 (default)
  191. // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32)
  192. // P3: 0x0A = standard inverse highlight, inversion every frame
  193. // P4: 0x00 = dispersion on
  194. write_cmd1(g, COMSCN, 0x01); // COM scan - How the LCD is connected to the controller
  195. // P1: 0x01 = Scan 1->80, 160<-81
  196. write_index(g, OSCON); // Internal oscillator ON
  197. write_index(g, SLPOUT); // Sleep out
  198. write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON
  199. write_cmd3(g, DATCTL, 0x00, 0x00, 0x02); // Data control
  200. // P1: 0x00 = page address normal, column address normal, address scan in column direction
  201. // P2: 0x00 = RGB sequence (default value)
  202. // P3: 0x02 = 4 bits per colour (Type A)
  203. write_cmd2(g, VOLCTR, 64*GDISP_INITIAL_CONTRAST/101, 0x03); // Voltage control (contrast setting)
  204. // P1 = Contrast (0..63)
  205. // P2 = 3 resistance ratio (only value that works)
  206. delayms(100); // Allow power supply to stabilise
  207. write_index(g, DISON); // Turn on the display
  208. // Finish Init
  209. post_init_board(g);
  210. // Release the bus
  211. release_bus(g);
  212. /* Turn on the back-light */
  213. set_backlight(g, GDISP_INITIAL_BACKLIGHT);
  214. /* Initialise the GDISP structure to match */
  215. g->g.Orientation = GDISP_ROTATE_0;
  216. g->g.Powermode = powerOn;
  217. g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
  218. g->g.Contrast = GDISP_INITIAL_CONTRAST;
  219. g->g.Width = GDISP_SCREEN_WIDTH;
  220. g->g.Height = GDISP_SCREEN_HEIGHT;
  221. return TRUE;
  222. }
  223. #if GDISP_HARDWARE_STREAM_WRITE
  224. LLDSPEC void gdisp_lld_write_start(GDisplay *g) {
  225. acquire_bus(g);
  226. set_viewport(g);
  227. g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE);
  228. }
  229. LLDSPEC void gdisp_lld_write_color(GDisplay *g) {
  230. uint16_t c;
  231. c = gdispColor2Native(g->p.color);
  232. #if GDISP_GE8_BROKEN_CONTROLLER
  233. if (!(g->flags & GDISP_FLG_RUNBYTE)) {
  234. PRIV->firstcolor = c;
  235. g->flags |= GDISP_FLG_RUNBYTE;
  236. }
  237. #endif
  238. if ((g->flags & GDISP_FLG_ODDBYTE)) {
  239. // Write the pair of pixels to the display
  240. write_data3(g, ((PRIV->savecolor >> 4) & 0xFF),
  241. (((PRIV->savecolor << 4) & 0xF0)|((c >> 8) & 0x0F)),
  242. (c & 0xFF));
  243. g->flags &= ~GDISP_FLG_ODDBYTE;
  244. } else {
  245. PRIV->savecolor = c;
  246. g->flags |= GDISP_FLG_ODDBYTE;
  247. }
  248. }
  249. LLDSPEC void gdisp_lld_write_stop(GDisplay *g) {
  250. if ((g->flags & GDISP_FLG_ODDBYTE)) {
  251. #if GDISP_GE8_BROKEN_CONTROLLER
  252. /**
  253. * We have a real problem here - we need to write a singular pixel
  254. * Methods that are supposed to work...
  255. * 1/ Write the pixel (2 bytes) and then send a NOP command. This doesn't work, the pixel doesn't get written
  256. * and it is maintained in the latch where it causes problems for the next window.
  257. * 2/ Just write a dummy extra pixel as stuff beyond the window gets discarded. This doesn't work as contrary to
  258. * the documentation the buffer wraps and the first pixel gets overwritten.
  259. * 3/ Put the controller in 16 bits per pixel Type B mode where each pixel is performed by writing two bytes. This
  260. * also doesn't work as the controller refuses to enter Type B mode (it stays in Type A mode).
  261. *
  262. * These methods might work on some controllers - just not on the one of the broken versions.
  263. *
  264. * For these broken controllers:
  265. * We know we can wrap to the first byte (just overprint it) if we are at the end of the stream area.
  266. * If not, we need to create a one pixel by one pixel window to fix this - Uuch. Fortunately this should only happen if the
  267. * user application uses the streaming calls and then terminates the stream early or after buffer wrap.
  268. * Since this is such an unlikely situation we just don't handle it.
  269. */
  270. write_data3(g, ((PRIV->savecolor >> 4) & 0xFF),
  271. (((PRIV->savecolor << 4) & 0xF0)|((PRIV->firstcolor >> 8) & 0x0F)),
  272. (PRIV->firstcolor & 0xFF));
  273. #else
  274. write_data2(g, ((PRIV->savecolor >> 4) & 0xFF), ((PRIV->savecolor << 4) & 0xF0));
  275. write_index(g, NOP);
  276. #endif
  277. }
  278. release_bus(g);
  279. }
  280. #endif
  281. #if GDISP_HARDWARE_DRAWPIXEL
  282. LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
  283. uint16_t c;
  284. c = gdispColor2Native(g->p.color);
  285. acquire_bus(g);
  286. set_viewpoint(g);
  287. write_data3(g, 0, ((c>>8) & 0x0F), (c & 0xFF));
  288. release_bus(g);
  289. }
  290. #endif
  291. /* ---- Optional Routines ---- */
  292. #if GDISP_HARDWARE_FILLS
  293. LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
  294. unsigned tuples;
  295. uint16_t c;
  296. tuples = (g->p.cx*g->p.cy+1)>>1; // With an odd sized area we over-print by one pixel.
  297. // This extra pixel overwrites the first pixel (harmless as it is the same colour)
  298. c = gdispColor2Native(g->p.color);
  299. acquire_bus(g);
  300. set_viewport(g);
  301. while(tuples--)
  302. write_data3(g, ((c >> 4) & 0xFF), (((c << 4) & 0xF0)|((c >> 8) & 0x0F)), (c & 0xFF));
  303. release_bus(g);
  304. }
  305. #endif
  306. #if GDISP_HARDWARE_BITFILLS
  307. LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
  308. coord_t lg, x, y;
  309. uint16_t c1, c2;
  310. unsigned tuples;
  311. const pixel_t *buffer;
  312. #if GDISP_PACKED_PIXELS
  313. unsigned pnum, pstart;
  314. const uint8_t *p;
  315. #else
  316. const pixel_t *p;
  317. #endif
  318. tuples = (g->p.cx * g->p.cy + 1)>>1;
  319. buffer = (const pixel_t *)g->p.ptr;
  320. /* Set up the data window to transfer */
  321. acquire_bus(g);
  322. set_viewport(g);
  323. /* to suppress compiler warnings */
  324. x = 0;
  325. y = 0;
  326. /*
  327. * Due to the way the Nokia6610 handles a decrementing column or page,
  328. * we have to make adjustments as to where it is actually drawing from in the bitmap.
  329. * For example, for 90 degree rotation the column is decremented on each
  330. * memory write. The controller always starts with column 0 and then decrements
  331. * to column cx-1, cx-2 etc. We therefore have to write-out the last bitmap line first.
  332. */
  333. switch(g->g.Orientation) {
  334. default:
  335. case GDISP_ROTATE_0: x = 0; y = 0; break;
  336. case GDISP_ROTATE_90: x = g->p.cx-1; y = 0; break;
  337. case GDISP_ROTATE_180: x = g->p.cx-1; y = g->p.cy-1; break;
  338. case GDISP_ROTATE_270: x = 0; y = g->p.cy-1; break;
  339. }
  340. #if !GDISP_PACKED_PIXELS
  341. // Although this controller uses packed pixels we support unpacked pixel
  342. // formats in this blit by packing the data as we feed it to the controller.
  343. lg = g->p.x2 - g->p.cx; // The buffer gap between lines
  344. buffer += g->p.y1 * g->p.x2 + g->p.x1; // The buffer start position
  345. p = buffer + g->p.x2*y + x; // Adjustment for controller craziness
  346. while(tuples--) {
  347. /* Get a pixel */
  348. c1 = gdispColor2Native(*p++);
  349. /* Check for line or buffer wrapping */
  350. if (++x >= g->p.cx) {
  351. x = 0;
  352. p += lg;
  353. if (++y >= g->p.cy) {
  354. y = 0;
  355. p = buffer;
  356. }
  357. }
  358. /* Get the next pixel */
  359. c2 = gdispColor2Native(*p++);
  360. /* Check for line or buffer wrapping */
  361. if (++x >= g->p.cx) {
  362. x = 0;
  363. p += lg;
  364. if (++y >= g->p.cy) {
  365. y = 0;
  366. p = buffer;
  367. }
  368. }
  369. /* Write the pair of pixels to the display */
  370. write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF));
  371. }
  372. #elif GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT
  373. // Although this controller uses packed pixels, we may have to feed it into
  374. // the controller with different packing to the source bitmap
  375. // There are 2 pixels per 3 bytes
  376. #if !GDISP_PACKED_LINES
  377. srccx = (g->p.x2 + 1) & ~1;
  378. #endif
  379. pstart = g->p.y1 * g->p.x2 + g->p.x1; // The starting pixel number
  380. buffer = (const pixel_t)(((const uint8_t *)buffer) + ((pstart>>1) * 3)); // The buffer start position
  381. lg = ((g->p.x2-g->p.cx)>>1)*3; // The buffer gap between lines
  382. pnum = pstart + g->p.x2*y + x; // Adjustment for controller craziness
  383. p = ((const uint8_t *)buffer) + (((g->p.x2*y + x)>>1)*3); // Adjustment for controller craziness
  384. while (tuples--) {
  385. /* Get a pixel */
  386. switch(pnum++ & 1) {
  387. case 0: c1 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break;
  388. case 1: c1 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); p += 3; break;
  389. }
  390. /* Check for line or buffer wrapping */
  391. if (++x >= g->p.cx) {
  392. x = 0;
  393. p += lg;
  394. pnum += g->p.x2 - g->p.cx;
  395. if (++y >= g->p.cy) {
  396. y = 0;
  397. p = (const uint8_t *)buffer;
  398. pnum = pstart;
  399. }
  400. }
  401. /* Get the next pixel */
  402. switch(pnum++ & 1) {
  403. case 0: c2 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break;
  404. case 1: c2 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); p += 3; break;
  405. }
  406. /* Check for line or buffer wrapping */
  407. if (++x >= g->p.cx) {
  408. x = 0;
  409. p += lg;
  410. pnum += g->p.x2 - g->p.cx;
  411. if (++y >= g->p.cy) {
  412. y = 0;
  413. p = (const uint8_t *)buffer;
  414. pnum = pstart;
  415. }
  416. }
  417. /* Write the pair of pixels to the display */
  418. write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF));
  419. }
  420. #else
  421. #error "Packed pixels is broken if you are not running native pixel format"
  422. #endif
  423. /* All done */
  424. release_bus(g);
  425. }
  426. #endif
  427. #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
  428. LLDSPEC void gdisp_lld_control(GDisplay *g) {
  429. /* The hardware is capable of supporting...
  430. * GDISP_CONTROL_POWER - supported
  431. * GDISP_CONTROL_ORIENTATION - supported
  432. * GDISP_CONTROL_BACKLIGHT - supported
  433. * GDISP_CONTROL_CONTRAST - supported
  434. */
  435. switch(g->p.x) {
  436. case GDISP_CONTROL_POWER:
  437. if (g->g.Powermode == (powermode_t)g->p.ptr)
  438. return;
  439. acquire_bus(g);
  440. switch((powermode_t)g->p.ptr) {
  441. case powerOff:
  442. set_backlight(g, 0); // Turn off the backlight
  443. write_index(g, DISOFF); // Turn off the display
  444. write_cmd1(g, PWRCTR, 0x00); // Power control - all off
  445. write_index(g, SLPIN); // Sleep in
  446. write_index(g, OSCOFF); // Internal oscillator off
  447. break;
  448. case powerOn:
  449. write_index(g, OSCON); // Internal oscillator on
  450. write_index(g, SLPOUT); // Sleep out
  451. write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON
  452. write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting)
  453. delayms(100); // Allow power supply to stabilise
  454. write_index(g, DISON); // Turn on the display
  455. write_index(g, PTLOUT); // Remove sleep window
  456. set_backlight(g, g->g.Backlight); // Turn on the backlight
  457. break;
  458. case powerSleep:
  459. write_index(g, OSCON); // Internal oscillator on
  460. write_index(g, SLPOUT); // Sleep out
  461. write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON
  462. write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting)
  463. delayms(100); // Allow power supply to stabilise
  464. write_index(g, DISON); // Turn on the display
  465. write_cmd2(g, PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window
  466. set_backlight(g, g->g.Backlight); // Turn on the backlight
  467. break;
  468. case powerDeepSleep:
  469. write_index(g, OSCON); // Internal oscillator on
  470. write_index(g, SLPOUT); // Sleep out
  471. write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON
  472. write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting)
  473. delayms(100); // Allow power supply to stabilise
  474. write_index(g, DISON); // Turn on the display
  475. write_cmd2(g, PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window
  476. set_backlight(g, 0); // Turn off the backlight
  477. break;
  478. default:
  479. release_bus(g);
  480. return;
  481. }
  482. release_bus(g);
  483. g->g.Powermode = (powermode_t)g->p.ptr;
  484. return;
  485. #if GDISP_NOKIA_ORIENTATION
  486. case GDISP_CONTROL_ORIENTATION:
  487. if (g->g.Orientation == (orientation_t)g->p.ptr)
  488. return;
  489. acquire_bus(g);
  490. switch((orientation_t)g->p.ptr) {
  491. case GDISP_ROTATE_0:
  492. write_cmd3(g, DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction
  493. g->g.Height = GDISP_SCREEN_HEIGHT;
  494. g->g.Width = GDISP_SCREEN_WIDTH;
  495. break;
  496. case GDISP_ROTATE_90:
  497. write_cmd3(g, DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction
  498. g->g.Height = GDISP_SCREEN_WIDTH;
  499. g->g.Width = GDISP_SCREEN_HEIGHT;
  500. break;
  501. case GDISP_ROTATE_180:
  502. write_cmd3(g, DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction
  503. g->g.Height = GDISP_SCREEN_HEIGHT;
  504. g->g.Width = GDISP_SCREEN_WIDTH;
  505. break;
  506. case GDISP_ROTATE_270:
  507. write_cmd3(g, DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction
  508. g->g.Height = GDISP_SCREEN_WIDTH;
  509. g->g.Width = GDISP_SCREEN_HEIGHT;
  510. break;
  511. default:
  512. release_bus(g);
  513. return;
  514. }
  515. release_bus(g);
  516. g->g.Orientation = (orientation_t)g->p.ptr;
  517. return;
  518. #endif
  519. case GDISP_CONTROL_BACKLIGHT:
  520. if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
  521. set_backlight(g, (unsigned)g->p.ptr);
  522. g->g.Backlight = (unsigned)g->p.ptr;
  523. return;
  524. case GDISP_CONTROL_CONTRAST:
  525. if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
  526. acquire_bus(g);
  527. write_cmd2(g, VOLCTR, 64*(unsigned)g->p.ptr/101, 0x03);
  528. release_bus(g);
  529. g->g.Contrast = (unsigned)g->p.ptr;
  530. return;
  531. }
  532. }
  533. #endif
  534. #endif /* GFX_USE_GDISP */