From 3c721ebfbbe3d8b913291660b51a7a193467df1c Mon Sep 17 00:00:00 2001 From: Marius Andra <marius.andra@gmail.com> Date: Thu, 30 Jan 2025 00:16:36 +0100 Subject: [PATCH] it8951 --- backend/app/drivers/devices.py | 5 + backend/app/drivers/waveshare.py | 16 +- backend/app/tasks/deploy_frame.py | 11 +- backend/list_devices.py | 1 + .../src/drivers/waveshare/it8951/DEV_Config.c | 186 ++++ .../src/drivers/waveshare/it8951/DEV_Config.h | 104 ++ .../drivers/waveshare/it8951/DEV_Config.nim | 68 ++ .../drivers/waveshare/it8951/EPD_10in3.nim | 84 ++ frameos/src/drivers/waveshare/it8951/IT8951.c | 921 ++++++++++++++++++ frameos/src/drivers/waveshare/it8951/IT8951.h | 209 ++++ .../src/drivers/waveshare/it8951/IT8951.nim | 188 ++++ frameos/src/drivers/waveshare/it8951/Makefile | 25 + .../waveshare/it8951/examples/example.c | 893 +++++++++++++++++ .../waveshare/it8951/examples/example.h | 44 + .../drivers/waveshare/it8951/examples/main.c | 192 ++++ frameos/src/drivers/waveshare/types.nim | 1 + frameos/src/drivers/waveshare/waveshare.nim | 33 +- frontend/src/devices.ts | 1 + 18 files changed, 2978 insertions(+), 4 deletions(-) create mode 100644 frameos/src/drivers/waveshare/it8951/DEV_Config.c create mode 100644 frameos/src/drivers/waveshare/it8951/DEV_Config.h create mode 100644 frameos/src/drivers/waveshare/it8951/DEV_Config.nim create mode 100644 frameos/src/drivers/waveshare/it8951/EPD_10in3.nim create mode 100644 frameos/src/drivers/waveshare/it8951/IT8951.c create mode 100644 frameos/src/drivers/waveshare/it8951/IT8951.h create mode 100644 frameos/src/drivers/waveshare/it8951/IT8951.nim create mode 100644 frameos/src/drivers/waveshare/it8951/Makefile create mode 100644 frameos/src/drivers/waveshare/it8951/examples/example.c create mode 100644 frameos/src/drivers/waveshare/it8951/examples/example.h create mode 100644 frameos/src/drivers/waveshare/it8951/examples/main.c diff --git a/backend/app/drivers/devices.py b/backend/app/drivers/devices.py index 45811398..4f231cda 100644 --- a/backend/app/drivers/devices.py +++ b/backend/app/drivers/devices.py @@ -31,6 +31,11 @@ def drivers_for_device(device: str) -> dict[str, Driver]: else: device_drivers = {"waveshare": waveshare, "spi": DRIVERS["spi"]} + if waveshare.variant == "EPD_10in3": + device_drivers["bootconfig"] = DRIVERS["bootConfig"] + device_drivers["bootconfig"].lines = [ + "dtoverlay=spi0-0cs", + ] if waveshare.variant == "EPD_13in3e": device_drivers["bootconfig"] = DRIVERS["bootConfig"] device_drivers["bootconfig"].lines = [ diff --git a/backend/app/drivers/waveshare.py b/backend/app/drivers/waveshare.py index 768c695e..a9cdb950 100644 --- a/backend/app/drivers/waveshare.py +++ b/backend/app/drivers/waveshare.py @@ -66,6 +66,8 @@ class WaveshareVariant: "EPD_4in0e": "SpectraSixColor", "EPD_7in3e": "SpectraSixColor", "EPD_13in3e": "SpectraSixColor", + + "EPD_10in3": "SixteenGray", } def get_variant_keys_for(folder: str) -> list[str]: @@ -77,13 +79,20 @@ def get_variant_keys_for(folder: str) -> list[str]: ] def get_variant_keys() -> list[str]: - return [*get_variant_keys_for("ePaper"), *get_variant_keys_for("epd12in48"), *get_variant_keys_for("epd13in3e")] + return [ + *get_variant_keys_for("ePaper"), + *get_variant_keys_for("it8951"), + *get_variant_keys_for("epd12in48"), + *get_variant_keys_for("epd13in3e"), + ] def get_variant_folder(variant_key: str) -> str: if variant_key in get_variant_keys_for("ePaper") : return "ePaper" elif variant_key == "EPD_13in3e": return "epd13in3e" + elif variant_key == "EPD_10in3": + return "it8951" else: return "epd12in48" @@ -181,6 +190,9 @@ def convert_waveshare_source(variant_key: Optional[str]) -> WaveshareVariant: variant.display_function = proc_name variant.display_arguments = get_proc_arguments(line, variant_key) # print("-> " + proc_name + "(" + (", ".join(variant.display_arguments)) + ") <-") + if (proc_name.lower() == f"{variant.prefix}_16Gray_Display".lower()): + variant.display_function = proc_name + variant.display_arguments = get_proc_arguments(line, variant_key) if variant.display_arguments == ["Black"]: variant.color_option = "Black" @@ -197,6 +209,8 @@ def convert_waveshare_source(variant_key: Optional[str]) -> WaveshareVariant: variant.color_option = "SevenColor" elif variant.display_arguments == ["SpectraSixColor"]: variant.color_option = "SpectraSixColor" + elif variant_key == "EPD_10in3": + variant.color_option = "SixteenGray" else: print(f"Unknown color: {variant_key} - {variant.display_function} -- {variant.display_arguments}" ) diff --git a/backend/app/tasks/deploy_frame.py b/backend/app/tasks/deploy_frame.py index ef61967c..d1e1f9e9 100644 --- a/backend/app/tasks/deploy_frame.py +++ b/backend/app/tasks/deploy_frame.py @@ -102,7 +102,7 @@ async def install_if_necessary(pkg: str, raise_on_error=True) -> int: ) if low_memory: - await log(db, redis, id, "stdout", "- Low memory device, stopping FrameOS for compile") + await log(db, redis, id, "stdout", "- Low memory device, stopping FrameOS for compilation") await exec_command(db, redis, frame, ssh, "sudo service frameos stop", raise_on_error=False) # 2. Remote steps @@ -486,7 +486,12 @@ async def create_local_build_archive( if waveshare := drivers.get('waveshare'): if waveshare.variant: variant_folder = get_variant_folder(waveshare.variant) - util_files = ["Debug.h", "DEV_Config.c", "DEV_Config.h"] + + if variant_folder == "it8951": + util_files = ["DEV_Config.c", "DEV_Config.h"] + else: + util_files = ["Debug.h", "DEV_Config.c", "DEV_Config.h"] + for uf in util_files: shutil.copy( os.path.join(source_dir, "src", "drivers", "waveshare", variant_folder, uf), @@ -501,6 +506,8 @@ async def create_local_build_archive( ]: c_file = re.sub(r'[bc]', 'bc', waveshare.variant) variant_files = [f"{waveshare.variant}.nim", f"{c_file}.c", f"{c_file}.h"] + elif waveshare.variant == "EPD_10in3": + variant_files = [f"{waveshare.variant}.nim", "IT8951.c", "IT8951.h", "IT8951.nim"] else: variant_files = [f"{waveshare.variant}.nim", f"{waveshare.variant}.c", f"{waveshare.variant}.h"] diff --git a/backend/list_devices.py b/backend/list_devices.py index db35ea82..de2942da 100644 --- a/backend/list_devices.py +++ b/backend/list_devices.py @@ -25,6 +25,7 @@ "BlackWhiteYellow": "Black/White/Yellow", "BlackWhiteYellowRed": "Black/White/Yellow/Red", "FourGray": "4 Grayscale", + "SixteenGray": "16 Grayscale", "SevenColor": "7 Color", "SpectraSixColor": "Spectra 6 Color", }.get(v.color_option, v.color_option) diff --git a/frameos/src/drivers/waveshare/it8951/DEV_Config.c b/frameos/src/drivers/waveshare/it8951/DEV_Config.c new file mode 100644 index 00000000..7d6210d6 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/DEV_Config.c @@ -0,0 +1,186 @@ +/***************************************************************************** +* | File : DEV_Config.c +* | Author : Waveshare team +* | Function : Hardware underlying interface +* | Info : +*---------------- +* | This version: V3.0 +* | Date : 2019-09-17 +* | Info : +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation 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 theex Software, and to permit persons to whom the Software is +# furished 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 OR 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. +# +******************************************************************************/ +#include "DEV_Config.h" +#include <fcntl.h> + +int GPIO_Handle; +int SPI_Handle; + +/****************************************************************************** +function: GPIO Write +parameter: +Info: +******************************************************************************/ +void DEV_Digital_Write(UWORD Pin, UBYTE Value) +{ + lgGpioWrite(GPIO_Handle, Pin, Value); +} + +/****************************************************************************** +function: GPIO Read +parameter: +Info: +******************************************************************************/ +UBYTE DEV_Digital_Read(UWORD Pin) +{ + UBYTE Read_Value = 0; + Read_Value = lgGpioRead(GPIO_Handle,Pin); + return Read_Value; +} + +/****************************************************************************** +function: SPI Write +parameter: +Info: +******************************************************************************/ +void DEV_SPI_WriteByte(UBYTE Value) +{ + lgSpiWrite(SPI_Handle,(char*)&Value, 1); +} + +/****************************************************************************** +function: SPI Read +parameter: +Info: +******************************************************************************/ +UBYTE DEV_SPI_ReadByte() +{ + UBYTE Read_Value = 0x00; + lgSpiRead(SPI_Handle, (char*)&Read_Value, 1); + return Read_Value; +} + +/****************************************************************************** +function: Time delay for ms +parameter: +Info: +******************************************************************************/ +void DEV_Delay_ms(UDOUBLE xms) +{ + lguSleep(xms/1000.0); +} + + +/****************************************************************************** +function: Time delay for us +parameter: +Info: +******************************************************************************/ +void DEV_Delay_us(UDOUBLE xus) +{ + lguSleep(xus/1000000.0); +} + + +/** + * GPIO Mode +**/ +static void DEV_GPIO_Mode(UWORD Pin, UWORD Mode) +{ + if(Mode == 0 || Mode == LG_SET_INPUT){ + lgGpioClaimInput(GPIO_Handle,LFLAGS,Pin); + // Debug("IN Pin = %d\r\n",Pin); + }else{ + lgGpioClaimOutput(GPIO_Handle, LFLAGS, Pin, LG_LOW); + // Debug("OUT Pin = %d\r\n",Pin); + } +} + + +/** + * GPIO Init +**/ +static void DEV_GPIO_Init(void) +{ + DEV_GPIO_Mode(EPD_BUSY_PIN, 0); + DEV_GPIO_Mode(EPD_RST_PIN, 1); + DEV_GPIO_Mode(EPD_CS_PIN, 1); + + DEV_Digital_Write(EPD_CS_PIN, 1); +} + + + +/****************************************************************************** +function: Module Initialize, the library and initialize the pins, SPI protocol +parameter: +Info: +******************************************************************************/ +UBYTE DEV_Module_Init(void) +{ + Debug("/***********************************/ \r\n"); + + char buffer[NUM_MAXBUF]; + FILE *fp; + + fp = popen("cat /proc/cpuinfo | grep 'Raspberry Pi 5'", "r"); + if (fp == NULL) { + Debug("It is not possible to determine the model of the Raspberry PI\n"); + return -1; + } + + if(fgets(buffer, sizeof(buffer), fp) != NULL) + { + GPIO_Handle = lgGpiochipOpen(4); + if (GPIO_Handle < 0) + { + Debug( "gpiochip4 Export Failed\n"); + return -1; + } + } + else + { + GPIO_Handle = lgGpiochipOpen(0); + if (GPIO_Handle < 0) + { + Debug( "gpiochip0 Export Failed\n"); + return -1; + } + } + SPI_Handle = lgSpiOpen(0, 0, 12500000, 0); + DEV_GPIO_Init(); + Debug("/***********************************/!! \r\n"); + return 0; +} + + + +/****************************************************************************** +function: Module exits, closes SPI and BCM2835 library +parameter: +Info: +******************************************************************************/ +void DEV_Module_Exit(void) +{ + // DEV_Digital_Write(EPD_CS_PIN, 0); + // DEV_Digital_Write(EPD_RST_PIN, 0); + // lgSpiClose(SPI_Handle); + // lgGpiochipClose(GPIO_Handle); +} diff --git a/frameos/src/drivers/waveshare/it8951/DEV_Config.h b/frameos/src/drivers/waveshare/it8951/DEV_Config.h new file mode 100644 index 00000000..398e2411 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/DEV_Config.h @@ -0,0 +1,104 @@ +/***************************************************************************** +* | File : DEV_Config.h +* | Author : Waveshare team +* | Function : Hardware underlying interface +* | Info : +* Used to shield the underlying layers of each master +* and enhance portability +*---------------- +* | This version: V2.0 +* | Date : 2018-10-30 +* | Info : +* 1.add: +* UBYTE\UWORD\UDOUBLE +* 2.Change: +* EPD_RST -> EPD_RST_PIN +* EPD_DC -> EPD_DC_PIN +* EPD_CS -> EPD_CS_PIN +* EPD_BUSY -> EPD_BUSY_PIN +* 3.Remote: +* EPD_RST_1\EPD_RST_0 +* EPD_DC_1\EPD_DC_0 +* EPD_CS_1\EPD_CS_0 +* EPD_BUSY_1\EPD_BUSY_0 +* 3.add: +* #define DEV_Digital_Write(_pin, _value) bcm2835_GPIOI_write(_pin, _value) +* #define DEV_Digital_Read(_pin) bcm2835_GPIOI_lev(_pin) +* #define DEV_SPI_WriteByte(__value) bcm2835_spi_transfer(__value) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation 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 +# furished 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 OR 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. +# +******************************************************************************/ +#ifndef _DEV_CONFIG_H_ +#define _DEV_CONFIG_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <lgpio.h> + +#define Debug(fmt,...) printf(fmt,##__VA_ARGS__) + +#define LFLAGS 0 +#define NUM_MAXBUF 4 + + +#define HIGH 0x1 +#define LOW 0x0 + +/** + * GPIO + **/ + +#define EPD_RST_PIN 17 +#define EPD_CS_PIN 8 +#define EPD_BUSY_PIN 24 + + + +/** + * data +**/ +#define UBYTE uint8_t +#define UWORD uint16_t +#define UDOUBLE uint32_t + + + + + +/*------------------------------------------------------------------------------------------------------*/ +void DEV_Digital_Write(UWORD Pin, UBYTE Value); +UBYTE DEV_Digital_Read(UWORD Pin); + +void DEV_SPI_WriteByte(UBYTE Value); +UBYTE DEV_SPI_ReadByte(); + +void DEV_Delay_ms(UDOUBLE xms); +void DEV_Delay_us(UDOUBLE xus); + +UBYTE DEV_Module_Init(void); +void DEV_Module_Exit(void); + + +#endif diff --git a/frameos/src/drivers/waveshare/it8951/DEV_Config.nim b/frameos/src/drivers/waveshare/it8951/DEV_Config.nim new file mode 100644 index 00000000..6eaa6e97 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/DEV_Config.nim @@ -0,0 +1,68 @@ +{.compile: "DEV_Config.c".} +{.passl: "-llgpio -lm -lrt".} +## *************************************************************************** +## | File : DEV_Config.h +## | Author : Waveshare team +## | Function : Hardware underlying interface +## | Info : +## Used to shield the underlying layers of each master +## and enhance portability +## ---------------- +## | This version: V2.0 +## | Date : 2018-10-30 +## | Info : +## 1.add: +## UBYTE\UWORD\UDOUBLE +## 2.Change: +## EPD_RST -> EPD_RST_PIN +## EPD_DC -> EPD_DC_PIN +## EPD_CS -> EPD_CS_PIN +## EPD_BUSY -> EPD_BUSY_PIN +## 3.Remote: +## EPD_RST_1\EPD_RST_0 +## EPD_DC_1\EPD_DC_0 +## EPD_CS_1\EPD_CS_0 +## EPD_BUSY_1\EPD_BUSY_0 +## 3.add: +## #define DEV_Digital_Write(_pin, _value) bcm2835_GPIOI_write(_pin, _value) +## #define DEV_Digital_Read(_pin) bcm2835_GPIOI_lev(_pin) +## #define DEV_SPI_WriteByte(__value) bcm2835_spi_transfer(__value) +## # +## # Permission is hereby granted, free of charge, to any person obtaining a copy +## # of this software and associated documnetation 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 +## # furished 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 OR 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. +## # +## **************************************************************************** + +## !!!Ignored construct: # _DEV_CONFIG_H_ [NewLine] # _DEV_CONFIG_H_ [NewLine] # < stdint . h > [NewLine] # < stdlib . h > [NewLine] # < stdio . h > [NewLine] # < unistd . h > [NewLine] # < errno . h > [NewLine] # < stdio . h > [NewLine] # < string . h > [NewLine] # < lgpio . h > [NewLine] # Debug ( fmt , ... ) printf ( fmt , ## __VA_ARGS__ ) [NewLine] # LFLAGS 0 [NewLine] # NUM_MAXBUF 4 [NewLine] # HIGH 0x1 [NewLine] # LOW 0x0 [NewLine] +## GPIO +## # EPD_RST_PIN 17 [NewLine] # EPD_CS_PIN 8 [NewLine] # EPD_BUSY_PIN 24 [NewLine] +## data +## # UBYTE uint8_t [NewLine] # UWORD uint16_t [NewLine] # UDOUBLE uint32_t [NewLine] ------------------------------------------------------------------------------------------------------ void DEV_Digital_Write ( UWORD Pin , UBYTE Value ) ; +## Error: did not expect ##!!! +type + UBYTE* = uint8 + UWORD* = uint16 + UDOUBLE* = uint32 + +proc DEV_Digital_Read*(Pin: UWORD): UBYTE {.importc: "DEV_Digital_Read".} +proc DEV_SPI_WriteByte*(Value: UBYTE) {.importc: "DEV_SPI_WriteByte".} +proc DEV_SPI_ReadByte*(): UBYTE {.importc: "DEV_SPI_ReadByte".} +proc DEV_Delay_ms*(xms: UDOUBLE) {.importc: "DEV_Delay_ms".} +proc DEV_Delay_us*(xus: UDOUBLE) {.importc: "DEV_Delay_us".} +proc DEV_Module_Init*(): UBYTE {.importc: "DEV_Module_Init".} +proc DEV_Module_Exit*() {.importc: "DEV_Module_Exit".} diff --git a/frameos/src/drivers/waveshare/it8951/EPD_10in3.nim b/frameos/src/drivers/waveshare/it8951/EPD_10in3.nim new file mode 100644 index 00000000..1adfb81d --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/EPD_10in3.nim @@ -0,0 +1,84 @@ +# Providing a familiar interface for the EPD 10in3 driver +import + DEV_Config, + IT8951, + std/bitops + +const + EPD_10IN3_WIDTH* = 1872 + EPD_10IN3_HEIGHT* = 1404 + +var initDone = false +var Dev_Info: IT8951_Dev_Info +var Init_Target_Memory_Addr: UWORD +# var A2_Mode = 6 + +proc EPD_10IN3_Init*(): UBYTE = + echo "Initializing?" + if DEV_Module_Init() != 0: + return -1.UBYTE + echo "Initializing!" + + # let temp = -1.48 + # let vcom = (temp * 1000.float64).UWORD + let vcom = 1480.UWORD + + # echo "Temp: ", temp + echo "VCOM: ", vcom + Dev_Info = EPD_IT8951_Init(vcom) + + echo Dev_Info + + if (Dev_Info.Panel_W != EPD_10IN3_WIDTH) or (Dev_Info.Panel_H != EPD_10IN3_HEIGHT): + echo "Panel size mismatch, expected ", EPD_10IN3_WIDTH, "x", EPD_10IN3_HEIGHT, " but got ", Dev_Info.Panel_W, "x", + Dev_Info.Panel_H + return -1.UBYTE + + Init_Target_Memory_Addr = bitor(Dev_Info.Memory_Addr_L, (Dev_Info.Memory_Addr_H shl 16)) + + echo "Memory Addr: ", Init_Target_Memory_Addr + + # TODO: support the other modes + # char* LUT_Version = (char*)Dev_Info.LUT_Version; + # if( strcmp(LUT_Version, "M641") == 0 ){ + # # //6inch e-Paper HAT(800,600), 6inch HD e-Paper HAT(1448,1072), 6inch HD touch e-Paper HAT(1448,1072) + # A2_Mode = 4; + # Four_Byte_Align = true; + # }else if( strcmp(LUT_Version, "M841_TFAB512") == 0 ){ + # # //Another firmware version for 6inch HD e-Paper HAT(1448,1072), 6inch HD touch e-Paper HAT(1448,1072) + # A2_Mode = 6; + # Four_Byte_Align = true; + # }else if( strcmp(LUT_Version, "M841") == 0 ){ + # # //9.7inch e-Paper HAT(1200,825) + # A2_Mode = 6; + # }else if( strcmp(LUT_Version, "M841_TFA2812") == 0 ){ + # # //7.8inch e-Paper HAT(1872,1404) + # A2_Mode = 6; + # }else if( strcmp(LUT_Version, "M841_TFA5210") == 0 ){ + # # //10.3inch e-Paper HAT(1872,1404) + # A2_Mode = 6; + # }else{ + # # //default set to 6 as A2 Mode + # A2_Mode = 6; + # } + + initDone = true + echo "Init done" + +proc EPD_10IN3_Clear*() = + echo "Clearing?" + if initDone: + echo "Clearing!" + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, INIT_Mode) + +proc EPD_10IN3_16Gray_Display*(Image: ptr UBYTE) = + echo "Displaying?" + if initDone: + echo "Displaying!" + EPD_IT8951_4bp_Refresh(Image, 0, 0, EPD_10IN3_WIDTH, EPD_10IN3_HEIGHT, false, Init_Target_Memory_Addr, false) + +proc EPD_10IN3_Sleep*() = + echo "Sleeping?" + if initDone: + echo "Sleeping!" + EPD_IT8951_Sleep() diff --git a/frameos/src/drivers/waveshare/it8951/IT8951.c b/frameos/src/drivers/waveshare/it8951/IT8951.c new file mode 100644 index 00000000..5d9e8832 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/IT8951.c @@ -0,0 +1,921 @@ +/***************************************************************************** +* | File : EPD_IT8951.c +* | Author : Waveshare team +* | Function : IT8951 Common driver +* | Info : +*---------------- +* | This version: V1.0 +* | Date : 2019-09-17 +* | Info : +* ----------------------------------------------------------------------------- +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation 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 +# furished 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 OR 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. +# +******************************************************************************/ +#include "IT8951.h" +#include <time.h> + +//basic mode definition +UBYTE INIT_Mode = 0; +UBYTE GC16_Mode = 2; +//A2_Mode's value is not fixed, is decide by firmware's LUT +UBYTE A2_Mode = 6; + +/****************************************************************************** +function : Software reset +parameter: +******************************************************************************/ +static void EPD_IT8951_Reset(void) +{ + DEV_Digital_Write(EPD_RST_PIN, HIGH); + DEV_Delay_ms(200); + DEV_Digital_Write(EPD_RST_PIN, LOW); + DEV_Delay_ms(10); + DEV_Digital_Write(EPD_RST_PIN, HIGH); + DEV_Delay_ms(200); +} + + +/****************************************************************************** +function : Wait until the busy_pin goes HIGH +parameter: +******************************************************************************/ +static void EPD_IT8951_ReadBusy(void) +{ + Debug("Busy ------\r\n"); + UBYTE Busy_State = DEV_Digital_Read(EPD_BUSY_PIN); + //0: busy, 1: idle + while(Busy_State == 0) { + Busy_State = DEV_Digital_Read(EPD_BUSY_PIN); + } + Debug("Busy Release ------\r\n"); +} + + +/****************************************************************************** +function : write command +parameter: command +******************************************************************************/ +static void EPD_IT8951_WriteCommand(UWORD Command) +{ + //Set Preamble for Write Command + UWORD Write_Preamble = 0x6000; + + EPD_IT8951_ReadBusy(); + + DEV_Digital_Write(EPD_CS_PIN, LOW); + + DEV_SPI_WriteByte(Write_Preamble>>8); + DEV_SPI_WriteByte(Write_Preamble); + + EPD_IT8951_ReadBusy(); + + DEV_SPI_WriteByte(Command>>8); + DEV_SPI_WriteByte(Command); + + DEV_Digital_Write(EPD_CS_PIN, HIGH); +} + + +/****************************************************************************** +function : write data +parameter: data +******************************************************************************/ +static void EPD_IT8951_WriteData(UWORD Data) +{ + //Set Preamble for Write Command + UWORD Write_Preamble = 0x0000; + + EPD_IT8951_ReadBusy(); + + DEV_Digital_Write(EPD_CS_PIN, LOW); + + DEV_SPI_WriteByte(Write_Preamble>>8); + DEV_SPI_WriteByte(Write_Preamble); + + EPD_IT8951_ReadBusy(); + + DEV_SPI_WriteByte(Data>>8); + DEV_SPI_WriteByte(Data); + + DEV_Digital_Write(EPD_CS_PIN, HIGH); +} + + +/****************************************************************************** +function : write multi data +parameter: data +******************************************************************************/ +static void EPD_IT8951_WriteMuitiData(UWORD* Data_Buf, UDOUBLE Length) +{ + //Set Preamble for Write Command + UWORD Write_Preamble = 0x0000; + + EPD_IT8951_ReadBusy(); + + DEV_Digital_Write(EPD_CS_PIN, LOW); + + DEV_SPI_WriteByte(Write_Preamble>>8); + DEV_SPI_WriteByte(Write_Preamble); + + EPD_IT8951_ReadBusy(); + + for(UDOUBLE i = 0; i<Length; i++) + { + DEV_SPI_WriteByte(Data_Buf[i]>>8); + DEV_SPI_WriteByte(Data_Buf[i]); + } + DEV_Digital_Write(EPD_CS_PIN, HIGH); +} + + + +/****************************************************************************** +function : read data +parameter: data +******************************************************************************/ +static UWORD EPD_IT8951_ReadData() +{ + UWORD ReadData; + UWORD Write_Preamble = 0x1000; + UWORD Read_Dummy; + + EPD_IT8951_ReadBusy(); + + DEV_Digital_Write(EPD_CS_PIN, LOW); + + DEV_SPI_WriteByte(Write_Preamble>>8); + DEV_SPI_WriteByte(Write_Preamble); + + EPD_IT8951_ReadBusy(); + + //dummy + Read_Dummy = DEV_SPI_ReadByte()<<8; + Read_Dummy |= DEV_SPI_ReadByte(); + + EPD_IT8951_ReadBusy(); + + ReadData = DEV_SPI_ReadByte()<<8; + ReadData |= DEV_SPI_ReadByte(); + + DEV_Digital_Write(EPD_CS_PIN, HIGH); + + return ReadData; +} + + + + +/****************************************************************************** +function : read multi data +parameter: data +******************************************************************************/ +static void EPD_IT8951_ReadMultiData(UWORD* Data_Buf, UDOUBLE Length) +{ + UWORD Write_Preamble = 0x1000; + UWORD Read_Dummy; + + EPD_IT8951_ReadBusy(); + + DEV_Digital_Write(EPD_CS_PIN, LOW); + + DEV_SPI_WriteByte(Write_Preamble>>8); + DEV_SPI_WriteByte(Write_Preamble); + + EPD_IT8951_ReadBusy(); + + //dummy + Read_Dummy = DEV_SPI_ReadByte()<<8; + Read_Dummy |= DEV_SPI_ReadByte(); + + EPD_IT8951_ReadBusy(); + + for(UDOUBLE i = 0; i<Length; i++) + { + Data_Buf[i] = DEV_SPI_ReadByte()<<8; + Data_Buf[i] |= DEV_SPI_ReadByte(); + } + + DEV_Digital_Write(EPD_CS_PIN, HIGH); +} + + + +/****************************************************************************** +function: write multi arg +parameter: data +description: some situation like this: +* 1 commander 0 argument +* 1 commander 1 argument +* 1 commander multi argument +******************************************************************************/ +static void EPD_IT8951_WriteMultiArg(UWORD Arg_Cmd, UWORD* Arg_Buf, UWORD Arg_Num) +{ + //Send Cmd code + EPD_IT8951_WriteCommand(Arg_Cmd); + //Send Data + for(UWORD i=0; i<Arg_Num; i++) + { + EPD_IT8951_WriteData(Arg_Buf[i]); + } +} + + +/****************************************************************************** +function : Cmd4 ReadReg +parameter: +******************************************************************************/ +static UWORD EPD_IT8951_ReadReg(UWORD Reg_Address) +{ + UWORD Reg_Value; + EPD_IT8951_WriteCommand(IT8951_TCON_REG_RD); + EPD_IT8951_WriteData(Reg_Address); + Reg_Value = EPD_IT8951_ReadData(); + return Reg_Value; +} + + + +/****************************************************************************** +function : Cmd5 WriteReg +parameter: +******************************************************************************/ +static void EPD_IT8951_WriteReg(UWORD Reg_Address,UWORD Reg_Value) +{ + EPD_IT8951_WriteCommand(IT8951_TCON_REG_WR); + EPD_IT8951_WriteData(Reg_Address); + EPD_IT8951_WriteData(Reg_Value); +} + + + +/****************************************************************************** +function : get VCOM +parameter: +******************************************************************************/ +static UWORD EPD_IT8951_GetVCOM(void) +{ + UWORD VCOM; + EPD_IT8951_WriteCommand(USDEF_I80_CMD_VCOM); + EPD_IT8951_WriteData(0x0000); + VCOM = EPD_IT8951_ReadData(); + return VCOM; +} + + + +/****************************************************************************** +function : set VCOM +parameter: +******************************************************************************/ +static void EPD_IT8951_SetVCOM(UWORD VCOM) +{ + EPD_IT8951_WriteCommand(USDEF_I80_CMD_VCOM); + EPD_IT8951_WriteData(0x0001); + EPD_IT8951_WriteData(VCOM); +} + + + +/****************************************************************************** +function : Cmd10 LD_IMG +parameter: +******************************************************************************/ +static void EPD_IT8951_LoadImgStart( IT8951_Load_Img_Info* Load_Img_Info ) +{ + UWORD Args; + Args = (\ + Load_Img_Info->Endian_Type<<8 | \ + Load_Img_Info->Pixel_Format<<4 | \ + Load_Img_Info->Rotate\ + ); + EPD_IT8951_WriteCommand(IT8951_TCON_LD_IMG); + EPD_IT8951_WriteData(Args); +} + + +/****************************************************************************** +function : Cmd11 LD_IMG_Area +parameter: +******************************************************************************/ +static void EPD_IT8951_LoadImgAreaStart( IT8951_Load_Img_Info* Load_Img_Info, IT8951_Area_Img_Info* Area_Img_Info ) +{ + UWORD Args[5]; + Args[0] = (\ + Load_Img_Info->Endian_Type<<8 | \ + Load_Img_Info->Pixel_Format<<4 | \ + Load_Img_Info->Rotate\ + ); + Args[1] = Area_Img_Info->Area_X; + Args[2] = Area_Img_Info->Area_Y; + Args[3] = Area_Img_Info->Area_W; + Args[4] = Area_Img_Info->Area_H; + EPD_IT8951_WriteMultiArg(IT8951_TCON_LD_IMG_AREA, Args,5); +} + +/****************************************************************************** +function : Cmd12 LD_IMG_End +parameter: +******************************************************************************/ +static void EPD_IT8951_LoadImgEnd(void) +{ + EPD_IT8951_WriteCommand(IT8951_TCON_LD_IMG_END); +} + + +/****************************************************************************** +function : EPD_IT8951_Get_System_Info +parameter: +******************************************************************************/ +static void EPD_IT8951_GetSystemInfo(void* Buf) +{ + IT8951_Dev_Info* Dev_Info; + + EPD_IT8951_WriteCommand(USDEF_I80_CMD_GET_DEV_INFO); + + EPD_IT8951_ReadMultiData((UWORD*)Buf, sizeof(IT8951_Dev_Info)/2); + + Dev_Info = (IT8951_Dev_Info*)Buf; + Debug("Panel(W,H) = (%d,%d)\r\n",Dev_Info->Panel_W, Dev_Info->Panel_H ); + Debug("Memory Address = %X\r\n",Dev_Info->Memory_Addr_L | (Dev_Info->Memory_Addr_H << 16)); + Debug("FW Version = %s\r\n", (UBYTE*)Dev_Info->FW_Version); + Debug("LUT Version = %s\r\n", (UBYTE*)Dev_Info->LUT_Version); +} + + +/****************************************************************************** +function : EPD_IT8951_Set_Target_Memory_Addr +parameter: +******************************************************************************/ +static void EPD_IT8951_SetTargetMemoryAddr(UDOUBLE Target_Memory_Addr) +{ + UWORD WordH = (UWORD)((Target_Memory_Addr >> 16) & 0x0000FFFF); + UWORD WordL = (UWORD)( Target_Memory_Addr & 0x0000FFFF); + + EPD_IT8951_WriteReg(LISAR+2, WordH); + EPD_IT8951_WriteReg(LISAR , WordL); +} + + +/****************************************************************************** +function : EPD_IT8951_WaitForDisplayReady +parameter: +******************************************************************************/ +static void EPD_IT8951_WaitForDisplayReady(void) +{ + //Check IT8951 Register LUTAFSR => NonZero Busy, Zero - Free + while( EPD_IT8951_ReadReg(LUTAFSR) ) + { + //wait in idle state + } +} + + + + + +/****************************************************************************** +function : EPD_IT8951_HostAreaPackedPixelWrite_1bp +parameter: +******************************************************************************/ +static void EPD_IT8951_HostAreaPackedPixelWrite_1bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write) +{ + UWORD Source_Buffer_Width, Source_Buffer_Height; + UWORD Source_Buffer_Length; + + UWORD* Source_Buffer = (UWORD*)Load_Img_Info->Source_Buffer_Addr; + EPD_IT8951_SetTargetMemoryAddr(Load_Img_Info->Target_Memory_Addr); + EPD_IT8951_LoadImgAreaStart(Load_Img_Info,Area_Img_Info); + + //from byte to word + //use 8bp to display 1bp, so here, divide by 2, because every byte has full bit. + Source_Buffer_Width = Area_Img_Info->Area_W/2; + Source_Buffer_Height = Area_Img_Info->Area_H; + Source_Buffer_Length = Source_Buffer_Width * Source_Buffer_Height; + + if(Packed_Write == true) + { + EPD_IT8951_WriteMuitiData(Source_Buffer, Source_Buffer_Length); + } + else + { + for(UDOUBLE i=0; i<Source_Buffer_Height; i++) + { + for(UDOUBLE j=0; j<Source_Buffer_Width; j++) + { + EPD_IT8951_WriteData(*Source_Buffer); + Source_Buffer++; + } + } + } + + EPD_IT8951_LoadImgEnd(); +} + + + + + +/****************************************************************************** +function : EPD_IT8951_HostAreaPackedPixelWrite_2bp +parameter: +******************************************************************************/ +static void EPD_IT8951_HostAreaPackedPixelWrite_2bp(IT8951_Load_Img_Info*Load_Img_Info, IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write) +{ + UWORD Source_Buffer_Width, Source_Buffer_Height; + UWORD Source_Buffer_Length; + + UWORD* Source_Buffer = (UWORD*)Load_Img_Info->Source_Buffer_Addr; + EPD_IT8951_SetTargetMemoryAddr(Load_Img_Info->Target_Memory_Addr); + EPD_IT8951_LoadImgAreaStart(Load_Img_Info,Area_Img_Info); + + //from byte to word + Source_Buffer_Width = (Area_Img_Info->Area_W*2/8)/2; + Source_Buffer_Height = Area_Img_Info->Area_H; + Source_Buffer_Length = Source_Buffer_Width * Source_Buffer_Height; + + if(Packed_Write == true) + { + EPD_IT8951_WriteMuitiData(Source_Buffer, Source_Buffer_Length); + } + else + { + for(UDOUBLE i=0; i<Source_Buffer_Height; i++) + { + for(UDOUBLE j=0; j<Source_Buffer_Width; j++) + { + EPD_IT8951_WriteData(*Source_Buffer); + Source_Buffer++; + } + } + } + + EPD_IT8951_LoadImgEnd(); +} + + + + + +/****************************************************************************** +function : EPD_IT8951_HostAreaPackedPixelWrite_4bp +parameter: +******************************************************************************/ +static void EPD_IT8951_HostAreaPackedPixelWrite_4bp(IT8951_Load_Img_Info*Load_Img_Info, IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write) +{ + UWORD Source_Buffer_Width, Source_Buffer_Height; + UWORD Source_Buffer_Length; + + UWORD* Source_Buffer = (UWORD*)Load_Img_Info->Source_Buffer_Addr; + EPD_IT8951_SetTargetMemoryAddr(Load_Img_Info->Target_Memory_Addr); + EPD_IT8951_LoadImgAreaStart(Load_Img_Info,Area_Img_Info); + + //from byte to word + Source_Buffer_Width = (Area_Img_Info->Area_W*4/8)/2; + Source_Buffer_Height = Area_Img_Info->Area_H; + Source_Buffer_Length = Source_Buffer_Width * Source_Buffer_Height; + + if(Packed_Write == true) + { + EPD_IT8951_WriteMuitiData(Source_Buffer, Source_Buffer_Length); + } + else + { + for(UDOUBLE i=0; i<Source_Buffer_Height; i++) + { + for(UDOUBLE j=0; j<Source_Buffer_Width; j++) + { + EPD_IT8951_WriteData(*Source_Buffer); + Source_Buffer++; + } + } + } + + EPD_IT8951_LoadImgEnd(); +} + + + + + + + +/****************************************************************************** +function : EPD_IT8951_HostAreaPackedPixelWrite_8bp +parameter: +Precautions: Can't Packed Write +******************************************************************************/ +static void EPD_IT8951_HostAreaPackedPixelWrite_8bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info) +{ + UWORD Source_Buffer_Width, Source_Buffer_Height; + + UWORD* Source_Buffer = (UWORD*)Load_Img_Info->Source_Buffer_Addr; + EPD_IT8951_SetTargetMemoryAddr(Load_Img_Info->Target_Memory_Addr); + EPD_IT8951_LoadImgAreaStart(Load_Img_Info,Area_Img_Info); + + //from byte to word + Source_Buffer_Width = (Area_Img_Info->Area_W*8/8)/2; + Source_Buffer_Height = Area_Img_Info->Area_H; + + for(UDOUBLE i=0; i<Source_Buffer_Height; i++) + { + for(UDOUBLE j=0; j<Source_Buffer_Width; j++) + { + EPD_IT8951_WriteData(*Source_Buffer); + Source_Buffer++; + } + } + EPD_IT8951_LoadImgEnd(); +} + + + + + + +/****************************************************************************** +function : EPD_IT8951_Display_Area +parameter: +******************************************************************************/ +static void EPD_IT8951_Display_Area(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode) +{ + UWORD Args[5]; + Args[0] = X; + Args[1] = Y; + Args[2] = W; + Args[3] = H; + Args[4] = Mode; + //0x0034 + EPD_IT8951_WriteMultiArg(USDEF_I80_CMD_DPY_AREA, Args,5); +} + + + +/****************************************************************************** +function : EPD_IT8951_Display_AreaBuf +parameter: +******************************************************************************/ +static void EPD_IT8951_Display_AreaBuf(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode, UDOUBLE Target_Memory_Addr) +{ + UWORD Args[7]; + Args[0] = X; + Args[1] = Y; + Args[2] = W; + Args[3] = H; + Args[4] = Mode; + Args[5] = (UWORD)Target_Memory_Addr; + Args[6] = (UWORD)(Target_Memory_Addr>>16); + //0x0037 + EPD_IT8951_WriteMultiArg(USDEF_I80_CMD_DPY_BUF_AREA, Args,7); +} + + + +/****************************************************************************** +function : EPD_IT8951_Display_1bp +parameter: +******************************************************************************/ +static void EPD_IT8951_Display_1bp(UWORD X, UWORD Y, UWORD W, UWORD H, UWORD Mode,UDOUBLE Target_Memory_Addr, UBYTE Back_Gray_Val,UBYTE Front_Gray_Val) +{ + //Set Display mode to 1 bpp mode - Set 0x18001138 Bit[18](0x1800113A Bit[2])to 1 + EPD_IT8951_WriteReg(UP1SR+2, EPD_IT8951_ReadReg(UP1SR+2) | (1<<2) ); + + EPD_IT8951_WriteReg(BGVR, (Front_Gray_Val<<8) | Back_Gray_Val); + + if(Target_Memory_Addr == 0) + { + EPD_IT8951_Display_Area(X,Y,W,H,Mode); + } + else + { + EPD_IT8951_Display_AreaBuf(X,Y,W,H,Mode,Target_Memory_Addr); + } + + EPD_IT8951_WaitForDisplayReady(); + + EPD_IT8951_WriteReg(UP1SR+2, EPD_IT8951_ReadReg(UP1SR+2) & ~(1<<2) ); +} + + +/****************************************************************************** +function : Enhanced driving capability +parameter: Enhanced driving capability for IT8951, in case the blurred display effect +******************************************************************************/ +void Enhance_Driving_Capability(void) +{ + UWORD RegValue = EPD_IT8951_ReadReg(0x0038); + Debug("The reg value before writing is %x\r\n", RegValue); + + EPD_IT8951_WriteReg(0x0038, 0x0602); + + RegValue = EPD_IT8951_ReadReg(0x0038); + Debug("The reg value after writing is %x\r\n", RegValue); +} + + + + +/****************************************************************************** +function : Cmd1 SYS_RUN +parameter: Run the system +******************************************************************************/ +void EPD_IT8951_SystemRun(void) +{ + EPD_IT8951_WriteCommand(IT8951_TCON_SYS_RUN); +} + + +/****************************************************************************** +function : Cmd2 STANDBY +parameter: Standby +******************************************************************************/ +void EPD_IT8951_Standby(void) +{ + EPD_IT8951_WriteCommand(IT8951_TCON_STANDBY); +} + + +/****************************************************************************** +function : Cmd3 SLEEP +parameter: Sleep +******************************************************************************/ +void EPD_IT8951_Sleep(void) +{ + EPD_IT8951_WriteCommand(IT8951_TCON_SLEEP); +} + + +/****************************************************************************** +function : EPD_IT8951_Init +parameter: +******************************************************************************/ +IT8951_Dev_Info EPD_IT8951_Init(UWORD VCOM) +{ + IT8951_Dev_Info Dev_Info; + + EPD_IT8951_Reset(); + + EPD_IT8951_SystemRun(); + + EPD_IT8951_GetSystemInfo(&Dev_Info); + + //Enable Pack write + EPD_IT8951_WriteReg(I80CPCR,0x0001); + + //Set VCOM by handle + if(VCOM != EPD_IT8951_GetVCOM()) + { + EPD_IT8951_SetVCOM(VCOM); + Debug("VCOM = -%.02fV\n",(float)EPD_IT8951_GetVCOM()/1000); + } + return Dev_Info; +} + + +/****************************************************************************** +function : EPD_IT8951_Clear_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_Clear_Refresh(IT8951_Dev_Info Dev_Info,UDOUBLE Target_Memory_Addr, UWORD Mode) +{ + + UDOUBLE ImageSize = ((Dev_Info.Panel_W * 4 % 8 == 0)? (Dev_Info.Panel_W * 4 / 8 ): (Dev_Info.Panel_W * 4 / 8 + 1)) * Dev_Info.Panel_H; + UBYTE* Frame_Buf = malloc (ImageSize); + memset(Frame_Buf, 0xFF, ImageSize); + + + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + Load_Img_Info.Pixel_Format = IT8951_4BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = 0; + Area_Img_Info.Area_Y = 0; + Area_Img_Info.Area_W = Dev_Info.Panel_W; + Area_Img_Info.Area_H = Dev_Info.Panel_H; + + EPD_IT8951_HostAreaPackedPixelWrite_4bp(&Load_Img_Info, &Area_Img_Info, false); + + EPD_IT8951_Display_Area(0, 0, Dev_Info.Panel_W, Dev_Info.Panel_H, Mode); + + free(Frame_Buf); + Frame_Buf = NULL; +} + + +/****************************************************************************** +function : EPD_IT8951_1bp_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_1bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, UBYTE Mode, UDOUBLE Target_Memory_Addr, bool Packed_Write) +{ + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + //Use 8bpp to set 1bpp + Load_Img_Info.Pixel_Format = IT8951_8BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = X/8; + Area_Img_Info.Area_Y = Y; + Area_Img_Info.Area_W = W/8; + Area_Img_Info.Area_H = H; + + + //clock_t start, finish; + //double duration; + + //start = clock(); + + EPD_IT8951_HostAreaPackedPixelWrite_1bp(&Load_Img_Info, &Area_Img_Info, Packed_Write); + + //finish = clock(); + //duration = (double)(finish - start) / CLOCKS_PER_SEC; + //Debug( "Write occupy %f second\n", duration ); + + //start = clock(); + + EPD_IT8951_Display_1bp(X,Y,W,H,Mode,Target_Memory_Addr,0xF0,0x00); + + //finish = clock(); + //duration = (double)(finish - start) / CLOCKS_PER_SEC; + //Debug( "Show occupy %f second\n", duration ); +} + + + +/****************************************************************************** +function : EPD_IT8951_1bp_Multi_Frame_Write +parameter: +******************************************************************************/ +void EPD_IT8951_1bp_Multi_Frame_Write(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H,UDOUBLE Target_Memory_Addr, bool Packed_Write) +{ + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + //Use 8bpp to set 1bpp + Load_Img_Info.Pixel_Format = IT8951_8BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = X/8; + Area_Img_Info.Area_Y = Y; + Area_Img_Info.Area_W = W/8; + Area_Img_Info.Area_H = H; + + EPD_IT8951_HostAreaPackedPixelWrite_1bp(&Load_Img_Info, &Area_Img_Info,Packed_Write); +} + + + + +/****************************************************************************** +function : EPD_IT8951_1bp_Multi_Frame_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_1bp_Multi_Frame_Refresh(UWORD X, UWORD Y, UWORD W, UWORD H,UDOUBLE Target_Memory_Addr) +{ + EPD_IT8951_WaitForDisplayReady(); + + EPD_IT8951_Display_1bp(X,Y,W,H, A2_Mode,Target_Memory_Addr,0xF0,0x00); +} + + + + +/****************************************************************************** +function : EPD_IT8951_2bp_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_2bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr, bool Packed_Write) +{ + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + Load_Img_Info.Pixel_Format = IT8951_2BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = X; + Area_Img_Info.Area_Y = Y; + Area_Img_Info.Area_W = W; + Area_Img_Info.Area_H = H; + + EPD_IT8951_HostAreaPackedPixelWrite_2bp(&Load_Img_Info, &Area_Img_Info,Packed_Write); + + if(Hold == true) + { + EPD_IT8951_Display_Area(X,Y,W,H, GC16_Mode); + } + else + { + EPD_IT8951_Display_AreaBuf(X,Y,W,H, GC16_Mode,Target_Memory_Addr); + } +} + + + + +/****************************************************************************** +function : EPD_IT8951_4bp_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_4bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr, bool Packed_Write) +{ + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + Load_Img_Info.Pixel_Format = IT8951_4BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = X; + Area_Img_Info.Area_Y = Y; + Area_Img_Info.Area_W = W; + Area_Img_Info.Area_H = H; + + EPD_IT8951_HostAreaPackedPixelWrite_4bp(&Load_Img_Info, &Area_Img_Info, Packed_Write); + + if(Hold == true) + { + EPD_IT8951_Display_Area(X,Y,W,H, GC16_Mode); + } + else + { + EPD_IT8951_Display_AreaBuf(X,Y,W,H, GC16_Mode,Target_Memory_Addr); + } +} + + +/****************************************************************************** +function : EPD_IT8951_8bp_Refresh +parameter: +******************************************************************************/ +void EPD_IT8951_8bp_Refresh(UBYTE *Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr) +{ + IT8951_Load_Img_Info Load_Img_Info; + IT8951_Area_Img_Info Area_Img_Info; + + EPD_IT8951_WaitForDisplayReady(); + + Load_Img_Info.Source_Buffer_Addr = Frame_Buf; + Load_Img_Info.Endian_Type = IT8951_LDIMG_L_ENDIAN; + Load_Img_Info.Pixel_Format = IT8951_8BPP; + Load_Img_Info.Rotate = IT8951_ROTATE_0; + Load_Img_Info.Target_Memory_Addr = Target_Memory_Addr; + + Area_Img_Info.Area_X = X; + Area_Img_Info.Area_Y = Y; + Area_Img_Info.Area_W = W; + Area_Img_Info.Area_H = H; + + EPD_IT8951_HostAreaPackedPixelWrite_8bp(&Load_Img_Info, &Area_Img_Info); + + if(Hold == true) + { + EPD_IT8951_Display_Area(X, Y, W, H, GC16_Mode); + } + else + { + EPD_IT8951_Display_AreaBuf(X, Y, W, H, GC16_Mode, Target_Memory_Addr); + } +} diff --git a/frameos/src/drivers/waveshare/it8951/IT8951.h b/frameos/src/drivers/waveshare/it8951/IT8951.h new file mode 100644 index 00000000..46a5812d --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/IT8951.h @@ -0,0 +1,209 @@ +/***************************************************************************** +* | File : EPD_IT8951.h +* | Author : Waveshare team +* | Function : IT8951 Common driver +* | Info : +*---------------- +* | This version: V1.0 +* | Date : 2019-09-17 +* | Info : +* ----------------------------------------------------------------------------- +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation 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 +# furished 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 OR 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. +# +******************************************************************************/ +#ifndef __EPD_IT8951_H_ +#define __EPD_IT8951_H_ + +#include <stdbool.h> + +#include "DEV_Config.h" + + + +extern UBYTE INIT_Mode; + +extern UBYTE GC16_Mode; + +extern UBYTE A2_Mode; + + +typedef struct IT8951_Load_Img_Info +{ + UWORD Endian_Type; + UWORD Pixel_Format; + UWORD Rotate; + UBYTE* Source_Buffer_Addr; + UDOUBLE Target_Memory_Addr; +}IT8951_Load_Img_Info; + +typedef struct IT8951_Area_Img_Info +{ + UWORD Area_X; + UWORD Area_Y; + UWORD Area_W; + UWORD Area_H; +}IT8951_Area_Img_Info; + +typedef struct IT8951_Dev_Info +{ + UWORD Panel_W; + UWORD Panel_H; + UWORD Memory_Addr_L; + UWORD Memory_Addr_H; + UWORD FW_Version[8]; + UWORD LUT_Version[8]; +}IT8951_Dev_Info; + +/*----------------------------------------------------------------------- +IT8951 Command defines +------------------------------------------------------------------------*/ + + +#define IT8951_TCON_SYS_RUN 0x0001 +#define IT8951_TCON_STANDBY 0x0002 +#define IT8951_TCON_SLEEP 0x0003 +#define IT8951_TCON_REG_RD 0x0010 +#define IT8951_TCON_REG_WR 0x0011 + +#define IT8951_TCON_MEM_BST_RD_T 0x0012 +#define IT8951_TCON_MEM_BST_RD_S 0x0013 +#define IT8951_TCON_MEM_BST_WR 0x0014 +#define IT8951_TCON_MEM_BST_END 0x0015 + +#define IT8951_TCON_LD_IMG 0x0020 +#define IT8951_TCON_LD_IMG_AREA 0x0021 +#define IT8951_TCON_LD_IMG_END 0x0022 + + +#define USDEF_I80_CMD_DPY_AREA 0x0034 +#define USDEF_I80_CMD_GET_DEV_INFO 0x0302 +#define USDEF_I80_CMD_DPY_BUF_AREA 0x0037 +#define USDEF_I80_CMD_VCOM 0x0039 + +/*----------------------------------------------------------------------- + IT8951 Mode defines +------------------------------------------------------------------------*/ + + +#define IT8951_ROTATE_0 0 +#define IT8951_ROTATE_90 1 +#define IT8951_ROTATE_180 2 +#define IT8951_ROTATE_270 3 + + +#define IT8951_2BPP 0 +#define IT8951_3BPP 1 +#define IT8951_4BPP 2 +#define IT8951_8BPP 3 + + +#define IT8951_LDIMG_L_ENDIAN 0 +#define IT8951_LDIMG_B_ENDIAN 1 + +/*----------------------------------------------------------------------- +IT8951 Registers defines +------------------------------------------------------------------------*/ + +#define DISPLAY_REG_BASE 0x1000 + + +#define LUT0EWHR (DISPLAY_REG_BASE + 0x00) +#define LUT0XYR (DISPLAY_REG_BASE + 0x40) +#define LUT0BADDR (DISPLAY_REG_BASE + 0x80) +#define LUT0MFN (DISPLAY_REG_BASE + 0xC0) +#define LUT01AF (DISPLAY_REG_BASE + 0x114) + + +#define UP0SR (DISPLAY_REG_BASE + 0x134) +#define UP1SR (DISPLAY_REG_BASE + 0x138) +#define LUT0ABFRV (DISPLAY_REG_BASE + 0x13C) +#define UPBBADDR (DISPLAY_REG_BASE + 0x17C) +#define LUT0IMXY (DISPLAY_REG_BASE + 0x180) +#define LUTAFSR (DISPLAY_REG_BASE + 0x224) +#define BGVR (DISPLAY_REG_BASE + 0x250) + + +#define SYS_REG_BASE 0x0000 + + +#define I80CPCR (SYS_REG_BASE + 0x04) + + +#define MCSR_BASE_ADDR 0x0200 +#define MCSR (MCSR_BASE_ADDR + 0x0000) +#define LISAR (MCSR_BASE_ADDR + 0x0008) + + +/* +void EPD_IT8951_SystemRun(); +void EPD_IT8951_Standby(); +void EPD_IT8951_Sleep(); + +UWORD EPD_IT8951_ReadReg(UWORD Reg_Address); +void EPD_IT8951_WriteReg(UWORD Reg_Address,UWORD Reg_Value); +UWORD EPD_IT8951_GetVCOM(void); +void EPD_IT8951_SetVCOM(UWORD VCOM); + +void EPD_IT8951_LoadImgStart( IT8951_Load_Img_Info* Load_Img_Info ); +void EPD_IT8951_LoadImgAreaStart( IT8951_Load_Img_Info* Load_Img_Info, IT8951_Area_Img_Info* Area_Img_Info ); +void EPD_IT8951_LoadImgEnd(void); + +void EPD_IT8951_GetSystemInfo(void* Buf); +void EPD_IT8951_SetTargetMemoryAddr(UDOUBLE Target_Memory_Addr); +void EPD_IT8951_WaitForDisplayReady(void); + + +void EPD_IT8951_HostAreaPackedPixelWrite_8bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info); + +void EPD_IT8951_HostAreaPackedPixelWrite_1bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write); + +void EPD_IT8951_HostAreaPackedPixelWrite_2bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write); + +void EPD_IT8951_Display_Area(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode); +void EPD_IT8951_Display_AreaBuf(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode, UDOUBLE Target_Memory_Addr); + +void EPD_IT8951_Display_1bp(UWORD X, UWORD Y, UWORD W, UWORD H, UWORD Mode,UDOUBLE Target_Memory_Addr, UBYTE Front_Gray_Val, UBYTE Back_Gray_Val); +*/ + +void Enhance_Driving_Capability(void); + +void EPD_IT8951_SystemRun(void); + +void EPD_IT8951_Standby(void); + +void EPD_IT8951_Sleep(void); + +IT8951_Dev_Info EPD_IT8951_Init(UWORD VCOM); + +void EPD_IT8951_Clear_Refresh(IT8951_Dev_Info Dev_Info,UDOUBLE Target_Memory_Addr, UWORD Mode); + +void EPD_IT8951_1bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, UBYTE Mode, UDOUBLE Target_Memory_Addr, bool Packed_Write); +void EPD_IT8951_1bp_Multi_Frame_Write(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H,UDOUBLE Target_Memory_Addr, bool Packed_Write); +void EPD_IT8951_1bp_Multi_Frame_Refresh(UWORD X, UWORD Y, UWORD W, UWORD H,UDOUBLE Target_Memory_Addr); + +void EPD_IT8951_2bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr, bool Packed_Write); + +void EPD_IT8951_4bp_Refresh(UBYTE* Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr, bool Packed_Write); + +void EPD_IT8951_8bp_Refresh(UBYTE *Frame_Buf, UWORD X, UWORD Y, UWORD W, UWORD H, bool Hold, UDOUBLE Target_Memory_Addr); + + + +#endif diff --git a/frameos/src/drivers/waveshare/it8951/IT8951.nim b/frameos/src/drivers/waveshare/it8951/IT8951.nim new file mode 100644 index 00000000..71b49ee6 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/IT8951.nim @@ -0,0 +1,188 @@ +{.compile: "IT8951.c".} +## *************************************************************************** +## | File : EPD_IT8951.h +## | Author : Waveshare team +## | Function : IT8951 Common driver +## | Info : +## ---------------- +## | This version: V1.0 +## | Date : 2019-09-17 +## | Info : +## ----------------------------------------------------------------------------- +## # +## # Permission is hereby granted, free of charge, to any person obtaining a copy +## # of this software and associated documnetation 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 +## # furished 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 OR 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. +## # +## **************************************************************************** + +import + DEV_Config + +var INIT_Mode*: UBYTE + +var GC16_Mode*: UBYTE + +var A2_Mode*: UBYTE + +type + IT8951_Load_Img_Info* {.bycopy.} = object + Endian_Type*: UWORD + Pixel_Format*: UWORD + Rotate*: UWORD + Source_Buffer_Addr*: ptr UBYTE + Target_Memory_Addr*: UDOUBLE + + IT8951_Area_Img_Info* {.bycopy.} = object + Area_X*: UWORD + Area_Y*: UWORD + Area_W*: UWORD + Area_H*: UWORD + + IT8951_Dev_Info* {.bycopy.} = object + Panel_W*: UWORD + Panel_H*: UWORD + Memory_Addr_L*: UWORD + Memory_Addr_H*: UWORD + FW_Version*: array[8, UWORD] + LUT_Version*: array[8, UWORD] + + +## ----------------------------------------------------------------------- +## IT8951 Command defines +## ------------------------------------------------------------------------ + +const + IT8951_TCON_SYS_RUN* = 0x0001 + IT8951_TCON_STANDBY* = 0x0002 + IT8951_TCON_SLEEP* = 0x0003 + IT8951_TCON_REG_RD* = 0x0010 + IT8951_TCON_REG_WR* = 0x0011 + IT8951_TCON_MEM_BST_RD_T* = 0x0012 + IT8951_TCON_MEM_BST_RD_S* = 0x0013 + IT8951_TCON_MEM_BST_WR* = 0x0014 + IT8951_TCON_MEM_BST_END* = 0x0015 + IT8951_TCON_LD_IMG* = 0x0020 + IT8951_TCON_LD_IMG_AREA* = 0x0021 + IT8951_TCON_LD_IMG_END* = 0x0022 + USDEF_I80_CMD_DPY_AREA* = 0x0034 + USDEF_I80_CMD_GET_DEV_INFO* = 0x0302 + USDEF_I80_CMD_DPY_BUF_AREA* = 0x0037 + USDEF_I80_CMD_VCOM* = 0x0039 + +## ----------------------------------------------------------------------- +## IT8951 Mode defines +## ------------------------------------------------------------------------ + +const + IT8951_ROTATE_0* = 0 + IT8951_ROTATE_90* = 1 + IT8951_ROTATE_180* = 2 + IT8951_ROTATE_270* = 3 + IT8951_2BPP* = 0 + IT8951_3BPP* = 1 + IT8951_4BPP* = 2 + IT8951_8BPP* = 3 + IT8951_LDIMG_L_ENDIAN* = 0 + IT8951_LDIMG_B_ENDIAN* = 1 + +## ----------------------------------------------------------------------- +## IT8951 Registers defines +## ------------------------------------------------------------------------ + +const + DISPLAY_REG_BASE* = 0x1000 + LUT0EWHR* = (DISPLAY_REG_BASE + 0x00) + LUT0XYR* = (DISPLAY_REG_BASE + 0x40) + LUT0BADDR* = (DISPLAY_REG_BASE + 0x80) + LUT0MFN* = (DISPLAY_REG_BASE + 0xC0) + LUT01AF* = (DISPLAY_REG_BASE + 0x114) + UP0SR* = (DISPLAY_REG_BASE + 0x134) + UP1SR* = (DISPLAY_REG_BASE + 0x138) + LUT0ABFRV* = (DISPLAY_REG_BASE + 0x13C) + UPBBADDR* = (DISPLAY_REG_BASE + 0x17C) + LUT0IMXY* = (DISPLAY_REG_BASE + 0x180) + LUTAFSR* = (DISPLAY_REG_BASE + 0x224) + BGVR* = (DISPLAY_REG_BASE + 0x250) + SYS_REG_BASE* = 0x0000 + I80CPCR* = (SYS_REG_BASE + 0x04) + MCSR_BASE_ADDR* = 0x0200 + MCSR* = (MCSR_BASE_ADDR + 0x0000) + LISAR* = (MCSR_BASE_ADDR + 0x0008) + +## +## void EPD_IT8951_SystemRun(); +## void EPD_IT8951_Standby(); +## void EPD_IT8951_Sleep(); +## +## UWORD EPD_IT8951_ReadReg(UWORD Reg_Address); +## void EPD_IT8951_WriteReg(UWORD Reg_Address,UWORD Reg_Value); +## UWORD EPD_IT8951_GetVCOM(void); +## void EPD_IT8951_SetVCOM(UWORD VCOM); +## +## void EPD_IT8951_LoadImgStart( IT8951_Load_Img_Info* Load_Img_Info ); +## void EPD_IT8951_LoadImgAreaStart( IT8951_Load_Img_Info* Load_Img_Info, IT8951_Area_Img_Info* Area_Img_Info ); +## void EPD_IT8951_LoadImgEnd(void); +## +## void EPD_IT8951_GetSystemInfo(void* Buf); +## void EPD_IT8951_SetTargetMemoryAddr(UDOUBLE Target_Memory_Addr); +## void EPD_IT8951_WaitForDisplayReady(void); +## +## +## void EPD_IT8951_HostAreaPackedPixelWrite_8bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info); +## +## void EPD_IT8951_HostAreaPackedPixelWrite_1bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write); +## +## void EPD_IT8951_HostAreaPackedPixelWrite_2bp(IT8951_Load_Img_Info*Load_Img_Info,IT8951_Area_Img_Info*Area_Img_Info, bool Packed_Write); +## +## void EPD_IT8951_Display_Area(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode); +## void EPD_IT8951_Display_AreaBuf(UWORD X,UWORD Y,UWORD W,UWORD H,UWORD Mode, UDOUBLE Target_Memory_Addr); +## +## void EPD_IT8951_Display_1bp(UWORD X, UWORD Y, UWORD W, UWORD H, UWORD Mode,UDOUBLE Target_Memory_Addr, UBYTE Front_Gray_Val, UBYTE Back_Gray_Val); +## + +proc Enhance_Driving_Capability*() {.importc: "Enhance_Driving_Capability".} +proc EPD_IT8951_SystemRun*() {.importc: "EPD_IT8951_SystemRun".} +proc EPD_IT8951_Standby*() {.importc: "EPD_IT8951_Standby".} +proc EPD_IT8951_Sleep*() {.importc: "EPD_IT8951_Sleep".} +proc EPD_IT8951_Init*(VCOM: UWORD): IT8951_Dev_Info {.importc: "EPD_IT8951_Init".} +proc EPD_IT8951_Clear_Refresh*(Dev_Info: IT8951_Dev_Info; + Target_Memory_Addr: UDOUBLE; Mode: UWORD) {. + importc: "EPD_IT8951_Clear_Refresh".} +proc EPD_IT8951_1bp_Refresh*(Frame_Buf: ptr UBYTE; X: UWORD; Y: UWORD; W: UWORD; H: UWORD; + Mode: UBYTE; Target_Memory_Addr: UDOUBLE; + Packed_Write: bool) {. + importc: "EPD_IT8951_1bp_Refresh".} +proc EPD_IT8951_1bp_Multi_Frame_Write*(Frame_Buf: ptr UBYTE; X: UWORD; Y: UWORD; + W: UWORD; H: UWORD; + Target_Memory_Addr: UDOUBLE; + Packed_Write: bool) {. + importc: "EPD_IT8951_1bp_Multi_Frame_Write".} +proc EPD_IT8951_1bp_Multi_Frame_Refresh*(X: UWORD; Y: UWORD; W: UWORD; H: UWORD; + Target_Memory_Addr: UDOUBLE) {. + importc: "EPD_IT8951_1bp_Multi_Frame_Refresh".} +proc EPD_IT8951_2bp_Refresh*(Frame_Buf: ptr UBYTE; X: UWORD; Y: UWORD; W: UWORD; H: UWORD; + Hold: bool; Target_Memory_Addr: UDOUBLE; + Packed_Write: bool) {. + importc: "EPD_IT8951_2bp_Refresh".} +proc EPD_IT8951_4bp_Refresh*(Frame_Buf: ptr UBYTE; X: UWORD; Y: UWORD; W: UWORD; H: UWORD; + Hold: bool; Target_Memory_Addr: UDOUBLE; + Packed_Write: bool) {. + importc: "EPD_IT8951_4bp_Refresh".} +proc EPD_IT8951_8bp_Refresh*(Frame_Buf: ptr UBYTE; X: UWORD; Y: UWORD; W: UWORD; H: UWORD; + Hold: bool; Target_Memory_Addr: UDOUBLE) {. + importc: "EPD_IT8951_8bp_Refresh".} diff --git a/frameos/src/drivers/waveshare/it8951/Makefile b/frameos/src/drivers/waveshare/it8951/Makefile new file mode 100644 index 00000000..cb3d38e7 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/Makefile @@ -0,0 +1,25 @@ +# This was used to convert the non-EPD *.h files +.PHONY: all normal transform-epd-files remove-slashes + +all: transform-epd-files + +dev-config: + `nimble path c2nim`/c2nim --assumendef:DEBUG --assumedef:USE_DEV_LIB --assumedef:RPI --assumendef:JETSON --assumendef:USE_BCM2835_LIB --assumendef:USE_WIRINGPI_LIB --assumendef:USE_LGPIO_LIB --assumendef:DEV_HARDWARE_SPI_DEBUG --assumendef:GPIOD_DEBUG --importc *.h + +transform-epd-files: remove-slashes + for file in *.h; do \ + base=$$(basename "$$file" .h); \ + `nimble path c2nim`/c2nim --assumendef:DEBUG --importc $$file; \ + echo '{.compile: "'$$base'.c".}' > "$$file.tmp"; \ + cat "$$base".nim >> "$$file.tmp"; \ + mv "$$file.tmp" "$$base".nim; \ + done + + +remove-slashes: + # c2nim stumbles if a line ends with an empty comment "//", and makes noise with a full comment + @if [ "$$(uname)" = "Darwin" ]; then \ + find . -type f -name 'EPD_*.h' -exec sed -i '' 's|//.*$$||' {} +; \ + else \ + find . -type f -name 'EPD_*.h' -exec sed -i 's|//$$||' {} +; \ + fi diff --git a/frameos/src/drivers/waveshare/it8951/examples/example.c b/frameos/src/drivers/waveshare/it8951/examples/example.c new file mode 100644 index 00000000..2648f366 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/examples/example.c @@ -0,0 +1,893 @@ +#include "example.h" + +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> + +#include "../lib/e-Paper/EPD_IT8951.h" +#include "../lib/GUI/GUI_Paint.h" +#include "../lib/GUI/GUI_BMPfile.h" +#include "../lib/Config/Debug.h" + +UBYTE *Refresh_Frame_Buf = NULL; + +UBYTE *Panel_Frame_Buf = NULL; +UBYTE *Panel_Area_Frame_Buf = NULL; + +bool Four_Byte_Align = false; + +extern int epd_mode; +extern UWORD VCOM; +extern UBYTE isColor; +/****************************************************************************** +function: Change direction of display, Called after Paint_NewImage() +parameter: + mode: display mode +******************************************************************************/ +static void Epd_Mode(int mode) +{ + if(mode == 3) { + Paint_SetRotate(ROTATE_0); + Paint_SetMirroring(MIRROR_NONE); + isColor = 1; + }else if(mode == 2) { + Paint_SetRotate(ROTATE_0); + Paint_SetMirroring(MIRROR_HORIZONTAL); + }else if(mode == 1) { + Paint_SetRotate(ROTATE_0); + Paint_SetMirroring(MIRROR_HORIZONTAL); + }else { + Paint_SetRotate(ROTATE_0); + Paint_SetMirroring(MIRROR_NONE); + } +} + + +/****************************************************************************** +function: Display_ColorPalette_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address +******************************************************************************/ +UBYTE Display_ColorPalette_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr){ + UWORD In_4bp_Refresh_Area_Width; + if(Four_Byte_Align == true){ + In_4bp_Refresh_Area_Width = Panel_Width - (Panel_Width % 32); + }else{ + In_4bp_Refresh_Area_Width = Panel_Width; + } + UWORD In_4bp_Refresh_Area_Height = Panel_Height/16; + + UDOUBLE Imagesize; + + clock_t In_4bp_Refresh_Start, In_4bp_Refresh_Finish; + double In_4bp_Refresh_Duration; + + Imagesize = ((In_4bp_Refresh_Area_Width*4 % 8 == 0)? (In_4bp_Refresh_Area_Width*4 / 8 ): (In_4bp_Refresh_Area_Width*4 / 8 + 1)) * In_4bp_Refresh_Area_Height; + + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for black memory...\r\n"); + return -1; + } + + Debug("Start to demostrate 4bpp palette example\r\n"); + In_4bp_Refresh_Start = clock(); + + UBYTE SixteenColorPattern[16] = {0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00}; + + for(int i=0; i < 16; i++){ + memset(Refresh_Frame_Buf, SixteenColorPattern[i], Imagesize); + EPD_IT8951_4bp_Refresh(Refresh_Frame_Buf, 0, i * In_4bp_Refresh_Area_Height, In_4bp_Refresh_Area_Width, In_4bp_Refresh_Area_Height, false, Init_Target_Memory_Addr, false); + } + + In_4bp_Refresh_Finish = clock(); + In_4bp_Refresh_Duration = (double)(In_4bp_Refresh_Finish - In_4bp_Refresh_Start) / CLOCKS_PER_SEC; + Debug( "Write and Show 4bp occupy %f second\n", In_4bp_Refresh_Duration ); + + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + return 0; +} + + +/****************************************************************************** +function: Display_CharacterPattern_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address + BitsPerPixel: Bits Per Pixel, 2^BitsPerPixel = grayscale +******************************************************************************/ +UBYTE Display_CharacterPattern_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr, UBYTE BitsPerPixel){ + UWORD Display_Area_Width; + if(Four_Byte_Align == true){ + Display_Area_Width = Panel_Width - (Panel_Width % 32); + }else{ + Display_Area_Width = Panel_Width; + } + UWORD Display_Area_Height = Panel_Height; + + UWORD Display_Area_Sub_Width = Display_Area_Width / 5; + UWORD Display_Area_Sub_Height = Display_Area_Height / 5; + + UDOUBLE Imagesize; + + Imagesize = ((Display_Area_Width * BitsPerPixel % 8 == 0)? (Display_Area_Width * BitsPerPixel / 8 ): (Display_Area_Width * BitsPerPixel / 8 + 1)) * Display_Area_Height; + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for image memory...\r\n"); + return -1; + } + + Paint_NewImage(Refresh_Frame_Buf, Display_Area_Width, Display_Area_Height, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(BitsPerPixel); + Paint_Clear(WHITE); + + + for(int y=20; y<Display_Area_Height - Display_Area_Sub_Height; y += Display_Area_Sub_Height )//To prevent arrays from going out of bounds + { + for(int x=20; x<Display_Area_Width - Display_Area_Sub_Width; x += Display_Area_Sub_Width )//To prevent arrays from going out of bounds + { + //For color definition of all BitsPerPixel, you can refer to GUI_Paint.h + Paint_DrawPoint(x+Display_Area_Sub_Width*3/8, y+Display_Area_Sub_Height*3/8, 0x10, DOT_PIXEL_7X7, DOT_STYLE_DFT); + Paint_DrawPoint(x+Display_Area_Sub_Width*5/8, y+Display_Area_Sub_Height*3/8, 0x30, DOT_PIXEL_7X7, DOT_STYLE_DFT); + Paint_DrawLine(x+Display_Area_Sub_Width*3/8, y+Display_Area_Sub_Height*5/8, x+Display_Area_Sub_Width*5/8, y+Display_Area_Sub_Height*5/8, 0x50, DOT_PIXEL_3X3, LINE_STYLE_SOLID); + Paint_DrawRectangle(x, y, x+Display_Area_Sub_Width, y+Display_Area_Sub_Height, 0x00, DOT_PIXEL_3X3, DRAW_FILL_EMPTY); + Paint_DrawCircle(x + Display_Area_Sub_Width/2, y + Display_Area_Sub_Height/2, Display_Area_Sub_Height/2, 0x50, DOT_PIXEL_2X2, DRAW_FILL_EMPTY); + Paint_DrawNum(x+Display_Area_Sub_Width*3/10, y+Display_Area_Sub_Height*1/4, 1234567890, &Font16, 0x20, 0xE0); + Paint_DrawString_EN(x+Display_Area_Sub_Width*3/10, y+Display_Area_Sub_Height*3/4, "hello world", &Font16, 0x30, 0xD0); + } + } + + + switch(BitsPerPixel){ + case BitsPerPixel_8:{ + EPD_IT8951_8bp_Refresh(Refresh_Frame_Buf, 0, 0, Display_Area_Width, Display_Area_Height, false, Init_Target_Memory_Addr); + break; + } + case BitsPerPixel_4:{ + EPD_IT8951_4bp_Refresh(Refresh_Frame_Buf, 0, 0, Display_Area_Width, Display_Area_Height, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_2:{ + EPD_IT8951_2bp_Refresh(Refresh_Frame_Buf, 0, 0, Display_Area_Width, Display_Area_Height, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_1:{ + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, 0, 0, Display_Area_Width, Display_Area_Height, A2_Mode, Init_Target_Memory_Addr,false); + break; + } + } + + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + return 0; +} + + + +/****************************************************************************** +function: Display_BMP_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address + BitsPerPixel: Bits Per Pixel, 2^BitsPerPixel = grayscale +******************************************************************************/ +UBYTE Display_BMP_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr, UBYTE BitsPerPixel){ + UWORD WIDTH; + if(Four_Byte_Align == true){ + WIDTH = Panel_Width - (Panel_Width % 32); + }else{ + WIDTH = Panel_Width; + } + UWORD HEIGHT = Panel_Height; + + UDOUBLE Imagesize; + + Imagesize = ((WIDTH * BitsPerPixel % 8 == 0)? (WIDTH * BitsPerPixel / 8 ): (WIDTH * BitsPerPixel / 8 + 1)) * HEIGHT; + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for black memory...\r\n"); + return -1; + } + + Paint_NewImage(Refresh_Frame_Buf, WIDTH, HEIGHT, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(BitsPerPixel); + Paint_Clear(WHITE); + + char Path[30]; + sprintf(Path,"./pic/%dx%d_0.bmp", WIDTH, HEIGHT); + + GUI_ReadBmp(Path, 0, 0); + + //you can draw your character and pattern on the image, for color definition of all BitsPerPixel, you can refer to GUI_Paint.h, + //Paint_DrawRectangle(50, 50, WIDTH/2, HEIGHT/2, 0x30, DOT_PIXEL_3X3, DRAW_FILL_EMPTY); + //Paint_DrawCircle(WIDTH*3/4, HEIGHT/4, 100, 0xF0, DOT_PIXEL_2X2, DRAW_FILL_EMPTY); + //Paint_DrawNum(WIDTH/4, HEIGHT/5, 709, &Font20, 0x30, 0xB0); + + switch(BitsPerPixel){ + case BitsPerPixel_8:{ + Paint_DrawString_EN(10, 10, "8 bits per pixel 16 grayscale", &Font24, 0xF0, 0x00); + EPD_IT8951_8bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr); + break; + } + case BitsPerPixel_4:{ + Paint_DrawString_EN(10, 10, "4 bits per pixel 16 grayscale", &Font24, 0xF0, 0x00); + EPD_IT8951_4bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_2:{ + Paint_DrawString_EN(10, 10, "2 bits per pixel 4 grayscale", &Font24, 0xC0, 0x00); + EPD_IT8951_2bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_1:{ + Paint_DrawString_EN(10, 10, "1 bit per pixel 2 grayscale", &Font24, 0x80, 0x00); + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, A2_Mode, Init_Target_Memory_Addr,false); + break; + } + } + + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + DEV_Delay_ms(5000); + + return 0; +} + + +/****************************************************************************** +function: Dynamic_Refresh_Example +parameter: + Dev_Info: Information structure read from IT8951 + Init_Target_Memory_Addr: Memory address of IT8951 target memory address +******************************************************************************/ +UBYTE Dynamic_Refresh_Example(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr){ + UWORD Panel_Width = Dev_Info.Panel_W; + UWORD Panel_Height = Dev_Info.Panel_H; + + UWORD Dynamic_Area_Width = 96; + UWORD Dynamic_Area_Height = 48; + + UDOUBLE Imagesize; + + UWORD Start_X = 0,Start_Y = 0; + + UWORD Dynamic_Area_Count = 0; + + UWORD Repeat_Area_Times = 0; + + //malloc enough memory for 1bp picture first + Imagesize = ((Panel_Width * 1 % 8 == 0)? (Panel_Width * 1 / 8 ): (Panel_Width * 1 / 8 + 1)) * Panel_Height; + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL){ + Debug("Failed to apply for picture memory...\r\n"); + return -1; + } + + clock_t Dynamic_Area_Start, Dynamic_Area_Finish; + double Dynamic_Area_Duration; + + while(1) + { + Dynamic_Area_Width = 128; + Dynamic_Area_Height = 96; + + Start_X = 0; + Start_Y = 0; + + Dynamic_Area_Count = 0; + + Dynamic_Area_Start = clock(); + Debug("Start to dynamic display...\r\n"); + + for(Dynamic_Area_Width = 96, Dynamic_Area_Height = 64; (Dynamic_Area_Width < Panel_Width - 32) && (Dynamic_Area_Height < Panel_Height - 24); Dynamic_Area_Width += 32, Dynamic_Area_Height += 24) + { + + Imagesize = ((Dynamic_Area_Width % 8 == 0)? (Dynamic_Area_Width / 8 ): (Dynamic_Area_Width / 8 + 1)) * Dynamic_Area_Height; + Paint_NewImage(Refresh_Frame_Buf, Dynamic_Area_Width, Dynamic_Area_Height, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(1); + + for(int y=Start_Y; y< Panel_Height - Dynamic_Area_Height; y += Dynamic_Area_Height) + { + for(int x=Start_X; x< Panel_Width - Dynamic_Area_Width; x += Dynamic_Area_Width) + { + Paint_Clear(WHITE); + + //For color definition of all BitsPerPixel, you can refer to GUI_Paint.h + Paint_DrawRectangle(0, 0, Dynamic_Area_Width-1, Dynamic_Area_Height, 0x00, DOT_PIXEL_2X2, DRAW_FILL_EMPTY); + + Paint_DrawCircle(Dynamic_Area_Width*3/4, Dynamic_Area_Height*3/4, 5, 0x00, DOT_PIXEL_1X1, DRAW_FILL_FULL); + + Paint_DrawNum(Dynamic_Area_Width/4, Dynamic_Area_Height/4, ++Dynamic_Area_Count, &Font20, 0x00, 0xF0); + + if(epd_mode == 2) + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, 1280-Dynamic_Area_Width-x, y, Dynamic_Area_Width, Dynamic_Area_Height, A2_Mode, Init_Target_Memory_Addr, true); + else if(epd_mode == 1) + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, Panel_Width-Dynamic_Area_Width-x-16, y, Dynamic_Area_Width, Dynamic_Area_Height, A2_Mode, Init_Target_Memory_Addr, true); + else + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, x, y, Dynamic_Area_Width, Dynamic_Area_Height, A2_Mode, Init_Target_Memory_Addr, true); + } + } + Start_X += 32; + Start_Y += 24; + } + + Dynamic_Area_Finish = clock(); + Dynamic_Area_Duration = (double)(Dynamic_Area_Finish - Dynamic_Area_Start) / CLOCKS_PER_SEC; + Debug( "Write and Show occupy %f second\n", Dynamic_Area_Duration ); + + Repeat_Area_Times ++; + if(Repeat_Area_Times > 0){ + break; + } + } + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + return 0; +} + + +/****************************************************************************** +function: Dynamic_GIF_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address + BitsPerPixel: Bits Per Pixel, 2^BitsPerPixel = grayscale +******************************************************************************/ +UBYTE Dynamic_GIF_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr){ + + UWORD Animation_Start_X = 0; + UWORD Animation_Start_Y = 0; + UWORD Animation_Area_Width = 800; + UWORD Animation_Area_Height = 600; + + if(Animation_Area_Width > Panel_Width){ + return -1; + } + if(Animation_Area_Height > Panel_Height){ + return -1; + } + + UDOUBLE Imagesize; + + UBYTE Pic_Count = 0; + UBYTE Pic_Num = 7; + char Path[30]; + + UDOUBLE Basical_Memory_Addr = Init_Target_Memory_Addr; + + UDOUBLE Target_Memory_Addr = Basical_Memory_Addr; + UWORD Repeat_Animation_Times = 0; + + clock_t Animation_Test_Start, Animation_Test_Finish; + double Animation_Test_Duration; + + Imagesize = ((Animation_Area_Width * 1 % 8 == 0)? (Animation_Area_Width * 1 / 8 ): (Animation_Area_Width * 1 / 8 + 1)) * Animation_Area_Height; + + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL){ + Debug("Failed to apply for image memory...\r\n"); + return -1; + } + + Paint_NewImage(Refresh_Frame_Buf, Animation_Area_Width, Animation_Area_Height, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(1); + + Debug("Start to write a animation\r\n"); + Animation_Test_Start = clock(); + for(int i=0; i < Pic_Num; i += 1){ + Paint_Clear(WHITE); + sprintf(Path,"./pic/800x600_gif_%d.bmp",Pic_Count++); + GUI_ReadBmp(Path, 0, 0); + //For color definition of all BitsPerPixel, you can refer to GUI_Paint.h + Paint_DrawNum(10, 10, i+1, &Font16, 0x00, 0xF0); + if(epd_mode == 2) + EPD_IT8951_1bp_Multi_Frame_Write(Refresh_Frame_Buf, 1280-Animation_Area_Width+Animation_Start_X, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr,false); + else if(epd_mode == 1) + EPD_IT8951_1bp_Multi_Frame_Write(Refresh_Frame_Buf, Panel_Width-Animation_Area_Width+Animation_Start_X-16, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr,false); + else + EPD_IT8951_1bp_Multi_Frame_Write(Refresh_Frame_Buf, Animation_Start_X, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr,false); + Target_Memory_Addr += Imagesize; + } + + Animation_Test_Finish = clock(); + Animation_Test_Duration = (double)(Animation_Test_Finish - Animation_Test_Start) / CLOCKS_PER_SEC; + Debug( "Write all frame occupy %f second\r\n", Animation_Test_Duration); + + Target_Memory_Addr = Basical_Memory_Addr; + + while(1){ + Debug("Start to show a animation\r\n"); + Animation_Test_Start = clock(); + + for(int i=0; i< Pic_Num; i += 1){ + if(epd_mode == 2) + EPD_IT8951_1bp_Multi_Frame_Refresh(Panel_Width-Animation_Area_Width+Animation_Start_X, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr); + else if(epd_mode == 1) + EPD_IT8951_1bp_Multi_Frame_Refresh(Panel_Width-Animation_Area_Width+Animation_Start_X-16, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr); + else + EPD_IT8951_1bp_Multi_Frame_Refresh(Animation_Start_X, Animation_Start_Y, Animation_Area_Width, Animation_Area_Height, Target_Memory_Addr); + Target_Memory_Addr += Imagesize; + } + Target_Memory_Addr = Basical_Memory_Addr; + + Animation_Test_Finish = clock(); + Animation_Test_Duration = (double)(Animation_Test_Finish - Animation_Test_Start) / CLOCKS_PER_SEC; + Debug( "Show all frame occupy %f second\r\n", Animation_Test_Duration ); + Debug( "The frame rate is: %lf fps\r\n", Pic_Num/Animation_Test_Duration); + + Repeat_Animation_Times ++; + if(Repeat_Animation_Times >15){ + break; + } + } + + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + return 0; +} + + + +/****************************************************************************** +function: Check_FrameRate_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address + BitsPerPixel: Bits Per Pixel, 2^BitsPerPixel = grayscale +******************************************************************************/ +UBYTE Check_FrameRate_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Target_Memory_Addr, UBYTE BitsPerPixel){ + UWORD Frame_Rate_Test_Width; + if(Four_Byte_Align == true){ + Frame_Rate_Test_Width = Panel_Width - (Panel_Width % 32); + }else{ + Frame_Rate_Test_Width = Panel_Width; + } + UWORD Frame_Rate_Test_Height = Panel_Height; + UDOUBLE Imagesize; + + UBYTE *Refresh_FrameRate_Buf = NULL; + + UBYTE Count = 0; + + clock_t Frame_Rate_Test_Start, Frame_Rate_Test_Finish; + double Frame_Rate_Test_Duration; + + Imagesize = ((Frame_Rate_Test_Width * BitsPerPixel % 8 == 0)? (Frame_Rate_Test_Width * BitsPerPixel / 8 ): (Frame_Rate_Test_Width * BitsPerPixel / 8 + 1)) * Frame_Rate_Test_Height; + + if((Refresh_FrameRate_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for image memory...\r\n"); + return -1; + } + + Paint_NewImage(Refresh_FrameRate_Buf, Frame_Rate_Test_Width, Frame_Rate_Test_Height, 0, BLACK); + Paint_SelectImage(Refresh_FrameRate_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(BitsPerPixel); + + Debug("Start to test Frame Rate\r\n"); + Frame_Rate_Test_Start = clock(); + + for(int i=0; i<10; i++){ + + Paint_Clear(WHITE); + //For color definition of all BitsPerPixel, you can refer to GUI_Paint.h + Paint_DrawRectangle(20, 20, Frame_Rate_Test_Width-20, Frame_Rate_Test_Height-20, 0x00, DOT_PIXEL_4X4, DRAW_FILL_EMPTY);//To prevent arrays from going out of bounds + Paint_DrawNum(Frame_Rate_Test_Width/2, Frame_Rate_Test_Height/2, ++Count, &Font24, 0x00, 0xF0); + Paint_DrawString_EN(Frame_Rate_Test_Width/2, Frame_Rate_Test_Height/4, "frame rate test", &Font20, 0xF0, 0x00); + Paint_DrawString_EN(Frame_Rate_Test_Width/2, Frame_Rate_Test_Height*3/4, "frame rate test", &Font20, 0xF0, 0x00); + + switch(BitsPerPixel){ + case 8:{ + if(epd_mode == 2) + EPD_IT8951_8bp_Refresh(Refresh_FrameRate_Buf, 1280-Frame_Rate_Test_Width, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr); + else if(epd_mode == 1) + EPD_IT8951_8bp_Refresh(Refresh_FrameRate_Buf, 1872-Frame_Rate_Test_Width-16, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr); + else + EPD_IT8951_8bp_Refresh(Refresh_FrameRate_Buf, 0, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr); + break; + } + case 4:{ + if(epd_mode == 2) + EPD_IT8951_4bp_Refresh(Refresh_FrameRate_Buf, 1280-Frame_Rate_Test_Width, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + else if(epd_mode == 1) + EPD_IT8951_4bp_Refresh(Refresh_FrameRate_Buf, 1872-Frame_Rate_Test_Width-16, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + else + EPD_IT8951_4bp_Refresh(Refresh_FrameRate_Buf, 0, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + break; + } + case 2:{ + if(epd_mode == 2) + EPD_IT8951_2bp_Refresh(Refresh_FrameRate_Buf, 1280-Frame_Rate_Test_Width, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + else if(epd_mode == 1) + EPD_IT8951_2bp_Refresh(Refresh_FrameRate_Buf, 1872-Frame_Rate_Test_Width-16, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + else + EPD_IT8951_2bp_Refresh(Refresh_FrameRate_Buf, 0, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, false, Target_Memory_Addr,false); + break; + } + case 1:{ + if(epd_mode == 2) + EPD_IT8951_1bp_Refresh(Refresh_FrameRate_Buf, 1280-Frame_Rate_Test_Width, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, A2_Mode, Target_Memory_Addr,false); + else if(epd_mode == 1) + EPD_IT8951_1bp_Refresh(Refresh_FrameRate_Buf, 1872-Frame_Rate_Test_Width-16, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, A2_Mode, Target_Memory_Addr,false); + else + EPD_IT8951_1bp_Refresh(Refresh_FrameRate_Buf, 0, 0, Frame_Rate_Test_Width, Frame_Rate_Test_Height, A2_Mode, Target_Memory_Addr,false); + break; + } + } + } + + Frame_Rate_Test_Finish = clock(); + Frame_Rate_Test_Duration = (double)(Frame_Rate_Test_Finish - Frame_Rate_Test_Start) / CLOCKS_PER_SEC; + Debug( "Write and Show 10 Frame occupy %f second\r\n", Frame_Rate_Test_Duration); + Debug( "The frame rate is: %lf fps\r\n", 10/Frame_Rate_Test_Duration); + + if(Refresh_FrameRate_Buf != NULL){ + free(Refresh_FrameRate_Buf); + Refresh_FrameRate_Buf = NULL; + } + + return 0; +} + +/****************************************************************************** +function: TouchPanel_ePaper_Example +parameter: + Panel_Width: Width of the panel + Panel_Height: Height of the panel + Init_Target_Memory_Addr: Memory address of IT8951 target memory address +******************************************************************************/ +UBYTE TouchPanel_ePaper_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr){ + int ret,fd; + UWORD Touch_Pannel_Area_Width; + if(Four_Byte_Align == true){ + Touch_Pannel_Area_Width = Panel_Width - (Panel_Width % 32); + }else{ + Touch_Pannel_Area_Width = Panel_Width; + } + UWORD Touch_Pannel_Area_Height = Panel_Height; + + UDOUBLE Imagesize; + + UWORD Touch_Point0[2]; + UWORD Touch_X = 0,Touch_Y = 0; + UWORD Touch_X_Old = 0,Touch_Y_Old = 0; + + UWORD Min_X = Panel_Width, Max_X = 0; + UWORD Min_Y = Panel_Height, Max_Y = 0; + + UWORD X_Start, X_End, Y_Start, Y_End, Width, Height; + + UBYTE First_Point_Flag = 1; + + UWORD Panel_Frame_Buf_WidthByte; + UWORD Panel_Area_Frame_Buf_WidthByte; + + if(access("/home/pi/FIFO",F_OK)){ + ret = mkfifo("/home/pi/FIFO",0777); + if(ret == -1){ + Debug("mkfifo error!\n"); + exit(0); + } + } + fd = open("/home/pi/FIFO",O_RDWR|O_NONBLOCK); + if( fd == -1 ) + { + Debug("Open error\r\n"); + exit(0); + } + + Panel_Frame_Buf_WidthByte = (Touch_Pannel_Area_Width * 1 % 8 == 0) ? (Touch_Pannel_Area_Width * 1 / 8 ): (Touch_Pannel_Area_Width * 1 / 8 + 1); + + Imagesize = ((Touch_Pannel_Area_Width * 1 % 8 == 0) ? (Touch_Pannel_Area_Width * 1 / 8 ): (Touch_Pannel_Area_Width *1 / 8 + 1)) * Touch_Pannel_Area_Height; + + if((Panel_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for Panel_Frame_Buf memory...\r\n"); + return -1; + } + + //Assume the entire screen is refreshed + if((Panel_Area_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for Panel_Area_Frame_Buf memory...\r\n"); + return -1; + } + + Paint_NewImage(Panel_Frame_Buf, Touch_Pannel_Area_Width, Touch_Pannel_Area_Height, 0, BLACK); + Paint_SelectImage(Panel_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(1); + Paint_Clear(WHITE); + + while(1) + { + Min_X = Panel_Width; + Max_X = 0; + Min_Y = Panel_Height; + Max_Y = 0; + + First_Point_Flag = 1; + + ret = read(fd,Touch_Point0,sizeof(Touch_Point0)); + + //Prepare the image + while(ret == 4){ + Touch_X = Touch_Point0[0]; + Touch_Y = Touch_Point0[1]; + Paint_NewImage(Panel_Frame_Buf, Touch_Pannel_Area_Width, Touch_Pannel_Area_Height, 0, BLACK); + Paint_SelectImage(Panel_Frame_Buf); + Paint_SetBitsPerPixel(1); + + if(First_Point_Flag == 0) + { + //For color definition of all BitsPerPixel, you can refer to GUI_Paint.h + Paint_DrawLine(Touch_X_Old, Touch_Y_Old, Touch_X, Touch_Y, 0x00, DOT_PIXEL_3X3, LINE_STYLE_SOLID); + } + Touch_X_Old = Touch_X; + Touch_Y_Old = Touch_Y; + First_Point_Flag = 0; + + if(Touch_X < Min_X){ + Min_X = Touch_X; + } + if(Touch_X > Max_X){ + Max_X = Touch_X; + } + if(Touch_Y < Min_Y){ + Min_Y = Touch_Y; + } + if(Touch_Y > Max_Y){ + Max_Y = Touch_Y; + } + + DEV_Delay_ms(15); + + Debug("Touch_X:%d\r\n",Touch_X); + Debug("Touch_Y:%d\r\n",Touch_Y); + ret = read(fd,Touch_Point0,sizeof(Touch_Point0)); + Debug("Stop ret:%d\r\n",ret); + } + + //If Min < Max, then Indicates that there is a refresh area + if( (Min_X<Max_X)||(Min_Y<Max_Y) ) + { + //----------Calculate Data, please be cautious that the width must be 32-bit aligned---------- + Debug("Min_X - Max_X Output:%d~%d\r\n",Min_X,Max_X); + Debug("Min_Y - Max_Y Output:%d~%d\r\n",Min_Y,Max_Y); + + X_Start = Min_X < 32 ? 0 : Min_X - (Min_X % 32); + Debug("X_Start:%d\r\n",X_Start); + X_End = ( Max_X + (32 - (Max_X % 32)) ) > Touch_Pannel_Area_Width ? ( Max_X - (Max_X % 32) ) : ( Max_X + (32 - (Max_X % 32)) ); + Debug("X_End:%d\r\n",X_End); + Y_Start = Min_Y; + Debug("Y_Start:%d\r\n",Y_Start); + Y_End = Max_Y; + Debug("Y_Start:%d\r\n",Y_End); + + Width = X_End - X_Start; + if(Width<=0){ + Width = 32; + } + Debug("Width:%d\r\n",Width); + Height = Y_End-Y_Start; + if(Height<=0){ + Height = 32; + } + Debug("Height:%d\r\n",Height); + + //----------Prepare Image---------- + Paint_NewImage(Panel_Area_Frame_Buf, Width, Height, 0, BLACK); + Paint_SelectImage(Panel_Area_Frame_Buf); + Epd_Mode(epd_mode); + Paint_Clear(WHITE); + + Panel_Area_Frame_Buf_WidthByte = (Width % 8 == 0) ? (Width / 8 ): (Width / 8 + 1); + + for(int y = 0; y< Height; y++){ + memcpy(Panel_Area_Frame_Buf + (y * Panel_Area_Frame_Buf_WidthByte), Panel_Frame_Buf + ((Y_Start + y) * Panel_Frame_Buf_WidthByte) + X_Start/8 , Panel_Area_Frame_Buf_WidthByte); + } + + //----------Display Image---------- + EPD_IT8951_1bp_Refresh(Panel_Area_Frame_Buf, X_Start, Y_Start, Width, Height, A2_Mode, Init_Target_Memory_Addr, true); + } + } + + if( Panel_Area_Frame_Buf != NULL ){ + free(Panel_Area_Frame_Buf); + Panel_Area_Frame_Buf = NULL; + } + + if( Panel_Frame_Buf != NULL ){ + free(Panel_Frame_Buf); + Panel_Frame_Buf = NULL; + } + + return 0; +} + + + +static UBYTE BMP_Test(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr, UBYTE BitsPerPixel, UBYTE Pic_Count) +{ + UWORD WIDTH; + + if(Four_Byte_Align == true){ + WIDTH = Panel_Width - (Panel_Width % 32); + }else{ + WIDTH = Panel_Width; + } + UWORD HEIGHT = Panel_Height; + + UDOUBLE Imagesize; + + Imagesize = ((WIDTH * BitsPerPixel % 8 == 0)? (WIDTH * BitsPerPixel / 8 ): (WIDTH * BitsPerPixel / 8 + 1)) * HEIGHT; + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize)) == NULL) { + Debug("Failed to apply for black memory...\r\n"); + return -1; + } + + Paint_NewImage(Refresh_Frame_Buf, WIDTH, HEIGHT, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(BitsPerPixel); + Paint_Clear(WHITE); + + + char Path[30]; + sprintf(Path,"./pic/%dx%d_%d.bmp", WIDTH, HEIGHT, Pic_Count); + GUI_ReadBmp(Path, 0, 0); + + switch(BitsPerPixel){ + case BitsPerPixel_8:{ + Paint_DrawString_EN(10, 10, "8 bits per pixel 16 grayscale", &Font24, 0xF0, 0x00); + EPD_IT8951_8bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr); + break; + } + case BitsPerPixel_4:{ + Paint_DrawString_EN(10, 10, "4 bits per pixel 16 grayscale", &Font24, 0xF0, 0x00); + EPD_IT8951_4bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_2:{ + Paint_DrawString_EN(10, 10, "2 bits per pixel 4 grayscale", &Font24, 0xC0, 0x00); + EPD_IT8951_2bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, false, Init_Target_Memory_Addr,false); + break; + } + case BitsPerPixel_1:{ + Paint_DrawString_EN(10, 10, "1 bit per pixel 2 grayscale", &Font24, 0x80, 0x00); + EPD_IT8951_1bp_Refresh(Refresh_Frame_Buf, 0, 0, WIDTH, HEIGHT, A2_Mode, Init_Target_Memory_Addr,false); + break; + } + } + + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + DEV_Delay_ms(5000); + + return 0; +} + + + + +void Factory_Test_Only(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr) +{ + while(1) + { + for(int i=0; i < 4; i++){ + EPD_IT8951_SystemRun(); + + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + // BMP_Test(Dev_Info.Panel_W, Dev_Info.Panel_H, Init_Target_Memory_Addr, BitsPerPixel_1, i); + // BMP_Test(Dev_Info.Panel_W, Dev_Info.Panel_H, Init_Target_Memory_Addr, BitsPerPixel_2, i); + BMP_Test(Dev_Info.Panel_W, Dev_Info.Panel_H, Init_Target_Memory_Addr, BitsPerPixel_4, i); + // BMP_Test(Dev_Info.Panel_W, Dev_Info.Panel_H, Init_Target_Memory_Addr, BitsPerPixel_8, i); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + EPD_IT8951_Sleep(); + DEV_Delay_ms(5000); + } + EPD_IT8951_SystemRun(); + + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + Dynamic_Refresh_Example(Dev_Info,Init_Target_Memory_Addr); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + + if(isColor) + Color_Test(Dev_Info, Init_Target_Memory_Addr); + + EPD_IT8951_Sleep(); + DEV_Delay_ms(5000); + } +} + +void Color_Test(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr) +{ + PAINT_TIME Time = {2020, 9, 30, 18, 10, 34}; + + while(1) + { + UWORD Panel_Width = Dev_Info.Panel_W; + UWORD Panel_Height = Dev_Info.Panel_H; + + UDOUBLE Imagesize; + + //malloc enough memory for 1bp picture first + Imagesize = ((Panel_Width * 1 % 8 == 0)? (Panel_Width * 1 / 8 ): (Panel_Width * 1 / 8 + 1)) * Panel_Height; + if((Refresh_Frame_Buf = (UBYTE *)malloc(Imagesize*4)) == NULL) { + Debug("Failed to apply for picture memory...\r\n"); + } + + Paint_NewImage(Refresh_Frame_Buf, Panel_Width, Panel_Height, 0, BLACK); + Paint_SelectImage(Refresh_Frame_Buf); + Epd_Mode(epd_mode); + Paint_SetBitsPerPixel(4); + Paint_Clear(WHITE); + + if(0) { + Paint_DrawRectangle(100, 100, 300, 300, 0x0f00, DOT_PIXEL_1X1, DRAW_FILL_FULL); //Red + Paint_DrawRectangle(100, 400, 300, 600, 0x00f0, DOT_PIXEL_1X1, DRAW_FILL_FULL); //Green + Paint_DrawRectangle(100, 700, 300, 900, 0x000f, DOT_PIXEL_1X1, DRAW_FILL_FULL); //Bule + + Paint_DrawCircle(500, 200, 100, 0x00ff, DOT_PIXEL_1X1, DRAW_FILL_FULL); + Paint_DrawCircle(500, 500, 100, 0x0f0f, DOT_PIXEL_1X1, DRAW_FILL_FULL); + Paint_DrawCircle(500, 800, 100, 0x0ff0, DOT_PIXEL_1X1, DRAW_FILL_FULL); + + Paint_DrawLine(1000, 200, 1100, 200, 0x055a, 10, LINE_STYLE_SOLID); + Paint_DrawLine(1000, 300, 1100, 300, 0x05a5, 20, LINE_STYLE_SOLID); + Paint_DrawLine(1000, 400, 1100, 400, 0x0a55, 30, LINE_STYLE_SOLID); + + Paint_DrawString_EN(1000, 500, "Hello, World!", &Font24, 0x0aa5, 0x0fff); + Paint_DrawString_EN(1000, 600, "Hello, World!", &Font24, 0x0a5a, 0x0fff); + Paint_DrawString_EN(1000, 700, "Hello, World!", &Font24, 0x05aa, 0x0fff); + + Paint_DrawString_CN(700, 400, "��� ѩ����", &Font24CN, 0x00fa, 0x0000); + Paint_DrawNum(700, 500, 123456789, &Font24, 0x0a0f, 0x0fff); + Paint_DrawTime(700, 600, &Time, &Font24, 0x0fa0, 0x0fff); + }else { + for(UWORD j=0; j<14; j++) { + for(UWORD i=0; i<19; i++) { + Paint_DrawRectangle(i*72, j*72+1, (i+1)*72-1, (j+1)*72, (i+j*19)*15, DOT_PIXEL_1X1, DRAW_FILL_FULL); + } + } + } + + EPD_IT8951_4bp_Refresh(Refresh_Frame_Buf, 0, 0, Panel_Width, Panel_Height, false, Init_Target_Memory_Addr, false); + + if(Refresh_Frame_Buf != NULL) { + free(Refresh_Frame_Buf); + Refresh_Frame_Buf = NULL; + } + + DEV_Delay_ms(5000); + break; + } +} diff --git a/frameos/src/drivers/waveshare/it8951/examples/example.h b/frameos/src/drivers/waveshare/it8951/examples/example.h new file mode 100644 index 00000000..96b9f179 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/examples/example.h @@ -0,0 +1,44 @@ +#ifndef __EXAMPLE__ +#define __EXAMPLE__ + +#include "../lib/e-Paper/EPD_IT8951.h" +#include "../lib/Config/DEV_Config.h" + + +// 1 bit per pixel, which is 2 grayscale +#define BitsPerPixel_1 1 +// 2 bit per pixel, which is 4 grayscale +#define BitsPerPixel_2 2 +// 4 bit per pixel, which is 16 grayscale +#define BitsPerPixel_4 4 +// 8 bit per pixel, which is 256 grayscale, but will automatically reduce by hardware to 4bpp, which is 16 grayscale +#define BitsPerPixel_8 8 + + +//For all refresh fram buf except touch panel +extern UBYTE *Refresh_Frame_Buf; + +//Only for touch panel +extern UBYTE *Panel_Frame_Buf; +extern UBYTE *Panel_Area_Frame_Buf; + +extern bool Four_Byte_Align; + +UBYTE Display_ColorPalette_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr); + +UBYTE Display_CharacterPattern_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr, UBYTE BitsPerPixel); + +UBYTE Display_BMP_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr, UBYTE BitsPerPixel); + +UBYTE Dynamic_Refresh_Example(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr); + +UBYTE Dynamic_GIF_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr); + +UBYTE Check_FrameRate_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Target_Memory_Addr, UBYTE BitsPerPixel); + +UBYTE TouchPanel_ePaper_Example(UWORD Panel_Width, UWORD Panel_Height, UDOUBLE Init_Target_Memory_Addr); + +void Factory_Test_Only(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr); +void Color_Test(IT8951_Dev_Info Dev_Info, UDOUBLE Init_Target_Memory_Addr); + +#endif diff --git a/frameos/src/drivers/waveshare/it8951/examples/main.c b/frameos/src/drivers/waveshare/it8951/examples/main.c new file mode 100644 index 00000000..330c9f44 --- /dev/null +++ b/frameos/src/drivers/waveshare/it8951/examples/main.c @@ -0,0 +1,192 @@ +#include "../lib/Config/DEV_Config.h" +#include "example.h" +#include "../lib/GUI/GUI_BMPfile.h" + +#include <math.h> + +#include <stdlib.h> //exit() +#include <signal.h> //signal() + +#define Enhance false + +#define USE_Factory_Test false + +#define USE_Normal_Demo true + +#define USE_Touch_Panel false + +UWORD VCOM = 2510; + +IT8951_Dev_Info Dev_Info = {0, 0}; +UWORD Panel_Width; +UWORD Panel_Height; +UDOUBLE Init_Target_Memory_Addr; +int epd_mode = 0; //0: no rotate, no mirror + //1: no rotate, horizontal mirror, for 10.3inch + //2: no totate, horizontal mirror, for 5.17inch + //3: no rotate, no mirror, isColor, for 6inch color + +void Handler(int signo){ + Debug("\r\nHandler:exit\r\n"); + if(Refresh_Frame_Buf != NULL){ + free(Refresh_Frame_Buf); + Debug("free Refresh_Frame_Buf\r\n"); + Refresh_Frame_Buf = NULL; + } + if(Panel_Frame_Buf != NULL){ + free(Panel_Frame_Buf); + Debug("free Panel_Frame_Buf\r\n"); + Panel_Frame_Buf = NULL; + } + if(Panel_Area_Frame_Buf != NULL){ + free(Panel_Area_Frame_Buf); + Debug("free Panel_Area_Frame_Buf\r\n"); + Panel_Area_Frame_Buf = NULL; + } + if(bmp_src_buf != NULL){ + free(bmp_src_buf); + Debug("free bmp_src_buf\r\n"); + bmp_src_buf = NULL; + } + if(bmp_dst_buf != NULL){ + free(bmp_dst_buf); + Debug("free bmp_dst_buf\r\n"); + bmp_dst_buf = NULL; + } + if(Dev_Info.Panel_W != 0){ + Debug("Going to sleep\r\n"); + EPD_IT8951_Sleep(); + } + DEV_Module_Exit(); + exit(0); +} + + +int main(int argc, char *argv[]) +{ + //Exception handling:ctrl + c + signal(SIGINT, Handler); + + if (argc < 2){ + Debug("Please input VCOM value on FPC cable!\r\n"); + Debug("Example: sudo ./epd -2.51\r\n"); + exit(1); + } + if (argc != 3){ + Debug("Please input e-Paper display mode!\r\n"); + Debug("Example: sudo ./epd -2.51 0 or sudo ./epd -2.51 1\r\n"); + Debug("Now, 10.3 inch glass panle is mode1, else is mode0\r\n"); + Debug("If you don't know what to type in just type 0 \r\n"); + exit(1); + } + + //Init the BCM2835 Device + if(DEV_Module_Init()!=0){ + return -1; + } + + double temp; + sscanf(argv[1],"%lf",&temp); + VCOM = (UWORD)(fabs(temp)*1000); + Debug("VCOM value:%d\r\n", VCOM); + sscanf(argv[2],"%d",&epd_mode); + Debug("Display mode:%d\r\n", epd_mode); + Dev_Info = EPD_IT8951_Init(VCOM); + +#if(Enhance) + Debug("Attention! Enhanced driving ability, only used when the screen is blurred\r\n"); + Enhance_Driving_Capability(); +#endif + + //get some important info from Dev_Info structure + Panel_Width = Dev_Info.Panel_W; + Panel_Height = Dev_Info.Panel_H; + Init_Target_Memory_Addr = Dev_Info.Memory_Addr_L | (Dev_Info.Memory_Addr_H << 16); + char* LUT_Version = (char*)Dev_Info.LUT_Version; + if( strcmp(LUT_Version, "M641") == 0 ){ + //6inch e-Paper HAT(800,600), 6inch HD e-Paper HAT(1448,1072), 6inch HD touch e-Paper HAT(1448,1072) + A2_Mode = 4; + Four_Byte_Align = true; + }else if( strcmp(LUT_Version, "M841_TFAB512") == 0 ){ + //Another firmware version for 6inch HD e-Paper HAT(1448,1072), 6inch HD touch e-Paper HAT(1448,1072) + A2_Mode = 6; + Four_Byte_Align = true; + }else if( strcmp(LUT_Version, "M841") == 0 ){ + //9.7inch e-Paper HAT(1200,825) + A2_Mode = 6; + }else if( strcmp(LUT_Version, "M841_TFA2812") == 0 ){ + //7.8inch e-Paper HAT(1872,1404) + A2_Mode = 6; + }else if( strcmp(LUT_Version, "M841_TFA5210") == 0 ){ + //10.3inch e-Paper HAT(1872,1404) + A2_Mode = 6; + }else{ + //default set to 6 as A2 Mode + A2_Mode = 6; + } + Debug("A2 Mode:%d\r\n", A2_Mode); + + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, INIT_Mode); + +#if(USE_Factory_Test) + if(epd_mode == 3) // Color Test + Color_Test(Dev_Info, Init_Target_Memory_Addr); + else // Normal Test + Factory_Test_Only(Dev_Info, Init_Target_Memory_Addr); +#endif + + +#if(USE_Normal_Demo) + //Show 16 grayscale + Display_ColorPalette_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + //Show some character and pattern + Display_CharacterPattern_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr, BitsPerPixel_4); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + //Show a bmp file + //1bp use A2 mode by default, before used it, refresh the screen with WHITE + Display_BMP_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr, BitsPerPixel_1); + Display_BMP_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr, BitsPerPixel_2); + Display_BMP_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr, BitsPerPixel_4); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + //Show A2 mode refresh effect + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + Dynamic_Refresh_Example(Dev_Info,Init_Target_Memory_Addr); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + //Show how to display a gif, not works well on 6inch e-Paper HAT, 9.7inch e-Paper HAT, others work well + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + Dynamic_GIF_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); + + //Show how to test frame rate, test it individually,which is related to refresh area size and refresh mode + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + Check_FrameRate_Example(800, 600, Init_Target_Memory_Addr, BitsPerPixel_1); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, A2_Mode); + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, GC16_Mode); +#endif + + +#if(USE_Touch_Panel) + //show a simple demo for hand-painted tablet, only support for <6inch HD touch e-Paper> at present + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, INIT_Mode); + TouchPanel_ePaper_Example(Panel_Width, Panel_Height, Init_Target_Memory_Addr); +#endif + + //We recommended refresh the panel to white color before storing in the warehouse. + EPD_IT8951_Clear_Refresh(Dev_Info, Init_Target_Memory_Addr, INIT_Mode); + + //EPD_IT8951_Standby(); + EPD_IT8951_Sleep(); + + //In case RPI is transmitting image in no hold mode, which requires at most 10s + DEV_Delay_ms(5000); + + DEV_Module_Exit(); + return 0; +} diff --git a/frameos/src/drivers/waveshare/types.nim b/frameos/src/drivers/waveshare/types.nim index 71d07809..67d871be 100644 --- a/frameos/src/drivers/waveshare/types.nim +++ b/frameos/src/drivers/waveshare/types.nim @@ -4,5 +4,6 @@ type ColorOption* = enum BlackWhiteYellow = "BlackWhiteYellow" BlackWhiteYellowRed = "BlackWhiteYellowRed" FourGray = "FourGray" + SixteenGray = "SixteenGray" SevenColor = "SevenColor" SpectraSixColor = "SpectraSixColor" diff --git a/frameos/src/drivers/waveshare/waveshare.nim b/frameos/src/drivers/waveshare/waveshare.nim index 94000ff3..c0b117d5 100644 --- a/frameos/src/drivers/waveshare/waveshare.nim +++ b/frameos/src/drivers/waveshare/waveshare.nim @@ -60,7 +60,7 @@ proc init*(frameOS: FrameOS): Driver = "stack": e.getStackTrace()}) proc notifyImageAvailable*(self: Driver) = - self.logger.log(%*{"event": "render:dither", "info": "Dithered image available"}) + self.logger.log(%*{"event": "render:dither", "info": "Dithered image available, starting render"}) proc renderBlack*(self: Driver, image: Image) = var gray = newSeq[float](image.width * image.height) @@ -97,6 +97,23 @@ proc renderFourGray*(self: Driver, image: Image) = blackImage[index div 4] = blackImage[index div 4] or ((bw and 0b11) shl (6 - (index mod 4) * 2)) waveshareDriver.renderImage(blackImage) +proc renderSixteenGray*(self: Driver, image: Image) = + var gray = newSeq[float](image.width * image.height) + image.toGrayscaleFloat(gray, 15) + gray.floydSteinberg(image.width, image.height) + setLastFloatImage(gray) + self.notifyImageAvailable() + + let rowWidth = ceil(image.width.float / 2).int + var blackImage = newSeq[uint8](rowWidth * image.height) + for y in 0..<image.height: + for x in 0..<image.width: + let inputIndex = y * image.width + x + let index = y * rowWidth * 2 + x + let bw: uint8 = gray[inputIndex].uint8 # 0, 1, 2 or 3 + blackImage[index div 2] = blackImage[index div 2] or ((bw and 0b1111) shl ((index mod 2) * (-4))) + waveshareDriver.renderImage(blackImage) + proc renderBlackWhiteRed*(self: Driver, image: Image, isRed = true) = let pixels = ditherPaletteIndexed(image, @[(0, 0, 0), (255, if isRed: 0 else: 255, 0), (255, 255, 255)]) let inputRowWidth = int(ceil(image.width.float / 4)) @@ -166,6 +183,8 @@ proc render*(self: Driver, image: Image) = self.renderSpectraSixColor(image) of ColorOption.FourGray: self.renderFourGray(image) + of ColorOption.SixteenGray: + self.renderSixteenGray(image) of ColorOption.BlackWhiteYellowRed: self.renderBlackWhiteYellowRed(image) @@ -199,6 +218,18 @@ proc toPng*(rotate: int = 0): string = outputImage.data[index].g = pixel outputImage.data[index].b = pixel outputImage.data[index].a = 255 + of ColorOption.SixteenGray: + let pixels = getLastFloatImage() + if pixels.len == 0: + raise newException(Exception, "No render yet") + for y in 0 ..< height: + for x in 0 ..< width: + let index = y * width + x + let pixel = (pixels[index] * 17).uint8 + outputImage.data[index].r = pixel + outputImage.data[index].g = pixel + outputImage.data[index].b = pixel + outputImage.data[index].a = 255 of ColorOption.BlackWhiteRed, ColorOption.BlackWhiteYellow: let pixels = getLastPixels() if pixels.len == 0: diff --git a/frontend/src/devices.ts b/frontend/src/devices.ts index 8bd9eb20..f0dc3bf8 100644 --- a/frontend/src/devices.ts +++ b/frontend/src/devices.ts @@ -90,6 +90,7 @@ export const devices: Option[] = [ { value: 'waveshare.EPD_7in5_HD', label: 'Waveshare 7.5" (HD) 880x528 Black/White' }, { value: 'waveshare.EPD_7in5b_HD', label: 'Waveshare 7.5" (B HD) 880x528 Black/White/Red' }, { value: 'waveshare.EPD_10in2b', label: 'Waveshare 10.2" (B) 960x640 Black/White/Red' }, + { value: 'waveshare.EPD_10in3', label: 'Waveshare 10.3" 1872x1404 16 Grayscale' }, { value: 'waveshare.EPD_12in48', label: 'Waveshare 12.48" 1304x984 Black/White' }, { value: 'waveshare.EPD_12in48b', label: 'Waveshare 12.48" (B) 1304x984 Black/White/Red' }, { value: 'waveshare.EPD_12in48b_V2', label: 'Waveshare 12.48" (B V2) 1304x984 Black/White/Red' },