From b75747fdef37d3eb06de4202eae7ad989ba48cd6 Mon Sep 17 00:00:00 2001 From: UT2UH Date: Tue, 3 Nov 2020 01:06:12 +0200 Subject: [PATCH] K210 initial support added --- Processors/TFT_eSPI_K210.cpp | 179 +++++++++++++++ Processors/TFT_eSPI_K210.h | 378 +++++++++++++++++++++++++++++++ TFT_eSPI.cpp | 104 ++++++++- User_Setup_Select.h | 2 + User_Setups/Setup210_Maixduino.h | 169 ++++++++++++++ library.json | 6 +- 6 files changed, 824 insertions(+), 14 deletions(-) create mode 100644 Processors/TFT_eSPI_K210.cpp create mode 100644 Processors/TFT_eSPI_K210.h create mode 100644 User_Setups/Setup210_Maixduino.h diff --git a/Processors/TFT_eSPI_K210.cpp b/Processors/TFT_eSPI_K210.cpp new file mode 100644 index 0000000..331be1d --- /dev/null +++ b/Processors/TFT_eSPI_K210.cpp @@ -0,0 +1,179 @@ + //////////////////////////////////////////////////// + // TFT_eSPI driver functions for K210 processor // + // based on https://github.com/fukuen/TFT_eSPI // + //////////////////////////////////////////////////// + +#include "TFT_eSPI_K210.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// Global variables +//////////////////////////////////////////////////////////////////////////////////////// + +// Select the SPI port to use +#if defined (ARDUINO_M5STICK_V) + SPIClass spi_(SPI0, TFT_SCLK, TFT_MISO, TFT_MOSI, -1, SPI_FREQUENCY); +#else + SPIClass spi_(SPI0); +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: tft_Read_8 +** Description: Bit bashed SPI to read bidirectional SDA line +***************************************************************************************/ +uint8_t TFT_eSPI::tft_Read_8(void) +{ + uint8_t ret = 0; + + for (uint8_t i = 0; i < 8; i++) { // read results + ret <<= 1; + SCLK_L; + if (digitalRead(TFT_MOSI)) ret |= 1; + SCLK_H; + } + + return ret; +} + +/*************************************************************************************** +** Function name: beginSDA +** Description: Detach SPI from pin to permit software SPI +***************************************************************************************/ +void TFT_eSPI::begin_SDA_Read(void) +{ + // Release configured SPI port for SDA read + spi_.end(); +} + +/*************************************************************************************** +** Function name: endSDA +** Description: Attach SPI pins after software SPI +***************************************************************************************/ +void TFT_eSPI::end_SDA_Read(void) +{ + // Configure SPI port ready for next TFT access + spi_.begin(); +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // #if defined (TFT_SDA_READ) +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined (RPI_WRITE_STROBE) && !defined (ILI9488_DRIVER) // SPI 16 bit colour TFT +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for K210 +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + uint32_t data = ((uint32_t)color << 16) | (uint32_t)color; + tft_fill_data(&data, len); +} + +/*************************************************************************************** +** Function name: pushPixels - for K210 +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + tft_write_byte((uint8_t*)data, len * 2); +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (RPI_WRITE_STROBE) // Code for RPi TFT with write strobe #### UNTESTED ##### +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for K210 RPi TFT +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ + + if(len) { tft_Write_16(color); len--; } + while(len--) {WR_L; WR_H;} +} + +/*************************************************************************************** +** Function name: pushPixels - for K210 RPi TFT +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) +{ + uint16_t *data = (uint16_t*)data_in; + + if (_swapBytes) while ( len-- ) {tft_Write_16S(*data); data++;} + else while ( len-- ) {tft_Write_16(*data); data++;} +} + +//////////////////////////////////////////////////////////////////////////////////////// +#elif defined (ILI9488_DRIVER) // Now code for ILI9488 24 bit SPI colour TFT +//////////////////////////////////////////////////////////////////////////////////////// + +/*************************************************************************************** +** Function name: pushBlock - for K210 and 3 byte RGB display +** Description: Write a block of pixels of the same colour +***************************************************************************************/ +void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) +{ + // Split out the colours + uint8_t r = (color & 0xF800)>>8; + uint8_t g = (color & 0x07E0)>>3; + uint8_t b = (color & 0x001F)<<3; + + while ( len-- ) {tft_Write_8(r); tft_Write_8(g); tft_Write_8(b);} +} + +/*************************************************************************************** +** Function name: pushPixels - for K210 and 3 byte RGB display +** Description: Write a sequence of pixels +***************************************************************************************/ +void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + if (_swapBytes) { + while ( len-- ) { + uint16_t color = *data >> 8 | *data << 8; + tft_Write_8((color & 0xF800)>>8); + tft_Write_8((color & 0x07E0)>>3); + tft_Write_8((color & 0x001F)<<3); + data++; + } + } + else { + while ( len-- ) { + tft_Write_8((*data & 0xF800)>>8); + tft_Write_8((*data & 0x07E0)>>3); + tft_Write_8((*data & 0x001F)<<3); + data++; + } + } +} + +/*************************************************************************************** +** Function name: pushSwapBytePixels - for K210 and 3 byte RGB display +** Description: Write a sequence of pixels with swapped bytes +***************************************************************************************/ +void TFT_eSPI::pushSwapBytePixels(const void* data_in, uint32_t len){ + + uint16_t *data = (uint16_t*)data_in; + // ILI9488 write macro is not endianess dependant, so swap byte macro not used here + while ( len-- ) { + uint16_t color = *data >> 8 | *data << 8; + tft_Write_8((color & 0xF800)>>8); + tft_Write_8((color & 0x07E0)>>3); + tft_Write_8((color & 0x001F)<<3); + data++; + } +} + +//////////////////////////////////////////////////////////////////////////////////////// +#endif // End of display interface specific functions +//////////////////////////////////////////////////////////////////////////////////////// diff --git a/Processors/TFT_eSPI_K210.h b/Processors/TFT_eSPI_K210.h new file mode 100644 index 0000000..7872140 --- /dev/null +++ b/Processors/TFT_eSPI_K210.h @@ -0,0 +1,378 @@ + //////////////////////////////////////////////////// + // TFT_eSPI driver functions for K210 processor // + // based on https://github.com/fukuen/TFT_eSPI // + //////////////////////////////////////////////////// + +#ifndef _TFT_eSPI_K210H_ +#define _TFT_eSPI_K210H_ + +// Processor ID reported by getSetup() +#define PROCESSOR_ID 0x0210 + +// Include processor specific header +#include +#include "gpio.h" +#include "fpioa.h" +#include "kendryte-standalone-sdk/lib/drivers/include/spi.h" +#include "kendryte-standalone-sdk/lib/drivers/include/sysctl.h" +#include "dmac.h" +#include "sleep.h" +#include + +#if defined(ARDUINO_MAIX_AMIGO) || defined(ARDUINO_MAIX_CUBE) + #include + #include +#elif defined(ARDUINO_M5STICK_V) + #include + #include +#endif + +#define RST_PIN 6 +#define DCX_PIN 7 +#define SPI_NUM SPI_DEVICE_0 +#define SS_PIN SPI_CHIP_SELECT_3 +#define DMA_CH DMAC_CHANNEL3 + +static int8_t g_gpio_rst; +static uint8_t g_gpio_dcx; +static spi_chip_select_t g_ss; +static dmac_channel_number_t g_dma_ch; +static spi_device_num_t g_spi_num; + +void tft_io_init(void) +{ +#if defined(ARDUINO_MAIX_AMIGO) || defined(ARDUINO_MAIX_CUBE) + AXP173 Axp = AXP173(); + Wire.begin((uint8_t) SDA, (uint8_t) SCL, 400000); + Axp.begin(true); //Wire is already enabled +#elif defined(ARDUINO_M5STICK_V) + sysctl_set_power_mode(SYSCTL_POWER_BANK3,SYSCTL_POWER_V33); + AXP192 Axp = AXP192(); + Wire.begin((uint8_t) SDA, (uint8_t) SCL, 400000); + Axp.begin(true); //Wire is already enabled +#endif + g_spi_num = SPI_NUM; + g_dma_ch = DMA_CH; + g_ss = SS_PIN; + /* Init SPI IO map and function settings */ + fpioa_set_function(TFT_CS, (fpioa_function_t)(FUNC_SPI0_SS0 + SS_PIN)); +#if defined (ARDUINO_M5STICK_V) + fpioa_set_function(TFT_SCLK, FUNC_SPI0_SCLK); +#else + fpioa_set_function(TFT_WR, FUNC_SPI0_SCLK); +#endif + sysctl_set_spi0_dvp_data(1); + + //tft_hard_init(uint8_t spi, uint8_t ss, uint8_t rst, uint8_t dcx, uint32_t freq, int8_t rst_pin, int8_t dcx_pin, uint8_t dma_ch){ + fpioa_set_function(TFT_DC, (fpioa_function_t)(FUNC_GPIO0 + DCX_PIN)); + g_gpio_dcx = DCX_PIN; + gpio_set_drive_mode(g_gpio_dcx, GPIO_DM_OUTPUT); + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH); + + fpioa_set_function(TFT_RST, (fpioa_function_t)(FUNC_GPIO0 + RST_PIN)); + g_gpio_rst = RST_PIN; + gpio_set_drive_mode(g_gpio_rst, GPIO_DM_OUTPUT); + gpio_set_pin(g_gpio_rst, GPIO_PV_HIGH); + + gpio_set_pin(g_gpio_rst, GPIO_PV_LOW); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); +#endif + spi_set_clk_rate(g_spi_num, SPI_FREQUENCY); + gpio_set_pin(g_gpio_rst, GPIO_PV_HIGH); +} + +void tft_write_command(uint8_t cmd) +{ + gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); + spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, (uint8_t *)(&cmd), 1, SPI_TRANS_CHAR); +} + +void tft_write_byte(uint8_t *data_buf, uint32_t length) +{ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); + spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length, SPI_TRANS_CHAR); +} + +void tft_write_half(uint16_t *data_buf, uint32_t length) +{ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 16, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0); + spi_init_non_standard(g_spi_num, 16, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length, SPI_TRANS_SHORT); +} + +void tft_write_word(uint32_t *data_buf, uint32_t length) +{ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 32, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0); + spi_init_non_standard(g_spi_num, 0, 32, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length, SPI_TRANS_INT); +} + +void tft_fill_data(uint32_t *data_buf, uint32_t length) +{ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 32, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0); + spi_init_non_standard(g_spi_num, 0, 32, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_fill_data_dma(g_dma_ch, g_spi_num, g_ss, data_buf, length); +} + +void tft_write_cs() +{ +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); + spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif +} + +void tft_write_a_byte(uint8_t data) +{ +// dmac_wait_done(g_dma_ch); +// spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); +// spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, (uint8_t *)(&data), 1, SPI_TRANS_CHAR); +} + +void tft_write_a_half(uint16_t data) +{ +// dmac_wait_done(g_dma_ch); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 16, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0); + spi_init_non_standard(g_spi_num, 16, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, (uint16_t *)(&data), 1, SPI_TRANS_SHORT); +} + +void tft_write_a_word(uint32_t data) +{ + uint8_t tmp[4] = { static_cast((data >> 24) & 0xff), static_cast((data >> 16) & 0xff), static_cast((data >> 8) & 0xff), static_cast(data & 0xff) }; + dmac_wait_done(g_dma_ch); +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); + spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_send_data_normal_dma(g_dma_ch, g_spi_num, g_ss, (uint8_t *)tmp, 4, SPI_TRANS_CHAR); +} + +uint8_t tft_read_a_byte(void) +{ + uint8_t tmp; +#if defined (ARDUINO_M5STICK_V) + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0); +#else + spi_init(g_spi_num, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0); + spi_init_non_standard(g_spi_num, 8, 0, 0, SPI_AITM_AS_FRAME_FORMAT); +#endif + spi_receive_data_standard_dma(g_dma_ch, g_dma_ch, g_spi_num, g_ss, NULL, 0, (uint8_t *)(&tmp), 1); + return tmp; +} + + +// Processor specific code used by SPI bus transaction startWrite and endWrite functions +#define SET_BUS_WRITE_MODE // Not used +#define SET_BUS_READ_MODE // Not used + +// Code to check if DMA is busy, used by SPI bus transaction startWrite and endWrite functions +#define DMA_BUSY_CHECK // Not used so leave blank + +// SUPPORT_TRANSACTIONS is mandatory for K210 +#if !defined (SUPPORT_TRANSACTIONS) + #define SUPPORT_TRANSACTIONS +#endif + +// Initialise processor specific SPI functions, used by init() +#define INIT_TFT_DATA_BUS // Not used + +// If smooth font is used then it is likely SPIFFS will be needed +#ifdef SMOOTH_FONT + // Call up the SPIFFS (SPI FLASH Filing System) for the anti-aliased fonts + // #define FS_NO_GLOBALS + // #include + // #include "Maixduino_SPIFFS.h" + // #define FONT_FS_AVAILABLE +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the DC (TFT Data/Command or Register Select (RS))pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if (TFT_DC >= 0) + #if defined (RPI_DISPLAY_TYPE) + #if defined (ILI9486_DRIVER) + // RPi ILI9486 display needs a slower DC change + #define DC_C gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW); \ + gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW) + #define DC_D gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW); \ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH) + #else + // Other RPi displays need a slower C->D change + #define DC_C gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW) + #define DC_D gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW); \ + gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH) + #endif + #else + #define DC_C gpio_set_pin(g_gpio_dcx, GPIO_PV_LOW) + #define DC_D gpio_set_pin(g_gpio_dcx, GPIO_PV_HIGH) + #endif +#else + #define DC_C // No macro allocated so it generates no code + #define DC_D // No macro allocated so it generates no code +#endif + + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the CS (TFT chip select) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if (TFT_CS >= 0) + #ifdef RPI_DISPLAY_TYPE // RPi display needs a slower CS change + #define CS_L digitalWrite(TFT_CS, HIGH); tft_write_cs() + #define CS_H tft_write_cs(); digitalWrite(TFT_CS, HIGH) + #else + #define CS_L tft_write_cs() + #define CS_H digitalWrite(TFT_CS, HIGH) + #endif +#else + #define CS_L // No macro allocated so it generates no code + #define CS_H // No macro allocated so it generates no code +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the WR (TFT Write) pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined TFT_WR || (TFT_WR < 0) + #define WR_L // No macro allocated so it generates no code + #define WR_H // No macro allocated so it generates no code +#else + #define WR_L digitalWrite(TFT_WR, LOW) + #define WR_H digitalWrite(TFT_WR, HIGH) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Define the touch screen chip select pin drive code +//////////////////////////////////////////////////////////////////////////////////////// +#if !defined TOUCH_CS || (TOUCH_CS < 0) + #define T_CS_L // No macro allocated so it generates no code + #define T_CS_H // No macro allocated so it generates no code +#else + #define T_CS_L digitalWrite(TOUCH_CS, LOW) + #define T_CS_H digitalWrite(TOUCH_CS, HIGH) +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Make sure SPI default pins are assigned if not specified by user or set to -1 +//////////////////////////////////////////////////////////////////////////////////////// +#ifndef TFT_MISO + #define TFT_MISO -1 +#endif +#ifndef TFT_MOSI + #define TFT_MOSI -1 +#endif +#ifndef TFT_SCLK + #define TFT_SCLK -1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to an ILI9488 TFT +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB + + // Write 8 bits to TFT + #define tft_Write_8(C) spi_.transfer(C) + + // Convert 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16(C) spi_.transfer(((C) & 0xF800)>>8); \ + spi_.transfer(((C) & 0x07E0)>>3); \ + spi_.transfer(((C) & 0x001F)<<3) + + // Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes + #define tft_Write_16S(C) spi_.transfer((C) & 0xF8); \ + spi_.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \ + spi_.transfer(((C) & 0x1F00)>>5) + // Write 32 bits to TFT + #define tft_Write_32(C) spi_.transfer16((C)>>16); spi_.transfer16((uint16_t)(C)) + + // Write two address coordinates + #define tft_Write_32C(C,D) spi_.transfer16(C); spi_.transfer16(D) + + // Write same value twice + #define tft_Write_32D(C) spi_.transfer16(C); spi_.transfer16(C) + +#else +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to write commands/pixel colour data to an Raspberry Pi TFT +//////////////////////////////////////////////////////////////////////////////////////// + #if defined (RPI_DISPLAY_TYPE) + // RPi TFT type always needs 16 bit transfers + #define tft_Write_8(C) spi_.transfer(0); spi_.transfer(C) + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros for all other SPI displays +//////////////////////////////////////////////////////////////////////////////////////// + #else + // K210 low level SPI writes for 8, 16 and 32 bit values + // Write 8 bits + #define tft_Write_8(C) tft_write_a_byte(C) + + // Write 16 bits with corrected endianess for 16 bit colours + #define tft_Write_16(C) tft_write_a_half(C) + + // Write 16 bits + #define tft_Write_16S(C) tft_write_a_half(((C)>>8 & 0xFF) | ((C)<<8)) + + // Write 32 bits + #define tft_Write_32(C) tft_write_a_word(C) + + // Write two address coordinates + #define tft_Write_32C(C,D) tft_write_a_word((C)<<16 | (D)) + + // Write same value twice + #define tft_Write_32D(C) tft_write_a_word((C)<<16 | (C)) + #endif +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// Macros to read from display using SPI or software SPI +//////////////////////////////////////////////////////////////////////////////////////// +#if defined (TFT_SDA_READ) + // Macros to support a bit banged function call for K210 and bi-directional SDA pin + #define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(); + #define SCLK_L digitalWrite(TFT_SCLK, LOW) + #define SCLK_H digitalWrite(TFT_SCLK, LOW) +#else + // Use a SPI read transfer + #define tft_Read_8() tft_read_a_byte() +#endif + +#endif // Header end diff --git a/TFT_eSPI.cpp b/TFT_eSPI.cpp index b992f28..dbb4f23 100644 --- a/TFT_eSPI.cpp +++ b/TFT_eSPI.cpp @@ -20,6 +20,8 @@ #include "Processors/TFT_eSPI_ESP32.c" #elif defined (ESP8266) #include "Processors/TFT_eSPI_ESP8266.c" +#elif defined (K210) + #include "Processors/TFT_eSPI_K210.cpp" #elif defined (STM32) // (_VARIANT_ARDUINO_STM32_) stm32_def.h #include "Processors/TFT_eSPI_STM32.c" #else @@ -98,7 +100,11 @@ inline void TFT_eSPI::begin_tft_read(void){ } #else #if !defined(TFT_PARALLEL_8_BIT) - spi.setFrequency(SPI_READ_FREQUENCY); + #if defined(K210) + spi_.setFrequency(SPI_READ_FREQUENCY); + #else + spi.setFrequency(SPI_READ_FREQUENCY); + #endif #endif CS_L; #endif @@ -318,7 +324,11 @@ inline void TFT_eSPI::end_tft_read(void){ } #else #if !defined(TFT_PARALLEL_8_BIT) - spi.setFrequency(SPI_FREQUENCY); + #if defined (K210) + spi_.setFrequency(SPI_FREQUENCY); + #else + spi.setFrequency(SPI_FREQUENCY); + #endif #endif if(!inTransaction) {CS_H;} #endif @@ -522,7 +532,15 @@ void TFT_eSPI::init(uint8_t tc) spi.pins(6, 7, 8, 0); #endif - spi.begin(); // This will set HMISO to input + #if defined (K210) + #if defined(TFT_PARALLEL_8_BIT) + spi_.begin(); // This will set HMISO to input + #else + spi_.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, -1); //M5StickV + #endif + #else + spi.begin(); // This will set HMISO to input + #endif #else #if !defined(TFT_PARALLEL_8_BIT) @@ -562,6 +580,12 @@ void TFT_eSPI::init(uint8_t tc) } // end of: if just _booted // Toggle RST low to reset + begin_tft_write(); + +#if defined (K210) + tft_io_init(); +#endif + #ifdef TFT_RST if (TFT_RST >= 0) { digitalWrite(TFT_RST, HIGH); @@ -645,6 +669,7 @@ void TFT_eSPI::init(uint8_t tc) #if defined (TFT_BL) && defined (TFT_BACKLIGHT_ON) pinMode(TFT_BL, OUTPUT); digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); +//TODO K210 #else #if defined (TFT_BL) && defined (M5STACK) // Turn on the back-light LED @@ -1036,6 +1061,9 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da // Set masked pins D0- D7 to input busDir(dir_mask, INPUT); + // Total pixel count + uint32_t len = w * h; + #if defined (ILI9341_DRIVER) | defined (ILI9488_DRIVER) // Read 3 bytes // Dummy read to throw away don't care value readByte(); @@ -1140,15 +1168,15 @@ void TFT_eSPI::readRect(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t *da #else - // The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse - // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left - uint8_t r = (tft_Read_8()&0x7E)<<1; - uint8_t g = (tft_Read_8()&0x7E)<<1; - uint8_t b = (tft_Read_8()&0x7E)<<1; - color = color565(r, g, b); + // The 6 colour bits are in MS 6 bits of each byte but we do not include the extra clock pulse + // so we use a trick and mask the middle 6 bits of the byte, then only shift 1 place left + uint8_t r = (tft_Read_8()&0x7E)<<1; + uint8_t g = (tft_Read_8()&0x7E)<<1; + uint8_t b = (tft_Read_8()&0x7E)<<1; + color = color565(r, g, b); #endif - // Swapped colour byte order for compatibility with pushRect() + // Swapped colour byte order for compatibility with pushRect() *line++ = color << 8 | color >> 8; } data += w; @@ -2705,6 +2733,19 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 uint8_t mask = 0x1; begin_tft_write(); +#ifdef K210 + for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); + column[5] = 0; + + for (int8_t j = 0; j < 8; j++) { + for (int8_t k = 0; k < 5; k++ ) { + if (column[k] & mask) {drawPixel(xd + k, yd + j, color);} + else {drawPixel(xd + k, yd + j, bg);} + } + mask <<= 1; + drawPixel(xd + 5, yd + j, bg); + } +#else setWindow(xd, yd, xd+5, yd+8); for (int8_t i = 0; i < 5; i++ ) column[i] = pgm_read_byte(font + (c * 5) + i); @@ -2718,6 +2759,7 @@ void TFT_eSPI::drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32 mask <<= 1; tft_Write_16(bg); } +#endif end_tft_write(); } @@ -3777,6 +3819,25 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) begin_tft_write(); +#ifdef K210 + setWindow(xd, yd, xd + width - 1, yd + height - 1); + + uint8_t mask; + for (int32_t i = 0; i < height; i++) { + pX = width; + for (int32_t k = 0; k < w; k++) { + line = pgm_read_byte((uint8_t *) (flash_address + w * i + k) ); + mask = 0x80; + while (mask && pX) { + if (line & mask) {drawPixel(xd + k, yd + i, textcolor);} + else {drawPixel(xd + k, yd + i, textbgcolor);} + pX--; + mask = mask >> 1; + } + } + if (pX) {drawPixel(xd + width, yd + i, textbgcolor);} + } +#else setWindow(xd, yd, xd + width - 1, yd + height - 1); uint8_t mask; @@ -3794,6 +3855,7 @@ int16_t TFT_eSPI::drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font) } if (pX) {tft_Write_16(textbgcolor);} } +#endif end_tft_write(); } @@ -4232,7 +4294,11 @@ int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY) { isDigits = true; // Eliminate jiggle in monospaced fonts char str[12]; +#ifdef K210 + __utoa(long_num, str, 10); +#else ltoa(long_num, str, 10); +#endif return drawString(str, poX, poY, textfont); } @@ -4240,7 +4306,11 @@ int16_t TFT_eSPI::drawNumber(long long_num, int32_t poX, int32_t poY, uint8_t fo { isDigits = true; // Eliminate jiggle in monospaced fonts char str[12]; +#ifdef K210 + __utoa(long_num, str, 10); +#else ltoa(long_num, str, 10); +#endif return drawString(str, poX, poY, font); } @@ -4289,7 +4359,11 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t uint32_t temp = (uint32_t)floatNumber; // Put integer part into array +#ifdef K210 + __utoa(temp, str + ptr, 10); +#else ltoa(temp, str + ptr, 10); +#endif // Find out where the null is to get the digit count loaded while ((uint8_t)str[ptr] != 0) ptr++; // Move the pointer along @@ -4309,7 +4383,11 @@ int16_t TFT_eSPI::drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t i++; floatNumber *= 10; // for the next decimal temp = floatNumber; // get the decimal +#ifdef K210 + __utoa(temp, str + ptr, 10); +#else ltoa(temp, str + ptr, 10); +#endif ptr++; digits++; // Increment pointer and digits count floatNumber -= temp; // Remove that digit } @@ -4394,7 +4472,11 @@ void TFT_eSPI::setTextFont(uint8_t f) #if !defined (TFT_PARALLEL_8_BIT) SPIClass& TFT_eSPI::getSPIinstance(void) { - return spi; + #if defined (K210) + return spi_; + #else + return spi; + #endif } #endif diff --git a/User_Setup_Select.h b/User_Setup_Select.h index ec0268e..f199233 100644 --- a/User_Setup_Select.h +++ b/User_Setup_Select.h @@ -76,6 +76,8 @@ //#include // Setup file for ESP8266 and ST7789 135 x 240 TFT +//#include // Setup file for all K210 with 1- or 8-wire SPI TFT + //#include diff --git a/User_Setups/Setup210_Maixduino.h b/User_Setups/Setup210_Maixduino.h new file mode 100644 index 0000000..7d92d22 --- /dev/null +++ b/User_Setups/Setup210_Maixduino.h @@ -0,0 +1,169 @@ +//Use Maixduino Core and https://github.com/sipeed/Maixduino/pull/99 +// or https://github.com/UT2UH/Maixduino with missing boards added +//Define your board here as compile-time variable ARDUINO_{build.board} does not work (for me only?) +#define ARDUINO_MAIX_AMIGO +//#define ARDUINO_MAIX_GO +//#define ARDUINO_M5STICK_V + +#if defined (ARDUINO_MAIX_AMIGO) + // ILI9486 320 x 480 display in 8-bit parallel mode + #define ILI9486_DRIVER // Configure all registers + #define TFT_WIDTH 320 + #define TFT_HEIGHT 480 + + #define TFT_CS 36 // Chip select control pin + #define TFT_RST 37 // Reset pin + #define TFT_DC 38 // Data Command control pin + #define TFT_WR 39 // Write strobe control pin + #define TFT_LED -1 // Define as not used + + #define TOUCH_W 320 + #define TOUCH_H 280 + #define CST_DEVICE_ADDR 0x38 + #define CST_INT 33 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_MAIX_CUBE) + // ST7789 240 x 240 1.3" IPS display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 240 + + #define TFT_MISO 26 + #define TFT_MOSI 28 + #define TFT_SCLK 27 + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED 17 + #define HAS_BACKLIGHT + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_MAIX_GO) + // ST7789 240 x 320 display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 + +// If colours are inverted (white shows as black) then uncomment one of the next +// 2 lines try both options, one of the options should correct the inversion. + // #define TFT_INVERSION_ON + #define TFT_INVERSION_OFF + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED -1 + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined(ARDUINO_MAIX_DUINO) + // ST7789 240 x 320 display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 + #define TFT_INVERSION_OFF + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED 17 + #define HAS_BACKLIGHT + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_DOCK_M1) || defined (ARDUINO_DOCK_M1W) + // ST7789 240 x 320 display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 + #define TFT_INVERSION_OFF + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED -1 + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_MAIX_BIT) || defined (ARDUINO_MAIX_BIT_MIC) + // ST7789 240 x 320 display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 + #define TFT_INVERSION_OFF + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED -1 + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_AIOT_DAAN) + // ST7789 240 x 320 display in 8-bit parallel mode + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 240 + #define TFT_HEIGHT 320 + + #define TFT_CS 36 + #define TFT_RST 37 + #define TFT_DC 38 + #define TFT_WR 39 + #define TFT_LED -1 + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 20000000 + +#elif defined (ARDUINO_M5STICK_V) +// ST7789 240 x 280 display + #define ST7789_2_DRIVER // Configure all registers + #define TFT_WIDTH 135 + #define TFT_HEIGHT 240 + #define CGRAM_OFFSET // Library will add offsets required + + #define TFT_MISO -1 + #define TFT_MOSI 18 + #define TFT_SCLK 19 + + #define TFT_DC 20 + #define TFT_RST 21 + #define TFT_CS 22 + #define TFT_LED -1 + + #define TOUCH_INT -1 + + #define SPI_FREQUENCY 40000000 + #define SPI_READ_FREQUENCY 20000000 + +#endif + +#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH +#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters +#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters +#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm +#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:. +#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-. +//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT +#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts + +#define SMOOTH_FONT diff --git a/library.json b/library.json index a353b11..3ddd7c2 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "name": "TFT_eSPI", "version": "2.3.4", - "keywords": "Arduino, tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", - "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32", + "keywords": "Arduino, tft, ePaper, display, STM32, K210, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140", + "description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32, K210 and STM32", "repository": { "type": "git", @@ -17,5 +17,5 @@ } ], "frameworks": "arduino", - "platforms": "espressif8266, espressif32, ststm32" + "platforms": "espressif8266, espressif32, ststm32, k210" }