gdisp_IS31FL3731C.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include "gfx.h"
  15. #if GFX_USE_GDISP
  16. #define GDISP_DRIVER_VMT GDISPVMT_IS31FL3731C_ERGODOX
  17. #include "drivers/gdisp/IS31FL3731C/gdisp_lld_config.h"
  18. #include "src/gdisp/gdisp_driver.h"
  19. #include "board_IS31FL3731C.h"
  20. /*===========================================================================*/
  21. /* Driver local definitions. */
  22. /*===========================================================================*/
  23. #ifndef GDISP_SCREEN_HEIGHT
  24. #define GDISP_SCREEN_HEIGHT 9
  25. #endif
  26. #ifndef GDISP_SCREEN_WIDTH
  27. #define GDISP_SCREEN_WIDTH 16
  28. #endif
  29. #ifndef GDISP_INITIAL_CONTRAST
  30. #define GDISP_INITIAL_CONTRAST 0
  31. #endif
  32. #ifndef GDISP_INITIAL_BACKLIGHT
  33. #define GDISP_INITIAL_BACKLIGHT 100
  34. #endif
  35. #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)
  36. #define IS31_ADDR_DEFAULT 0x74
  37. #define IS31_REG_CONFIG 0x00
  38. // bits in reg
  39. #define IS31_REG_CONFIG_PICTUREMODE 0x00
  40. #define IS31_REG_CONFIG_AUTOPLAYMODE 0x08
  41. #define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18
  42. // D2:D0 bits are starting frame for autoplay mode
  43. #define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode
  44. #define IS31_REG_AUTOPLAYCTRL1 0x02
  45. // D6:D4 number of loops (000=infty)
  46. // D2:D0 number of frames to be used
  47. #define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms)
  48. #define IS31_REG_DISPLAYOPT 0x05
  49. #define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames
  50. #define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8
  51. // D2:D0 bits blink period time (*0.27s)
  52. #define IS31_REG_AUDIOSYNC 0x06
  53. #define IS31_REG_AUDIOSYNC_ENABLE 0x1
  54. #define IS31_REG_FRAMESTATE 0x07
  55. #define IS31_REG_BREATHCTRL1 0x08
  56. // D6:D4 fade out time (26ms*2^i)
  57. // D2:D0 fade in time (26ms*2^i)
  58. #define IS31_REG_BREATHCTRL2 0x09
  59. #define IS31_REG_BREATHCTRL2_ENABLE 0x10
  60. // D2:D0 extinguish time (3.5ms*2^i)
  61. #define IS31_REG_SHUTDOWN 0x0A
  62. #define IS31_REG_SHUTDOWN_OFF 0x0
  63. #define IS31_REG_SHUTDOWN_ON 0x1
  64. #define IS31_REG_AGCCTRL 0x0B
  65. #define IS31_REG_ADCRATE 0x0C
  66. #define IS31_COMMANDREGISTER 0xFD
  67. #define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine'
  68. #define IS31_FUNCTIONREG_SIZE 0xD
  69. #define IS31_FRAME_SIZE 0xB4
  70. #define IS31_PWM_REG 0x24
  71. #define IS31_PWM_SIZE 0x90
  72. #define IS31_LED_MASK_SIZE 0x12
  73. #define IS31_SCREEN_WIDTH 16
  74. #define IS31
  75. //Generated by http://jared.geek.nz/2013/feb/linear-led-pwm
  76. const unsigned char cie[256] = {
  77. 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
  78. 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
  79. 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
  80. 3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
  81. 5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
  82. 7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
  83. 10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
  84. 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
  85. 17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
  86. 22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
  87. 28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
  88. 34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
  89. 41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
  90. 49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
  91. 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
  92. 68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
  93. 80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
  94. 92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
  95. 106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
  96. 121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
  97. 138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
  98. 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
  99. 175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
  100. 196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
  101. 218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
  102. 242, 245, 247, 250, 252, 255,
  103. };
  104. /*===========================================================================*/
  105. /* Driver local functions. */
  106. /*===========================================================================*/
  107. typedef struct{
  108. uint8_t write_buffer_offset;
  109. uint8_t write_buffer[IS31_FRAME_SIZE];
  110. uint8_t frame_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH];
  111. uint8_t page;
  112. }__attribute__((__packed__)) PrivData;
  113. // Some common routines and macros
  114. #define PRIV(g) ((PrivData*)g->priv)
  115. /*===========================================================================*/
  116. /* Driver exported functions. */
  117. /*===========================================================================*/
  118. static GFXINLINE void write_page(GDisplay* g, uint8_t page) {
  119. uint8_t tx[2] __attribute__((aligned(2)));
  120. tx[0] = IS31_COMMANDREGISTER;
  121. tx[1] = page;
  122. write_data(g, tx, 2);
  123. }
  124. static GFXINLINE void write_register(GDisplay* g, uint8_t page, uint8_t reg, uint8_t data) {
  125. uint8_t tx[2] __attribute__((aligned(2)));
  126. tx[0] = reg;
  127. tx[1] = data;
  128. write_page(g, page);
  129. write_data(g, tx, 2);
  130. }
  131. static GFXINLINE void write_ram(GDisplay *g, uint8_t page, uint16_t offset, uint16_t length) {
  132. PRIV(g)->write_buffer_offset = offset;
  133. write_page(g, page);
  134. write_data(g, (uint8_t*)PRIV(g), length + 1);
  135. }
  136. LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
  137. // The private area is the display surface.
  138. g->priv = gfxAlloc(sizeof(PrivData));
  139. __builtin_memset(PRIV(g), 0, sizeof(PrivData));
  140. PRIV(g)->page = 0;
  141. // Initialise the board interface
  142. init_board(g);
  143. gfxSleepMilliseconds(10);
  144. // zero function page, all registers (assuming full_page is all zeroes)
  145. write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
  146. set_hardware_shutdown(g, false);
  147. gfxSleepMilliseconds(10);
  148. // software shutdown
  149. write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
  150. gfxSleepMilliseconds(10);
  151. // zero function page, all registers
  152. write_ram(g, IS31_FUNCTIONREG, 0, IS31_FUNCTIONREG_SIZE);
  153. gfxSleepMilliseconds(10);
  154. // zero all LED registers on all 8 pages, and enable the mask
  155. __builtin_memcpy(PRIV(g)->write_buffer, get_led_mask(g), IS31_LED_MASK_SIZE);
  156. for(uint8_t i=0; i<8; i++) {
  157. write_ram(g, i, 0, IS31_FRAME_SIZE);
  158. gfxSleepMilliseconds(1);
  159. }
  160. // software shutdown disable (i.e. turn stuff on)
  161. write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
  162. gfxSleepMilliseconds(10);
  163. // Finish Init
  164. post_init_board(g);
  165. /* Initialise the GDISP structure */
  166. g->g.Width = GDISP_SCREEN_WIDTH;
  167. g->g.Height = GDISP_SCREEN_HEIGHT;
  168. g->g.Orientation = GDISP_ROTATE_0;
  169. g->g.Powermode = powerOn;
  170. g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
  171. g->g.Contrast = GDISP_INITIAL_CONTRAST;
  172. return TRUE;
  173. }
  174. #if GDISP_HARDWARE_FLUSH
  175. LLDSPEC void gdisp_lld_flush(GDisplay *g) {
  176. // Don't flush if we don't need it.
  177. if (!(g->flags & GDISP_FLG_NEEDFLUSH))
  178. return;
  179. PRIV(g)->page++;
  180. PRIV(g)->page %= 2;
  181. // TODO: some smarter algorithm for this
  182. // We should run only one physical page at a time
  183. // This way we don't need to send so much data, and
  184. // we could use slightly less memory
  185. uint8_t* src = PRIV(g)->frame_buffer;
  186. for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) {
  187. for (int x=0;x<GDISP_SCREEN_WIDTH;x++) {
  188. PRIV(g)->write_buffer[get_led_address(g, x, y)]=cie[*src];
  189. ++src;
  190. }
  191. }
  192. write_ram(g, PRIV(g)->page, IS31_PWM_REG, IS31_PWM_SIZE);
  193. gfxSleepMilliseconds(1);
  194. write_register(g, IS31_FUNCTIONREG, IS31_REG_PICTDISP, PRIV(g)->page);
  195. g->flags &= ~GDISP_FLG_NEEDFLUSH;
  196. }
  197. #endif
  198. #if GDISP_HARDWARE_DRAWPIXEL
  199. LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
  200. coord_t x, y;
  201. switch(g->g.Orientation) {
  202. default:
  203. case GDISP_ROTATE_0:
  204. x = g->p.x;
  205. y = g->p.y;
  206. break;
  207. case GDISP_ROTATE_180:
  208. x = GDISP_SCREEN_WIDTH-1 - g->p.x;
  209. y = g->p.y;
  210. break;
  211. }
  212. PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x] = gdispColor2Native(g->p.color);
  213. g->flags |= GDISP_FLG_NEEDFLUSH;
  214. }
  215. #endif
  216. #if GDISP_HARDWARE_PIXELREAD
  217. LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
  218. coord_t x, y;
  219. switch(g->g.Orientation) {
  220. default:
  221. case GDISP_ROTATE_0:
  222. x = g->p.x;
  223. y = g->p.y;
  224. break;
  225. case GDISP_ROTATE_180:
  226. x = GDISP_SCREEN_WIDTH-1 - g->p.x;
  227. y = g->p.y;
  228. break;
  229. }
  230. return gdispNative2Color(PRIV(g)->frame_buffer[y * GDISP_SCREEN_WIDTH + x]);
  231. }
  232. #endif
  233. #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
  234. LLDSPEC void gdisp_lld_control(GDisplay *g) {
  235. switch(g->p.x) {
  236. case GDISP_CONTROL_POWER:
  237. if (g->g.Powermode == (powermode_t)g->p.ptr)
  238. return;
  239. switch((powermode_t)g->p.ptr) {
  240. case powerOff:
  241. case powerSleep:
  242. case powerDeepSleep:
  243. write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF);
  244. break;
  245. case powerOn:
  246. write_register(g, IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
  247. break;
  248. default:
  249. return;
  250. }
  251. g->g.Powermode = (powermode_t)g->p.ptr;
  252. return;
  253. case GDISP_CONTROL_ORIENTATION:
  254. if (g->g.Orientation == (orientation_t)g->p.ptr)
  255. return;
  256. switch((orientation_t)g->p.ptr) {
  257. /* Rotation is handled by the drawing routines */
  258. case GDISP_ROTATE_0:
  259. case GDISP_ROTATE_180:
  260. g->g.Height = GDISP_SCREEN_HEIGHT;
  261. g->g.Width = GDISP_SCREEN_WIDTH;
  262. break;
  263. case GDISP_ROTATE_90:
  264. case GDISP_ROTATE_270:
  265. g->g.Height = GDISP_SCREEN_WIDTH;
  266. g->g.Width = GDISP_SCREEN_HEIGHT;
  267. break;
  268. default:
  269. return;
  270. }
  271. g->g.Orientation = (orientation_t)g->p.ptr;
  272. return;
  273. case GDISP_CONTROL_CONTRAST:
  274. return;
  275. }
  276. }
  277. #endif // GDISP_NEED_CONTROL
  278. #endif // GFX_USE_GDISP