123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- /*
- * This file is subject to the terms of the GFX License. If a copy of
- * the license was not distributed with this file, you can obtain one at:
- *
- * http://ugfx.org/license.html
- */
- #include "gfx.h"
- #if GFX_USE_GDISP
- #define GDISP_DRIVER_VMT GDISPVMT_UC8173
- #include "gdisp_lld_config.h"
- #include "../../../src/gdisp/gdisp_driver.h"
- #include "UC8173.h"
- #include "board_UC8173.h"
- #if defined(GDISP_SCREEN_HEIGHT) || defined(GDISP_SCREEN_HEIGHT)
- #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
- #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored."
- #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
- COMPILER_WARNING("GDISP: This low level driver does not support setting a screen size. It is being ignored.")
- #endif
- #undef GDISP_SCREEN_WIDTH
- #undef GDISP_SCREEN_HEIGHT
- #endif
- #define GDISP_SCREEN_HEIGHT 240
- #define GDISP_SCREEN_WIDTH 240
- #define PRIV(g) ((UC8173_Private*)((g)->priv))
- #define FRAMEBUFFER(g) ((uint8_t *)(PRIV(g)+1))
- #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER << 0)
- #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_MONO
- #define LINE_BYTES (GDISP_SCREEN_WIDTH/8)
- #define WRITEBUFCMD DTM4
- #define xyaddr(x, y) (((x)>>3) + ((y) * LINE_BYTES))
- //#define xybit(x, c) ((c) << ((x) & 7)) // This one has the wrong order of the pixels inside the byte
- #define xybit(x, c) ((c) << (7-((x) & 7)))
- #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_GRAY4
- #define LINE_BYTES (GDISP_SCREEN_WIDTH/4)
- #define WRITEBUFCMD DTM2 // NOT SURE THIS IS RIGHT - MAY NEED TO USE DTM0 and then send a refresh???
- #define xyaddr(x, y) (((x)>>2) + ((y) * LINE_BYTES))
- //#define xybit(x, c) ((c) << (((x) & 3)<<1)) // This one has the wrong order of the pixels inside the byte
- #define xybit(x, c) ((c) << (6-((x) & 3)<<1))
- #else
- #error "UC8173: Unsupported driver color format"
- #endif
- typedef struct UC8173_Private {
- coord_t flushWindowX;
- coord_t flushWindowY;
- coord_t flushWindowWidth;
- coord_t flushWindowHeight;
- } UC8173_Private;
- // This function rounds a given integer up to a specified multiple. Note, multiple must be a power of 2!
- static GFXINLINE void _roundUp(coord_t* numToRound, uint8_t multiple)
- {
- *numToRound = (*numToRound + multiple - 1) & ~(multiple - 1);
- }
- static GFXINLINE void _wait_for_busy_high(GDisplay* g)
- {
- while (!getpin_busy(g));
- }
- static GFXINLINE void _wait_for_busy_low(GDisplay* g)
- {
- while (getpin_busy(g));
- }
- void _load_lut(GDisplay* g, uint32_t lutRegister, const uint8_t* lut, uint32_t lutCounter)
- {
- uint32_t i;
- write_cmd(g, lutRegister);
- for (i = 0; i < lutCounter; i++) {
- write_data(g, *lut);
- lut++;
- }
- }
- static void _upload_lut(GDisplay* g)
- {
- _load_lut(g, LUT_KWVCOM, _lut_KWvcom_DC_A2_240ms, 32);
- _load_lut(g, LUT_KW, _lut_kw_A2_240ms, 512);
- _load_lut(g, LUT_FT, _lut_ft, 128);
- }
- static void _clear_lut(GDisplay* g)
- {
- write_cmd(g, PON);
- _wait_for_busy_high(g);
- _load_lut(g, LUT_KW, _lut_None, 42);
- _load_lut(g, LUT_KWVCOM, _lut_None, 42);
- write_cmd(g, POF);
- _wait_for_busy_low(g);
- }
- #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
- static void _invertFramebuffer(GDisplay* g)
- {
- uint32_t i;
- for (i = 0; i < LINE_BYTES*GDISP_SCREEN_HEIGHT; i++) {
- FRAMEBUFFER(g)[i] = ~(FRAMEBUFFER(g)[i]);
- }
-
- // We should flush these changes to the display controller framebuffer at some point
- g->flags |= GDISP_FLG_NEEDFLUSH;
- }
- #endif
- LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
- {
- // Allocate the private area plus the framebuffer
- g->priv = gfxAlloc(sizeof(UC8173_Private) + LINE_BYTES*GDISP_SCREEN_HEIGHT);
- if (!g->priv) {
- return FALSE;
- }
- // Initialize the private area
- PRIV(g)->flushWindowX = 0;
- PRIV(g)->flushWindowY = 0;
- PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH;
- PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT;
- // Initialise the board interface
- if (!init_board(g)) {
- return FALSE;
- }
- // Hardware reset
- setpin_reset(g, FALSE);
- gfxSleepMilliseconds(100);
- setpin_reset(g, TRUE);
- gfxSleepMilliseconds(1000);
- // Acquire the bus
- acquire_bus(g);
- // Booster soft-start
- write_cmd(g, BTST);
- write_data(g, 0x17); //0x17
- write_data(g, 0x97); //0x97
- write_data(g, 0x20); //0x20
-
- // Power settings
- write_cmd(g, PWR);
- write_data(g, 0x03);
- write_data(g, 0x00);
- write_data(g, 0x2B); //1C 2B
- write_data(g, 0x2B); //1C 2B
- write_data(g, 0x00);
- // Power-on
- write_cmd(g, PON);
- _wait_for_busy_high(g);
- // Panel setting register
- write_cmd(g, PSR);
- write_data(g, 0x0F); //0x0B
- write_data(g, 0x86); //0x86
- // Power-off sequence
- write_cmd(g, PFS);
- write_data(g, 0x00);
- // PLL control
- write_cmd(g, LPRD);
- write_data(g, 0x25);
- // Internal temperature sensor enable
- write_cmd(g, TSE);
- write_data(g, 0x00); // Use internal temperature sensor
- // VCOM and data interval settings
- write_cmd(g, CDI);
- write_data(g, 0xE1);
- write_data(g, 0x20);
- write_data(g, 0x10);
-
- // Set display panel resolution
- write_cmd(g, TRES);
- write_data(g, 0xEF);
- write_data(g, 0x00);
- write_data(g, 0xEF);
- // Undocumented register, taken from sample code
- write_cmd(g, GDS);
- write_data(g, 0xA9);
- write_data(g, 0xA9);
- write_data(g, 0xEB);
- write_data(g, 0xEB);
- write_data(g, 0x02);
- // Auto measure VCOM
- write_cmd(g, AMV);
- write_data(g, 0x11); // 5 seconds, enabled
- _wait_for_busy_high(g);
- // Get current VCOM value
- // write_cmd(g, VV);
- // unsigned char vcom_temp = spi_9b_get();
- // vcom_temp = vcom_temp + 4;
- // Auto_VCOM = vcom_temp;
- // VCM_DC setting
- write_cmd(g, VDCS);
- write_data(g, 0x12); // Write vcom_temp here
-
- // Undocumented register, taken from sample code
- write_cmd(g, VBDS);
- write_data(g, 0x22);
-
- // Undocumented register, taken from sample code
- write_cmd(g, LVSEL);
- write_data(g, 0x02);
-
- // Undocumented register, taken from sample code
- write_cmd(g, GBS);
- write_data(g, 0x02);
- write_data(g, 0x02);
-
- // Undocumented register, taken from sample code
- write_cmd(g, GSS);
- write_data(g, 0x02);
- write_data(g, 0x02);
-
- // Undocumented register, taken from sample code
- write_cmd(g, DF); // For REGAL (???)
- write_data(g, 0x1F);
-
- // Clear the look-up table
- _clear_lut(g);
-
- // Finish Init
- post_init_board(g);
- // Release the bus
- release_bus(g);
- // Initialise the GDISP structure
- g->g.Width = GDISP_SCREEN_WIDTH;
- g->g.Height = GDISP_SCREEN_HEIGHT;
- g->g.Orientation = GDISP_ROTATE_0;
- g->g.Powermode = powerOn;
- g->g.Backlight = 0;
- g->g.Contrast = 0;
- return TRUE;
- }
- #if GDISP_HARDWARE_FLUSH
- LLDSPEC void gdisp_lld_flush(GDisplay* g)
- {
- coord_t y;
- // Don't flush unless we really need to
- if (!(g->flags & GDISP_FLG_NEEDFLUSH)) {
- return;
- }
-
- // Round the flushing window width and height up to the next multiple of four
- _roundUp(&(PRIV(g)->flushWindowWidth), 4);
- _roundUp(&(PRIV(g)->flushWindowWidth), 4);
- // Acquire the bus to communicate with the display controller
- acquire_bus(g);
-
- // Upload the new temperature LUT
- _upload_lut(g);
- // Setup the window
- write_cmd(g, DTMW);
- write_data(g, (uint8_t)((PRIV(g)->flushWindowX >> 0) & 0xFF));
- write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 8) & 0x03));
- write_data(g, (uint8_t)((PRIV(g)->flushWindowY >> 0) & 0xFF));
- write_data(g, (uint8_t)((((PRIV(g)->flushWindowWidth)-1) >> 0) & 0xFF));
- write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 8) & 0x03));
- write_data(g, (uint8_t)((((PRIV(g)->flushWindowHeight)-1) >> 0) & 0xFF));
- // Dump our framebuffer
- // Note: The display controller doesn't allow changing the vertical scanning direction
- // so we have to manually send the lines "the other way around" here.
- write_cmd(g, WRITEBUFCMD);
- for (y = GDISP_SCREEN_HEIGHT-1; y >= 0; y--) {
- write_data_burst(g, FRAMEBUFFER(g)+y*LINE_BYTES, LINE_BYTES);
- }
- // Power-up the DC/DC converter to update the display panel
- write_cmd(g, PON);
- _wait_for_busy_high(g);
- // Refresh the panel contents
- write_cmd(g, DRF);
- write_data(g, 0x00); // Enable REGAL function
- write_data(g, 0x00);
- write_data(g, 0x00);
- write_data(g, 0x00);
- write_data(g, 0xEF);
- write_data(g, 0x00);
- write_data(g, 0xEF);
- _wait_for_busy_high(g);
- // Power-down the DC/DC converter to make all the low-power pussys happy
- write_cmd(g, POF);
- _wait_for_busy_low(g);
- // Release the bus again
- release_bus(g);
- // Clear the 'need-flushing' flag
- g->flags &=~ GDISP_FLG_NEEDFLUSH;
- }
- #endif
- #if GDISP_HARDWARE_DRAWPIXEL
- LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g)
- {
- coord_t x, y;
- LLDCOLOR_TYPE *p;
- // Handle the different possible orientations
- switch(g->g.Orientation) {
- default:
- case GDISP_ROTATE_0:
- x = g->p.x;
- y = g->p.y;
- break;
- case GDISP_ROTATE_90:
- x = g->p.y;
- y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
- break;
- case GDISP_ROTATE_180:
- x = GDISP_SCREEN_WIDTH-1 - g->p.x;
- y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
- break;
- case GDISP_ROTATE_270:
- x = GDISP_SCREEN_WIDTH-1 - g->p.y;
- y = g->p.x;
- break;
- }
-
- // Modify the framebuffer content
- p = &FRAMEBUFFER(g)[xyaddr(x,y)];
- *p &=~ xybit(x, LLDCOLOR_MASK());
- *p |= xybit(x, gdispColor2Native(g->p.color));
- // ToDo
- // There appears to be an issue in the silicone, still talking to the manufacturer about this one. Update will follow!
- #if 0
- // Update the flush window region
- if (g->flags & GDISP_FLG_NEEDFLUSH) {
- if (x < PRIV(g)->flushWindowX)
- PRIV(g)->flushWindowX = x;
- if (y < PRIV(g)->flushWindowY)
- PRIV(g)->flushWindowY = y;
- if (x > PRIV(g)->flushWindowX + PRIV(g)->flushWindowWidth)
- PRIV(g)->flushWindowWidth =
- } else {
- PRIV(g)->flushWindowX = x;
- PRIV(g)->flushWindowY = y;
- PRIV(g)->flushWindowWidth = 1;
- PRIV(g)->flushWindowHeight = 1;
- }
- #else
- PRIV(g)->flushWindowX = 0;
- PRIV(g)->flushWindowY = 0;
- PRIV(g)->flushWindowWidth = GDISP_SCREEN_WIDTH;
- PRIV(g)->flushWindowHeight = GDISP_SCREEN_HEIGHT;
- #endif
- // We should flush these changes to the display controller framebuffer at some point
- g->flags |= GDISP_FLG_NEEDFLUSH;
- }
- #endif
-
- #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
- LLDSPEC void gdisp_lld_control(GDisplay* g) {
- switch(g->p.x) {
- case GDISP_CONTROL_INVERT:
- _invertFramebuffer(g);
- break;
-
- default:
- break;
- }
- }
- #endif
- #endif // GFX_USE_GDISP
|