µGFX library fork

gdisp_lld_UC8173.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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. #define GDISP_DRIVER_VMT GDISPVMT_UC8173
  10. #include "gdisp_lld_config.h"
  11. #include "../../../src/gdisp/gdisp_driver.h"
  12. #include "UC8173.h"
  13. #include "board_UC8173.h"
  14. #if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT)
  15. #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
  16. #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
  17. #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
  18. COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.")
  19. #endif
  20. #undef GDISP_SCREEN_WIDTH
  21. #undef GDISP_SCREEN_HEIGHT
  22. #endif
  23. #define GDISP_SCREEN_HEIGHT 240
  24. #define GDISP_SCREEN_WIDTH 240
  25. #define PRIV(g) ((UC8173_Private*)((g)->priv))
  26. #define FRAMEBUFFER(g) ((uint8_t *)(PRIV(g)+1))
  27. #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0)
  28. #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_MONO
  29. #define LINE_BYTES (GDISP_SCREEN_WIDTH/8)
  30. #define WRITEBUFCMD DTM4
  31. #define xyaddr(x, y) (((x)>>3) + ((y) * LINE_BYTES))
  32. //#define xybit(x, c) ((c) << ((x) & 7)) // This one has the wrong order of the pixels inside the byte
  33. #define xybit(x, c) ((c) << (7-((x) & 7)))
  34. #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_GRAY4
  35. #define LINE_BYTES (GDISP_SCREEN_WIDTH/4)
  36. #define WRITEBUFCMD DTM2 // NOT SURE THIS IS RIGHT - MAY NEED TO USE DTM0 and then send a refresh???
  37. #define xyaddr(x, y) (((x)>>2) + ((y) * LINE_BYTES))
  38. //#define xybit(x, c) ((c) << (((x) & 3)<<1)) // This one has the wrong order of the pixels inside the byte
  39. #define xybit(x, c) ((c) << (6-((x) & 3)<<1))
  40. #else
  41. #error "UC8173: Unsupported driver color format"
  42. #endif
  43. typedef struct UC8173_Private {
  44. coord_t flushWindowX;
  45. coord_t flushWindowY;
  46. coord_t flushWindowWidth;
  47. coord_t flushWindowHeight;
  48. } UC8173_Private;
  49. // This function rounds a given integer up to a specified multiple. Note, multiple must be a power of 2!
  50. static GFXINLINE void _roundUp(coord_t* numToRound, uint8_t multiple)
  51. {
  52. *numToRound = (*numToRound + multiple - 1) & ~(multiple - 1);
  53. }
  54. static GFXINLINE void _wait_for_busy_high(GDisplay* g)
  55. {
  56. while (!getpin_busy(g));
  57. }
  58. static GFXINLINE void _wait_for_busy_low(GDisplay* g)
  59. {
  60. while (getpin_busy(g));
  61. }
  62. void _load_lut(GDisplay* g, uint32_t lutRegister, const uint8_t* lut, uint32_t lutCounter)
  63. {
  64. uint32_t i;
  65. write_cmd(g, lutRegister);
  66. for (i = 0; i < lutCounter; i++) {
  67. write_data(g, *lut);
  68. lut++;
  69. }
  70. }
  71. static void _upload_lut(GDisplay* g)
  72. {
  73. _load_lut(g, LUT_KWVCOM, _lut_KWvcom_DC_A2_240ms, 32);
  74. _load_lut(g, LUT_KW, _lut_kw_A2_240ms, 512);
  75. _load_lut(g, LUT_FT, _lut_ft, 128);
  76. }
  77. static void _clear_lut(GDisplay* g)
  78. {
  79. write_cmd(g, PON);
  80. _wait_for_busy_high(g);
  81. _load_lut(g, LUT_KW, _lut_None, 42);
  82. _load_lut(g, LUT_KWVCOM, _lut_None, 42);
  83. write_cmd(g, POF);
  84. _wait_for_busy_low(g);
  85. }
  86. #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
  87. static void _invertFramebuffer(GDisplay* g)
  88. {
  89. uint32_t i;
  90. for (i = 0; i < LINE_BYTES*GDISP_SCREEN_HEIGHT; i++) {
  91. FRAMEBUFFER(g)[i] = ~(FRAMEBUFFER(g)[i]);
  92. }
  93. // We should flush these changes to the display controller framebuffer at some point
  94. g->flags |= GDISP_FLG_NEEDFLUSH;
  95. }
  96. #endif
  97. LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
  98. {
  99. // Allocate the private area plus the framebuffer
  100. g->priv = gfxAlloc(sizeof(UC8173_Private) + LINE_BYTES*GDISP_SCREEN_HEIGHT);
  101. if (!g->priv) {
  102. return FALSE;
  103. }
  104. // Initialize the private area
  105. PRIV(g)->flushWindowX = 0;
  106. PRIV(g)->flushWindowY = 0;
  107. PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH;
  108. PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT;
  109. // Initialise the board interface
  110. if (!init_board(g)) {
  111. return FALSE;
  112. }
  113. // Hardware reset
  114. setpin_reset(g, FALSE);
  115. gfxSleepMilliseconds(100);
  116. setpin_reset(g, TRUE);
  117. gfxSleepMilliseconds(1000);
  118. // Acquire the bus
  119. acquire_bus(g);
  120. // Booster soft-start
  121. write_cmd(g, BTST);
  122. write_data(g, 0x17); //0x17
  123. write_data(g, 0x97); //0x97
  124. write_data(g, 0x20); //0x20
  125. // Power settings
  126. write_cmd(g, PWR);
  127. write_data(g, 0x03);
  128. write_data(g, 0x00);
  129. write_data(g, 0x2B); //1C 2B
  130. write_data(g, 0x2B); //1C 2B
  131. write_data(g, 0x00);
  132. // Power-on
  133. write_cmd(g, PON);
  134. _wait_for_busy_high(g);
  135. // Panel setting register
  136. write_cmd(g, PSR);
  137. write_data(g, 0x0F); //0x0B
  138. write_data(g, 0x86); //0x86
  139. // Power-off sequence
  140. write_cmd(g, PFS);
  141. write_data(g, 0x00);
  142. // PLL control
  143. write_cmd(g, LPRD);
  144. write_data(g, 0x25);
  145. // Internal temperature sensor enable
  146. write_cmd(g, TSE);
  147. write_data(g, 0x00); // Use internal temperature sensor
  148. // VCOM and data interval settings
  149. write_cmd(g, CDI);
  150. write_data(g, 0xE1);
  151. write_data(g, 0x20);
  152. write_data(g, 0x10);
  153. // Set display panel resolution
  154. write_cmd(g, TRES);
  155. write_data(g, 0xEF);
  156. write_data(g, 0x00);
  157. write_data(g, 0xEF);
  158. // Undocumented register, taken from sample code
  159. write_cmd(g, GDS);
  160. write_data(g, 0xA9);
  161. write_data(g, 0xA9);
  162. write_data(g, 0xEB);
  163. write_data(g, 0xEB);
  164. write_data(g, 0x02);
  165. // Auto measure VCOM
  166. write_cmd(g, AMV);
  167. write_data(g, 0x11); // 5 seconds, enabled
  168. _wait_for_busy_high(g);
  169. // Get current VCOM value
  170. // write_cmd(g, VV);
  171. // unsigned char vcom_temp = spi_9b_get();
  172. // vcom_temp = vcom_temp + 4;
  173. // Auto_VCOM = vcom_temp;
  174. // VCM_DC setting
  175. write_cmd(g, VDCS);
  176. write_data(g, 0x12); // Write vcom_temp here
  177. // Undocumented register, taken from sample code
  178. write_cmd(g, VBDS);
  179. write_data(g, 0x22);
  180. // Undocumented register, taken from sample code
  181. write_cmd(g, LVSEL);
  182. write_data(g, 0x02);
  183. // Undocumented register, taken from sample code
  184. write_cmd(g, GBS);
  185. write_data(g, 0x02);
  186. write_data(g, 0x02);
  187. // Undocumented register, taken from sample code
  188. write_cmd(g, GSS);
  189. write_data(g, 0x02);
  190. write_data(g, 0x02);
  191. // Undocumented register, taken from sample code
  192. write_cmd(g, DF); // For REGAL (???)
  193. write_data(g, 0x1F);
  194. // Clear the look-up table
  195. _clear_lut(g);
  196. // Finish Init
  197. post_init_board(g);
  198. // Release the bus
  199. release_bus(g);
  200. // Initialise the GDISP structure
  201. g->g.Width = GDISP_SCREEN_WIDTH;
  202. g->g.Height = GDISP_SCREEN_HEIGHT;
  203. g->g.Orientation = GDISP_ROTATE_0;
  204. g->g.Powermode = powerOn;
  205. g->g.Backlight = 0;
  206. g->g.Contrast = 0;
  207. return TRUE;
  208. }
  209. #if GDISP_HARDWARE_FLUSH
  210. LLDSPEC void gdisp_lld_flush(GDisplay* g)
  211. {
  212. coord_t y;
  213. // Don't flush unless we really need to
  214. if (!(g->flags & GDISP_FLG_NEEDFLUSH)) {
  215. return;
  216. }
  217. // Round the flushing window width and height up to the next multiple of four
  218. _roundUp(&(PRIV(g)->flushWindowWidth), 4);
  219. _roundUp(&(PRIV(g)->flushWindowWidth), 4);
  220. // Acquire the bus to communicate with the display controller
  221. acquire_bus(g);
  222. // Upload the new temperature LUT
  223. _upload_lut(g);
  224. // Setup the window
  225. write_cmd(g, DTMW);
  226. write_data(g, (uint8_t)((PRIV(g)->flushWindowX >> 0) & 0xFF));
  227. write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 8) & 0x03));
  228. write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 0) & 0xFF));
  229. write_data(g, (uint8_t)((((PRIV(g)->flushWindowWidth)-1) >> 0) & 0xFF));
  230. write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 8) & 0x03));
  231. write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 0) & 0xFF));
  232. // Dump our framebuffer
  233. // Note: The display controller doesn't allow changing the vertical scanning direction
  234. // so we have to manually send the lines "the other way around" here.
  235. write_cmd(g, WRITEBUFCMD);
  236. for (y = GDISP_SCREEN_HEIGHT-1; y >= 0; y--) {
  237. write_data_burst(g, FRAMEBUFFER(g)+y*LINE_BYTES, LINE_BYTES);
  238. }
  239. // Power-up the DC/DC converter to update the display panel
  240. write_cmd(g, PON);
  241. _wait_for_busy_high(g);
  242. // Refresh the panel contents
  243. write_cmd(g, DRF);
  244. write_data(g, 0x00); // Enable REGAL function
  245. write_data(g, 0x00);
  246. write_data(g, 0x00);
  247. write_data(g, 0x00);
  248. write_data(g, 0xEF);
  249. write_data(g, 0x00);
  250. write_data(g, 0xEF);
  251. _wait_for_busy_high(g);
  252. // Power-down the DC/DC converter to make all the low-power pussys happy
  253. write_cmd(g, POF);
  254. _wait_for_busy_low(g);
  255. // Release the bus again
  256. release_bus(g);
  257. // Clear the 'need-flushing' flag
  258. g->flags &=~ GDISP_FLG_NEEDFLUSH;
  259. }
  260. #endif
  261. #if GDISP_HARDWARE_DRAWPIXEL
  262. LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g)
  263. {
  264. coord_t x, y;
  265. LLDCOLOR_TYPE *p;
  266. // Handle the different possible orientations
  267. switch(g->g.Orientation) {
  268. default:
  269. case GDISP_ROTATE_0:
  270. x = g->p.x;
  271. y = g->p.y;
  272. break;
  273. case GDISP_ROTATE_90:
  274. x = g->p.y;
  275. y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
  276. break;
  277. case GDISP_ROTATE_180:
  278. x = GDISP_SCREEN_WIDTH-1 - g->p.x;
  279. y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
  280. break;
  281. case GDISP_ROTATE_270:
  282. x = GDISP_SCREEN_WIDTH-1 - g->p.y;
  283. y = g->p.x;
  284. break;
  285. }
  286. // Modify the framebuffer content
  287. p = &FRAMEBUFFER(g)[xyaddr(x,y)];
  288. *p &=~ xybit(x, LLDCOLOR_MASK());
  289. *p |= xybit(x, gdispColor2Native(g->p.color));
  290. // ToDo
  291. // There appears to be an issue in the silicone, still talking to the manufacturer about this one. Update will follow!
  292. #if 0
  293. // Update the flush window region
  294. if (g->flags & GDISP_FLG_NEEDFLUSH) {
  295. if (x < PRIV(g)->flushWindowX)
  296. PRIV(g)->flushWindowX = x;
  297. if (y < PRIV(g)->flushWindowY)
  298. PRIV(g)->flushWindowY = y;
  299. if (x > PRIV(g)->flushWindowX + PRIV(g)->flushWindowWidth)
  300. PRIV(g)->flushWindowWidth =
  301. } else {
  302. PRIV(g)->flushWindowX = x;
  303. PRIV(g)->flushWindowY = y;
  304. PRIV(g)->flushWindowWidth = 1;
  305. PRIV(g)->flushWindowHeight = 1;
  306. }
  307. #else
  308. PRIV(g)->flushWindowX = 0;
  309. PRIV(g)->flushWindowY = 0;
  310. PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH;
  311. PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT;
  312. #endif
  313. // We should flush these changes to the display controller framebuffer at some point
  314. g->flags |= GDISP_FLG_NEEDFLUSH;
  315. }
  316. #endif
  317. #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
  318. LLDSPEC void gdisp_lld_control(GDisplay* g) {
  319. switch(g->p.x) {
  320. case GDISP_CONTROL_INVERT:
  321. _invertFramebuffer(g);
  322. break;
  323. default:
  324. break;
  325. }
  326. }
  327. #endif
  328. #endif // GFX_USE_GDISP