diff --git a/docs/contributors.txt b/docs/contributors.txt index 2586ed61..654e1540 100644 --- a/docs/contributors.txt +++ b/docs/contributors.txt @@ -6,6 +6,8 @@ At this point we want to thank all of these people for their work. NickName RealName Contribution ======== ======== ============ +Mobyfab Fabien Poussin SSD1289 driver + inmarket Andrew Hannam GDISP (restructorizing the entire library) VMT ASYNC and MULTITHREAD implementation diff --git a/docs/releases.txt b/docs/releases.txt index f895106e..47073038 100644 --- a/docs/releases.txt +++ b/docs/releases.txt @@ -4,4 +4,6 @@ *** 0.1.0 *** FIX: removed gdisp and touchpad prefix of driver directories +UPDATE: added SSD1289 driver (by Mobyfab) + diff --git a/drivers/gdisp/SSD1963/gdisp_lld.c b/drivers/gdisp/SSD1963/gdisp_lld.c new file mode 100644 index 00000000..750affc4 --- /dev/null +++ b/drivers/gdisp/SSD1963/gdisp_lld.c @@ -0,0 +1,771 @@ +/* + ChibiOS-LCD-Driver - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS-LCD-Driver. + + ChibiOS-LCD-Driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS-LCD-Driver is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file SSD1963/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "gdisp.h" + +#if HAL_USE_GDISP || defined(__DOXYGEN__) + +/* Include the emulation code for things we don't support */ +#include "gdisp_emulation.c" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if GDISP_NEED_TEXT + #include "gdisp_fonts.h" +#endif + +/* All the board specific code should go in these include file so the driver + * can be ported to another board just by creating a suitable file. + */ +#if defined(BOARD_YOURBOARDNAME) + #include "gdisp_lld_board_yourboardname.h" +#else + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +#include "ssd1963.h" + + +#if defined(LCD_USE_FSMC) +__inline void GDISP_LLD(writeindex)(uint8_t cmd) { + LCD_REG = cmd; +} + +__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) { + LCD_REG = lcdReg; + LCD_RAM = lcdRegValue; +} + +__inline void GDISP_LLD(writedata)(uint16_t data) { + LCD_RAM = data; +} + +__inline uint16_t GDISP_LLD(readdata)(void) { + return (LCD_RAM); +} + +__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) { + LCD_REG = lcdReg; + return (LCD_RAM); +} + +__inline void GDISP_LLD(writestreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START); +} + +__inline void GDISP_LLD(readstreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START); +} + +__inline void GDISP_LLD(writestream)(uint16_t *buffer, uint16_t size) { + uint16_t i; + for(i = 0; i < size; i++) + LCD_RAM = buffer[i]; +} + +__inline void GDISP_LLD(readstream)(uint16_t *buffer, size_t size) { + uint16_t i; + + for(i = 0; i < size; i++) { + buffer[i] = LCD_RAM; + } +} + +#elif defined(LCD_USE_GPIO) + +__inline void GDISP_LLD(writeindex)(uint8_t cmd) { + Set_CS; Set_RS; Set_WR; Clr_RD; + palWritePort(LCD_DATA_PORT, cmd); + Clr_CS; +} + +__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) { + Set_CS; Set_RS; Set_WR; Clr_RD; + palWritePort(LCD_DATA_PORT, lcdReg); + Clr_RS; + palWritePort(LCD_DATA_PORT, lcdRegValue); + Clr_CS; +} +__inline void GDISP_LLD(writedata)(uint16_t data) { + Set_CS; Clr_RS; Set_WR; Clr_RD; + palWritePort(LCD_DATA_PORT, data); + Clr_CS; +} + +__inline uint16_t GDISP_LLD(readdata)(void) { + Set_CS; Clr_RS; Clr_WR; Set_RD; + uint16_t data = palReadPort(LCD_DATA_PORT); + Clr_CS; + return data; +} + +__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) { + Set_CS; Set_RS; Clr_WR; Set_RD; + palWritePort(LCD_DATA_PORT, lcdReg); + Clr_RS; + uint16_t data = palReadPort(LCD_DATA_PORT); + Clr_CS; + return data; +} + +__inline void GDISP_LLD(writestreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START); +} + +__inline void GDISP_LLD(readstreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START); +} + +__inline void GDISP_LLD(writestream)(uint16_t *buffer, uint16_t size) { + uint16_t i; + Set_CS; Clr_RS; Set_WR; Clr_RD; + for(i = 0; i < size; i++) { + Set_WR; + palWritePort(LCD_DATA_PORT, buffer[i]); + Clr_WR; + } + Clr_CS; +} + +__inline void GDISP_LLD(readstream)(uint16_t *buffer, size_t size) { + uint16_t i; + Set_CS; Clr_RS; Clr_WR; Set_RD; + for(i = 0; i < size; i++) { + Set_RD; + buffer[i] = palReadPort(LCD_DATA_PORT); + Clr_RD; + } +} +#endif + +/* ---- Required Routines ---- */ +/* + The following 2 routines are required. + All other routines are optional. +*/ + +/** + * @brief Low level GDISP driver initialisation. + * @return TRUE if successful, FALSE on error. + * + * @notapi + */ +bool_t GDISP_LLD(init)(void) { + /* Initialise your display */ + + /* Initialise the GDISP structure to match */ + GDISP.Width = SCREEN_WIDTH; + GDISP.Height = SCREEN_HEIGHT; + GDISP.Orientation = landscape; + GDISP.Powermode = powerOn; + GDISP.Backlight = 100; + GDISP.Contrast = 50; + +#if defined(LCD_USE_FSMC) + + #if defined(STM32F1XX) || defined(STM32F3XX) + /* FSMC setup for F1/F3 */ + rccEnableAHB(RCC_AHBENR_FSMCEN, 0); + + #elif defined(STM32F4XX) || defined(STM32F2XX) + /* STM32F2-F4 FSMC init */ + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); + #else + #error "FSMC not implemented for this device" + #endif + + /* set pins to FSMC mode */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + + const unsigned char FSMC_Bank = 0; + /* FSMC timing */ + FSMC_Bank1->BTCR[FSMC_Bank+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ + | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ + | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + + #elif defined(LCD_USE_GPIO) + IOBus busCMD = {LCD_CMD_PORT, (1 << LCD_CS) | (1 << LCD_RS) | (1 << LCD_WR) | (1 << LCD_RD), 0}; + IOBus busDATA = {LCD_CMD_PORT, 0xFFFFF, 0}; + palSetBusMode(&busCMD, PAL_MODE_OUTPUT_PUSHPULL); + palSetBusMode(&busDATA, PAL_MODE_OUTPUT_PUSHPULL); + + #else + #error "Please define LCD_USE_FSMC or LCD_USE_GPIO" +#endif + GDISP_LLD(writeindex)(SSD1963_SOFT_RESET); + chThdSleepMicroseconds(100); + + /* Driver PLL config */ + GDISP_LLD(writeindex)(SSD1963_SET_PLL_MN); + GDISP_LLD(writedata)(35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz) + GDISP_LLD(writedata)(2); // SYSclk = PLLclk / 3 (120MHz) + GDISP_LLD(writedata)(4); // Apply calculation bit, else it is ignored + + GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Enable PLL + GDISP_LLD(writedata)(0x01); + chThdSleepMicroseconds(200); + + GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Use PLL + GDISP_LLD(writedata)(0x03); + chThdSleepMicroseconds(200); + + GDISP_LLD(writeindex)(SSD1963_SOFT_RESET); + chThdSleepMicroseconds(100); + + /* Screen size */ + GDISP_LLD(writeindex)(SSD1963_SET_LCD_MODE); +// GDISP_LLD(writedata)(0x0000); + GDISP_LLD(writedata)(0b00011000); + GDISP_LLD(writedata)(0x0000); + GDISP_LLD(writedata)(mHIGH((SCREEN_WIDTH+1))); + GDISP_LLD(writedata)((SCREEN_WIDTH+1)); + GDISP_LLD(writedata)(mHIGH((SCREEN_HEIGHT+1))); + GDISP_LLD(writedata)((SCREEN_HEIGHT+1)); + GDISP_LLD(writedata)(0x0000); + + GDISP_LLD(writeindex)(SSD1963_SET_PIXEL_DATA_INTERFACE); + GDISP_LLD(writedata)(SSD1963_PDI_16BIT565); + + /* LCD Clock specs */ + GDISP_LLD(writeindex)(SSD1963_SET_LSHIFT_FREQ); + GDISP_LLD(writedata)((LCD_FPR >> 16) & 0xFF); + GDISP_LLD(writedata)((LCD_FPR >> 8) & 0xFF); + GDISP_LLD(writedata)(LCD_FPR & 0xFF); + + GDISP_LLD(writeindex)(SSD1963_SET_HORI_PERIOD); + GDISP_LLD(writedata)(mHIGH(SCREEN_HSYNC_PERIOD)); + GDISP_LLD(writedata)(mLOW(SCREEN_HSYNC_PERIOD)); + GDISP_LLD(writedata)(mHIGH((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(mLOW((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(SCREEN_HSYNC_PULSE); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + + GDISP_LLD(writeindex)(SSD1963_SET_VERT_PERIOD); + GDISP_LLD(writedata)(mHIGH(SCREEN_VSYNC_PERIOD)); + GDISP_LLD(writedata)(mLOW(SCREEN_VSYNC_PERIOD)); + GDISP_LLD(writedata)(mHIGH((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(mLOW((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(SCREEN_VSYNC_PULSE); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + + /* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel */ + GDISP_LLD(writeindex)(SSD1963_SET_TEAR_ON); + GDISP_LLD(writedata)(0x0000); + + /* Turn on */ + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON); +#if defined(LCD_USE_FSMC) + /* FSMC delay reduced as the controller now runs at full speed */ + FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_1 | FSMC_BTR1_BUSTURN_0 ; + FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; +#endif + + return TRUE; +} + +void GDISP_LLD(setwindow)(coord_t x0, coord_t y0, coord_t x1, coord_t y1) { + #if GDISP_NEED_VALIDATION + if (x0 >= GDISP.Width || y0 >= GDISP.Height) return; + else if (x1 >= GDISP.Width || y1 >= GDISP.Height) return; + #endif + GDISP_LLD(writeindex)(SSD1963_SET_PAGE_ADDRESS); + GDISP_LLD(writedata)((y0 >> 8) & 0xFF); + GDISP_LLD(writedata)((y0 >> 0) & 0xFF); + GDISP_LLD(writedata)((y1 >> 8) & 0xFF); + GDISP_LLD(writedata)((y1 >> 0) & 0xFF); + GDISP_LLD(writeindex)(SSD1963_SET_COLUMN_ADDRESS); + GDISP_LLD(writedata)((x0 >> 8) & 0xFF); + GDISP_LLD(writedata)((x0 >> 0) & 0xFF); + GDISP_LLD(writedata)((x1 >> 8) & 0xFF); + GDISP_LLD(writedata)((x1 >> 0) & 0xFF); +} + +/** + * @brief Draws a pixel on the display. + * + * @param[in] x X location of the pixel + * @param[in] y Y location of the pixel + * @param[in] color The color of the pixel + * + * @notapi + */ +void GDISP_LLD(drawpixel)(coord_t x, coord_t y, color_t color) { + #if GDISP_NEED_VALIDATION + if (x >= GDISP.Width || y >= GDISP.Height) return; + #endif + + GDISP_LLD(setwindow)(x, y, x, y); + GDISP_LLD(writestreamstart)(); + GDISP_LLD(writedata)(color); +} + +/* ---- Optional Routines ---- */ +/* + All the below routines are optional. + Defining them will increase speed but everything + will work if they are not defined. + If you are not using a routine - turn it off using + the appropriate GDISP_HARDWARE_XXXX macro. + Don't bother coding for obvious similar routines if + there is no performance penalty as the emulation software + makes a good job of using similar routines. + eg. If fillarea() is defined there is little + point in defining clear() unless the + performance bonus is significant. + For good performance it is suggested to implement + fillarea() and blitarea(). +*/ + +#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) + /** + * @brief Clear the display. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] color The color of the pixel + * + * @notapi + */ + void GDISP_LLD(clear)(color_t color) { + GDISP_LLD(fillarea)(0, 0, GDISP.Width-1, GDISP.Height-1, color); + } +#endif + +#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__) + /** + * @brief Draw a line. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] x0, y0 The start of the line + * @param[in] x1, y1 The end of the line + * @param[in] color The color of the line + * + * @notapi + */ + void GDISP_LLD(drawline)(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { + #if GDISP_NEED_VALIDATION + /* Need to clip to screen */ + #endif + /* Code here */ + } +#endif + +#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) + /** + * @brief Fill an area with a color. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] x, y The start filled area + * @param[in] cx, cy The width and height to be filled + * @param[in] color The color of the fill + * + * @notapi + */ + void GDISP_LLD(fillarea)(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { + #if GDISP_NEED_VALIDATION + if (cx < 1 || cy < 1 || x >= GDISP.Width || y >= GDISP.Height) return; + if (x+cx > GDISP.Width) cx = GDISP.Width - x; + if (y+cy > GDISP.Height) cy = GDISP.Height - y; + #endif + + uint32_t index = 0, area; + area = (cx+1)*(cy+1); + + GDISP_LLD(setwindow)(x, y, x+cx, y+cy); + GDISP_LLD(writestreamstart)(); + + for(index = 0; index <= area; index++) + GDISP_LLD(writedata)(color); + + } +#endif + +#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) + /** + * @brief Fill an area with a bitmap. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] x, y The start filled area + * @param[in] cx, cy The width and height to be filled + * @param[in] buffer The pixels to use to fill the area. + * + * @notapi + */ + void GDISP_LLD(blitarea)(coord_t x, coord_t y, coord_t cx, coord_t cy, const pixel_t *buffer) { + #if GDISP_NEED_VALIDATION + if (cx < 1 || cy < 1 || x >= GDISP.Width || y >= GDISP.Height) return; + if (x+cx > GDISP.Width) return; + if (y+cy > GDISP.Height) cy = GDISP.Height - y; + #endif + /* Code here */ + } +#endif + +/* Circular Drawing Functions */ +#if (GDISP_NEED_CIRCLE && GDISP_HARDWARE_CIRCLES) || defined(__DOXYGEN__) + /** + * @brief Draw a circle. + * @note Optional - The high level driver can emulate using software. + * @note If GDISP_NEED_CLIPPING is defined this routine MUST behave + * correctly if the circle is over the edges of the screen. + * + * @param[in] x, y The centre of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color of the circle + * + * @notapi + */ + void GDISP_LLD(drawcircle)(coord_t x, coord_t y, coord_t radius, color_t color) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_CIRCLE && GDISP_HARDWARE_CIRCLEFILLS) || defined(__DOXYGEN__) + /** + * @brief Create a filled circle. + * @note Optional - The high level driver can emulate using software. + * @note If GDISP_NEED_CLIPPING is defined this routine MUST behave + * correctly if the circle is over the edges of the screen. + * + * @param[in] x, y The centre of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color of the circle + * + * @notapi + */ + void GDISP_LLD(fillcircle)(coord_t x, coord_t y, coord_t radius, color_t color) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_ELLIPSE && GDISP_HARDWARE_ELLIPSES) || defined(__DOXYGEN__) + /** + * @brief Draw an ellipse. + * @note Optional - The high level driver can emulate using software. + * @note If GDISP_NEED_CLIPPING is defined this routine MUST behave + * correctly if the ellipse is over the edges of the screen. + * + * @param[in] x, y The centre of the ellipse + * @param[in] a, b The dimensions of the ellipse + * @param[in] color The color of the ellipse + * + * @notapi + */ + void GDISP_LLD(drawellipse)(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_ELLIPSE && GDISP_HARDWARE_ELLIPSEFILLS) || defined(__DOXYGEN__) + /** + * @brief Create a filled ellipse. + * @note Optional - The high level driver can emulate using software. + * @note If GDISP_NEED_CLIPPING is defined this routine MUST behave + * correctly if the ellipse is over the edges of the screen. + * + * @param[in] x, y The centre of the ellipse + * @param[in] a, b The dimensions of the ellipse + * @param[in] color The color of the ellipse + * + * @notapi + */ + void GDISP_LLD(fillellipse)(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_TEXT && GDISP_HARDWARE_TEXT) || defined(__DOXYGEN__) + /** + * @brief Draw a character using a transparent background. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] x, y The top-left corner of the text + * @param[in] c The character to print + * @param[in] color The color of the character + * + * @notapi + */ + void GDISP_LLD(drawchar)(coord_t x, coord_t y, char c, font_t font, color_t color) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_TEXT && GDISP_HARDWARE_TEXTFILLS) || defined(__DOXYGEN__) + /** + * @brief Draw a character using a filled background. + * @note Optional - The high level driver can emulate using software. + * + * @param[in] x, y The top-left corner of the text + * @param[in] c The character to print + * @param[in] color The color of the character + * @param[in] bgcolor The background color + * + * @notapi + */ + void GDISP_LLD(fillchar)(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { + #if GDISP_NEED_VALIDATION + /* Code here */ + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) + /** + * @brief Get the color of a particular pixel. + * @note Optional. + * @note If x,y is off the screen, the result is undefined. + * @return The color of the specified pixel. + * + * @param[in] x, y The start of the text + * + * @notapi + */ + color_t GDISP_LLD(getpixelcolor)(coord_t x, coord_t y) { + #if GDISP_NEED_VALIDATION + if (x >= GDISP.Width || y >= GDISP.Height) return 0; + #endif + /* Code here */ + } +#endif + +#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) + /** + * @brief Scroll vertically a section of the screen. + * @note Optional. + * @note If x,y + cx,cy is off the screen, the result is undefined. + * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. + * + * @param[in] x, y The start of the area to be scrolled + * @param[in] cx, cy The size of the area to be scrolled + * @param[in] lines The number of lines to scroll (Can be positive or negative) + * @param[in] bgcolor The color to fill the newly exposed area. + * + * @notapi + */ + void GDISP_LLD(verticalscroll)(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { + #if GDISP_NEED_VALIDATION + if (cx < 1 || cy < 1 || x >= GDISP.Width || y >= GDISP.Height) return; + if (x+cx > GDISP.Width) cx = GDISP.Width - x; + if (y+cy > GDISP.Height) cy = GDISP.Height - y; + #endif + /* Code here */ + + /* + uint16_t size = x1 - x0 ; + + lld_lcdWriteIndex(SSD1963_SET_SCROLL_AREA); + lld_lcdWriteData((x0 >> 8) & 0xFF); + lld_lcdWriteData((x0 >> 0) & 0xFF); + lld_lcdWriteData((size >> 8) & 0xFF); + lld_lcdWriteData((size >> 0) & 0xFF); + lld_lcdWriteData(((lcd_height-x1) >> 8) & 0xFF); + lld_lcdWriteData(((lcd_height-x1) >> 0) & 0xFF); + + lld_lcdWriteIndex(SSD1963_SET_SCROLL_START); + lld_lcdWriteData((lines >> 8) & 0xFF); + lld_lcdWriteData((lines >> 0) & 0xFF); + */ + } + +#endif + +#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) + /** + * @brief Driver Control + * @detail Unsupported control codes are ignored. + * @note The value parameter should always be typecast to (void *). + * @note There are some predefined and some specific to the low level driver. + * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t + * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t + * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver + * that only supports off/on anything other + * than zero is on. + * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. + * GDISP_CONTROL_LLD - Low level driver control constants start at + * this value. + * + * @param[in] what What to do. + * @param[in] value The value to use (always cast to a void *). + * + * @notapi + */ + void GDISP_LLD(control)(unsigned what, void *value) { + switch(what) { + case GDISP_CONTROL_POWER: + if (GDISP.Powermode == (gdisp_powermode_t)value) + return; + switch((gdisp_powermode_t)value) { + case powerOff: + GDISP_LLD(writeindex)(SSD1963_EXIT_SLEEP_MODE); // leave sleep mode + chThdSleepMicroseconds(5000); + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF); + GDISP_LLD(writeindex)(SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode + break; + case powerOn: + GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000); // 2x Dummy reads to wake up from deep sleep + GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000); + if (GDISP.Powermode != powerSleep) + GDISP_LLD(init)(); + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON); + + break; + case powerSleep: + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF); + GDISP_LLD(writeindex)(SSD1963_ENTER_SLEEP_MODE); // enter sleep mode + chThdSleepMicroseconds(5000); + break; + default: + return; + } + GDISP.Powermode = (gdisp_powermode_t)value; + return; + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + case portrait: + /* Code here */ + GDISP.Height = SCREEN_HEIGHT; + GDISP.Width = SCREEN_WIDTH; + break; + case landscape: + /* Code here */ + GDISP.Height = SCREEN_WIDTH; + GDISP.Width = SCREEN_HEIGHT; + break; + case portraitInv: + /* Code here */ + GDISP.Height = SCREEN_HEIGHT; + GDISP.Width = SCREEN_WIDTH; + break; + case landscapeInv: + /* Code here */ + GDISP.Height = SCREEN_WIDTH; + GDISP.Width = SCREEN_HEIGHT; + break; + default: + return; + } + GDISP.Orientation = (gdisp_orientation_t)value; + return; +/* + case GDISP_CONTROL_BACKLIGHT: + case GDISP_CONTROL_CONTRAST: +*/ + } + } +#endif + +#if (GDISP_NEED_QUERY && GDISP_HARDWARE_QUERY) || defined(__DOXYGEN__) +/** + * @brief Query a driver value. + * @detail Typecase the result to the type you want. + * @note GDISP_QUERY_WIDTH - (coord_t) Gets the width of the screen + * GDISP_QUERY_HEIGHT - (coord_t) Gets the height of the screen + * GDISP_QUERY_POWER - (gdisp_powermode_t) Get the current powermode + * GDISP_QUERY_ORIENTATION - (gdisp_orientation_t) Get the current screen orientation + * GDISP_QUERY_BACKLIGHT - (coord_t) Get the backlight state (0 to 100) + * GDISP_QUERY_CONTRAST - (coord_t) Get the contrast (0 to 100). + * GDISP_QUERY_LLD - Low level driver control constants start at + * this value. + * + * @param[in] what What to Query + * + * @notapi + */ +void *GDISP_LLD(query)(unsigned what) { + switch(what) { + case GDISP_QUERY_WIDTH: return (void *)(unsigned)GDISP.Width; + case GDISP_QUERY_HEIGHT: return (void *)(unsigned)GDISP.Height; + case GDISP_QUERY_POWER: return (void *)(unsigned)GDISP.Powermode; + case GDISP_QUERY_ORIENTATION: return (void *)(unsigned)GDISP.Orientation; + case GDISP_QUERY_BACKLIGHT: return (void *)(unsigned)GDISP.Backlight; + case GDISP_QUERY_CONTRAST: return (void *)(unsigned)GDISP.Contrast; + case GDISP_QUERY_LLD+0: + /* Code here */ + default: return (void *)-1; + } +} +#endif + +#endif /* HAL_USE_GDISP */ +/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld.mk b/drivers/gdisp/SSD1963/gdisp_lld.mk new file mode 100644 index 00000000..26d7a57a --- /dev/null +++ b/drivers/gdisp/SSD1963/gdisp_lld.mk @@ -0,0 +1,5 @@ +# List the required driver. +LCDSRC += $(LCDLIB)/drivers/gdisp/SSD1963/gdisp_lld.c + +# Required include directories +LCDINC += $(LCDLIB)/drivers/gdisp/SSD1963 diff --git a/drivers/gdisp/SSD1963/gdisp_lld_config.h b/drivers/gdisp/SSD1963/gdisp_lld_config.h new file mode 100644 index 00000000..85dd7282 --- /dev/null +++ b/drivers/gdisp/SSD1963/gdisp_lld_config.h @@ -0,0 +1,66 @@ +/* + ChibiOS-LCD-Driver Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS-LCD-Driver. + + ChibiOS-LCD-Driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS-LCD-Driver is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file SSD1963/gdisp_lld_config.h + * @brief GDISP Graphic Driver subsystem low level driver header. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if HAL_USE_GDISP || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_DRIVER_NAME "SSD1963" +#define GDISP_LLD(x) gdisp_lld_##x##_SSD1963 + +#define GDISP_HARDWARE_LINES FALSE +#define GDISP_HARDWARE_CLEARS TRUE +#define GDISP_HARDWARE_FILLS TRUE +#define GDISP_HARDWARE_BITFILLS FALSE +#define GDISP_HARDWARE_CIRCLES FALSE +#define GDISP_HARDWARE_CIRCLEFILLS FALSE +#define GDISP_HARDWARE_ELLIPSES FALSE +#define GDISP_HARDWARE_ELLIPSEFILLS FALSE +#define GDISP_HARDWARE_TEXT FALSE +#define GDISP_HARDWARE_TEXTFILLS FALSE +#define GDISP_HARDWARE_SCROLL FALSE +#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_CONTROL FALSE +#define GDISP_HARDWARE_QUERY FALSE + +#define GDISP_SOFTWARE_TEXTFILLDRAW FALSE +#define GDISP_SOFTWARE_TEXTBLITCOLUMN FALSE + +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_PACKED_PIXELS FALSE +#define GDISP_PACKED_LINES FALSE + +#endif /* HAL_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ +/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld_panel.h b/drivers/gdisp/SSD1963/gdisp_lld_panel.h new file mode 100644 index 00000000..6d13155c --- /dev/null +++ b/drivers/gdisp/SSD1963/gdisp_lld_panel.h @@ -0,0 +1,53 @@ +/* + ChibiOS-LCD-Driver Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS-LCD-Driver. + + ChibiOS-LCD-Driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS-LCD-Driver is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file SSD1963/gdisp_lld_panel.h + * @brief TFT LCD panel properties. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_PANEL_H +#define _GDISP_LLD_PANEL_H + +/* LCD panel specs */ +#define SCREEN_WIDTH 480 +#define SCREEN_HEIGHT 272 + +#define SCREEN_FPS 60ULL + +#define SCREEN_HSYNC_BACK_PORCH 2LL +#define SCREEN_HSYNC_FRONT_PORCH 2ULL +#define SCREEN_HSYNC_PULSE 41ULL + +#define SCREEN_VSYNC_BACK_PORCH 2ULL +#define SCREEN_VSYNC_FRONT_PORCH 2ULL +#define SCREEN_VSYNC_PULSE 10ULL + +#define SCREEN_HSYNC_PERIOD (SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH + SCREEN_WIDTH + SCREEN_HSYNC_FRONT_PORCH) +#define SCREEN_VSYNC_PERIOD (SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH + SCREEN_HEIGHT + SCREEN_VSYNC_FRONT_PORCH) + +#define SCREEN_PCLK (SCREEN_HSYNC_PERIOD * SCREEN_VSYNC_PERIOD * SCREEN_FPS) +#define LCD_FPR ((SCREEN_PCLK * 1048576)/100000000) + +#endif +/** @} */ diff --git a/drivers/gdisp/SSD1963/readme.txt b/drivers/gdisp/SSD1963/readme.txt new file mode 100644 index 00000000..7803cda0 --- /dev/null +++ b/drivers/gdisp/SSD1963/readme.txt @@ -0,0 +1,12 @@ +To use this driver: + +1. Add in your halconf.h: + a) #define HAL_USE_GDISP TRUE + b) Any optional high level driver defines (see gdisp.h) eg: GDISP_NEED_MULTITHREAD + c) One (only) of: + #define LCD_USE_GPIO (Work in progress) + #define LCD_USE_FSMC + d) Edit gdisp_lld_panel.h with your panel properties + +2. To your makefile add the following lines: + include $(LCDLIB)/drivers/gdisp/SSD1963/gdisp_lld.mk \ No newline at end of file diff --git a/drivers/gdisp/SSD1963/ssd1963.h b/drivers/gdisp/SSD1963/ssd1963.h new file mode 100644 index 00000000..198a160b --- /dev/null +++ b/drivers/gdisp/SSD1963/ssd1963.h @@ -0,0 +1,141 @@ +/* + ChibiOS-LCD-Driver - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS-LCD-Driver. + + ChibiOS-LCD-Driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS-LCD-Driver is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file SSD1963/ssd1963.h + * @brief SSD1963 specific data. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef SSD1963_H +#define SSD1963_H + +#include "gdisp_lld_panel.h" + +#if defined(LCD_USE_GPIO) + #define Set_CS palSetPad(LCD_CMD_PORT, LCD_CS); + #define Clr_CS palClearPad(LCD_CMD_PORT, LCD_CS); + #define Set_RS palSetPad(LCD_CMD_PORT, LCD_RS); + #define Clr_RS palClearPad(LCD_CMD_PORT, LCD_RS); + #define Set_WR palSetPad(LCD_CMD_PORT, LCD_WR); + #define Clr_WR palClearPad(LCD_CMD_PORT, LCD_WR); + #define Set_RD palSetPad(LCD_CMD_PORT, LCD_RD); + #define Clr_RD palClearPad(LCD_CMD_PORT, LCD_RD); +#endif + +#if defined(LCD_USE_FSMC) + /* Using FSMC A16 as RS */ + #define LCD_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ + #define LCD_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ +#endif + +#define mHIGH(x) (x >> 8) +#define mLOW(x) (x & 0xFF) + +/* SSD1963 commands */ + +#define SSD1963_NOP 0x0000 +#define SSD1963_SOFT_RESET 0x0001 +#define SSD1963_GET_POWER_MODE 0x000A +#define SSD1963_GET_ADDRESS_MODE 0x000B +#define SSD1963_GET_DISPLAY_MODE 0x000D +#define SSD1963_GET_TEAR_EFFECT_STATUS 0x000E +#define SSD1963_ENTER_SLEEP_MODE 0x0010 +#define SSD1963_EXIT_SLEEP_MODE 0x0011 +#define SSD1963_ENTER_PARTIAL_MODE 0x0012 +#define SSD1963_ENTER_NORMAL_MODE 0x0013 +#define SSD1963_EXIT_INVERT_MODE 0x0020 +#define SSD1963_ENTER_INVERT_MODE 0x0021 +#define SSD1963_SET_GAMMA_CURVE 0x0026 +#define SSD1963_SET_DISPLAY_OFF 0x0028 +#define SSD1963_SET_DISPLAY_ON 0x0029 +#define SSD1963_SET_COLUMN_ADDRESS 0x002A +#define SSD1963_SET_PAGE_ADDRESS 0x002B +#define SSD1963_WRITE_MEMORY_START 0x002C +#define SSD1963_READ_MEMORY_START 0x002E +#define SSD1963_SET_PARTIAL_AREA 0x0030 +#define SSD1963_SET_SCROLL_AREA 0x0033 +#define SSD1963_SET_TEAR_OFF 0x0034 +#define SSD1963_SET_TEAR_ON 0x0035 +#define SSD1963_SET_ADDRESS_MODE 0x0036 +#define SSD1963_SET_SCROLL_START 0x0037 +#define SSD1963_EXIT_IDLE_MODE 0x0038 +#define SSD1963_ENTER_IDLE_MODE 0x0039 +#define SSD1963_SET_PIXEL_FORMAT 0x003A +#define SSD1963_WRITE_MEMORY_CONTINUE 0x003C +#define SSD1963_READ_MEMORY_CONTINUE 0x003E +#define SSD1963_SET_TEAR_SCANLINE 0x0044 +#define SSD1963_GET_SCANLINE 0x0045 +#define SSD1963_READ_DDB 0x00A1 +#define SSD1963_SET_LCD_MODE 0x00B0 +#define SSD1963_GET_LCD_MODE 0x00B1 +#define SSD1963_SET_HORI_PERIOD 0x00B4 +#define SSD1963_GET_HORI_PERIOD 0x00B5 +#define SSD1963_SET_VERT_PERIOD 0x00B6 +#define SSD1963_GET_VERT_PERIOD 0x00B7 +#define SSD1963_SET_GPIO_CONF 0x00B8 +#define SSD1963_GET_GPIO_CONF 0x00B9 +#define SSD1963_SET_GPIO_VALUE 0x00BA +#define SSD1963_GET_GPIO_STATUS 0x00BB +#define SSD1963_SET_POST_PROC 0x00BC +#define SSD1963_GET_POST_PROC 0x00BD +#define SSD1963_SET_PWM_CONF 0x00BE +#define SSD1963_GET_PWM_CONF 0x00BF +#define SSD1963_GET_LCD_GEN0 0x00C0 +#define SSD1963_SET_LCD_GEN0 0x00C1 +#define SSD1963_GET_LCD_GEN1 0x00C2 +#define SSD1963_SET_LCD_GEN1 0x00C3 +#define SSD1963_GET_LCD_GEN2 0x00C4 +#define SSD1963_SET_LCD_GEN2 0x00C5 +#define SSD1963_GET_LCD_GEN3 0x00C6 +#define SSD1963_SET_LCD_GEN3 0x00C7 +#define SSD1963_SET_GPIO0_ROP 0x00C8 +#define SSD1963_GET_GPIO0_ROP 0x00C9 +#define SSD1963_SET_GPIO1_ROP 0x00CA +#define SSD1963_GET_GPIO1_ROP 0x00CB +#define SSD1963_SET_GPIO2_ROP 0x00CC +#define SSD1963_GET_GPIO2_ROP 0x00CD +#define SSD1963_SET_GPIO3_ROP 0x00CE +#define SSD1963_GET_GPIO3_ROP 0x00CF +#define SSD1963_SET_DBC_CONF 0x00D0 +#define SSD1963_GET_DBC_CONF 0x00D1 +#define SSD1963_SET_DBC_TH 0x00D4 +#define SSD1963_GET_DBC_TH 0x00D5 +#define SSD1963_SET_PLL 0x00E0 +#define SSD1963_SET_PLL_MN 0x00E2 +#define SSD1963_GET_PLL_MN 0x00E3 +#define SSD1963_GET_PLL_STATUS 0x00E4 +#define SSD1963_SET_DEEP_SLEEP 0x00E5 +#define SSD1963_SET_LSHIFT_FREQ 0x00E6 +#define SSD1963_GET_LSHIFT_FREQ 0x00E7 +#define SSD1963_SET_PIXEL_DATA_INTERFACE 0x00F0 + #define SSD1963_PDI_8BIT 0 + #define SSD1963_PDI_12BIT 1 + #define SSD1963_PDI_16BIT 2 + #define SSD1963_PDI_16BIT565 3 + #define SSD1963_PDI_18BIT 4 + #define SSD1963_PDI_24BIT 5 + #define SSD1963_PDI_9BIT 6 +#define SSD1963_GET_PIXEL_DATA_INTERFACE 0x00F1 + +#endif +/** @} */ diff --git a/src/gdisp.c b/src/gdisp.c index f5da45b9..c3b83214 100644 --- a/src/gdisp.c +++ b/src/gdisp.c @@ -659,6 +659,89 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } } +/* + * @brief Internal helper function for gdispDrawArc() + * + * @note DO NOT USE DIRECTLY! + * + * @param[in] x, y The middle point of the arc + * @param[in] start The start angle of the arc + * @param[in] end The end angle of the arc + * @param[in] radius The radius of the arc + * @param[in] color The color in which the arc will be drawn + * + * @notapi + */ +void _draw_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) { + if (start >= 0 && start <= 180) { + float x_maxI = x + radius*cos(start*M_PI/180); + float x_minI; + + if (end > 180) + x_minI = x - radius; + else + x_minI = x + radius*cos(end*M_PI/180); + + int a = 0; + int b = radius; + int P = 1 - radius; + + do { + if(x-a <= x_maxI && x-a >= x_minI) + gdispDrawPixel(x-a, y+b, color); + if(x+a <= x_maxI && x+a >= x_minI) + gdispDrawPixel(x+a, y+b, color); + if(x-b <= x_maxI && x-b >= x_minI) + gdispDrawPixel(x-b, y+a, color); + if(x+b <= x_maxI && x+b >= x_minI) + gdispDrawPixel(x+b, y+a, color); + + if (P < 0) { + P = P + 3 + 2*a; + a = a + 1; + } else { + P = P + 5 + 2*(a - b); + a = a + 1; + b = b - 1; + } + } while(a <= b); + } + + if (end > 180 && end <= 360) { + float x_maxII = x+radius*cos(end*M_PI/180); + float x_minII; + + if(start <= 180) + x_minII = x - radius; + else + x_minII = x+radius*cos(start*M_PI/180); + + int a = 0; + int b = radius; + int P = 1 - radius; + + do { + if(x-a <= x_maxII && x-a >= x_minII) + gdispDrawPixel(x-a, y-b, color); + if(x+a <= x_maxII && x+a >= x_minII) + gdispDrawPixel(x+a, y-b, color); + if(x-b <= x_maxII && x-b >= x_minII) + gdispDrawPixel(x-b, y-a, color); + if(x+b <= x_maxII && x+b >= x_minII) + gdispDrawPixel(x+b, y-a, color); + + if (P < 0) { + P = P + 3 + 2*a; + a = a + 1; + } else { + P = P + 5 + 2*(a - b); + a = a + 1; + b = b - 1; + } + } while (a <= b); + } +} + /* * @brief Draw an arc. * @pre The GDISP must be in powerOn or powerSleep mode. @@ -672,12 +755,11 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { * @api */ void gdispDrawArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) { - uint16_t i; - float step = 0.01; - - for(i = 0; i <= (int)((abs(end-start)) / step); i++) { - gdispDrawPixel( ((float)x + (float)radius * cosf((float)start * M_PI / 180.0f) + (float)i * step * M_PI / 180.0f), - ((float)y + (float)radius * sinf((float)start * M_PI / 180.0f) + (float)i * step * M_PI / 180.0f), color); + if(end < start) { + _draw_arc(x, y, start, 360, radius, color); + _draw_arc(x, y, 0, end, radius, color); + } else { + _draw_arc(x, y, start, end, radius, color); } } @@ -694,7 +776,13 @@ void gdispDrawArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t * @api */ void gdispFillArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) { - + /* ToDo */ + (void)x; + (void)y; + (void)radius; + (void)start; + (void)end; + (void)color; } #if GDISP_NEED_TEXT || defined(__DOXYGEN__)