diff --git a/include/lv_drv_conf.h b/include/lv_drv_conf.h new file mode 100644 index 00000000..797d8e1c --- /dev/null +++ b/include/lv_drv_conf.h @@ -0,0 +1,357 @@ +/** + * @file lv_drv_conf.h + * + */ + +#if 1 /*Set it to "1" to enable the content*/ + +#ifndef LV_DRV_CONF_H +#define LV_DRV_CONF_H + +#include "lv_conf.h" + +/********************* + * DELAY INTERFACE + *********************/ +#define LV_DRV_DELAY_INCLUDE /*Dummy include by default*/ +#define LV_DRV_DELAY_US(us) delayMicroseconds(ud) /*Delay the given number of microseconds*/ +#define LV_DRV_DELAY_MS(ms) delay(ms) /*Delay the given number of milliseconds*/ + +/********************* + * DISPLAY INTERFACE + *********************/ + +/*------------ + * Common + *------------*/ +#define LV_DRV_DISP_INCLUDE /*Dummy include by default*/ +#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/ +#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ + +/*--------- + * SPI + *---------*/ +#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ +#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/ +#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/ + +/*------------------ + * Parallel port + *-----------------*/ +#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/ +#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/ +#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/ +#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/ +#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/ + +/*************************** + * INPUT DEVICE INTERFACE + ***************************/ + +/*---------- + * Common + *----------*/ +#define LV_DRV_INDEV_INCLUDE /*Dummy include by default*/ +#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ +#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/ + +/*--------- + * SPI + *---------*/ +#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ +#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/ + +/*--------- + * I2C + *---------*/ +#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/ +#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/ +#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/ +#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/ +#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/ + +/********************* + * DISPLAY DRIVERS + *********************/ +#define USE_TFT_ESPI 1 +#define USE_FSMC_ILI9341 1 + +/*------------------- + * Monitor of PC + *-------------------*/ +#ifndef USE_MONITOR +#define USE_MONITOR 0 +#endif + +#if USE_MONITOR +#define MONITOR_HOR_RES LV_HOR_RES +#define MONITOR_VER_RES LV_VER_RES + +/* Scale window by this factor (useful when simulating small screens) */ +#define MONITOR_ZOOM 1 + +/* Used to test true double buffering with only address changing. + * Set LV_VDB_SIZE = (LV_HOR_RES * LV_VER_RES) and LV_VDB_DOUBLE = 1 and LV_COLOR_DEPTH = 32" */ +#define MONITOR_DOUBLE_BUFFERED 0 + +/*Eclipse: Visual Studio: */ +#define MONITOR_SDL_INCLUDE_PATH + +/*Different rendering might be used if running in a Virtual machine*/ +#define MONITOR_VIRTUAL_MACHINE 0 + +/*Open two windows to test multi display support*/ +#define MONITOR_DUAL 0 +#endif + +/*----------------------------------- + * Native Windows (including mouse) + *----------------------------------*/ +#ifndef USE_WINDOWS +#define USE_WINDOWS 0 +#endif + +#define USE_WINDOWS 0 +#if USE_WINDOWS +#define WINDOW_HOR_RES 480 +#define WINDOW_VER_RES 320 +#endif + +/*---------------- + * SSD1963 + *--------------*/ +#ifndef USE_SSD1963 +#define USE_SSD1963 0 +#endif + +#if USE_SSD1963 +#define SSD1963_HOR_RES LV_HOR_RES +#define SSD1963_VER_RES LV_VER_RES +#define SSD1963_HT 531 +#define SSD1963_HPS 43 +#define SSD1963_LPS 8 +#define SSD1963_HPW 10 +#define SSD1963_VT 288 +#define SSD1963_VPS 12 +#define SSD1963_FPS 4 +#define SSD1963_VPW 10 +#define SSD1963_HS_NEG 0 /*Negative hsync*/ +#define SSD1963_VS_NEG 0 /*Negative vsync*/ +#define SSD1963_ORI 0 /*0, 90, 180, 270*/ +#define SSD1963_COLOR_DEPTH 16 +#endif + +/*---------------- + * R61581 + *--------------*/ +#ifndef USE_R61581 +#define USE_R61581 0 +#endif + +#if USE_R61581 +#define R61581_HOR_RES LV_HOR_RES +#define R61581_VER_RES LV_VER_RES +#define R61581_HSPL 0 /*HSYNC signal polarity*/ +#define R61581_HSL 10 /*HSYNC length (Not Implemented)*/ +#define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/ +#define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */ +#define R61581_VSPL 0 /*VSYNC signal polarity*/ +#define R61581_VSL 10 /*VSYNC length (Not Implemented)*/ +#define R61581_VFP 8 /*Vertical Front poarch*/ +#define R61581_VBP 8 /*Vertical Back poarch */ +#define R61581_DPL 0 /*DCLK signal polarity*/ +#define R61581_EPL 1 /*ENABLE signal polarity*/ +#define R61581_ORI 0 /*0, 180*/ +#define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/ +#endif + +/*------------------------------ + * ST7565 (Monochrome, low res.) + *-----------------------------*/ +#ifndef USE_ST7565 +#define USE_ST7565 0 +#endif + +#if USE_ST7565 +/*No settings*/ +#endif /*USE_ST7565*/ + +/*------------------------------------------ + * UC1610 (4 gray 160*[104|128]) + * (EA DOGXL160 160x104 tested) + *-----------------------------------------*/ +#ifndef USE_UC1610 +#define USE_UC1610 0 +#endif + +#if USE_UC1610 +#define UC1610_HOR_RES LV_HOR_RES +#define UC1610_VER_RES LV_VER_RES +#define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */ +#define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */ +#define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */ +#endif /*USE_UC1610*/ + +/*------------------------------------------------- + * SHARP memory in pixel monochrome display series + * LS012B7DD01 (184x38 pixels.) + * LS013B7DH03 (128x128 pixels.) + * LS013B7DH05 (144x168 pixels.) + * LS027B7DH01 (400x240 pixels.) (tested) + * LS032B7DD02 (336x536 pixels.) + * LS044Q7DH01 (320x240 pixels.) + *------------------------------------------------*/ +#ifndef USE_SHARP_MIP +#define USE_SHARP_MIP 0 +#endif + +#if USE_SHARP_MIP +#define SHARP_MIP_HOR_RES LV_HOR_RES +#define SHARP_MIP_VER_RES LV_VER_RES +#define SHARP_MIP_SOFT_COM_INVERSION 0 +#define SHARP_MIP_REV_BYTE( \ + b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/ +#endif /*USE_SHARP_MIP*/ + +/*----------------------------------------- + * Linux frame buffer device (/dev/fbx) + *-----------------------------------------*/ +#ifndef USE_FBDEV +#define USE_FBDEV 0 +#endif + +#if USE_FBDEV +#define FBDEV_PATH "/dev/fb0" +#endif + +/*----------------------------------------- + * FreeBSD frame buffer device (/dev/fbx) + *.........................................*/ +#ifndef USE_BSD_FBDEV +#define USE_BSD_FBDEV 0 +#endif + +#if USE_BSD_FBDEV +#define FBDEV_PATH "/dev/fb0" +#endif + +/********************* + * INPUT DEVICES + *********************/ + +/*-------------- + * XPT2046 + *--------------*/ +#ifndef USE_XPT2046 +#define USE_XPT2046 1 +#endif + +#if USE_XPT2046 +#define XPT2046_HOR_RES 480 +#define XPT2046_VER_RES 320 +#define XPT2046_X_MIN 200 +#define XPT2046_Y_MIN 200 +#define XPT2046_X_MAX 3800 +#define XPT2046_Y_MAX 3800 +#define XPT2046_AVG 4 +#define XPT2046_INV 0 +#endif + +/*----------------- + * FT5406EE8 + *-----------------*/ +#ifndef USE_FT5406EE8 +#define USE_FT5406EE8 0 +#endif + +#if USE_FT5406EE8 +#define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/ +#endif + +/*--------------- + * AD TOUCH + *--------------*/ +#ifndef USE_AD_TOUCH +#define USE_AD_TOUCH 0 +#endif + +#if USE_AD_TOUCH +/*No settings*/ +#endif + +/*--------------------------------------- + * Mouse or touchpad on PC (using SDL) + *-------------------------------------*/ +#ifndef USE_MOUSE +#define USE_MOUSE 0 +#endif + +#if USE_MOUSE +/*No settings*/ +#endif + +/*------------------------------------------- + * Mousewheel as encoder on PC (using SDL) + *------------------------------------------*/ +#ifndef USE_MOUSEWHEEL +#define USE_MOUSEWHEEL 0 +#endif + +#if USE_MOUSEWHEEL +/*No settings*/ +#endif + +/*------------------------------------------------- + * Touchscreen as libinput interface (for Linux based systems) + *------------------------------------------------*/ +#ifndef USE_LIBINPUT +#define USE_LIBINPUT 0 +#endif + +#if USE_LIBINPUT +#define LIBINPUT_NAME \ + "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ +#endif /*USE_LIBINPUT*/ + +/*------------------------------------------------- + * Mouse or touchpad as evdev interface (for Linux based systems) + *------------------------------------------------*/ +#ifndef USE_EVDEV +#define USE_EVDEV 0 +#endif + +#if USE_EVDEV +#define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test \ + them*/ +#define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ + +#define EVDEV_SCALE 0 /* Scale input, e.g. if touchscreen resolution does not match display resolution */ +#if EVDEV_SCALE +#define EVDEV_SCALE_HOR_RES (4096) /* Horizontal resolution of touchscreen */ +#define EVDEV_SCALE_VER_RES (4096) /* Vertical resolution of touchscreen */ +#endif /*EVDEV_SCALE*/ + +#define EVDEV_CALIBRATE \ + 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/ +#if EVDEV_CALIBRATE +#define EVDEV_HOR_MIN 3800 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/ +#define EVDEV_HOR_MAX 200 +#define EVDEV_VER_MIN 200 +#define EVDEV_VER_MAX 3800 +#endif /*EVDEV_SCALE*/ +#endif /*USE_EVDEV*/ + +/*------------------------------- + * Keyboard of a PC (using SDL) + *------------------------------*/ +#ifndef USE_KEYBOARD +#define USE_KEYBOARD 0 +#endif + +#if USE_KEYBOARD +/*No settings*/ +#endif + +#endif /*LV_DRV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/lib/lv_drivers/.gitignore b/lib/lv_drivers/.gitignore new file mode 100644 index 00000000..2372cca0 --- /dev/null +++ b/lib/lv_drivers/.gitignore @@ -0,0 +1 @@ +**/*.o \ No newline at end of file diff --git a/lib/lv_drivers/LICENSE b/lib/lv_drivers/LICENSE new file mode 100644 index 00000000..cc227abe --- /dev/null +++ b/lib/lv_drivers/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 LittlevGL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/lv_drivers/README.md b/lib/lv_drivers/README.md new file mode 100644 index 00000000..160d08ae --- /dev/null +++ b/lib/lv_drivers/README.md @@ -0,0 +1,7 @@ +# Display and Touch pad drivers + +Display controller and touchpad driver to can be directly used with [LittlevGL](https://littlevgl.com). + +To learn more about using drivers in LittlevGL visit the [Porting guide](https://littlevgl.com/porting). + +If you used a new display or touch pad driver with LittlevGL please share it with other people! diff --git a/lib/lv_drivers/display/R61581.c b/lib/lv_drivers/display/R61581.c new file mode 100644 index 00000000..4d21bff9 --- /dev/null +++ b/lib/lv_drivers/display/R61581.c @@ -0,0 +1,425 @@ +/** + * @file R61581.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "R61581.h" +#if USE_R61581 != 0 + +#include +#include "lvgl/lv_core/lv_vdb.h" +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ +#define R61581_CMD_MODE 0 +#define R61581_DATA_MODE 1 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void r61581_io_init(void); +static void r61581_reset(void); +static void r61581_set_tft_spec(void); +static inline void r61581_cmd_mode(void); +static inline void r61581_data_mode(void); +static inline void r61581_cmd(uint8_t cmd); +static inline void r61581_data(uint8_t data); + +/********************** + * STATIC VARIABLES + **********************/ +static bool cmd_mode = true; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the R61581 display controller + * @return HW_RES_OK or any error from hw_res_t enum + */ +void r61581_init(void) +{ + r61581_io_init(); + + /*Slow mode until the PLL is not started in the display controller*/ + LV_DRV_DISP_PAR_SLOW; + + r61581_reset(); + + r61581_set_tft_spec(); + + r61581_cmd(0x13); //SET display on + + r61581_cmd(0x29); //SET display on + LV_DRV_DELAY_MS(30); + + /*Parallel to max speed*/ + LV_DRV_DISP_PAR_FAST; +} + +void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > R61581_HOR_RES - 1) return; + if(y1 > R61581_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; + + + //Set the rectangular area + r61581_cmd(0x002A); + r61581_data(act_x1 >> 8); + r61581_data(0x00FF & act_x1); + r61581_data(act_x2 >> 8); + r61581_data(0x00FF & act_x2); + + r61581_cmd(0x002B); + r61581_data(act_y1 >> 8); + r61581_data(0x00FF & act_y1); + r61581_data(act_y2 >> 8); + r61581_data(0x00FF & act_y2); + + r61581_cmd(0x2c); + + int16_t i; + uint16_t full_w = x2 - x1 + 1; + + r61581_data_mode(); + +#if LV_COLOR_DEPTH == 16 + uint16_t act_w = act_x2 - act_x1 + 1; + for(i = act_y1; i <= act_y2; i++) { + LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); + color_p += full_w; + } +#else + int16_t j; + for(i = act_y1; i <= act_y2; i++) { + for(j = 0; j <= act_x2 - act_x1 + 1; j++) { + LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); + color_p += full_w; + } + } +#endif + + lv_flush_ready(); +} + +void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > R61581_HOR_RES - 1) return; + if(y1 > R61581_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; + + //Set the rectangular area + r61581_cmd(0x002A); + r61581_data(act_x1 >> 8); + r61581_data(0x00FF & act_x1); + r61581_data(act_x2 >> 8); + r61581_data(0x00FF & act_x2); + + r61581_cmd(0x002B); + r61581_data(act_y1 >> 8); + r61581_data(0x00FF & act_y1); + r61581_data(act_y2 >> 8); + r61581_data(0x00FF & act_y2); + + r61581_cmd(0x2c); + + r61581_data_mode(); + + uint16_t color16 = lv_color_to16(color); + uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1); + uint32_t i; + for(i = 0; i < size; i++) { + LV_DRV_DISP_PAR_WR_WORD(color16); + } +} + +void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > R61581_HOR_RES - 1) return; + if(y1 > R61581_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2; + + + //Set the rectangular area + r61581_cmd(0x002A); + r61581_data(act_x1 >> 8); + r61581_data(0x00FF & act_x1); + r61581_data(act_x2 >> 8); + r61581_data(0x00FF & act_x2); + + r61581_cmd(0x002B); + r61581_data(act_y1 >> 8); + r61581_data(0x00FF & act_y1); + r61581_data(act_y2 >> 8); + r61581_data(0x00FF & act_y2); + + r61581_cmd(0x2c); + + int16_t i; + uint16_t full_w = x2 - x1 + 1; + + r61581_data_mode(); + +#if LV_COLOR_DEPTH == 16 + uint16_t act_w = act_x2 - act_x1 + 1; + for(i = act_y1; i <= act_y2; i++) { + LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); + color_p += full_w; + } +#else + int16_t j; + for(i = act_y1; i <= act_y2; i++) { + for(j = 0; j <= act_x2 - act_x1 + 1; j++) { + LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j])); + color_p += full_w; + } + } +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Io init + */ +static void r61581_io_init(void) +{ + LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) + cmd_mode = true; +} + +/** + * Reset + */ +static void r61581_reset(void) +{ + /*Hardware reset*/ + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(50); + LV_DRV_DISP_RST(0); + LV_DRV_DELAY_MS(50); + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(50); + + /*Chip enable*/ + LV_DRV_DISP_PAR_CS(1); + LV_DRV_DELAY_MS(10); + LV_DRV_DISP_PAR_CS(0); + LV_DRV_DELAY_MS(5); + + /*Software reset*/ + r61581_cmd(0x01); + LV_DRV_DELAY_MS(20); + + r61581_cmd(0x01); + LV_DRV_DELAY_MS(20); + + r61581_cmd(0x01); + LV_DRV_DELAY_MS(20); +} + +/** + * TFT specific initialization + */ +static void r61581_set_tft_spec(void) +{ + r61581_cmd(0xB0); + r61581_data(0x00); + + r61581_cmd(0xB3); + r61581_data(0x02); + r61581_data(0x00); + r61581_data(0x00); + r61581_data(0x10); + + r61581_cmd(0xB4); + r61581_data(0x00);//0X10 + + r61581_cmd(0xB9); //PWM + r61581_data(0x01); + r61581_data(0xFF); //FF brightness + r61581_data(0xFF); + r61581_data(0x18); + + /*Panel Driving Setting*/ + r61581_cmd(0xC0); + r61581_data(0x02); + r61581_data(0x3B); + r61581_data(0x00); + r61581_data(0x00); + r61581_data(0x00); + r61581_data(0x01); + r61581_data(0x00);//NW + r61581_data(0x43); + + /*Display Timing Setting for Normal Mode */ + r61581_cmd(0xC1); + r61581_data(0x08); + r61581_data(0x15); //CLOCK + r61581_data(R61581_VFP); + r61581_data(R61581_VBP); + + /*Source/VCOM/Gate Driving Timing Setting*/ + r61581_cmd(0xC4); + r61581_data(0x15); + r61581_data(0x03); + r61581_data(0x03); + r61581_data(0x01); + + /*Interface Setting*/ + r61581_cmd(0xC6); + r61581_data((R61581_DPL << 0) | + (R61581_EPL << 1) | + (R61581_HSPL << 4) | + (R61581_VSPL << 5)); + + /*Gamma Set*/ + r61581_cmd(0xC8); + r61581_data(0x0c); + r61581_data(0x05); + r61581_data(0x0A); + r61581_data(0x6B); + r61581_data(0x04); + r61581_data(0x06); + r61581_data(0x15); + r61581_data(0x10); + r61581_data(0x00); + r61581_data(0x31); + + + r61581_cmd(0x36); + if(R61581_ORI == 0) r61581_data(0xE0); + else r61581_data(0x20); + + r61581_cmd(0x0C); + r61581_data(0x55); + + r61581_cmd(0x3A); + r61581_data(0x55); + + r61581_cmd(0x38); + + r61581_cmd(0xD0); + r61581_data(0x07); + r61581_data(0x07); + r61581_data(0x14); + r61581_data(0xA2); + + r61581_cmd(0xD1); + r61581_data(0x03); + r61581_data(0x5A); + r61581_data(0x10); + + r61581_cmd(0xD2); + r61581_data(0x03); + r61581_data(0x04); + r61581_data(0x04); + + r61581_cmd(0x11); + LV_DRV_DELAY_MS(10); + + r61581_cmd(0x2A); + r61581_data(0x00); + r61581_data(0x00); + r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF); + r61581_data((R61581_HOR_RES - 1) & 0XFF); + + r61581_cmd(0x2B); + r61581_data(0x00); + r61581_data(0x00); + r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF); + r61581_data((R61581_VER_RES - 1) & 0XFF); + + LV_DRV_DELAY_MS(10); + + r61581_cmd(0x29); + LV_DRV_DELAY_MS(5); + + r61581_cmd(0x2C); + LV_DRV_DELAY_MS(5); +} + +/** + * Command mode + */ +static inline void r61581_cmd_mode(void) +{ + if(cmd_mode == false) { + LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE) + cmd_mode = true; + } +} + +/** + * Data mode + */ +static inline void r61581_data_mode(void) +{ + if(cmd_mode != false) { + LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE); + cmd_mode = false; + } +} + +/** + * Write command + * @param cmd the command + */ +static inline void r61581_cmd(uint8_t cmd) +{ + r61581_cmd_mode(); + LV_DRV_DISP_PAR_WR_WORD(cmd); +} + +/** + * Write data + * @param data the data + */ +static inline void r61581_data(uint8_t data) +{ + r61581_data_mode(); + LV_DRV_DISP_PAR_WR_WORD(data); +} +#endif diff --git a/lib/lv_drivers/display/R61581.h b/lib/lv_drivers/display/R61581.h new file mode 100644 index 00000000..3ba4ff93 --- /dev/null +++ b/lib/lv_drivers/display/R61581.h @@ -0,0 +1,57 @@ +/** + * @file R61581.h + * + */ + +#ifndef R61581_H +#define R61581_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_R61581 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void r61581_init(void); +void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +/********************** + * MACROS + **********************/ + +#endif /* USE_R61581 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* R61581_H */ diff --git a/lib/lv_drivers/display/SHARP_MIP.c b/lib/lv_drivers/display/SHARP_MIP.c new file mode 100644 index 00000000..129ac2f3 --- /dev/null +++ b/lib/lv_drivers/display/SHARP_MIP.c @@ -0,0 +1,182 @@ +/** + * @file SHARP_MIP.c + * + */ + +/*------------------------------------------------------------------------------------------------- + * SHARP memory in pixel monochrome display series + * LS012B7DD01 (184x38 pixels.) + * LS013B7DH03 (128x128 pixels.) + * LS013B7DH05 (144x168 pixels.) + * LS027B7DH01 (400x240 pixels.) (tested) + * LS032B7DD02 (336x536 pixels.) + * LS044Q7DH01 (320x240 pixels.) + * + * These displays need periodic com inversion, there are two ways : + * - software com inversion : + * define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW, + * call sharp_mip_com_inversion() periodically + * - hardware com inversion with EXTCOMIN display pin : + * define SHARP_MIP_SOFT_COM_INVERSION 0, + * set EXTMODE display pin HIGH and handle + * EXTCOMIN waveform (for example with mcu pwm output), + * see datasheet pages 8-12 for details + * + * VDB size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure : + * [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line + * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line + * ........................................................................................... + * [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line + * [DUMMY (2 bytes)] + * + * Since extra bytes (dummy, addresses, header) are stored in VDB, we need to use + * an "oversized" VDB. Buffer declaration in "lv_port_disp.c" becomes for example : + * static lv_disp_buf_t disp_buf; + * static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2]; + * lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X); + *-----------------------------------------------------------------------------------------------*/ + +/********************* + * INCLUDES + *********************/ + +#include "SHARP_MIP.h" + +#if USE_SHARP_MIP + +#include +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ + +#define SHARP_MIP_HEADER 0 +#define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */ +#define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */ + /* H -> outputs VCOM = H, L -> outputs VCOM = L */ +#define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +#if SHARP_MIP_SOFT_COM_INVERSION +static bool_t com_output_state = false; +#endif + +/********************** + * MACROS + **********************/ + +/* + * Return the VDB byte index corresponding to the pixel + * relatives coordinates (x, y) in the area. + * The area is rounded to a whole screen line. + */ +#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2) + +/* + * Return the byte bitmask of a pixel bit corresponding + * to VDB arrangement (8 pixels per byte on lines). + */ +#define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7)) + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void sharp_mip_init(void) { + /* These displays have nothing to initialize */ +} + + +void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { + + /*Return if the area is out the screen*/ + if(area->y2 < 0) return; + if(area->y1 > SHARP_MIP_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1; + uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2; + + uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/ + uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/ + uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */ + + /* Set lines to flush dummy byte & gate address in VDB*/ + for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) { + buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1)); + buf[BUFIDX(0, act_y) - 2] = 0; + } + + /* Set last dummy two bytes in VDB */ + buf[BUFIDX(0, buf_h) - 1] = 0; + buf[BUFIDX(0, buf_h) - 2] = 0; + + /* Set frame header in VDB */ + buf[0] = SHARP_MIP_HEADER | + SHARP_MIP_UPDATE_RAM_FLAG; + + /* Write the frame on display memory */ + LV_DRV_DISP_SPI_CS(1); + LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); + LV_DRV_DISP_SPI_CS(0); + + lv_disp_flush_ready(disp_drv); +} + +void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) { + (void) disp_drv; + (void) buf_w; + (void) opa; + + if (lv_color_to1(color) != 0) { + buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set VDB pixel bit to 1 for other colors than BLACK*/ + } else { + buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set VDB pixel bit to 0 for BLACK color*/ + } +} + +void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) { + (void) disp_drv; + + /* Round area to a whole line */ + area->x1 = 0; + area->x2 = SHARP_MIP_HOR_RES - 1; +} + +#if SHARP_MIP_SOFT_COM_INVERSION +void sharp_mip_com_inversion(void) { + uint8_t inversion_header[2] = {0}; + + /* Set inversion header */ + if (com_output_state) { + com_output_state = false; + } else { + inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG; + com_output_state = true; + } + + /* Write inversion header on display memory */ + LV_DRV_DISP_SPI_CS(1); + LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2); + LV_DRV_DISP_SPI_CS(0); +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/display/SHARP_MIP.h b/lib/lv_drivers/display/SHARP_MIP.h new file mode 100644 index 00000000..c10d8459 --- /dev/null +++ b/lib/lv_drivers/display/SHARP_MIP.h @@ -0,0 +1,63 @@ +/** + * @file SHARP_MIP.h + * + */ + +#ifndef SHARP_MIP_H +#define SHARP_MIP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_SHARP_MIP + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void sharp_mip_init(void); +void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); +void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area); +void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#if SHARP_MIP_SOFT_COM_INVERSION +void sharp_mip_com_inversion(void); +#endif + +/********************** + * MACROS + **********************/ + +#endif /* USE_SHARP_MIP */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SHARP_MIP_H */ diff --git a/lib/lv_drivers/display/SSD1963.c b/lib/lv_drivers/display/SSD1963.c new file mode 100644 index 00000000..c961066b --- /dev/null +++ b/lib/lv_drivers/display/SSD1963.c @@ -0,0 +1,292 @@ +/** + * @file SSD1963.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "SSD1963.h" +#if USE_SSD1963 + +#include +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ +#define SSD1963_CMD_MODE 0 +#define SSD1963_DATA_MODE 1 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static inline void ssd1963_cmd_mode(void); +static inline void ssd1963_data_mode(void); +static inline void ssd1963_cmd(uint8_t cmd); +static inline void ssd1963_data(uint8_t data); +static void ssd1963_io_init(void); +static void ssd1963_reset(void); +static void ssd1963_set_clk(void); +static void ssd1963_set_tft_spec(void); +static void ssd1963_init_bl(void); + +/********************** + * STATIC VARIABLES + **********************/ +static bool cmd_mode = true; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void ssd1963_init(void) +{ + + LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); + cmd_mode = true; + + LV_DRV_DELAY_MS(250); + + + ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M + ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal + ssd1963_data(0x0002); + ssd1963_data(0x0004); + ssd1963_cmd(0x00E0); // PLL enable + ssd1963_data(0x0001); + LV_DRV_DELAY_MS(1); + ssd1963_cmd(0x00E0); + ssd1963_data(0x0003); // now, use PLL output as system clock + LV_DRV_DELAY_MS(1); + ssd1963_cmd(0x0001); // software reset + LV_DRV_DELAY_MS(1); + ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution + + ssd1963_data(0x0001); //HX8257C + ssd1963_data(0x0033); //HX8257C + ssd1963_data(0x0033); //HX8257C + + + ssd1963_cmd(0x00B0); //LCD SPECIFICATION + ssd1963_data(0x0020); + ssd1963_data(0x0000); + ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP + ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF); + ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP + ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF); + ssd1963_data(0x0000); + LV_DRV_DELAY_MS(1);//Delay10us(5); + ssd1963_cmd(0x00B4); //HSYNC + ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT + ssd1963_data(SSD1963_HT & 0X00FF); + ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS + ssd1963_data(SSD1963_HPS & 0X00FF); + ssd1963_data(SSD1963_HPW); //Set HPW + ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS + ssd1963_data(SSD1963_LPS & 0X00FF); + ssd1963_data(0x0000); + + ssd1963_cmd(0x00B6); //VSYNC + ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT + ssd1963_data(SSD1963_VT & 0X00FF); + ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS + ssd1963_data(SSD1963_VPS & 0X00FF); + ssd1963_data(SSD1963_VPW); //Set VPW + ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS + ssd1963_data(SSD1963_FPS & 0X00FF); + + ssd1963_cmd(0x00B8); + ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF + ssd1963_data(0x0001); //GPIO0 normal + + ssd1963_cmd(0x00BA); + ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN + + ssd1963_cmd(0x0036); //rotation + ssd1963_data(0x0008); //RGB=BGR + + ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data + ssd1963_data(0x0050); //16-bit/pixel + + ssd1963_cmd(0x00F0); //Pixel Data Interface Format + ssd1963_data(0x0003); //16-bit(565 format) data + + ssd1963_cmd(0x00BC); + ssd1963_data(0x0040); //contrast value + ssd1963_data(0x0080); //brightness value + ssd1963_data(0x0040); //saturation value + ssd1963_data(0x0001); //Post Processor Enable + + LV_DRV_DELAY_MS(1); + + ssd1963_cmd(0x0029); //display on + + ssd1963_cmd(0x00BE); //set PWM for B/L + ssd1963_data(0x0006); + ssd1963_data(0x0080); + ssd1963_data(0x0001); + ssd1963_data(0x00f0); + ssd1963_data(0x0000); + ssd1963_data(0x0000); + + ssd1963_cmd(0x00d0); + ssd1963_data(0x000d); + + //DisplayBacklightOn(); + + LV_DRV_DELAY_MS(30); +} + +void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +{ + + /*Return if the area is out the screen*/ + if(area->x2 < 0) return; + if(area->y2 < 0) return; + if(area->x1 > SSD1963_HOR_RES - 1) return; + if(area->y1 > SSD1963_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; + int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; + int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2; + int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2; + + //Set the rectangular area + ssd1963_cmd(0x002A); + ssd1963_data(act_x1 >> 8); + ssd1963_data(0x00FF & act_x1); + ssd1963_data(act_x2 >> 8); + ssd1963_data(0x00FF & act_x2); + + ssd1963_cmd(0x002B); + ssd1963_data(act_y1 >> 8); + ssd1963_data(0x00FF & act_y1); + ssd1963_data(act_y2 >> 8); + ssd1963_data(0x00FF & act_y2); + + ssd1963_cmd(0x2c); + int16_t i; + uint16_t full_w = area->x2 - area->x1 + 1; + + ssd1963_data_mode(); + LV_DRV_DISP_PAR_CS(0); +#if LV_COLOR_DEPTH == 16 + uint16_t act_w = act_x2 - act_x1 + 1; + for(i = act_y1; i <= act_y2; i++) { + LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w); + color_p += full_w; + } + LV_DRV_DISP_PAR_CS(1); +#else + int16_t j; + for(i = act_y1; i <= act_y2; i++) { + for(j = 0; j <= act_x2 - act_x1 + 1; j++) { + LV_DRV_DISP_PAR_WR_WORD(color_p[j]); + color_p += full_w; + } + } +#endif + + lv_disp_flush_ready(disp_drv); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void ssd1963_io_init(void) +{ + LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); + cmd_mode = true; +} + +static void ssd1963_reset(void) +{ + /*Hardware reset*/ + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(50); + LV_DRV_DISP_RST(0); + LV_DRV_DELAY_MS(50); + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(50); + + /*Chip enable*/ + LV_DRV_DISP_PAR_CS(0); + LV_DRV_DELAY_MS(10); + LV_DRV_DISP_PAR_CS(1); + LV_DRV_DELAY_MS(5); + + /*Software reset*/ + ssd1963_cmd(0x01); + LV_DRV_DELAY_MS(20); + + ssd1963_cmd(0x01); + LV_DRV_DELAY_MS(20); + + ssd1963_cmd(0x01); + LV_DRV_DELAY_MS(20); + +} + +/** + * Command mode + */ +static inline void ssd1963_cmd_mode(void) +{ + if(cmd_mode == false) { + LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE); + cmd_mode = true; + } +} + +/** + * Data mode + */ +static inline void ssd1963_data_mode(void) +{ + if(cmd_mode != false) { + LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE); + cmd_mode = false; + } +} + +/** + * Write command + * @param cmd the command + */ +static inline void ssd1963_cmd(uint8_t cmd) +{ + + LV_DRV_DISP_PAR_CS(0); + ssd1963_cmd_mode(); + LV_DRV_DISP_PAR_WR_WORD(cmd); + LV_DRV_DISP_PAR_CS(1); + +} + +/** + * Write data + * @param data the data + */ +static inline void ssd1963_data(uint8_t data) +{ + + LV_DRV_DISP_PAR_CS(0); + ssd1963_data_mode(); + LV_DRV_DISP_PAR_WR_WORD(data); + LV_DRV_DISP_PAR_CS(1); + +} + +#endif diff --git a/lib/lv_drivers/display/SSD1963.h b/lib/lv_drivers/display/SSD1963.h new file mode 100644 index 00000000..49639f59 --- /dev/null +++ b/lib/lv_drivers/display/SSD1963.h @@ -0,0 +1,150 @@ +/** + * @file SSD1963.h + * + */ + +#ifndef SSD1963_H +#define SSD1963_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_SSD1963 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ +// SSD1963 command table +#define CMD_NOP 0x00 //No operation +#define CMD_SOFT_RESET 0x01 //Software reset +#define CMD_GET_PWR_MODE 0x0A //Get the current power mode +#define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order +#define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format +#define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode +#define CMD_GET_SIGNAL_MODE 0x0E // +#define CMD_GET_DIAGNOSTIC 0x0F +#define CMD_ENT_SLEEP 0x10 +#define CMD_EXIT_SLEEP 0x11 +#define CMD_ENT_PARTIAL_MODE 0x12 +#define CMD_ENT_NORMAL_MODE 0x13 +#define CMD_EXIT_INVERT_MODE 0x20 +#define CMD_ENT_INVERT_MODE 0x21 +#define CMD_SET_GAMMA 0x26 +#define CMD_BLANK_DISPLAY 0x28 +#define CMD_ON_DISPLAY 0x29 +#define CMD_SET_COLUMN 0x2A +#define CMD_SET_PAGE 0x2B +#define CMD_WR_MEMSTART 0x2C +#define CMD_RD_MEMSTART 0x2E +#define CMD_SET_PARTIAL_AREA 0x30 +#define CMD_SET_SCROLL_AREA 0x33 +#define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display +#define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display +#define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel +#define CMD_SET_SCROLL_START 0x37 +#define CMD_EXIT_IDLE_MODE 0x38 +#define CMD_ENT_IDLE_MODE 0x39 +#define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used +#define CMD_WR_MEM_AUTO 0x3C +#define CMD_RD_MEM_AUTO 0x3E +#define CMD_SET_TEAR_SCANLINE 0x44 +#define CMD_GET_SCANLINE 0x45 +#define CMD_RD_DDB_START 0xA1 +#define CMD_RD_DDB_AUTO 0xA8 +#define CMD_SET_PANEL_MODE 0xB0 +#define CMD_GET_PANEL_MODE 0xB1 +#define CMD_SET_HOR_PERIOD 0xB4 +#define CMD_GET_HOR_PERIOD 0xB5 +#define CMD_SET_VER_PERIOD 0xB6 +#define CMD_GET_VER_PERIOD 0xB7 +#define CMD_SET_GPIO_CONF 0xB8 +#define CMD_GET_GPIO_CONF 0xB9 +#define CMD_SET_GPIO_VAL 0xBA +#define CMD_GET_GPIO_STATUS 0xBB +#define CMD_SET_POST_PROC 0xBC +#define CMD_GET_POST_PROC 0xBD +#define CMD_SET_PWM_CONF 0xBE +#define CMD_GET_PWM_CONF 0xBF +#define CMD_SET_LCD_GEN0 0xC0 +#define CMD_GET_LCD_GEN0 0xC1 +#define CMD_SET_LCD_GEN1 0xC2 +#define CMD_GET_LCD_GEN1 0xC3 +#define CMD_SET_LCD_GEN2 0xC4 +#define CMD_GET_LCD_GEN2 0xC5 +#define CMD_SET_LCD_GEN3 0xC6 +#define CMD_GET_LCD_GEN3 0xC7 +#define CMD_SET_GPIO0_ROP 0xC8 +#define CMD_GET_GPIO0_ROP 0xC9 +#define CMD_SET_GPIO1_ROP 0xCA +#define CMD_GET_GPIO1_ROP 0xCB +#define CMD_SET_GPIO2_ROP 0xCC +#define CMD_GET_GPIO2_ROP 0xCD +#define CMD_SET_GPIO3_ROP 0xCE +#define CMD_GET_GPIO3_ROP 0xCF +#define CMD_SET_ABC_DBC_CONF 0xD0 +#define CMD_GET_ABC_DBC_CONF 0xD1 +#define CMD_SET_DBC_HISTO_PTR 0xD2 +#define CMD_GET_DBC_HISTO_PTR 0xD3 +#define CMD_SET_DBC_THRES 0xD4 +#define CMD_GET_DBC_THRES 0xD5 +#define CMD_SET_ABM_TMR 0xD6 +#define CMD_GET_ABM_TMR 0xD7 +#define CMD_SET_AMB_LVL0 0xD8 +#define CMD_GET_AMB_LVL0 0xD9 +#define CMD_SET_AMB_LVL1 0xDA +#define CMD_GET_AMB_LVL1 0xDB +#define CMD_SET_AMB_LVL2 0xDC +#define CMD_GET_AMB_LVL2 0xDD +#define CMD_SET_AMB_LVL3 0xDE +#define CMD_GET_AMB_LVL3 0xDF +#define CMD_PLL_START 0xE0 //start the PLL +#define CMD_PLL_STOP 0xE1 //disable the PLL +#define CMD_SET_PLL_MN 0xE2 +#define CMD_GET_PLL_MN 0xE3 +#define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status +#define CMD_ENT_DEEP_SLEEP 0xE5 +#define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency +#define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings +#define CMD_SET_DATA_INTERFACE 0xF0 +#define CMD_GET_DATA_INTERFACE 0xF1 + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void ssd1963_init(void); +void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); + +/********************** + * MACROS + **********************/ + +#endif /* USE_SSD1963 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SSD1963_H */ diff --git a/lib/lv_drivers/display/ST7565.c b/lib/lv_drivers/display/ST7565.c new file mode 100644 index 00000000..e4eac4b2 --- /dev/null +++ b/lib/lv_drivers/display/ST7565.c @@ -0,0 +1,289 @@ +/** + * @file ST7565.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "ST7565.h" +#if USE_ST7565 + +#include +#include +#include +#include "lvgl/lv_core/lv_vdb.h" +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ +#define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/ + +#define ST7565_CMD_MODE 0 +#define ST7565_DATA_MODE 1 + +#define ST7565_HOR_RES 128 +#define ST7565_VER_RES 64 + +#define CMD_DISPLAY_OFF 0xAE +#define CMD_DISPLAY_ON 0xAF + +#define CMD_SET_DISP_START_LINE 0x40 +#define CMD_SET_PAGE 0xB0 + +#define CMD_SET_COLUMN_UPPER 0x10 +#define CMD_SET_COLUMN_LOWER 0x00 + +#define CMD_SET_ADC_NORMAL 0xA0 +#define CMD_SET_ADC_REVERSE 0xA1 + +#define CMD_SET_DISP_NORMAL 0xA6 +#define CMD_SET_DISP_REVERSE 0xA7 + +#define CMD_SET_ALLPTS_NORMAL 0xA4 +#define CMD_SET_ALLPTS_ON 0xA5 +#define CMD_SET_BIAS_9 0xA2 +#define CMD_SET_BIAS_7 0xA3 + +#define CMD_RMW 0xE0 +#define CMD_RMW_CLEAR 0xEE +#define CMD_INTERNAL_RESET 0xE2 +#define CMD_SET_COM_NORMAL 0xC0 +#define CMD_SET_COM_REVERSE 0xC8 +#define CMD_SET_POWER_CONTROL 0x28 +#define CMD_SET_RESISTOR_RATIO 0x20 +#define CMD_SET_VOLUME_FIRST 0x81 +#define CMD_SET_VOLUME_SECOND 0x00 +#define CMD_SET_STATIC_OFF 0xAC +#define CMD_SET_STATIC_ON 0xAD +#define CMD_SET_STATIC_REG 0x00 +#define CMD_SET_BOOSTER_FIRST 0xF8 +#define CMD_SET_BOOSTER_234 0x00 +#define CMD_SET_BOOSTER_5 0x01 +#define CMD_SET_BOOSTER_6 0x03 +#define CMD_NOP 0xE3 +#define CMD_TEST 0xF0 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2); +static void st7565_command(uint8_t cmd); +static void st7565_data(uint8_t data); + +/********************** + * STATIC VARIABLES + **********************/ +static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA}; +static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the ST7565 + */ +void st7565_init(void) +{ + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(10); + LV_DRV_DISP_RST(0); + LV_DRV_DELAY_MS(10); + LV_DRV_DISP_RST(1); + LV_DRV_DELAY_MS(10); + + LV_DRV_DISP_SPI_CS(0); + + st7565_command(CMD_SET_BIAS_7); + st7565_command(CMD_SET_ADC_NORMAL); + st7565_command(CMD_SET_COM_NORMAL); + st7565_command(CMD_SET_DISP_START_LINE); + st7565_command(CMD_SET_POWER_CONTROL | 0x4); + LV_DRV_DELAY_MS(50); + + st7565_command(CMD_SET_POWER_CONTROL | 0x6); + LV_DRV_DELAY_MS(50); + + st7565_command(CMD_SET_POWER_CONTROL | 0x7); + LV_DRV_DELAY_MS(10); + + st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs) + + st7565_command(CMD_DISPLAY_ON); + st7565_command(CMD_SET_ALLPTS_NORMAL); + + /*Set brightness*/ + st7565_command(CMD_SET_VOLUME_FIRST); + st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f)); + + LV_DRV_DISP_SPI_CS(1); + + memset(lcd_fb, 0x00, sizeof(lcd_fb)); +} + + +void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > ST7565_HOR_RES - 1) return; + if(y1 > ST7565_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; + + int32_t x, y; + + /*Set the first row in */ + + /*Refresh frame buffer*/ + for(y = act_y1; y <= act_y2; y++) { + for(x = act_x1; x <= act_x2; x++) { + if(lv_color_to1(*color_p) != 0) { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); + } else { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); + } + color_p ++; + } + + color_p += x2 - act_x2; /*Next row*/ + } + + st7565_sync(act_x1, act_y1, act_x2, act_y2); + lv_flush_ready(); +} + + + +void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > ST7565_HOR_RES - 1) return; + if(y1 > ST7565_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; + + int32_t x, y; + uint8_t white = lv_color_to1(color); + + /*Refresh frame buffer*/ + for(y = act_y1; y <= act_y2; y++) { + for(x = act_x1; x <= act_x2; x++) { + if(white != 0) { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); + } else { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); + } + } + } + + st7565_sync(act_x1, act_y1, act_x2, act_y2); +} + +void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + /*Return if the area is out the screen*/ + if(x2 < 0) return; + if(y2 < 0) return; + if(x1 > ST7565_HOR_RES - 1) return; + if(y1 > ST7565_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + int32_t act_x1 = x1 < 0 ? 0 : x1; + int32_t act_y1 = y1 < 0 ? 0 : y1; + int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2; + int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2; + + int32_t x, y; + + /*Set the first row in */ + + /*Refresh frame buffer*/ + for(y = act_y1; y <= act_y2; y++) { + for(x = act_x1; x <= act_x2; x++) { + if(lv_color_to1(*color_p) != 0) { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8))); + } else { + lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8))); + } + color_p ++; + } + + color_p += x2 - act_x2; /*Next row*/ + } + + st7565_sync(act_x1, act_y1, act_x2, act_y2); +} +/********************** + * STATIC FUNCTIONS + **********************/ +/** + * Flush a specific part of the buffer to the display + * @param x1 left coordinate of the area to flush + * @param y1 top coordinate of the area to flush + * @param x2 right coordinate of the area to flush + * @param y2 bottom coordinate of the area to flush + */ +static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2) +{ + + LV_DRV_DISP_SPI_CS(0); + + uint8_t c, p; + for(p = y1 / 8; p <= y2 / 8; p++) { + st7565_command(CMD_SET_PAGE | pagemap[p]); + st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf)); + st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf)); + st7565_command(CMD_RMW); + + for(c = x1; c <= x2; c++) { + st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]); + } + } + + LV_DRV_DISP_SPI_CS(1); +} + +/** + * Write a command to the ST7565 + * @param cmd the command + */ +static void st7565_command(uint8_t cmd) +{ + LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE); + LV_DRV_DISP_SPI_WR_BYTE(cmd); +} + +/** + * Write data to the ST7565 + * @param data the data + */ +static void st7565_data(uint8_t data) +{ + LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE); + LV_DRV_DISP_SPI_WR_BYTE(data); +} + +#endif diff --git a/lib/lv_drivers/display/ST7565.h b/lib/lv_drivers/display/ST7565.h new file mode 100644 index 00000000..1a96df43 --- /dev/null +++ b/lib/lv_drivers/display/ST7565.h @@ -0,0 +1,58 @@ +/** + * @file ST7565.h + * + */ + +#ifndef ST7565_H +#define ST7565_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_ST7565 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void st7565_init(void); +void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + +/********************** + * MACROS + **********************/ + +#endif /* USE_ST7565 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ST7565_H */ diff --git a/lib/lv_drivers/display/UC1610.c b/lib/lv_drivers/display/UC1610.c new file mode 100644 index 00000000..b678277c --- /dev/null +++ b/lib/lv_drivers/display/UC1610.c @@ -0,0 +1,206 @@ +/** + * @file UC1610.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "UC1610.h" + +#if USE_UC1610 + +#include +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ +#define UC1610_CMD_MODE 0 +#define UC1610_DATA_MODE 1 +#define UC1610_RESET_MODE 0 +#define UC1610_SET_MODE 1 + +/* hardware control commands */ +#define UC1610_SYSTEM_RESET 0xE2 /* software reset */ +#define UC1610_NOP 0xE3 +#define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */ +#define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */ +#define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */ +#define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */ +#define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */ +#define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */ +#define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */ +#define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */ +#define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */ + +/* ram address control */ +#define UC1610_SET_AC 0x88 /* set ram address control */ +#define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */ +#define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */ +#define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */ + +/* set cursor ram address */ +#define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */ +#define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */ +#define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */ + +/* display control commands */ +#define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */ +#define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */ +#define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */ +#define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */ +#define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */ +#define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirorring */ +#define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1 +#define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1) +#define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2) + +/* window program mode */ +#define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */ + /* reset before changing boundaries */ +#define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */ +#define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */ +#define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */ +#define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static uint8_t cmd_buf[12]; + +/********************** + * MACROS + **********************/ + +/* Return the byte bitmask of a pixel color corresponding to VDB arrangement */ +#define PIXIDX(y, c) ((c) << (((y) & 3) << 1)) + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void uc1610_init(void) { + LV_DRV_DELAY_MS(12); + + /* initialization sequence */ +#if UC1610_INIT_HARD_RST + LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */ + LV_DRV_DELAY_MS(1); + LV_DRV_DISP_RST(UC1610_SET_MODE); +#else + cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */ + LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); + LV_DRV_DISP_SPI_CS(0); + LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1); + LV_DRV_DISP_SPI_CS(1); +#endif + + LV_DRV_DELAY_MS(2); + cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */ + cmd_buf[1] = UC1610_VER_RES - 1; + cmd_buf[2] = UC1610_SET_PANEL_LOADING; + cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO; + cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */ + cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100; +#if UC1610_TOP_VIEW + cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */ + UC1610_SET_MAPPING_CONTROL_MY_FLAG | + UC1610_SET_MAPPING_CONTROL_MX_FLAG; +#else + cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */ +#endif + cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */ + cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0; + cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */ + cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */ + cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */ + + LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); + LV_DRV_DISP_SPI_CS(0); + LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12); + LV_DRV_DISP_SPI_CS(1); +} + + +void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { + /*Return if the area is out the screen*/ + if(area->x2 < 0) return; + if(area->y2 < 0) return; + if(area->x1 > UC1610_HOR_RES - 1) return; + if(area->y1 > UC1610_VER_RES - 1) return; + + /*Truncate the area to the screen*/ + uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1; + uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1; + uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2; + uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2; + + uint8_t * buf = (uint8_t *) color_p; + uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1); + + /*Set display window to fill*/ + cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */ + cmd_buf[1] = UC1610_SET_WP_STARTING_CA; + cmd_buf[2] = act_x1; + cmd_buf[3] = UC1610_SET_WP_ENDING_CA; + cmd_buf[4] = act_x2; + cmd_buf[5] = UC1610_SET_WP_STARTING_PA; + cmd_buf[6] = act_y1 >> 2; + cmd_buf[7] = UC1610_SET_WP_ENDING_PA; + cmd_buf[8] = act_y2 >> 2; + cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */ + + LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE); + LV_DRV_DISP_SPI_CS(0); + LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10); + LV_DRV_DISP_SPI_CS(1); + + /*Flush VDB on display memory*/ + LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE); + LV_DRV_DISP_SPI_CS(0); + LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size); + LV_DRV_DISP_SPI_CS(1); + + lv_disp_flush_ready(disp_drv); +} + +void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) { + (void) disp_drv; + (void) opa; + + uint16_t idx = x + buf_w * (y >> 2); + + /* Convert color to depth 2 */ +#if LV_COLOR_DEPTH == 1 + uint8_t color2 = color.full * 3; +#else + uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2); +#endif + + buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */ + buf[idx] |= PIXIDX(y, color2); /* write new color */ +} + +void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) { + (void) disp_drv; + + /* Round y window to display memory page size */ + area->y1 = (area->y1 & (~3)); + area->y2 = (area->y2 & (~3)) + 3; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/display/UC1610.h b/lib/lv_drivers/display/UC1610.h new file mode 100644 index 00000000..38b1fa3c --- /dev/null +++ b/lib/lv_drivers/display/UC1610.h @@ -0,0 +1,58 @@ +/** + * @file UC1610.h + * + */ + +#ifndef UC1610_H +#define UC1610_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_UC1610 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void uc1610_init(void); +void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); +void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area); +void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); + +/********************** + * MACROS + **********************/ + +#endif /* USE_UC1610 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UC1610_H */ diff --git a/lib/lv_drivers/display/display.mk b/lib/lv_drivers/display/display.mk new file mode 100644 index 00000000..d0255920 --- /dev/null +++ b/lib/lv_drivers/display/display.mk @@ -0,0 +1,12 @@ +CSRCS += fbdev.c +CSRCS += monitor.c +CSRCS += R61581.c +CSRCS += SSD1963.c +CSRCS += ST7565.c +CSRCS += UC1610.c +CSRCS += SHARP_MIP.c + +DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers/display +VPATH += :$(LVGL_DIR)/lv_drivers/display + +CFLAGS += "-I$(LVGL_DIR)/lv_drivers/display" diff --git a/lib/lv_drivers/display/fbdev.c b/lib/lv_drivers/display/fbdev.c new file mode 100644 index 00000000..14c6cf14 --- /dev/null +++ b/lib/lv_drivers/display/fbdev.c @@ -0,0 +1,241 @@ +/** + * @file fbdev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "fbdev.h" +#if USE_FBDEV || USE_BSD_FBDEV + +#include +#include +#include +#include +#include +#include +#include + +#if USE_BSD_FBDEV +#include +#include +#include +#include +#else /* USE_BSD_FBDEV */ +#include +#endif /* USE_BSD_FBDEV */ + +/********************* + * DEFINES + *********************/ +#ifndef FBDEV_PATH +#define FBDEV_PATH "/dev/fb0" +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STRUCTURES + **********************/ + +struct bsd_fb_var_info{ + uint32_t xoffset; + uint32_t yoffset; + uint32_t xres; + uint32_t yres; + int bits_per_pixel; + }; + +struct bsd_fb_fix_info{ + long int line_length; +}; + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +#if USE_BSD_FBDEV +static struct bsd_fb_var_info vinfo; +static struct bsd_fb_fix_info finfo; +#else +static struct fb_var_screeninfo vinfo; +static struct fb_fix_screeninfo finfo; +#endif /* USE_BSD_FBDEV */ +static char *fbp = 0; +static long int screensize = 0; +static int fbfd = 0; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void fbdev_init(void) +{ + // Open the file for reading and writing + fbfd = open(FBDEV_PATH, O_RDWR); + if(fbfd == -1) { + perror("Error: cannot open framebuffer device"); + return; + } + printf("The framebuffer device was opened successfully.\n"); + +#if USE_BSD_FBDEV + struct fbtype fb; + unsigned line_length; + + //Get fb type + if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) { + perror("ioctl(FBIOGTYPE)"); + return; + } + + //Get screen width + if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) { + perror("ioctl(FBIO_GETLINEWIDTH)"); + return; + } + + vinfo.xres = (unsigned) fb.fb_width; + vinfo.yres = (unsigned) fb.fb_height; + vinfo.bits_per_pixel = fb.fb_depth + 8; + vinfo.xoffset = 0; + vinfo.yoffset = 0; + finfo.line_length = line_length; +#else /* USE_BSD_FBDEV */ + + // Get fixed screen information + if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) { + perror("Error reading fixed information"); + return; + } + + // Get variable screen information + if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + perror("Error reading variable information"); + return; + } +#endif /* USE_BSD_FBDEV */ + + printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); + + // Figure out the size of the screen in bytes + screensize = finfo.smem_len; //finfo.line_length * vinfo.yres; + + // Map the device to memory + fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); + if((intptr_t)fbp == -1) { + perror("Error: failed to map framebuffer device to memory"); + return; + } + memset(fbp, 0, screensize); + + printf("The framebuffer device was mapped to memory successfully.\n"); + +} + +void fbdev_exit(void) +{ + close(fbfd); +} + +/** + * Flush a buffer to the marked area + * @param drv pointer to driver where this function belongs + * @param area an area where to copy `color_p` + * @param color_p an array of pixel to copy to the `area` part of the screen + */ +void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p) +{ + if(fbp == NULL || + area->x2 < 0 || + area->y2 < 0 || + area->x1 > (int32_t)vinfo.xres - 1 || + area->y1 > (int32_t)vinfo.yres - 1) { + lv_disp_flush_ready(drv); + return; + } + + /*Truncate the area to the screen*/ + int32_t act_x1 = area->x1 < 0 ? 0 : area->x1; + int32_t act_y1 = area->y1 < 0 ? 0 : area->y1; + int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2; + int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2; + + + lv_coord_t w = lv_area_get_width(area); + long int location = 0; + long int byte_location = 0; + unsigned char bit_location = 0; + + /*32 or 24 bit per pixel*/ + if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) { + uint32_t * fbp32 = (uint32_t *)fbp; + int32_t y; + for(y = act_y1; y <= act_y2; y++) { + location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4; + memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4); + color_p += w; + } + } + /*16 bit per pixel*/ + else if(vinfo.bits_per_pixel == 16) { + uint16_t * fbp16 = (uint16_t *)fbp; + int32_t y; + for(y = act_y1; y <= act_y2; y++) { + location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2; + memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2); + color_p += w; + } + } + /*8 bit per pixel*/ + else if(vinfo.bits_per_pixel == 8) { + uint8_t * fbp8 = (uint8_t *)fbp; + int32_t y; + for(y = act_y1; y <= act_y2; y++) { + location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length; + memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1)); + color_p += w; + } + } + /*1 bit per pixel*/ + else if(vinfo.bits_per_pixel == 1) { + uint8_t * fbp8 = (uint8_t *)fbp; + int32_t x; + int32_t y; + for(y = act_y1; y <= act_y2; y++) { + for(x = act_x1; x <= act_x2; x++) { + location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres; + byte_location = location / 8; /* find the byte we need to change */ + bit_location = location % 8; /* inside the byte found, find the bit we need to change */ + fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location); + fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location; + color_p++; + } + + color_p += area->x2 - act_x2; + } + } else { + /*Not supported bit per pixel*/ + } + + //May be some direct update command is required + //ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect)); + + lv_disp_flush_ready(drv); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/display/fbdev.h b/lib/lv_drivers/display/fbdev.h new file mode 100644 index 00000000..9f0e2d5c --- /dev/null +++ b/lib/lv_drivers/display/fbdev.h @@ -0,0 +1,58 @@ +/** + * @file fbdev.h + * + */ + +#ifndef FBDEV_H +#define FBDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_FBDEV || USE_BSD_FBDEV + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void fbdev_init(void); +void fbdev_exit(void); +void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_FBDEV*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*FBDEV_H*/ diff --git a/lib/lv_drivers/display/fsmc_ili9341.cpp b/lib/lv_drivers/display/fsmc_ili9341.cpp new file mode 100644 index 00000000..6d890d52 --- /dev/null +++ b/lib/lv_drivers/display/fsmc_ili9341.cpp @@ -0,0 +1,109 @@ +/** + * @file fsmc_ili9341.cpp + * + */ + +/********************* + * INCLUDES + *********************/ +#include "fsmc_ili9341.h" + +#if USE_FSMC_ILI9341 != 0 + +#include +#include +#include +//#include +#include + +#include "GxTFT_GFX.h" // Hardware-specific library +#include "GxTFT.h" // Hardware-specific library +#define TFT_Class GxTFT + +#include "GxIO/GxIO.h" + +// select one GxIO class, +// note: "error: 'GxIO_Class' does not name a type": indicates target board selection mismatch +// this version is for use with Arduino package STM32GENERIC, board "BLACK F407VE/ZE/ZG boards". +// Specific Board "BLACK F407ZG (M4 DEMO)" +// I use it with ST-LINK-V2, Upload method "STLink[Automatic serial = SerialUSB]", USB disabled. +// For Serial I use a Serial to USB converter on PA9, PA10, "SerialUART1". +// https://github.com/danieleff/STM32GENERIC +#include "GxIO/STM32DUINO/GxIO_STM32F4_FSMC/GxIO_STM32F4_FSMC.h" +#include "myTFTs/my_3.2_TFT_320x240_ILI9341_STM32F407ZGM4_FSMC.h" + +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +// For 3.2" TFT of bundle 1 of: +// https://www.aliexpress.com/item/STM32F407ZGT6-Development-Board-ARM-M4-STM32F4-cortex-M4-core-Board-Compatibility-Multiple-Extension/32795142050.html +// select one GxCTRL class +#include // 240x320 +#include "GxReadRegisters.h" + +/********************* + * DEFINES + *********************/ +#if !defined(ESP8266) +#define yield() +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the R61581 display controller + * @return HW_RES_OK or any error from hw_res_t enum + */ +void fsmc_ili9341_init(uint8_t rotation) +{ + tft.init(); + tft.setRotation(rotation); +} + +void fsmc_ili9341_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + size_t len = (x2 - x1 + 1) * (y2 - y1 + 1); /* Number of pixels */ + + /* Update TFT */ + // tft.startWrite(); /* Start new TFT transaction */ + tft.setWindow(x1, y1, x2, y2); /* set the working window */ + tft.pushColors((uint16_t *)color_p, len); /* Write words at once */ + // tft.endWrite(); /* terminate TFT transaction */ + + /* Tell lvgl that flushing is done */ + // lv_disp_flush_ready(); +} + +void fsmc_ili9341_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + tft.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1, color.full); +} + +void fsmc_ili9341_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + fsmc_ili9341_flush(x1, y1, x2, y2, color_p); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/display/fsmc_ili9341.h b/lib/lv_drivers/display/fsmc_ili9341.h new file mode 100644 index 00000000..1ed9c49d --- /dev/null +++ b/lib/lv_drivers/display/fsmc_ili9341.h @@ -0,0 +1,67 @@ +/** + * @file fsmc_ili9341.h + * + */ + +#ifndef TFT_FSMC_ILI9341_DRV_H +#define TFT_FSMC_ILI9341_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_FSMC_ILI9341 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ +#define ILI9341_DRIVER 1 +#define TFT_WIDTH 240 +#define TFT_HEIGHT 320 +#define TFT_ROTATION 2 // 0=0, 1=90, 2=180 or 3=270 degree +#define SPI_FREQUENCY 40000000 +#define SPI_TOUCH_FREQUENCY 2500000 +#define SPI_READ_FREQUENCY 20000000 +#define USER_SETUP_LOADED 1 +#define TOUCH_DRIVER 0 // XPT2606 Resistive touch panel driver +#define SUPPORT_TRANSACTIONS + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void fsmc_ili9341_init(uint8_t rotation); +void fsmc_ili9341_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +void fsmc_ili9341_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +void fsmc_ili9341_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +/********************** + * MACROS + **********************/ + +#endif /* USE_FSMC_ILI9341 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* TFT_FSMC_ILI9341_DRV_H */ diff --git a/lib/lv_drivers/display/monitor.c b/lib/lv_drivers/display/monitor.c new file mode 100644 index 00000000..491646b4 --- /dev/null +++ b/lib/lv_drivers/display/monitor.c @@ -0,0 +1,415 @@ +/** + * @file monitor.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "monitor.h" +#if USE_MONITOR + +#ifndef MONITOR_SDL_INCLUDE_PATH +# define MONITOR_SDL_INCLUDE_PATH +#endif + +#include +#include +#include +#include MONITOR_SDL_INCLUDE_PATH +#include "../indev/mouse.h" +#include "../indev/keyboard.h" +#include "../indev/mousewheel.h" + +/********************* + * DEFINES + *********************/ +#define SDL_REFR_PERIOD 50 /*ms*/ + +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif + +#ifndef MONITOR_HOR_RES +#define MONITOR_HOR_RES LV_HOR_RES +#endif + +#ifndef MONITOR_VER_RES +#define MONITOR_VER_RES LV_VER_RES +#endif + +#if defined(__APPLE__) && defined(TARGET_OS_MAC) +# if __APPLE__ && TARGET_OS_MAC +#define MONITOR_APPLE +# endif +#endif + +#if defined(__EMSCRIPTEN__) +# define MONITOR_EMSCRIPTEN +#endif + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + SDL_Window * window; + SDL_Renderer * renderer; + SDL_Texture * texture; + volatile bool sdl_refr_qry; +#if MONITOR_DOUBLE_BUFFERED + uint32_t * tft_fb_act; +#else + uint32_t tft_fb[LV_HOR_RES_MAX * LV_VER_RES_MAX]; +#endif +}monitor_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static int monitor_sdl_refr_thread(void * param); +static void window_create(monitor_t * m); +static void window_update(monitor_t * m); + +/*********************** + * GLOBAL PROTOTYPES + ***********************/ + +/********************** + * STATIC VARIABLES + **********************/ +monitor_t monitor; + +#if MONITOR_DUAL +monitor_t monitor2; +#endif + +static volatile bool sdl_inited = false; +static volatile bool sdl_quit_qry = false; + +int quit_filter(void * userdata, SDL_Event * event); +static void monitor_sdl_clean_up(void); +static void monitor_sdl_init(void); +#ifdef MONITOR_EMSCRIPTEN +void monitor_sdl_refr_core(void); /* called from Emscripten loop */ +#else +static void monitor_sdl_refr_core(void); +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the monitor + */ +void monitor_init(void) +{ + /*OSX needs to initialize SDL here*/ +#if defined(MONITOR_APPLE) || defined(MONITOR_EMSCRIPTEN) + monitor_sdl_init(); +#endif + +#ifndef MONITOR_EMSCRIPTEN + SDL_CreateThread(monitor_sdl_refr_thread, "sdl_refr", NULL); + while(sdl_inited == false); /*Wait until 'sdl_refr' initializes the SDL*/ +#endif +} + +/** + * Flush a buffer to the marked area + * @param drv pointer to driver where this function belongs + * @param area an area where to copy `color_p` + * @param color_p an array of pixel to copy to the `area` part of the screen + */ +void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +{ + lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res; + lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res; + +// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2); + + /*Return if the area is out the screen*/ + if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { + + lv_disp_flush_ready(disp_drv); + return; + } + +#if MONITOR_DOUBLE_BUFFERED + monitor.tft_fb_act = (uint32_t *)color_p; + + monitor.sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + lv_disp_flush_ready(disp_drv); +#else + + int32_t y; +#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/ + int32_t x; + for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { + for(x = area->x1; x <= area->x2; x++) { + monitor.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p); + color_p++; + } + + } +#else + uint32_t w = lv_area_get_width(area); + for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { + memcpy(&monitor.tft_fb[y * MONITOR_HOR_RES + area->x1], color_p, w * sizeof(lv_color_t)); + color_p += w; + } +#endif + + monitor.sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + lv_disp_flush_ready(disp_drv); +#endif +} + + +#if MONITOR_DUAL + +/** + * Flush a buffer to the marked area + * @param drv pointer to driver where this function belongs + * @param area an area where to copy `color_p` + * @param color_p an array of pixel to copy to the `area` part of the screen + */ +void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) +{ + lv_coord_t hres = disp_drv->rotated == 0 ? disp_drv->hor_res : disp_drv->ver_res; + lv_coord_t vres = disp_drv->rotated == 0 ? disp_drv->ver_res : disp_drv->hor_res; + + /*Return if the area is out the screen*/ + if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) { + lv_disp_flush_ready(disp_drv); + return; + } + +#if MONITOR_DOUBLE_BUFFERED + monitor2.tft_fb_act = (uint32_t *)color_p; + + monitor2.sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + lv_disp_flush_ready(disp_drv); +#else + + int32_t y; +#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/ + int32_t x; + for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { + for(x = area->x1; x <= area->x2; x++) { + monitor2.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p); + color_p++; + } + + } +#else + uint32_t w = lv_area_get_width(area); + for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) { + memcpy(&monitor2.tft_fb[y * disp_drv->hor_res + area->x1], color_p, w * sizeof(lv_color_t)); + color_p += w; + } +#endif + + monitor2.sdl_refr_qry = true; + + /*IMPORTANT! It must be called to tell the system the flush is ready*/ + lv_disp_flush_ready(disp_drv); +#endif +} +#endif + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * SDL main thread. All SDL related task have to be handled here! + * It initializes SDL, handles drawing and the mouse. + */ + +static int monitor_sdl_refr_thread(void * param) +{ + (void)param; + + /*If not OSX initialize SDL in the Thread*/ +#ifndef MONITOR_APPLE + monitor_sdl_init(); +#endif + /*Run until quit event not arrives*/ + while(sdl_quit_qry == false) { + /*Refresh handling*/ + monitor_sdl_refr_core(); + } + + monitor_sdl_clean_up(); + exit(0); + + return 0; +} + +int quit_filter(void * userdata, SDL_Event * event) +{ + (void)userdata; + + if(event->type == SDL_WINDOWEVENT) { + if(event->window.event == SDL_WINDOWEVENT_CLOSE) { + sdl_quit_qry = true; + } + } + else if(event->type == SDL_QUIT) { + sdl_quit_qry = true; + } + + + + return 1; +} + +static void monitor_sdl_clean_up(void) +{ + SDL_DestroyTexture(monitor.texture); + SDL_DestroyRenderer(monitor.renderer); + SDL_DestroyWindow(monitor.window); + +#if MONITOR_DUAL + SDL_DestroyTexture(monitor2.texture); + SDL_DestroyRenderer(monitor2.renderer); + SDL_DestroyWindow(monitor2.window); + +#endif + + SDL_Quit(); +} + +static void monitor_sdl_init(void) +{ + /*Initialize the SDL*/ + SDL_Init(SDL_INIT_VIDEO); + + SDL_SetEventFilter(quit_filter, NULL); + + window_create(&monitor); +#if MONITOR_DUAL + window_create(&monitor2); + int x, y; + SDL_GetWindowPosition(monitor2.window, &x, &y); + SDL_SetWindowPosition(monitor.window, x + MONITOR_HOR_RES / 2 + 10, y); + SDL_SetWindowPosition(monitor2.window, x - MONITOR_HOR_RES / 2 - 10, y); +#endif + + sdl_inited = true; +} + +#ifdef MONITOR_EMSCRIPTEN +void monitor_sdl_refr_core(void) +#else +static void monitor_sdl_refr_core(void) +#endif +{ + + if(monitor.sdl_refr_qry != false) { + monitor.sdl_refr_qry = false; + window_update(&monitor); + } + +#if MONITOR_DUAL + if(monitor2.sdl_refr_qry != false) { + monitor2.sdl_refr_qry = false; + window_update(&monitor2); + } +#endif + +#if !defined(MONITOR_APPLE) && !defined(MONITOR_EMSCRIPTEN) + SDL_Event event; + while(SDL_PollEvent(&event)) { +#if USE_MOUSE != 0 + mouse_handler(&event); +#endif + +#if USE_MOUSEWHEEL != 0 + mousewheel_handler(&event); +#endif + +#if USE_KEYBOARD + keyboard_handler(&event); +#endif + if((&event)->type == SDL_WINDOWEVENT) { + switch((&event)->window.event) { +#if SDL_VERSION_ATLEAST(2, 0, 5) + case SDL_WINDOWEVENT_TAKE_FOCUS: +#endif + case SDL_WINDOWEVENT_EXPOSED: + window_update(&monitor); +#if MONITOR_DUAL + window_update(&monitor2); +#endif + break; + default: + break; + } + } + } +#endif /*MONITOR_APPLE*/ + + /*Sleep some time*/ + SDL_Delay(SDL_REFR_PERIOD); + +} + +static void window_create(monitor_t * m) +{ + m->window = SDL_CreateWindow("TFT Simulator", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ + +#if MONITOR_VIRTUAL_MACHINE || defined(MONITOR_EMSCRIPTEN) + m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_SOFTWARE); +#else + m->renderer = SDL_CreateRenderer(m->window, -1, 0); +#endif + m->texture = SDL_CreateTexture(m->renderer, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES); + SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_BLEND); + + /*Initialize the frame buffer to gray (77 is an empirical value) */ +#if MONITOR_DOUBLE_BUFFERED + SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t)); +#else + memset(m->tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t)); +#endif + + m->sdl_refr_qry = true; + +} + +static void window_update(monitor_t * m) +{ +#if MONITOR_DOUBLE_BUFFERED == 0 + SDL_UpdateTexture(m->texture, NULL, m->tft_fb, MONITOR_HOR_RES * sizeof(uint32_t)); +#else + if(m->tft_fb_act == NULL) return; + SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t)); +#endif + SDL_RenderClear(m->renderer); + /*Test: Draw a background to test transparent screens (LV_COLOR_SCREEN_TRANSP)*/ + // SDL_SetRenderDrawColor(renderer, 0xff, 0, 0, 0xff); + // SDL_Rect r; + // r.x = 0; r.y = 0; r.w = MONITOR_HOR_RES; r.w = MONITOR_VER_RES; + // SDL_RenderDrawRect(renderer, &r); + + /*Update the renderer with the texture containing the rendered image*/ + SDL_RenderCopy(m->renderer, m->texture, NULL, NULL); + SDL_RenderPresent(m->renderer); +} + +#endif /*USE_MONITOR*/ diff --git a/lib/lv_drivers/display/monitor.h b/lib/lv_drivers/display/monitor.h new file mode 100644 index 00000000..6ef4d6d3 --- /dev/null +++ b/lib/lv_drivers/display/monitor.h @@ -0,0 +1,57 @@ +/** + * @file monitor.h + * + */ + +#ifndef MONITOR_H +#define MONITOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_MONITOR + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void monitor_init(void); +void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); +void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); + +/********************** + * MACROS + **********************/ + +#endif /* USE_MONITOR */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* MONITOR_H */ diff --git a/lib/lv_drivers/display/tft_espi_drv.cpp b/lib/lv_drivers/display/tft_espi_drv.cpp new file mode 100644 index 00000000..01d3e93e --- /dev/null +++ b/lib/lv_drivers/display/tft_espi_drv.cpp @@ -0,0 +1,97 @@ +/** + * @file tft_espi_drv.cpp + * + */ + +/********************* + * INCLUDES + *********************/ +#include "tft_espi_drv.h" +#include "../../../src/hasp_tft.h" + +#if USE_TFT_ESPI != 0 + +#include +#include "TFT_eSPI.h" + +#include LV_DRV_DISP_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static TFT_eSPI tft; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the R61581 display controller + * @return HW_RES_OK or any error from hw_res_t enum + */ +void tft_espi_init(uint8_t rotation) +{ + /* TFT init */ + tft.begin(); + tft.setSwapBytes(true); /* set endianess */ + tft.setRotation(rotation); + +#ifdef USE_DMA_TO_TFT + // DMA - should work with STM32F2xx/F4xx/F7xx processors + // NOTE: >>>>>> DMA IS FOR SPI DISPLAYS ONLY <<<<<< + tft.initDMA(); // Initialise the DMA engine (tested with STM32F446 and STM32F767) +#endif + + tftSetup(tft); +} + +void tft_espi_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + size_t len = (x2 - x1 + 1) * (y2 - y1 + 1); /* Number of pixels */ + + /* Update TFT */ + tft.startWrite(); /* Start new TFT transaction */ + tft.setWindow(x1, y1, x2, y2); /* set the working window */ +#ifdef USE_DMA_TO_TFT + tft.pushPixelsDMA((uint16_t *)color_p, len); /* Write words at once */ +#else + tft.pushPixels((uint16_t *)color_p, len); /* Write words at once */ +#endif + tft.endWrite(); /* terminate TFT transaction */ + + /* Tell lvgl that flushing is done */ + // lv_disp_flush_ready(); +} + +void tft_espi_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color) +{ + tft.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1, color.full); +} + +void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + tft_espi_flush(x1, y1, x2, y2, color_p); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/display/tft_espi_drv.h b/lib/lv_drivers/display/tft_espi_drv.h new file mode 100644 index 00000000..c7791372 --- /dev/null +++ b/lib/lv_drivers/display/tft_espi_drv.h @@ -0,0 +1,67 @@ +/** + * @file tft_espi_drv.h + * + */ + +#ifndef TFT_ESPI_DRV_H +#define TFT_ESPI_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_TFT_ESPI + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ +#define ILI9341_DRIVER 1 +#define TFT_WIDTH 240 +#define TFT_HEIGHT 320 +#define TFT_ROTATION 2 // 0=0, 1=90, 2=180 or 3=270 degree +#define SPI_FREQUENCY 40000000 +#define SPI_TOUCH_FREQUENCY 2500000 +#define SPI_READ_FREQUENCY 20000000 +#define USER_SETUP_LOADED 1 +#define TOUCH_DRIVER 0 // XPT2606 Resistive touch panel driver +#define SUPPORT_TRANSACTIONS + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void tft_espi_init(uint8_t rotation); +void tft_espi_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +void tft_espi_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +void tft_espi_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +/********************** + * MACROS + **********************/ + +#endif /* USE_TFT_ESPI */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* TFT_ESPI_DRV_H */ diff --git a/lib/lv_drivers/docs/astyle_c b/lib/lv_drivers/docs/astyle_c new file mode 100644 index 00000000..9b9d7f3c --- /dev/null +++ b/lib/lv_drivers/docs/astyle_c @@ -0,0 +1 @@ +--style=kr --convert-tabs --indent=spaces=4 --indent-switches --pad-oper --unpad-paren --align-pointer=middle --suffix=.bak --lineend=linux --min-conditional-indent= diff --git a/lib/lv_drivers/docs/astyle_h b/lib/lv_drivers/docs/astyle_h new file mode 100644 index 00000000..d9c76337 --- /dev/null +++ b/lib/lv_drivers/docs/astyle_h @@ -0,0 +1 @@ +--convert-tabs --indent=spaces=4 diff --git a/lib/lv_drivers/indev/AD_touch.c b/lib/lv_drivers/indev/AD_touch.c new file mode 100644 index 00000000..c09c3593 --- /dev/null +++ b/lib/lv_drivers/indev/AD_touch.c @@ -0,0 +1,383 @@ +/** + * @file AD_touch.c + * + */ + +#include "AD_touch.h" + +#if USE_AD_TOUCH + +#include LV_DRV_INDEV_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +#define SAMPLE_POINTS 4 + +#define CALIBRATIONINSET 20 // range 0 <= CALIBRATIONINSET <= 40 + +#define RESISTIVETOUCH_AUTO_SAMPLE_MODE +#define TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD 350 // between 0-0x03ff the lesser this value + + +// Current ADC values for X and Y channels +int16_t adcX = 0; +int16_t adcY = 0; +volatile unsigned int adcTC = 0; + +// coefficient values +volatile long _trA; +volatile long _trB; +volatile long _trC; +volatile long _trD; + +volatile int16_t xRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULX, TOUCHCAL_URX, TOUCHCAL_LRX, TOUCHCAL_LLX}; +volatile int16_t yRawTouch[SAMPLE_POINTS] = {TOUCHCAL_ULY, TOUCHCAL_URY, TOUCHCAL_LRY, TOUCHCAL_LLY}; + +#define TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR 8 + +// use this scale factor to avoid working in floating point numbers +#define SCALE_FACTOR (1 << TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR) + +typedef enum { + IDLE, //0 + SET_X, //1 + RUN_X, //2 + GET_X, //3 + RUN_CHECK_X, //4 + CHECK_X, //5 + SET_Y, //6 + RUN_Y, //7 + GET_Y, //8 + CHECK_Y, //9 + SET_VALUES, //10 + GET_POT, //11 + RUN_POT //12 +} TOUCH_STATES; + +volatile TOUCH_STATES state = IDLE; + +#define CAL_X_INSET (((GetMaxX() + 1) * (CALIBRATIONINSET >> 1)) / 100) +#define CAL_Y_INSET (((GetMaxY() + 1) * (CALIBRATIONINSET >> 1)) / 100) + +int stat; +int16_t temp_x, temp_y; + + +static int16_t TouchGetX(void); +static int16_t TouchGetRawX(void); +static int16_t TouchGetY(void); +static int16_t TouchGetRawY(void); +static int16_t TouchDetectPosition(void); +static void TouchCalculateCalPoints(void); + + +/********************************************************************/ +void ad_touch_init(void) +{ + // Initialize ADC for auto sampling mode + AD1CON1 = 0; // reset + AD1CON2 = 0; // AVdd, AVss, int every conversion, MUXA only + AD1CON3 = 0x1FFF; // 31 Tad auto-sample, Tad = 256*Tcy + AD1CON1 = 0x80E0; // Turn on A/D module, use auto-convert + + + ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; + ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; + + AD1CSSL = 0; // No scanned inputs + + state = SET_X; // set the state of the state machine to start the sampling + + /*Load calibration data*/ + xRawTouch[0] = TOUCHCAL_ULX; + yRawTouch[0] = TOUCHCAL_ULY; + xRawTouch[1] = TOUCHCAL_URX; + yRawTouch[1] = TOUCHCAL_URY; + xRawTouch[3] = TOUCHCAL_LLX; + yRawTouch[3] = TOUCHCAL_LLY; + xRawTouch[2] = TOUCHCAL_LRX; + yRawTouch[2] = TOUCHCAL_LRY; + + TouchCalculateCalPoints(); +} + +/*Use this in lv_indev_drv*/ +bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + static int16_t last_x = 0; + static int16_t last_y = 0; + + int16_t x, y; + + x = TouchGetX(); + y = TouchGetY(); + + if((x > 0) && (y > 0)) { + data->point.x = x; + data->point.y = y; + last_x = data->point.x; + last_y = data->point.y; + data->state = LV_INDEV_STATE_PR; + } else { + data->point.x = last_x; + data->point.y = last_y; + data->state = LV_INDEV_STATE_REL; + } + + return false; +} + +/* Call periodically (e.g. in every 1 ms) to handle reading with ADC*/ +int16_t ad_touch_handler(void) +{ + static int16_t tempX, tempY; + int16_t temp; + + switch(state) { + case IDLE: + adcX = 0; + adcY = 0; + break; + + case SET_VALUES: + if(!TOUCH_ADC_DONE) + break; + if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { + adcX = 0; + adcY = 0; + } else { + adcX = tempX; + adcY = tempY; + } + state = SET_X; + return 1; // touch screen acquisition is done + + case SET_X: + TOUCH_ADC_INPUT_SEL = ADC_XPOS; + + ResistiveTouchScreen_XPlus_Config_As_Input(); + ResistiveTouchScreen_YPlus_Config_As_Input(); + ResistiveTouchScreen_XMinus_Config_As_Input(); + ResistiveTouchScreen_YMinus_Drive_Low(); + ResistiveTouchScreen_YMinus_Config_As_Output(); + + ADPCFG_YPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin + ADPCFG_XPOS = RESISTIVETOUCH_ANALOG; // set to analog pin + + TOUCH_ADC_START = 1; // run conversion + state = CHECK_X; + break; + + case CHECK_X: + case CHECK_Y: + + if(TOUCH_ADC_DONE == 0) { + break; + } + + if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD > (WORD)ADC1BUF0) { + if(state == CHECK_X) { + ResistiveTouchScreen_YPlus_Drive_High(); + ResistiveTouchScreen_YPlus_Config_As_Output(); + tempX = 0; + state = RUN_X; + } else { + ResistiveTouchScreen_XPlus_Drive_High(); + ResistiveTouchScreen_XPlus_Config_As_Output(); + tempY = 0; + state = RUN_Y; + } + } else { + adcX = 0; + adcY = 0; + state = SET_X; + return 1; // touch screen acquisition is done + break; + } + + case RUN_X: + case RUN_Y: + TOUCH_ADC_START = 1; + state = (state == RUN_X) ? GET_X : GET_Y; + // no break needed here since the next state is either GET_X or GET_Y + break; + + case GET_X: + case GET_Y: + if(!TOUCH_ADC_DONE) + break; + + temp = ADC1BUF0; + if(state == GET_X) { + if(temp != tempX) { + tempX = temp; + state = RUN_X; + break; + } + } else { + if(temp != tempY) { + tempY = temp; + state = RUN_Y; + break; + } + } + + if(state == GET_X) + ResistiveTouchScreen_YPlus_Config_As_Input(); + else + ResistiveTouchScreen_XPlus_Config_As_Input(); + TOUCH_ADC_START = 1; + state = (state == GET_X) ? SET_Y : SET_VALUES; + break; + + case SET_Y: + if(!TOUCH_ADC_DONE) + break; + + if((WORD)TOUCHSCREEN_RESISTIVE_PRESS_THRESHOLD < (WORD)ADC1BUF0) { + adcX = 0; + adcY = 0; + state = SET_X; + return 1; // touch screen acquisition is done + break; + } + + TOUCH_ADC_INPUT_SEL = ADC_YPOS; + + ResistiveTouchScreen_XPlus_Config_As_Input(); + ResistiveTouchScreen_YPlus_Config_As_Input(); + ResistiveTouchScreen_XMinus_Drive_Low(); + ResistiveTouchScreen_XMinus_Config_As_Output(); + ResistiveTouchScreen_YMinus_Config_As_Input(); + + ADPCFG_YPOS = RESISTIVETOUCH_ANALOG; // set to analog pin + ADPCFG_XPOS = RESISTIVETOUCH_DIGITAL; // set to digital pin + TOUCH_ADC_START = 1; // run conversion + state = CHECK_Y; + break; + + default: + state = SET_X; + return 1; // touch screen acquisition is done + } + stat = state; + temp_x = adcX; + temp_y = adcY; + + return 0; // touch screen acquisition is not done +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/********************************************************************/ +static int16_t TouchGetX(void) +{ + long result; + + result = TouchGetRawX(); + + if(result > 0) { + result = (long)((((long)_trC * result) + _trD) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); + + } + return ((int16_t)result); +} +/********************************************************************/ +static int16_t TouchGetRawX(void) +{ +#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY + return adcY; +#else + return adcX; +#endif +} + +/********************************************************************/ +static int16_t TouchGetY(void) +{ + + long result; + + result = TouchGetRawY(); + + if(result > 0) { + result = (long)((((long)_trA * result) + (long)_trB) >> TOUCHSCREEN_RESISTIVE_CALIBRATION_SCALE_FACTOR); + + } + return ((int16_t)result); +} + +/********************************************************************/ +static int16_t TouchGetRawY(void) +{ +#ifdef TOUCHSCREEN_RESISTIVE_SWAP_XY + return adcX; +#else + return adcY; +#endif +} + + +static void TouchCalculateCalPoints(void) +{ + long trA, trB, trC, trD; // variables for the coefficients + long trAhold, trBhold, trChold, trDhold; + long test1, test2; // temp variables (must be signed type) + + int16_t xPoint[SAMPLE_POINTS], yPoint[SAMPLE_POINTS]; + + yPoint[0] = yPoint[1] = CAL_Y_INSET; + yPoint[2] = yPoint[3] = (GetMaxY() - CAL_Y_INSET); + xPoint[0] = xPoint[3] = CAL_X_INSET; + xPoint[1] = xPoint[2] = (GetMaxX() - CAL_X_INSET); + + // calculate points transfer functiona + // based on two simultaneous equations solve for the + // constants + + // use sample points 1 and 4 + // Dy1 = aTy1 + b; Dy4 = aTy4 + b + // Dx1 = cTx1 + d; Dy4 = aTy4 + b + + test1 = (long)yPoint[0] - (long)yPoint[3]; + test2 = (long)yRawTouch[0] - (long)yRawTouch[3]; + + trA = ((long)((long)test1 * SCALE_FACTOR) / test2); + trB = ((long)((long)yPoint[0] * SCALE_FACTOR) - (trA * (long)yRawTouch[0])); + + test1 = (long)xPoint[0] - (long)xPoint[2]; + test2 = (long)xRawTouch[0] - (long)xRawTouch[2]; + + trC = ((long)((long)test1 * SCALE_FACTOR) / test2); + trD = ((long)((long)xPoint[0] * SCALE_FACTOR) - (trC * (long)xRawTouch[0])); + + trAhold = trA; + trBhold = trB; + trChold = trC; + trDhold = trD; + + // use sample points 2 and 3 + // Dy2 = aTy2 + b; Dy3 = aTy3 + b + // Dx2 = cTx2 + d; Dy3 = aTy3 + b + + test1 = (long)yPoint[1] - (long)yPoint[2]; + test2 = (long)yRawTouch[1] - (long)yRawTouch[2]; + + trA = ((long)(test1 * SCALE_FACTOR) / test2); + trB = ((long)((long)yPoint[1] * SCALE_FACTOR) - (trA * (long)yRawTouch[1])); + + test1 = (long)xPoint[1] - (long)xPoint[3]; + test2 = (long)xRawTouch[1] - (long)xRawTouch[3]; + + trC = ((long)((long)test1 * SCALE_FACTOR) / test2); + trD = ((long)((long)xPoint[1] * SCALE_FACTOR) - (trC * (long)xRawTouch[1])); + + // get the average and use the average + _trA = (trA + trAhold) >> 1; + _trB = (trB + trBhold) >> 1; + _trC = (trC + trChold) >> 1; + _trD = (trD + trDhold) >> 1; +} + +#endif diff --git a/lib/lv_drivers/indev/AD_touch.h b/lib/lv_drivers/indev/AD_touch.h new file mode 100644 index 00000000..7c07ab37 --- /dev/null +++ b/lib/lv_drivers/indev/AD_touch.h @@ -0,0 +1,120 @@ +/** + * @file AD_touch.h + * + */ + +#ifndef AD_TOUCH_H +#define AD_TOUCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_AD_TOUCH + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#define _SUPPRESS_PLIB_WARNING +#include + +#include "GenericTypeDefs.h" + +#define DISP_ORIENTATION 0 +#define DISP_HOR_RESOLUTION 320 +#define DISP_VER_RESOLUTION 240 + +/*GetMaxX Macro*/ +#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) +#define GetMaxX() (DISP_VER_RESOLUTION - 1) +#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) +#define GetMaxX() (DISP_HOR_RESOLUTION - 1) +#endif + +/*GetMaxY Macro*/ +#if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270) +#define GetMaxY() (DISP_HOR_RESOLUTION - 1) +#elif (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180) +#define GetMaxY() (DISP_VER_RESOLUTION - 1) +#endif + +/********************************************************************* + * HARDWARE PROFILE FOR THE RESISTIVE TOUCHSCREEN + *********************************************************************/ + +#define TOUCH_ADC_INPUT_SEL AD1CHS + +// ADC Sample Start +#define TOUCH_ADC_START AD1CON1bits.SAMP + +// ADC Status +#define TOUCH_ADC_DONE AD1CON1bits.DONE + +#define RESISTIVETOUCH_ANALOG 1 +#define RESISTIVETOUCH_DIGITAL 0 + +// ADC channel constants +#define ADC_XPOS ADC_CH0_POS_SAMPLEA_AN12 +#define ADC_YPOS ADC_CH0_POS_SAMPLEA_AN13 + +// ADC Port Control Bits +#define ADPCFG_XPOS AD1PCFGbits.PCFG12 //XR +#define ADPCFG_YPOS AD1PCFGbits.PCFG13 //YD + +// X port definitions +#define ResistiveTouchScreen_XPlus_Drive_High() LATBbits.LATB12 = 1 +#define ResistiveTouchScreen_XPlus_Drive_Low() LATBbits.LATB12 = 0 //LAT_XPOS +#define ResistiveTouchScreen_XPlus_Config_As_Input() TRISBbits.TRISB12 = 1 //TRIS_XPOS +#define ResistiveTouchScreen_XPlus_Config_As_Output() TRISBbits.TRISB12 = 0 + +#define ResistiveTouchScreen_XMinus_Drive_High() LATFbits.LATF0 = 1 +#define ResistiveTouchScreen_XMinus_Drive_Low() LATFbits.LATF0 = 0 //LAT_XNEG +#define ResistiveTouchScreen_XMinus_Config_As_Input() TRISFbits.TRISF0 = 1 //TRIS_XNEG +#define ResistiveTouchScreen_XMinus_Config_As_Output() TRISFbits.TRISF0 = 0 + +// Y port definitions +#define ResistiveTouchScreen_YPlus_Drive_High() LATBbits.LATB13 = 1 +#define ResistiveTouchScreen_YPlus_Drive_Low() LATBbits.LATB13 = 0 //LAT_YPOS +#define ResistiveTouchScreen_YPlus_Config_As_Input() TRISBbits.TRISB13 = 1 //TRIS_YPOS +#define ResistiveTouchScreen_YPlus_Config_As_Output() TRISBbits.TRISB13 = 0 + +#define ResistiveTouchScreen_YMinus_Drive_High() LATFbits.LATF1 = 1 +#define ResistiveTouchScreen_YMinus_Drive_Low() LATFbits.LATF1 = 0 //LAT_YNEG +#define ResistiveTouchScreen_YMinus_Config_As_Input() TRISFbits.TRISF1 = 1 //TRIS_YNEG +#define ResistiveTouchScreen_YMinus_Config_As_Output() TRISFbits.TRISF1 = 0 + +// Default calibration points +#define TOUCHCAL_ULX 0x0348 +#define TOUCHCAL_ULY 0x00CC +#define TOUCHCAL_URX 0x00D2 +#define TOUCHCAL_URY 0x00CE +#define TOUCHCAL_LLX 0x034D +#define TOUCHCAL_LLY 0x0335 +#define TOUCHCAL_LRX 0x00D6 +#define TOUCHCAL_LRY 0x032D + +void ad_touch_init(void); +bool ad_touch_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); +int16_t ad_touch_handler(void); + +#endif /* USE_AD_TOUCH */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AD_TOUCH_H */ diff --git a/lib/lv_drivers/indev/FT5406EE8.c b/lib/lv_drivers/indev/FT5406EE8.c new file mode 100644 index 00000000..e753a183 --- /dev/null +++ b/lib/lv_drivers/indev/FT5406EE8.c @@ -0,0 +1,179 @@ +/** + * @file FT5406EE8.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "FT5406EE8.h" +#if USE_FT5406EE8 + +#include +#include +#include LV_DRV_INDEV_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ + +#define I2C_WR_BIT 0x00 +#define I2C_RD_BIT 0x01 + +/*DEVICE MODES*/ +#define OPERAT_MD 0x00 +#define TEST_MD 0x04 +#define SYS_INF_MD 0x01 + +/*OPERATING MODE*/ +#define DEVICE_MODE 0x00 +#define GEST_ID 0x01 +#define TD_STATUS 0x02 + +#define FT5406EE8_FINGER_MAX 10 + +/*Register adresses*/ +#define FT5406EE8_REG_DEVICE_MODE 0x00 +#define FT5406EE8_REG_GEST_ID 0x01 +#define FT5406EE8_REG_TD_STATUS 0x02 +#define FT5406EE8_REG_YH 0x03 +#define FT5406EE8_REG_YL 0x04 +#define FT5406EE8_REG_XH 0x05 +#define FT5406EE8_REG_XL 0x06 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static bool ft5406ee8_get_touch_num(void); +static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * + */ +void ft5406ee8_init(void) +{ + +} + +/** + * Get the current position and state of the touchpad + * @param data store the read data here + * @return false: because no ore data to be read + */ +bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + static int16_t x_last; + static int16_t y_last; + int16_t x; + int16_t y; + bool valid = true; + + valid = ft5406ee8_get_touch_num(); + if(valid == true) { + valid = ft5406ee8_read_finger1(&x, &y); + } + + if(valid == true) { + x = (uint32_t)((uint32_t)x * 320) / 2048; + y = (uint32_t)((uint32_t)y * 240) / 2048; + + + x_last = x; + y_last = y; + } else { + x = x_last; + y = y_last; + } + + data->point.x = x; + data->point.y = y; + data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; + return false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static bool ft5406ee8_get_touch_num(void) +{ + bool ok = true; + uint8_t t_num = 0; + + LV_DRV_INDEV_I2C_START; + LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); + LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_TD_STATUS) + LV_DRV_INDEV_I2C_RESTART; + LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); + t_num = LV_DRV_INDEV_I2C_READ(0); + + /* Error if not touched or too much finger */ + if(t_num > FT5406EE8_FINGER_MAX || t_num == 0) { + ok = false; + } + + return ok; +} + +/** + * Read the x and y coordinated + * @param x store the x coordinate here + * @param y store the y coordinate here + * @return false: not valid point; true: valid point + */ +static bool ft5406ee8_read_finger1(int16_t * x, int16_t * y) +{ + uint8_t temp_xH = 0; + uint8_t temp_xL = 0; + uint8_t temp_yH = 0; + uint8_t temp_yL = 0; + + /*Read Y High and low byte*/ + LV_DRV_INDEV_I2C_START; + LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_WR_BIT); + LV_DRV_INDEV_I2C_WR(FT5406EE8_REG_YH) + LV_DRV_INDEV_I2C_RESTART; + LV_DRV_INDEV_I2C_WR((FT5406EE8_I2C_ADR << 1) | I2C_RD_BIT); + temp_yH = LV_DRV_INDEV_I2C_READ(1); + temp_yL = LV_DRV_INDEV_I2C_READ(1); + + /*The upper two bit must be 2 on valid press*/ + if(((temp_yH >> 6) & 0xFF) != 2) { + (void) LV_DRV_INDEV_I2C_READ(0); /*Dummy read to close read sequence*/ + *x = 0; + *y = 0; + return false; + } + + /*Read X High and low byte*/ + temp_xH = LV_DRV_INDEV_I2C_READ(1); + temp_xL = LV_DRV_INDEV_I2C_READ(0); + + /*Save the result*/ + *x = (temp_xH & 0x0F) << 8; + *x += temp_xL; + *y = (temp_yH & 0x0F) << 8; + *y += temp_yL; + + return true; +} + +#endif diff --git a/lib/lv_drivers/indev/FT5406EE8.h b/lib/lv_drivers/indev/FT5406EE8.h new file mode 100644 index 00000000..2d1eda7d --- /dev/null +++ b/lib/lv_drivers/indev/FT5406EE8.h @@ -0,0 +1,56 @@ +/** + * @file FT5406EE8.h + * + */ + +#ifndef FT5406EE8_H +#define FT5406EE8_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_FT5406EE8 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void ft5406ee8_init(void); +bool ft5406ee8_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +/********************** + * MACROS + **********************/ + +#endif /* USE_FT5406EE8 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FT5406EE8_H */ diff --git a/lib/lv_drivers/indev/XPT2046.c b/lib/lv_drivers/indev/XPT2046.c new file mode 100644 index 00000000..f27fa763 --- /dev/null +++ b/lib/lv_drivers/indev/XPT2046.c @@ -0,0 +1,174 @@ +/** + * @file XPT2046.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "XPT2046.h" +#if USE_XPT2046 + +#include +#include LV_DRV_INDEV_INCLUDE +#include LV_DRV_DELAY_INCLUDE + +/********************* + * DEFINES + *********************/ +#define CMD_X_READ 0b10010000 +#define CMD_Y_READ 0b11010000 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void xpt2046_corr(int16_t * x, int16_t * y); +static void xpt2046_avg(int16_t * x, int16_t * y); + +/********************** + * STATIC VARIABLES + **********************/ +int16_t avg_buf_x[XPT2046_AVG]; +int16_t avg_buf_y[XPT2046_AVG]; +uint8_t avg_last; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the XPT2046 + */ +void xpt2046_init(void) +{ + +} + +/** + * Get the current position and state of the touchpad + * @param data store the read data here + * @return false: because no ore data to be read + */ +bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + static int16_t last_x = 0; + static int16_t last_y = 0; + uint8_t buf; + + int16_t x = 0; + int16_t y = 0; + + uint8_t irq = LV_DRV_INDEV_IRQ_READ; + + if(irq == 0) { + LV_DRV_INDEV_SPI_CS(0); + + LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_X_READ); /*Start x read*/ + + buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read x MSB*/ + x = buf << 8; + buf = LV_DRV_INDEV_SPI_XCHG_BYTE(CMD_Y_READ); /*Until x LSB converted y command can be sent*/ + x += buf; + + buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y MSB*/ + y = buf << 8; + + buf = LV_DRV_INDEV_SPI_XCHG_BYTE(0); /*Read y LSB*/ + y += buf; + + /*Normalize Data*/ + x = x >> 3; + y = y >> 3; + xpt2046_corr(&x, &y); + xpt2046_avg(&x, &y); + + last_x = x; + last_y = y; + data->state = LV_INDEV_STATE_PR; + + LV_DRV_INDEV_SPI_CS(1); + } else { + x = last_x; + y = last_y; + avg_last = 0; + data->state = LV_INDEV_STATE_REL; + } + + data->point.x = x; + data->point.y = y; + + return false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +static void xpt2046_corr(int16_t * x, int16_t * y) +{ +#if XPT2046_XY_SWAP != 0 + int16_t swap_tmp; + swap_tmp = *x; + *x = *y; + *y = swap_tmp; +#endif + + if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN; + else(*x) = 0; + + if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN; + else(*y) = 0; + + (*x) = (uint32_t)((uint32_t)(*x) * XPT2046_HOR_RES) / + (XPT2046_X_MAX - XPT2046_X_MIN); + + (*y) = (uint32_t)((uint32_t)(*y) * XPT2046_VER_RES) / + (XPT2046_Y_MAX - XPT2046_Y_MIN); + +#if XPT2046_X_INV != 0 + (*x) = XPT2046_HOR_RES - (*x); +#endif + +#if XPT2046_Y_INV != 0 + (*y) = XPT2046_VER_RES - (*y); +#endif + + +} + + +static void xpt2046_avg(int16_t * x, int16_t * y) +{ + /*Shift out the oldest data*/ + uint8_t i; + for(i = XPT2046_AVG - 1; i > 0 ; i--) { + avg_buf_x[i] = avg_buf_x[i - 1]; + avg_buf_y[i] = avg_buf_y[i - 1]; + } + + /*Insert the new point*/ + avg_buf_x[0] = *x; + avg_buf_y[0] = *y; + if(avg_last < XPT2046_AVG) avg_last++; + + /*Sum the x and y coordinates*/ + int32_t x_sum = 0; + int32_t y_sum = 0; + for(i = 0; i < avg_last ; i++) { + x_sum += avg_buf_x[i]; + y_sum += avg_buf_y[i]; + } + + /*Normalize the sums*/ + (*x) = (int32_t)x_sum / avg_last; + (*y) = (int32_t)y_sum / avg_last; +} + +#endif diff --git a/lib/lv_drivers/indev/XPT2046.h b/lib/lv_drivers/indev/XPT2046.h new file mode 100644 index 00000000..7eee8c00 --- /dev/null +++ b/lib/lv_drivers/indev/XPT2046.h @@ -0,0 +1,56 @@ +/** + * @file XPT2046.h + * + */ + +#ifndef XPT2046_H +#define XPT2046_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_XPT2046 + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void xpt2046_init(void); +bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +/********************** + * MACROS + **********************/ + +#endif /* USE_XPT2046 */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* XPT2046_H */ diff --git a/lib/lv_drivers/indev/evdev.c b/lib/lv_drivers/indev/evdev.c new file mode 100644 index 00000000..9912e099 --- /dev/null +++ b/lib/lv_drivers/indev/evdev.c @@ -0,0 +1,223 @@ +/** + * @file evdev.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "evdev.h" +#if USE_EVDEV != 0 + +#include +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +int map(int x, int in_min, int in_max, int out_min, int out_max); + +/********************** + * STATIC VARIABLES + **********************/ +int evdev_fd; +int evdev_root_x; +int evdev_root_y; +int evdev_button; + +int evdev_key_val; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the evdev interface + */ +void evdev_init(void) +{ + evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY); + if(evdev_fd == -1) { + perror("unable open evdev interface:"); + return; + } + + fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); + + evdev_root_x = 0; + evdev_root_y = 0; + evdev_key_val = 0; + evdev_button = LV_INDEV_STATE_REL; +} +/** + * reconfigure the device file for evdev + * @param dev_name set the evdev device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool evdev_set_file(char* dev_name) +{ + if(evdev_fd != -1) { + close(evdev_fd); + } + evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY); + + if(evdev_fd == -1) { + perror("unable open evdev interface:"); + return false; + } + + fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK); + + evdev_root_x = 0; + evdev_root_y = 0; + evdev_key_val = 0; + evdev_button = LV_INDEV_STATE_REL; + + return true; +} +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data) +{ + struct input_event in; + + while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) { + if(in.type == EV_REL) { + if(in.code == REL_X) + #if EVDEV_SWAP_AXES + evdev_root_y += in.value; + #else + evdev_root_x += in.value; + #endif + else if(in.code == REL_Y) + #if EVDEV_SWAP_AXES + evdev_root_x += in.value; + #else + evdev_root_y += in.value; + #endif + } else if(in.type == EV_ABS) { + if(in.code == ABS_X) + #if EVDEV_SWAP_AXES + evdev_root_y = in.value; + #else + evdev_root_x = in.value; + #endif + else if(in.code == ABS_Y) + #if EVDEV_SWAP_AXES + evdev_root_x = in.value; + #else + evdev_root_y = in.value; + #endif + else if(in.code == ABS_MT_POSITION_X) + #if EVDEV_SWAP_AXES + evdev_root_y = in.value; + #else + evdev_root_x = in.value; + #endif + else if(in.code == ABS_MT_POSITION_Y) + #if EVDEV_SWAP_AXES + evdev_root_x = in.value; + #else + evdev_root_y = in.value; + #endif + } else if(in.type == EV_KEY) { + if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { + if(in.value == 0) + evdev_button = LV_INDEV_STATE_REL; + else if(in.value == 1) + evdev_button = LV_INDEV_STATE_PR; + } else if(drv->type == LV_INDEV_TYPE_KEYPAD) { + data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + switch(in.code) { + case KEY_BACKSPACE: + data->key = LV_KEY_BACKSPACE; + break; + case KEY_ENTER: + data->key = LV_KEY_ENTER; + break; + case KEY_UP: + data->key = LV_KEY_UP; + break; + case KEY_LEFT: + data->key = LV_KEY_PREV; + break; + case KEY_RIGHT: + data->key = LV_KEY_NEXT; + break; + case KEY_DOWN: + data->key = LV_KEY_DOWN; + break; + default: + data->key = 0; + break; + } + evdev_key_val = data->key; + evdev_button = data->state; + return false; + } + } + } + + if(drv->type == LV_INDEV_TYPE_KEYPAD) { + /* No data retrieved */ + data->key = evdev_key_val; + data->state = evdev_button; + return false; + } + if(drv->type != LV_INDEV_TYPE_POINTER) + return false; + /*Store the collected data*/ + +#if EVDEV_SCALE + data->point.x = map(evdev_root_x, 0, EVDEV_SCALE_HOR_RES, 0, lv_disp_get_hor_res(drv->disp)); + data->point.y = map(evdev_root_y, 0, EVDEV_SCALE_VER_RES, 0, lv_disp_get_ver_res(drv->disp)); +#endif +#if EVDEV_CALIBRATE + data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, lv_disp_get_hor_res(drv->disp)); + data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, lv_disp_get_ver_res(drv->disp)); +#else + data->point.x = evdev_root_x; + data->point.y = evdev_root_y; +#endif + + data->state = evdev_button; + + if(data->point.x < 0) + data->point.x = 0; + if(data->point.y < 0) + data->point.y = 0; + if(data->point.x >= lv_disp_get_hor_res(drv->disp)) + data->point.x = lv_disp_get_hor_res(drv->disp) - 1; + if(data->point.y >= lv_disp_get_ver_res(drv->disp)) + data->point.y = lv_disp_get_ver_res(drv->disp) - 1; + + return false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ +int map(int x, int in_min, int in_max, int out_min, int out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +#endif diff --git a/lib/lv_drivers/indev/evdev.h b/lib/lv_drivers/indev/evdev.h new file mode 100644 index 00000000..3a598dd4 --- /dev/null +++ b/lib/lv_drivers/indev/evdev.h @@ -0,0 +1,73 @@ +/** + * @file evdev.h + * + */ + +#ifndef EVDEV_H +#define EVDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_EVDEV + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the evdev + */ +void evdev_init(void); +/** + * reconfigure the device file for evdev + * @param dev_name set the evdev device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool evdev_set_file(char* dev_name); +/** + * Get the current position and state of the evdev + * @param data store the evdev data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data); + + +/********************** + * MACROS + **********************/ + +#endif /* USE_EVDEV */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* EVDEV_H */ diff --git a/lib/lv_drivers/indev/indev.mk b/lib/lv_drivers/indev/indev.mk new file mode 100644 index 00000000..09ff47d0 --- /dev/null +++ b/lib/lv_drivers/indev/indev.mk @@ -0,0 +1,12 @@ +CSRCS += FT5406EE8.c +CSRCS += keyboard.c +CSRCS += mouse.c +CSRCS += mousewheel.c +CSRCS += evdev.c +CSRCS += libinput.c +CSRCS += XPT2046.c + +DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers/indev +VPATH += :$(LVGL_DIR)/lv_drivers/indev + +CFLAGS += "-I$(LVGL_DIR)/lv_drivers/indev" diff --git a/lib/lv_drivers/indev/keyboard.c b/lib/lv_drivers/indev/keyboard.c new file mode 100644 index 00000000..2f4549af --- /dev/null +++ b/lib/lv_drivers/indev/keyboard.c @@ -0,0 +1,130 @@ +/** + * @file sdl_kb.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "keyboard.h" +#if USE_KEYBOARD + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static uint32_t keycode_to_ascii(uint32_t sdl_key); + +/********************** + * STATIC VARIABLES + **********************/ +static uint32_t last_key; +static lv_indev_state_t state; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the keyboard + */ +void keyboard_init(void) +{ + /*Nothing to init*/ +} + +/** + * Get the last pressed or released character from the PC's keyboard + * @param indev_drv pointer to the related input device driver + * @param data store the read data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + (void) indev_drv; /*Unused*/ + data->state = state; + data->key = keycode_to_ascii(last_key); + + return false; +} + +/** + * It is called periodically from the SDL thread to check a key is pressed/released + * @param event describes the event + */ +void keyboard_handler(SDL_Event * event) +{ + /* We only care about SDL_KEYDOWN and SDL_KEYUP events */ + switch(event->type) { + case SDL_KEYDOWN: /*Button press*/ + last_key = event->key.keysym.sym; /*Save the pressed key*/ + state = LV_INDEV_STATE_PR; /*Save the key is pressed now*/ + break; + case SDL_KEYUP: /*Button release*/ + state = LV_INDEV_STATE_REL; /*Save the key is released but keep the last key*/ + break; + default: + break; + + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * Convert the key code LV_KEY_... "codes" or leave them if they are not control characters + * @param sdl_key the key code + * @return + */ +static uint32_t keycode_to_ascii(uint32_t sdl_key) +{ + /*Remap some key to LV_KEY_... to manage groups*/ + switch(sdl_key) { + case SDLK_RIGHT: + case SDLK_KP_PLUS: + return LV_KEY_RIGHT; + + case SDLK_LEFT: + case SDLK_KP_MINUS: + return LV_KEY_LEFT; + + case SDLK_UP: + return LV_KEY_UP; + + case SDLK_DOWN: + return LV_KEY_DOWN; + + case SDLK_ESCAPE: + return LV_KEY_ESC; + +#ifdef LV_KEY_BACKSPACE /*For backward compatibility*/ + case SDLK_BACKSPACE: + return LV_KEY_BACKSPACE; +#endif + +#ifdef LV_KEY_DEL /*For backward compatibility*/ + case SDLK_DELETE: + return LV_KEY_DEL; +#endif + case SDLK_KP_ENTER: + case '\r': + return LV_KEY_ENTER; + + default: + return sdl_key; + } +} +#endif diff --git a/lib/lv_drivers/indev/keyboard.h b/lib/lv_drivers/indev/keyboard.h new file mode 100644 index 00000000..03ca15b3 --- /dev/null +++ b/lib/lv_drivers/indev/keyboard.h @@ -0,0 +1,78 @@ +/** + * @file keyboard.h + * + */ + +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_KEYBOARD + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef MONITOR_SDL_INCLUDE_PATH +#define MONITOR_SDL_INCLUDE_PATH +#endif + +#include MONITOR_SDL_INCLUDE_PATH + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Initialize the keyboard + */ +void keyboard_init(void); + +/** + * Get the last pressed or released character from the PC's keyboard + * @param indev_drv pointer to the related input device driver + * @param data store the read data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +/** + * It is called periodically from the SDL thread to check a key is pressed/released + * @param event describes the event + */ +void keyboard_handler(SDL_Event *event); + +/********************** + * MACROS + **********************/ + +#endif /*USE_KEYBOARD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*KEYBOARD_H*/ diff --git a/lib/lv_drivers/indev/libinput.c b/lib/lv_drivers/indev/libinput.c new file mode 100644 index 00000000..98dfd7df --- /dev/null +++ b/lib/lv_drivers/indev/libinput.c @@ -0,0 +1,175 @@ +/** + * @file libinput.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "libinput_drv.h" +#if USE_LIBINPUT != 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static int open_restricted(const char *path, int flags, void *user_data); +static void close_restricted(int fd, void *user_data); + +/********************** + * STATIC VARIABLES + **********************/ +static int libinput_fd; +static int libinput_button; +static const int timeout = 0; // do not block +static const nfds_t nfds = 1; +static struct pollfd fds[1]; +static lv_point_t most_recent_touch_point = { .x = 0, .y = 0}; + +static struct libinput *libinput_context; +static struct libinput_device *libinput_device; +const static struct libinput_interface interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * reconfigure the device file for libinput + * @param dev_name set the libinput device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool libinput_set_file(char* dev_name) +{ + // This check *should* not be necessary, yet applications crashes even on NULL handles. + // citing libinput.h:libinput_path_remove_device: + // > If no matching device exists, this function does nothing. + if (libinput_device) { + libinput_device = libinput_device_unref(libinput_device); + libinput_path_remove_device(libinput_device); + } + + libinput_device = libinput_path_add_device(libinput_context, dev_name); + if(!libinput_device) { + perror("unable to add device to libinput context:"); + return false; + } + libinput_device = libinput_device_ref(libinput_device); + if(!libinput_device) { + perror("unable to reference device within libinput context:"); + return false; + } + + libinput_button = LV_INDEV_STATE_REL; + + return true; +} + +/** + * Initialize the libinput interface + */ +void libinput_init(void) +{ + libinput_device = NULL; + libinput_context = libinput_path_create_context(&interface, NULL); + if(!libinput_set_file(LIBINPUT_NAME)) { + perror("unable to add device \"" LIBINPUT_NAME "\" to libinput context:"); + return; + } + libinput_fd = libinput_get_fd(libinput_context); + + /* prepare poll */ + fds[0].fd = libinput_fd; + fds[0].events = POLLIN; + fds[0].revents = 0; +} + +/** + * Get the current position and state of the libinput + * @param indev_drv driver object itself + * @param data store the libinput data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + struct libinput_event *event; + struct libinput_event_touch *touch_event = NULL; + int rc = 0; + + rc = poll(fds, nfds, timeout); + switch (rc){ + case -1: + perror(NULL); + case 0: + goto report_most_recent_state; + default: + break; + } + libinput_dispatch(libinput_context); + while((event = libinput_get_event(libinput_context)) != NULL) { + enum libinput_event_type type = libinput_event_get_type(event); + switch (type) { + case LIBINPUT_EVENT_TOUCH_MOTION: + case LIBINPUT_EVENT_TOUCH_DOWN: + touch_event = libinput_event_get_touch_event(event); + most_recent_touch_point.x = libinput_event_touch_get_x_transformed(touch_event, LV_HOR_RES); + most_recent_touch_point.y = libinput_event_touch_get_y_transformed(touch_event, LV_VER_RES); + libinput_button = LV_INDEV_STATE_PR; + break; + case LIBINPUT_EVENT_TOUCH_UP: + libinput_button = LV_INDEV_STATE_REL; + break; + default: + break; + } + libinput_event_destroy(event); + } +report_most_recent_state: + data->point.x = most_recent_touch_point.x; + data->point.y = most_recent_touch_point.y; + data->state = libinput_button; + + return false; +} + + +/********************** + * STATIC FUNCTIONS + **********************/ + +static int open_restricted(const char *path, int flags, void *user_data) +{ + int fd = open(path, flags); + return fd < 0 ? -errno : fd; +} + +static void close_restricted(int fd, void *user_data) +{ + close(fd); +} + +#endif diff --git a/lib/lv_drivers/indev/libinput_drv.h b/lib/lv_drivers/indev/libinput_drv.h new file mode 100644 index 00000000..ae1ee42c --- /dev/null +++ b/lib/lv_drivers/indev/libinput_drv.h @@ -0,0 +1,74 @@ +/** + * @file libinput.h + * + */ + +#ifndef LVGL_LIBINPUT_H +#define LVGL_LIBINPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_LIBINPUT + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the libinput + */ +void libinput_init(void); +/** + * reconfigure the device file for libinput + * @param dev_name set the libinput device filename + * @return true: the device file set complete + * false: the device file doesn't exist current system + */ +bool libinput_set_file(char* dev_name); +/** + * Get the current position and state of the libinput + * @param indev_drv driver object itself + * @param data store the libinput data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool libinput_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + + +/********************** + * MACROS + **********************/ + +#endif /* USE_LIBINPUT */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LVGL_LIBINPUT_H */ diff --git a/lib/lv_drivers/indev/mouse.c b/lib/lv_drivers/indev/mouse.c new file mode 100644 index 00000000..01d850fa --- /dev/null +++ b/lib/lv_drivers/indev/mouse.c @@ -0,0 +1,98 @@ +/** + * @file mouse.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "mouse.h" +#if USE_MOUSE != 0 + +/********************* + * DEFINES + *********************/ +#ifndef MONITOR_ZOOM +#define MONITOR_ZOOM 1 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static bool left_button_down = false; +static int16_t last_x = 0; +static int16_t last_y = 0; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the mouse + */ +void mouse_init(void) +{ + +} + +/** + * Get the current position and state of the mouse + * @param indev_drv pointer to the related input device driver + * @param data store the mouse data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + (void) indev_drv; /*Unused*/ + + /*Store the collected data*/ + data->point.x = last_x; + data->point.y = last_y; + data->state = left_button_down ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + + return false; +} + +/** + * It will be called from the main SDL thread + */ +void mouse_handler(SDL_Event * event) +{ + switch(event->type) { + case SDL_MOUSEBUTTONUP: + if(event->button.button == SDL_BUTTON_LEFT) + left_button_down = false; + break; + case SDL_MOUSEBUTTONDOWN: + if(event->button.button == SDL_BUTTON_LEFT) { + left_button_down = true; + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + } + break; + case SDL_MOUSEMOTION: + last_x = event->motion.x / MONITOR_ZOOM; + last_y = event->motion.y / MONITOR_ZOOM; + + break; + } + +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/indev/mouse.h b/lib/lv_drivers/indev/mouse.h new file mode 100644 index 00000000..bd04dee1 --- /dev/null +++ b/lib/lv_drivers/indev/mouse.h @@ -0,0 +1,78 @@ +/** + * @file mouse.h + * + */ + +#ifndef MOUSE_H +#define MOUSE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_MOUSE + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef MONITOR_SDL_INCLUDE_PATH +#define MONITOR_SDL_INCLUDE_PATH +#endif + +#include MONITOR_SDL_INCLUDE_PATH + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the mouse + */ +void mouse_init(void); + +/** + * Get the current position and state of the mouse + * @param indev_drv pointer to the related input device driver + * @param data store the mouse data here + * @return false: because the points are not buffered, so no more data to be read + */ +bool mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +/** + * It will be called from the main SDL thread + */ +void mouse_handler(SDL_Event *event); + +/********************** + * MACROS + **********************/ + +#endif /* USE_MOUSE */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* MOUSE_H */ diff --git a/lib/lv_drivers/indev/mousewheel.c b/lib/lv_drivers/indev/mousewheel.c new file mode 100644 index 00000000..7ada72fd --- /dev/null +++ b/lib/lv_drivers/indev/mousewheel.c @@ -0,0 +1,100 @@ +/** + * @file mousewheel.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "mousewheel.h" +#if USE_MOUSEWHEEL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static int16_t enc_diff = 0; +static lv_indev_state_t state = LV_INDEV_STATE_REL; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the mousewheel + */ +void mousewheel_init(void) +{ + /*Nothing to init*/ +} + +/** + * Get encoder (i.e. mouse wheel) ticks difference and pressed state + * @param indev_drv pointer to the related input device driver + * @param data store the read data here + * @return false: all ticks and button state are handled + */ +bool mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) +{ + (void) indev_drv; /*Unused*/ + + data->state = state; + data->enc_diff = enc_diff; + enc_diff = 0; + + return false; /*No more data to read so return false*/ +} + +/** + * It is called periodically from the SDL thread to check mouse wheel state + * @param event describes the event + */ +void mousewheel_handler(SDL_Event * event) +{ + switch(event->type) { + case SDL_MOUSEWHEEL: + // Scroll down (y = -1) means positive encoder turn, + // so invert it +#ifdef __EMSCRIPTEN__ + /*Escripten scales it wrong*/ + if(event->wheel.y < 0) enc_diff++; + if(event->wheel.y > 0) enc_diff--; +#else + enc_diff = -event->wheel.y; +#endif + break; + case SDL_MOUSEBUTTONDOWN: + if(event->button.button == SDL_BUTTON_MIDDLE) { + state = LV_INDEV_STATE_PR; + } + break; + case SDL_MOUSEBUTTONUP: + if(event->button.button == SDL_BUTTON_MIDDLE) { + state = LV_INDEV_STATE_REL; + } + break; + default: + break; + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif diff --git a/lib/lv_drivers/indev/mousewheel.h b/lib/lv_drivers/indev/mousewheel.h new file mode 100644 index 00000000..cbe1ed45 --- /dev/null +++ b/lib/lv_drivers/indev/mousewheel.h @@ -0,0 +1,79 @@ +/** + * @file mousewheel.h + * + */ + +#ifndef MOUSEWHEEL_H +#define MOUSEWHEEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../../lv_drv_conf.h" +#endif +#endif + +#if USE_MOUSEWHEEL + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#ifndef MONITOR_SDL_INCLUDE_PATH +#define MONITOR_SDL_INCLUDE_PATH +#endif + +#include MONITOR_SDL_INCLUDE_PATH + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the encoder + */ +void mousewheel_init(void); + +/** + * Get encoder (i.e. mouse wheel) ticks difference and pressed state + * @param indev_drv pointer to the related input device driver + * @param data store the read data here + * @return false: all ticks and button state are handled + */ +bool mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +/** + * It is called periodically from the SDL thread to check a key is pressed/released + * @param event describes the event + */ +void mousewheel_handler(SDL_Event *event); + +/********************** + * MACROS + **********************/ + +#endif /*USE_MOUSEWHEEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*MOUSEWHEEL_H*/ diff --git a/lib/lv_drivers/library.json b/lib/lv_drivers/library.json new file mode 100644 index 00000000..cdb6e888 --- /dev/null +++ b/lib/lv_drivers/library.json @@ -0,0 +1,13 @@ +{ + "name": "lv_drivers", + "version": "6.0.2", + "keywords": "littlevgl, lvgl, driver, display, touchpad", + "description": "Drivers for LittlevGL graphics library.", + "repository": { + "type": "git", + "url": "https://github.com/littlevgl/lv_drivers.git" + }, + "build": { + "includeDir": "." + } +} diff --git a/lib/lv_drivers/lv_drivers.mk b/lib/lv_drivers/lv_drivers.mk new file mode 100644 index 00000000..1bb786c1 --- /dev/null +++ b/lib/lv_drivers/lv_drivers.mk @@ -0,0 +1,10 @@ +include $(LVGL_DIR)/lv_drivers/display/display.mk +include $(LVGL_DIR)/lv_drivers/indev/indev.mk + + +CSRCS += win_drv.c + +DEPPATH += --dep-path $(LVGL_DIR)/lv_drivers +VPATH += :$(LVGL_DIR)/lv_drivers + +CFLAGS += "-I$(LVGL_DIR)/lv_drivers" diff --git a/lib/lv_drivers/lv_drv_conf_templ.h b/lib/lv_drivers/lv_drv_conf_templ.h new file mode 100644 index 00000000..e3367d38 --- /dev/null +++ b/lib/lv_drivers/lv_drv_conf_templ.h @@ -0,0 +1,357 @@ +/** + * @file lv_drv_conf.h + * + */ + +/* + * COPY THIS FILE AS lv_drv_conf.h + */ + +#if 0 /*Set it to "1" to enable the content*/ + +#ifndef LV_DRV_CONF_H +#define LV_DRV_CONF_H + +#include "lv_conf.h" + +/********************* + * DELAY INTERFACE + *********************/ +#define LV_DRV_DELAY_INCLUDE /*Dummy include by default*/ +#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/ +#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/ + +/********************* + * DISPLAY INTERFACE + *********************/ + +/*------------ + * Common + *------------*/ +#define LV_DRV_DISP_INCLUDE /*Dummy include by default*/ +#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/ +#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ + +/*--------- + * SPI + *---------*/ +#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ +#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/ +#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/ + +/*------------------ + * Parallel port + *-----------------*/ +#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/ +#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/ +#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/ +#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/ +#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/ + +/*************************** + * INPUT DEVICE INTERFACE + ***************************/ + +/*---------- + * Common + *----------*/ +#define LV_DRV_INDEV_INCLUDE /*Dummy include by default*/ +#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/ +#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/ + +/*--------- + * SPI + *---------*/ +#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/ +#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/ + +/*--------- + * I2C + *---------*/ +#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/ +#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/ +#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/ +#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/ +#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/ + + +/********************* + * DISPLAY DRIVERS + *********************/ + +/*------------------- + * Monitor of PC + *-------------------*/ +#ifndef USE_MONITOR +# define USE_MONITOR 0 +#endif + +#if USE_MONITOR +# define MONITOR_HOR_RES LV_HOR_RES +# define MONITOR_VER_RES LV_VER_RES + +/* Scale window by this factor (useful when simulating small screens) */ +# define MONITOR_ZOOM 1 + +/* Used to test true double buffering with only address changing. + * Set LV_VDB_SIZE = (LV_HOR_RES * LV_VER_RES) and LV_VDB_DOUBLE = 1 and LV_COLOR_DEPTH = 32" */ +# define MONITOR_DOUBLE_BUFFERED 0 + +/*Eclipse: Visual Studio: */ +# define MONITOR_SDL_INCLUDE_PATH + +/*Different rendering might be used if running in a Virtual machine*/ +# define MONITOR_VIRTUAL_MACHINE 0 + +/*Open two windows to test multi display support*/ +# define MONITOR_DUAL 0 +#endif + +/*----------------------------------- + * Native Windows (including mouse) + *----------------------------------*/ +#ifndef USE_WINDOWS +# define USE_WINDOWS 0 +#endif + +#define USE_WINDOWS 0 +#if USE_WINDOWS +# define WINDOW_HOR_RES 480 +# define WINDOW_VER_RES 320 +#endif + +/*---------------- + * SSD1963 + *--------------*/ +#ifndef USE_SSD1963 +# define USE_SSD1963 0 +#endif + +#if USE_SSD1963 +# define SSD1963_HOR_RES LV_HOR_RES +# define SSD1963_VER_RES LV_VER_RES +# define SSD1963_HT 531 +# define SSD1963_HPS 43 +# define SSD1963_LPS 8 +# define SSD1963_HPW 10 +# define SSD1963_VT 288 +# define SSD1963_VPS 12 +# define SSD1963_FPS 4 +# define SSD1963_VPW 10 +# define SSD1963_HS_NEG 0 /*Negative hsync*/ +# define SSD1963_VS_NEG 0 /*Negative vsync*/ +# define SSD1963_ORI 0 /*0, 90, 180, 270*/ +# define SSD1963_COLOR_DEPTH 16 +#endif + +/*---------------- + * R61581 + *--------------*/ +#ifndef USE_R61581 +# define USE_R61581 0 +#endif + +#if USE_R61581 +# define R61581_HOR_RES LV_HOR_RES +# define R61581_VER_RES LV_VER_RES +# define R61581_HSPL 0 /*HSYNC signal polarity*/ +# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/ +# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/ +# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */ +# define R61581_VSPL 0 /*VSYNC signal polarity*/ +# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/ +# define R61581_VFP 8 /*Vertical Front poarch*/ +# define R61581_VBP 8 /*Vertical Back poarch */ +# define R61581_DPL 0 /*DCLK signal polarity*/ +# define R61581_EPL 1 /*ENABLE signal polarity*/ +# define R61581_ORI 0 /*0, 180*/ +# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/ +#endif + +/*------------------------------ + * ST7565 (Monochrome, low res.) + *-----------------------------*/ +#ifndef USE_ST7565 +# define USE_ST7565 0 +#endif + +#if USE_ST7565 +/*No settings*/ +#endif /*USE_ST7565*/ + +/*------------------------------------------ + * UC1610 (4 gray 160*[104|128]) + * (EA DOGXL160 160x104 tested) + *-----------------------------------------*/ +#ifndef USE_UC1610 +# define USE_UC1610 0 +#endif + +#if USE_UC1610 +# define UC1610_HOR_RES LV_HOR_RES +# define UC1610_VER_RES LV_VER_RES +# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */ +# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */ +# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */ +#endif /*USE_UC1610*/ + +/*------------------------------------------------- + * SHARP memory in pixel monochrome display series + * LS012B7DD01 (184x38 pixels.) + * LS013B7DH03 (128x128 pixels.) + * LS013B7DH05 (144x168 pixels.) + * LS027B7DH01 (400x240 pixels.) (tested) + * LS032B7DD02 (336x536 pixels.) + * LS044Q7DH01 (320x240 pixels.) + *------------------------------------------------*/ +#ifndef USE_SHARP_MIP +# define USE_SHARP_MIP 0 +#endif + +#if USE_SHARP_MIP +# define SHARP_MIP_HOR_RES LV_HOR_RES +# define SHARP_MIP_VER_RES LV_VER_RES +# define SHARP_MIP_SOFT_COM_INVERSION 0 +# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/ +#endif /*USE_SHARP_MIP*/ + +/*----------------------------------------- + * Linux frame buffer device (/dev/fbx) + *-----------------------------------------*/ +#ifndef USE_FBDEV +# define USE_FBDEV 0 +#endif + +#if USE_FBDEV +# define FBDEV_PATH "/dev/fb0" +#endif + +/*----------------------------------------- + * FreeBSD frame buffer device (/dev/fbx) + *.........................................*/ +#ifndef USE_BSD_FBDEV +# define USE_BSD_FBDEV 0 +#endif + +#if USE_BSD_FBDEV +# define FBDEV_PATH "/dev/fb0" +#endif + +/********************* + * INPUT DEVICES + *********************/ + +/*-------------- + * XPT2046 + *--------------*/ +#ifndef USE_XPT2046 +# define USE_XPT2046 0 +#endif + +#if USE_XPT2046 +# define XPT2046_HOR_RES 480 +# define XPT2046_VER_RES 320 +# define XPT2046_X_MIN 200 +# define XPT2046_Y_MIN 200 +# define XPT2046_X_MAX 3800 +# define XPT2046_Y_MAX 3800 +# define XPT2046_AVG 4 +# define XPT2046_INV 0 +#endif + +/*----------------- + * FT5406EE8 + *-----------------*/ +#ifndef USE_FT5406EE8 +# define USE_FT5406EE8 0 +#endif + +#if USE_FT5406EE8 +# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/ +#endif + +/*--------------- + * AD TOUCH + *--------------*/ +#ifndef USE_AD_TOUCH +# define USE_AD_TOUCH 0 +#endif + +#if USE_AD_TOUCH +/*No settings*/ +#endif + + +/*--------------------------------------- + * Mouse or touchpad on PC (using SDL) + *-------------------------------------*/ +#ifndef USE_MOUSE +# define USE_MOUSE 0 +#endif + +#if USE_MOUSE +/*No settings*/ +#endif + +/*------------------------------------------- + * Mousewheel as encoder on PC (using SDL) + *------------------------------------------*/ +#ifndef USE_MOUSEWHEEL +# define USE_MOUSEWHEEL 0 +#endif + +#if USE_MOUSEWHEEL +/*No settings*/ +#endif + +/*------------------------------------------------- + * Touchscreen as libinput interface (for Linux based systems) + *------------------------------------------------*/ +#ifndef USE_LIBINPUT +# define USE_LIBINPUT 0 +#endif + +#if USE_LIBINPUT +# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ +#endif /*USE_LIBINPUT*/ + +/*------------------------------------------------- + * Mouse or touchpad as evdev interface (for Linux based systems) + *------------------------------------------------*/ +#ifndef USE_EVDEV +# define USE_EVDEV 0 +#endif + +#if USE_EVDEV +# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/ +# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/ + +# define EVDEV_SCALE 0 /* Scale input, e.g. if touchscreen resolution does not match display resolution */ +# if EVDEV_SCALE +# define EVDEV_SCALE_HOR_RES (4096) /* Horizontal resolution of touchscreen */ +# define EVDEV_SCALE_VER_RES (4096) /* Vertical resolution of touchscreen */ +# endif /*EVDEV_SCALE*/ + +# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/ +# if EVDEV_CALIBRATE +# define EVDEV_HOR_MIN 3800 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/ +# define EVDEV_HOR_MAX 200 +# define EVDEV_VER_MIN 200 +# define EVDEV_VER_MAX 3800 +# endif /*EVDEV_SCALE*/ +#endif /*USE_EVDEV*/ + +/*------------------------------- + * Keyboard of a PC (using SDL) + *------------------------------*/ +#ifndef USE_KEYBOARD +# define USE_KEYBOARD 0 +#endif + +#if USE_KEYBOARD +/*No settings*/ +#endif + +#endif /*LV_DRV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/lib/lv_drivers/win_drv.c b/lib/lv_drivers/win_drv.c new file mode 100644 index 00000000..3115f555 --- /dev/null +++ b/lib/lv_drivers/win_drv.c @@ -0,0 +1,318 @@ +/** + * @file win_drv.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "win_drv.h" +#if USE_WINDOWS + +#include +#include +#include "lvgl/lvgl.h" + +#if LV_COLOR_DEPTH < 16 +#error Windows driver only supports true RGB colors at this time +#endif + +/********************** + * DEFINES + **********************/ + + #define WINDOW_STYLE (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME)) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void do_register(void); +static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p); +static void win_drv_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); +static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); +static bool win_drv_read(lv_indev_t *drv, lv_indev_data_t * data); +static void msg_handler(void *param); + +static COLORREF lv_color_to_colorref(const lv_color_t color); + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + +/********************** + * GLOBAL VARIABLES + **********************/ + +bool lv_win_exit_flag = false; +lv_disp_t *lv_windows_disp; + +/********************** + * STATIC VARIABLES + **********************/ +static HWND hwnd; +static uint32_t *fbp = NULL; /* Raw framebuffer memory */ +static bool mouse_pressed; +static int mouse_x, mouse_y; + + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +const char g_szClassName[] = "LittlevGL"; + +HWND windrv_init(void) +{ + WNDCLASSEX wc; + RECT winrect; + HICON lvgl_icon; + + //Step 1: Registering the Window Class + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + lvgl_icon = (HICON) LoadImage( NULL, "lvgl_icon.bmp", IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + + if(lvgl_icon == NULL) + lvgl_icon = LoadIcon(NULL, IDI_APPLICATION); + + wc.hIcon = lvgl_icon; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = g_szClassName; + wc.hIconSm = lvgl_icon; + + if(!RegisterClassEx(&wc)) + { + return NULL; + } + + winrect.left = 0; + winrect.right = WINDOW_HOR_RES - 1; + winrect.top = 0; + winrect.bottom = WINDOW_VER_RES - 1; + AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, WS_EX_CLIENTEDGE); + OffsetRect(&winrect, -winrect.left, -winrect.top); + // Step 2: Creating the Window + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + g_szClassName, + "LittlevGL Simulator", + WINDOW_STYLE, + CW_USEDEFAULT, CW_USEDEFAULT, winrect.right, winrect.bottom, + NULL, NULL, GetModuleHandle(NULL), NULL); + + if(hwnd == NULL) + { + return NULL; + } + + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); + + + lv_task_create(msg_handler, 0, LV_TASK_PRIO_HIGHEST, NULL); + lv_win_exit_flag = false; + do_register(); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void do_register(void) +{ + /*----------------------------- + * Create a buffer for drawing + *----------------------------*/ + + /* LittlevGL requires a buffer where it draw the objects. The buffer's has to be greater than 1 display row + * + * There are three buffering configurations: + * 1. Create ONE buffer some rows: LittlevGL will draw the display's content here and writes it to your display + * 2. Create TWO buffer some rows: LittlevGL will draw the display's content to a buffer and writes it your display. + * You should use DMA to write the buffer's content to the display. + * It will enable LittlevGL to draw the next part of the screen to the other buffer while + * the data is being sent form the first buffer. It makes rendering and flushing parallel. + * 3. Create TWO screen buffer: Similar to 2) but the buffer have to be screen sized. When LittlevGL is ready it will give the + * whole frame to display. This way you only need to change the frame buffer's address instead of + * copying the pixels. + * */ + + /* Example for 1) */ + static lv_disp_buf_t disp_buf_1; + static lv_color_t buf1_1[WINDOW_HOR_RES * WINDOW_VER_RES]; /*A buffer for 10 rows*/ + lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, WINDOW_HOR_RES * WINDOW_VER_RES); /*Initialize the display buffer*/ + + + /*----------------------------------- + * Register the display in LittlevGL + *----------------------------------*/ + + lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + + /*Set up the functions to access to your display*/ + + /*Set the resolution of the display*/ + disp_drv.hor_res = WINDOW_HOR_RES; + disp_drv.ver_res = WINDOW_VER_RES; + + /*Used to copy the buffer's content to the display*/ + disp_drv.flush_cb = win_drv_flush; + + /*Set a display buffer*/ + disp_drv.buffer = &disp_buf_1; + + /*Finally register the driver*/ + lv_windows_disp = lv_disp_drv_register(&disp_drv); + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = win_drv_read; + lv_indev_drv_register(&indev_drv); +} + +static void msg_handler(void *param) +{ + (void)param; + + MSG msg; + BOOL bRet; + if( (bRet = PeekMessage( &msg, NULL, 0, 0, TRUE )) != 0) + { + if (bRet == -1) + { + return; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + if(msg.message == WM_QUIT) + lv_win_exit_flag = true; +} + + static bool win_drv_read(lv_indev_t *drv, lv_indev_data_t * data) +{ + data->state = mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + data->point.x = mouse_x; + data->point.y = mouse_y; + return false; +} + + static void on_paint(void) + { + HBITMAP bmp = CreateBitmap(WINDOW_HOR_RES, WINDOW_VER_RES, 1, 32, fbp); + PAINTSTRUCT ps; + + HDC hdc = BeginPaint(hwnd, &ps); + + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hbmOld = SelectObject(hdcMem, bmp); + + BitBlt(hdc, 0, 0, WINDOW_HOR_RES, WINDOW_VER_RES, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hbmOld); + DeleteDC(hdcMem); + + EndPaint(hwnd, &ps); + DeleteObject(bmp); + +} +/** + * Flush a buffer to the marked area + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color_p an array of colors + */ +static void win_drv_flush(lv_disp_t *drv, lv_area_t *area, const lv_color_t * color_p) +{ + win_drv_map(area->x1, area->y1, area->x2, area->y2, color_p); + lv_disp_flush_ready(drv); +} + +/** + * Put a color map to the marked area + * @param x1 left coordinate + * @param y1 top coordinate + * @param x2 right coordinate + * @param y2 bottom coordinate + * @param color_p an array of colors + */ +static void win_drv_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) +{ + for(int y = y1; y <= y2; y++) + { + for(int x = x1; x <= x2; x++) + { + fbp[y*WINDOW_HOR_RES+x] = lv_color_to32(*color_p); + color_p++; + } + } + InvalidateRect(hwnd, NULL, FALSE); + UpdateWindow(hwnd); +} + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + switch(msg) { + case WM_CREATE: + fbp = malloc(4*WINDOW_HOR_RES*WINDOW_VER_RES); + if(fbp == NULL) + return 1; + + return 0; + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + mouse_x = GET_X_LPARAM(lParam); + mouse_y = GET_Y_LPARAM(lParam); + if(msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { + mouse_pressed = (msg == WM_LBUTTONDOWN); + } + return 0; + case WM_CLOSE: + free(fbp); + fbp = NULL; + DestroyWindow(hwnd); + return 0; + case WM_PAINT: + on_paint(); + return 0; + case WM_DESTROY: + PostQuitMessage(0); + return 0; + default: + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} +static COLORREF lv_color_to_colorref(const lv_color_t color) +{ + uint32_t raw_color = lv_color_to32(color); + lv_color32_t tmp; + tmp.full = raw_color; + uint32_t colorref = RGB(tmp.ch.red, tmp.ch.green, tmp.ch.blue); + return colorref; +} +#endif + + + diff --git a/lib/lv_drivers/win_drv.h b/lib/lv_drivers/win_drv.h new file mode 100644 index 00000000..7a0f9b25 --- /dev/null +++ b/lib/lv_drivers/win_drv.h @@ -0,0 +1,60 @@ +/** + * @file fbdev.h + * + */ + +#ifndef WINDRV_H +#define WINDRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifndef LV_DRV_NO_CONF +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_drv_conf.h" +#else +#include "../lv_drv_conf.h" +#endif +#endif + +#if USE_WINDOWS + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +extern bool lv_win_exit_flag; +extern lv_disp_t *lv_windows_disp; + +HWND windrv_init(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_WINDOWS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*WIN_DRV_H*/ diff --git a/platformio.ini b/platformio.ini index 8a971a18..16f99923 100644 --- a/platformio.ini +++ b/platformio.ini @@ -69,6 +69,7 @@ build_flags = ;-w ; Suppress warnings -D CORE_DEBUG_LEVEL=1 ; Errors -D LV_CONF_INCLUDE_SIMPLE + -D LV_LVGL_H_INCLUDE_SIMPLE ; for lv_drivers -D SPIFFS_TEMPORAL_FD_CACHE ; speedup opening recent files -D ARDUINOJSON_DECODE_UNICODE=1 ; for utf-8 symbols -D ARDUINOJSON_ENABLE_PROGMEM=1 ; for PROGMEM arguments diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 7c33af36..3c862cc9 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -3,11 +3,21 @@ #include "lv_conf.h" #include "lvgl.h" + +// Display Driver +#include "lv_drv_conf.h" +#include "display/tft_espi_drv.h" +#include "display/fsmc_ili9341.h" + +// Touch Driver + +// Filesystem Driver #include "lv_fs_if.h" -#include "TFT_eSPI.h" + +//#include "TFT_eSPI.h" //#include "lv_zifont.h" -#include "hasp_tft.h" +//#include "hasp_tft.h" #include "hasp_debug.h" #include "hasp_config.h" #include "hasp_dispatch.h" @@ -82,7 +92,7 @@ static Ticker tick; /* timer for interrupt handler */ #else static Ticker tick(lv_tick_handler, guiTickPeriod); #endif -static TFT_eSPI tft; // = TFT_eSPI(); /* TFT instance */ +// static TFT_eSPI tft; // = TFT_eSPI(); /* TFT instance */ static uint16_t calData[5] = {0, 65535, 0, 65535, 0}; static bool guiCheckSleep() @@ -195,8 +205,9 @@ static void gui_take_screenshot(uint8_t * data_p, size_t len) } /* Experimetnal Display flushing */ -static void IRAM_ATTR tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) +static void IRAM_ATTR tft_espi_flush_cb(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) { +#if 0 size_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1); /* Number of pixels */ /* Update TFT */ @@ -209,6 +220,9 @@ static void IRAM_ATTR tft_espi_flush(lv_disp_drv_t * disp, const lv_area_t * are if(guiSnapshot != 0) { gui_take_screenshot((uint8_t *)color_p, len * sizeof(lv_color_t)); /* Number of bytes */ } +#endif + + fsmc_ili9341_flush(area->x1, area->y1, area->x2, area->y2, color_p); /* Tell lvgl that flushing is done */ lv_disp_flush_ready(disp); @@ -555,14 +569,14 @@ bool IRAM_ATTR my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * { //#ifdef TOUCH_CS uint16_t touchX, touchY; - + bool touched; #if TOUCH_DRIVER == 0 - bool touched = tft.getTouch(&touchX, &touchY, 600); + // touched = tft.getTouch(&touchX, &touchY, 600); #elif TOUCH_DRIVER == 1 // return false; - bool touched = GT911_getXY(&touchX, &touchY, true); + touched = GT911_getXY(&touchX, &touchY, true); #else - bool touched = Touch_getXY(&touchX, &touchY, false); + touched = Touch_getXY(&touchX, &touchY, false); #endif if(!touched) return false; @@ -571,21 +585,21 @@ bool IRAM_ATTR my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * // Ignore first press? - if(touchX > tft.width() || touchY > tft.height()) { - Serial.print(F("Y or y outside of expected parameters.. x: ")); - Serial.print(touchX); - Serial.print(F(" / y: ")); - Serial.println(touchY); - } else { - /*Save the state and save the pressed coordinate*/ - data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; - data->point.x = touchX; - data->point.y = touchY; - /* Serial.print("Data x"); - Serial.println(touchX); - Serial.print("Data y"); - Serial.println(touchY);*/ - } + // if(touchX > tft.width() || touchY > tft.height()) { + // Serial.print(F("Y or y outside of expected parameters.. x: ")); + // Serial.print(touchX); + // Serial.print(F(" / y: ")); + // Serial.println(touchY); + // } else { + /*Save the state and save the pressed coordinate*/ + data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + data->point.x = touchX; + data->point.y = touchY; + /* Serial.print("Data x"); + Serial.println(touchX); + Serial.print("Data y"); + Serial.println(touchY);*/ + //} //#endif return false; /*Return `false` because we are not buffering and no more data to read*/ @@ -593,7 +607,7 @@ bool IRAM_ATTR my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * void guiCalibrate() { -#if TOUCH_DRIVER == 0 +#if TOUCH_DRIVER == 0 && 0 tft.fillScreen(TFT_BLACK); tft.setCursor(20, 0); tft.setTextFont(1); @@ -620,6 +634,8 @@ void guiCalibrate() void guiSetup() { /* TFT init */ + tft_espi_init(guiRotation); +#if 0 tft.begin(); tft.setSwapBytes(true); /* set endianess */ @@ -632,6 +648,7 @@ void guiSetup() tft.setRotation(guiRotation); /* 1/3=Landscape or 0/2=Portrait orientation */ #if TOUCH_DRIVER == 0 tft.setTouch(calData); +#endif #endif /* Initialize the Virtual Device Buffers */ @@ -675,7 +692,7 @@ void guiSetup() #endif /* Dump TFT Configuration */ - tftSetup(tft); + // tftSetup(tft); #ifdef USE_DMA_TO_TFT Log.verbose(F("TFT: DMA : ENABELD")); #else @@ -715,7 +732,7 @@ void guiSetup() /* Initialize the display driver */ lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); - disp_drv.flush_cb = tft_espi_flush; + disp_drv.flush_cb = tft_espi_flush_cb; disp_drv.buffer = &disp_buf; if(guiRotation == 0 || guiRotation == 2 || guiRotation == 4 || guiRotation == 6) { /* 1/3=Landscape or 0/2=Portrait orientation */ @@ -912,7 +929,9 @@ bool guiGetConfig(const JsonObject & settings) v.set(calData[i]); } else { changed = true; +#if 0 tft.setTouch(calData); +#endif } i++; } @@ -924,7 +943,9 @@ bool guiGetConfig(const JsonObject & settings) array.add(calData[i]); } changed = true; +#if 0 tft.setTouch(calData); +#endif } if(changed) configOutput(settings); @@ -981,7 +1002,9 @@ bool guiSetConfig(const JsonObject & settings) oobeSetAutoCalibrate(true); } +#if 0 if(status) tft.setTouch(calData); +#endif changed |= status; } diff --git a/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini b/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini new file mode 100644 index 00000000..07efbcb0 --- /dev/null +++ b/user_setups/stm32f4xx/STM32F407VET6_black_fsmc.ini @@ -0,0 +1,54 @@ +;***************************************************; +; STM32F4xx build with ; +; - STM32F407VET6 black board ; +; - FSMC 16 bit ili9341 TFT ; +; - xpt2046 touch controller ; +;***************************************************; + +[env:STM32F407VET6_black_fsmc] +platform = ststm32 +board = black_f407ve +;board_build.mcu = stm32f407vet6 +; upload_protocol = dfu +upload_protocol = stlink +debug_tool = stlink +monitor_port = COM19 ; To change the port, use platform_override.ini +build_flags = + ${env.build_flags} + ${flags.stm32_flags} + -I include/stm32f4 + -I include/GxTFT/src + -I include/GxTFT/src/GxCTRL/GxCTRL_ILI9341 +; -- TFT_eSPI build options ------------------------ + -D ILI9341_DRIVER=1 + -D TFT_WIDTH=240 + -D TFT_HEIGHT=320 + -D USER_SETUP_LOADED=1 + -D TOUCH_CS=PA6 ;NC + -D TFT_RST=-1 ;D4 + -D STM32 + -D TFT_SPI3 + -D USE_DMA_TO_TFT + -D HASP_USE_TASMOTA_SLAVE=1 + -D HASP_OUTPUT_PIN=PA1 ; User LED D2 on DevEBox board + -D HASP_INPUT_PIN=PA0 ; User Button K1 on DevEBox board + -D STM32_SERIAL1 ; Set this option to use Serial1 as default sersial port, leave out if using Serial2 + -D HASP_USE_ETHERNET=1 + -D USE_BUILTIN_ETHERNET=1 + -D HAL_ETH_MODULE_ENABLED=1 + ; -D LAN8742A_PHY_ADDRESS=0x01U ; moved to include\stm32f4\hal_conf_custom.h + ; -D DP83848_PHY_ADDRESS=0x01U + +lib_deps = + ${env.lib_deps} + Ticker@^3.1.5 + ; STM32duino LwIP@^2.1.2 + ; STM32duino STM32Ethernet@^1.0.5 + https://github.com/stm32duino/LwIP.git + https://github.com/stm32duino/STM32Ethernet.git + https://github.com/khoih-prog/EthernetWebServer_STM32 + Adafruit GFX Library@^1.7.5 + ;https://github.com/ZinggJM/GxTFT.git + XPT2046_Touchscreen + +src_filter = +<*> -<.git/> -<.svn/> - - - - - +