/* * 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 */ /* Robert Offner 2017 * This is a driver for the RA6963 or T6963 Displays. * It should work with displays up to 240 pixel in width and 64 pixel in height * ATTENTION some newer displays on ebay look like T6963 Type but they're not! * They use a new controller: ST7920. These are easy to identify: NO CS pin but * a PSB Pin which switches from parallel to serial communication mode. * If it cost less than 10.- it is probably a ST7920. * * Version: 0.1 * * History: * * v0.1 Initial Release * .) tested with readback and without on a 72MHz STM32F103. Display ws a 128x64 * type Graphic LCD (Looks like KS0108 Types). STREAM_READ is not implemented. */ #include "gfx.h" #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_RA6963 #include "gdisp_lld_config.h" #include "src/gdisp/gdisp_driver.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GISP_SCREEN_HEIGHT #endif #if defined(GDISP_SCREEN_WIDTH) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_WIDTH #endif #include "board_RA6963.h" // RA6963 Commands //Register Setting #define RA6963_SET_CURSOR_POINTER 0x21 #define RA6963_SET_OFFSET_REGISTER 0x22 #define RA6963_SET_ADDRESS_POINTER 0x24 //Set Control Word #define RA6963_SET_TEXT_HOME_ADDRESS 0x40 #define RA6963_SET_TEXT_AREA 0x41 #define RA6963_SET_GRAPHIC_HOME_ADDRESS 0x42 #define RA6963_SET_GRAPHIC_AREA 0x43 //Mode Set #define RA6963_MODE_SET 0x80 #define RA6963_MODE_OR 0x00 #define RA6963_MODE_XOR 0x01 #define RA6963_MODE_AND 0x03 #define RA6963_MODE_TEXT_ATTRIBUTE 0x04 #define RA6963_MODE_INTERNAL_CGROM 0x00 #define RA6963_MODE_EXTERNAL_CGRAM 0x08 //Display Mode #define RA6963_DISPLAY_MODE 0x90 #define RA6963_CURSOR_BLINK_ON 0x01 #define RA6963_CURSOR_DISPLAY_ON 0x02 #define RA6963_TEXT_DISPLAY_ON 0x04 #define RA6963_GRAPHIC_DISPLAY_ON 0x08 //Cursor Pattern Select #define RA6963_CURSOR_PATTERN_SELECT 0xA0 #define RA6963_CURSOR_1_LINE 0x00 #define RA6963_CURSOR_2_LINE 0x01 #define RA6963_CURSOR_3_LINE 0x02 #define RA6963_CURSOR_4_LINE 0x03 #define RA6963_CURSOR_5_LINE 0x04 #define RA6963_CURSOR_6_LINE 0x05 #define RA6963_CURSOR_7_LINE 0x06 #define RA6963_CURSOR_8_LINE 0x07 //Data Read/Write #define RA6963_DATA_WRITE_AND_INCREMENT 0xC0 #define RA6963_DATA_READ_AND_INCREMENT 0xC1 #define RA6963_DATA_WRITE_AND_DECREMENT 0xC2 #define RA6963_DATA_READ_AND_DECREMENT 0xC3 #define RA6963_DATA_WRITE_AND_NONVARIALBE 0xC4 #define RA6963_DATA_READ_AND_NONVARIABLE 0xC5 //Data auto Read/Write #define RA6963_SET_DATA_AUTO_WRITE 0xB0 #define RA6963_SET_DATA_AUTO_READ 0xB1 #define RA6963_AUTO_RESET 0xB2 //Screen Peek #define RA6963_SCREEN_PEEK 0xE0 //Screen copy #define RA6963_SCREEN_COPY 0xE8 // Status Register Bits #define RA6963_STATUS_BUSY1 0x01 #define RA6963_STATUS_BUSY2 0x02 #define RA6963_STATUS_DARRDY 0x04 #define RA6963_STATUS_DAWRDY 0x08 #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 64 #endif #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 128 #endif #define RA6963_FONT_WIDTH 8 #define RA6963_GRAPHIC_AREA (GDISP_SCREEN_WIDTH / RA6963_FONT_WIDTH) //16 #define RA6963_TEXT_AREA (GDISP_SCREEN_WIDTH / RA6963_FONT_WIDTH) //16 #define RA6963_GRAPHIC_SIZE (RA6963_GRAPHIC_AREA * GDISP_SCREEN_HEIGHT) //1024 #define RA6963_TEXT_SIZE (RA6963_TEXT_AREA * (GDISP_SCREEN_HEIGHT/8))//128 //#define RA6963_TEXT_HOME 0 //#define RA6963_GRAPHIC_HOME (RA6963_TEXT_HOME + RA6963_TEXT_SIZE) //128 #define RA6963_GRAPHIC_HOME 0 #define RA6963_TEXT_HOME (RA6963_GRAPHIC_HOME + RA6963_GRAPHIC_SIZE) //#define RA6963_OFFSET_REGISTER 2 #if (RA6963_NEED_READ == FALSE) #define BUFFSZ (RA6963_GRAPHIC_SIZE) #define RAM(g) ((uint8_t *)g->priv) #define POS (((g->p.x) / RA6963_FONT_WIDTH) + ((g->p.y) * RA6963_GRAPHIC_AREA)) #endif #ifndef GDISP_INITIAL_CONTRAST #define GDISP_INITIAL_CONTRAST 50 #endif #ifndef GDISP_INITIAL_BACKLIGHT #define GDISP_INITIAL_BACKLIGHT 100 #endif /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ #ifndef write_data_repeat #define write_data_repeat(g, data, count) { int i; for (i = 0; i < count; ++i) write_data (g, data); } #endif /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if (RA6963_NEED_READ == FALSE) // The private area is the display surface. g->priv = gfxAlloc(BUFFSZ); #else g->priv = 0; #endif // Initialise the board interface init_board(g); #if RA6963_HAS_RESET //Make Hardware Reset setpin_reset(g, TRUE); gfxSleepMilliseconds(100); setpin_reset(g, FALSE); #endif gfxSleepMilliseconds(50); //RA6963 needs Data first THEN command! write_data(g, (uint8_t)RA6963_GRAPHIC_HOME); //0 write_data(g, (uint8_t)(RA6963_GRAPHIC_HOME>>8)); //0 write_cmd(g, RA6963_SET_GRAPHIC_HOME_ADDRESS); //0x42 write_data(g, (uint8_t)RA6963_GRAPHIC_AREA); //16 write_data(g, 0); //0 write_cmd(g, RA6963_SET_GRAPHIC_AREA); //0x43 write_data(g, (uint8_t)RA6963_TEXT_HOME); //0x00 write_data(g, (uint8_t)(RA6963_TEXT_HOME>>8)); //0x04 = 0x400 write_cmd(g, RA6963_SET_TEXT_HOME_ADDRESS); //0x40 write_data(g, (uint8_t)RA6963_TEXT_AREA); //16 write_data(g, (uint8_t)(RA6963_TEXT_AREA>>8)); //0 write_cmd(g, RA6963_SET_TEXT_AREA); //0x41 /* write_data(g, (uint8_t)RA6963_OFFSET_REGISTER); write_data(g, 0); write_cmd(g, RA6963_SET_OFFSET_REGISTER);*/ write_data(g, 0x00); write_data(g, 0x00); write_cmd(g, RA6963_SET_ADDRESS_POINTER); write_data(g, 0x00); write_data(g, 0x00); write_cmd(g, RA6963_SET_CURSOR_POINTER); //write_cmd(g, RA6963_CURSOR_PATTERN_SELECT | RA6963_CURSOR_1_LINE); write_cmd(g, RA6963_MODE_SET | RA6963_MODE_OR); //write_cmd(g, RA6963_DISPLAY_MODE | RA6963_TEXT_DISPLAY_ON | RA6963_GRAPHIC_DISPLAY_ON); write_cmd(g, RA6963_DISPLAY_MODE | RA6963_GRAPHIC_DISPLAY_ON); // Finish Init post_init_board(g); #if RA6963_NEED_BACKLIGHT // Turn on the back-light set_backlight(g, GDISP_INITIAL_BACKLIGHT); #endif // 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 = GDISP_INITIAL_BACKLIGHT; g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } static void set_viewport(GDisplay *g) { if ((g->p.x >= GDISP_SCREEN_WIDTH) || (g->p.y >= GDISP_SCREEN_HEIGHT)) return; // 0 + ( x / 8 ) + ( y * 16 ) //uint16_t addr = (RA6963_GRAPHIC_HOME + ((g->p.x) / RA6963_FONT_WIDTH) + ((g->p.y) * RA6963_GRAPHIC_AREA)); uint16_t addr = (RA6963_GRAPHIC_HOME + ((g->p.x >> 3) + (g->p.y << 4))); #warning "check function set_viewport about the shift operations if you change the resolution!" write_data(g, (uint8_t)addr); write_data(g, (uint8_t)(addr>>8)); write_cmd(g, RA6963_SET_ADDRESS_POINTER); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { uint8_t temp; #if (RA6963_NEED_READ == FALSE) temp = RAM(g)[POS]; #else temp = read_data(g); #endif if (g->p.color != White) { temp |= (1 << (RA6963_FONT_WIDTH - 1 - ((g->p.x) % RA6963_FONT_WIDTH))); } else { temp &= ~(1 << (RA6963_FONT_WIDTH - 1 - ((g->p.x) % RA6963_FONT_WIDTH))); } write_data(g, temp); #if (RA6963_NEED_READ == FALSE) RAM(g)[POS] = temp; #endif //write_cmd(g, RA6963_DATA_WRITE_AND_INCREMENT); write_cmd(g, RA6963_DATA_WRITE_AND_NONVARIALBE); } LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { set_viewport(g); gdisp_lld_write_color(g); } #if GDISP_HARDWARE_STREAM_WRITE LLDSPEC void gdisp_lld_write_start(GDisplay *g) { //acquire_bus(g); set_viewport(g); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { //release_bus(g); } #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDisplay *g) { acquire_bus(g); set_viewport(g); setreadmode(g); dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { uint16_t data; data = read_data(g); return gdispNative2Color(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); release_bus(g); } #endif #if GDISP_HARDWARE_FILLS LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { uint8_t data, j; set_viewport(g); if (g->p.color != White) { data = 0xFF; // set dot } else { data = 0; // clr dot } for (j=0; j < (g->p.cy)/8; j++) { write_data_repeat(g, data, (g->p.cx)); (g->p.cy) +=8; set_viewport(g); } } #endif // GDISP_HARDWARE_FILLS #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; switch((powermode_t)g->p.ptr) { case powerOff: acquire_bus(g); write_index(g, 0x28); gfxSleepMilliseconds(10); write_index(g, 0x10); release_bus(g); break; case powerOn: acquire_bus(g); write_index(g, 0x11); gfxSleepMilliseconds(120); write_index(g, 0x29); release_bus(g); if (g->g.Powermode != powerSleep) gdisp_lld_init(g); break; case powerSleep: acquire_bus(g); write_index(g, 0x28); gfxSleepMilliseconds(10); write_index(g, 0x10); release_bus(g); break; default: return; } g->g.Powermode = (powermode_t)g->p.ptr; return; case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: acquire_bus(g); write_index(g, 0x36); write_data(g, 0x08); release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: acquire_bus(g); write_index(g, 0x36); write_data(g, 0x68); release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: acquire_bus(g); write_index(g, 0x36); write_data(g, 0xC8); release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: acquire_bus(g); write_index(g, 0x36); write_data(g, 0xA8); release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; } g->g.Orientation = (orientation_t)g->p.ptr; return; default: return; } } #endif #endif /* GFX_USE_GDISP */