Files
CDashDisplay/lib/Arduino_GFX/src/Arduino_DataBus.h
T
esilva f9d0bfa4d9 First commit
I shall move all this to another branch -> master_vendored or something
2025-03-12 21:42:39 +00:00

308 lines
13 KiB
C++

/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#ifndef _ARDUINO_DATABUS_H_
#define _ARDUINO_DATABUS_H_
#include <Arduino.h>
#include "YCbCr2RGB.h"
#define GFX_SKIP_OUTPUT_BEGIN -2
#define GFX_NOT_DEFINED -1
#define GFX_STR_HELPER(x) #x
#define GFX_STR(x) GFX_STR_HELPER(x)
#if defined(__AVR__)
#define LITTLE_FOOT_PRINT // reduce program size for limited flash MCU
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint8_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_ARCH_AIRMCU)
#define LITTLE_FOOT_PRINT // reduce program size for limited flash MCU
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_ARCH_NRF52840)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint16_t ARDUINOGFX_PORT_t;
#elif defined(TARGET_RP2040) || defined(PICO_RP2350)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ESP32)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ESP8266)
#define ESP8266SAFEBATCHBITSIZE (2048 * 8 * 9)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_ARCH_STM32)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(__arm__)
#if defined(ARDUINO_ARCH_SAMD)
// Adafruit M0, M4
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(CONFIG_ARCH_CHIP_CXD56XX) // Sony Spresense
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint8_t ARDUINOGFX_PORT_t;
#elif defined(RTL8722DM)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(CORE_TEENSY)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
// PJRC Teensy 4.x
typedef uint32_t ARDUINOGFX_PORT_t;
#else
// PJRC Teensy 3.x
typedef uint8_t ARDUINOGFX_PORT_t;
#endif
#else
// Arduino Due?
// USE_FAST_PINIO not available here (yet)...Due has a totally different
// GPIO register set and will require some changes elsewhere (e.g. in
// constructors especially).
#endif
#else // !ARM
// Unknow architecture, USE_FAST_PINIO is not available here (yet)
// but don't worry about it too much...the digitalWrite() implementation
// on these platforms is reasonably efficient and already RAM-resident,
// only gotcha then is no parallel connection support for now.
#endif // !ARM
#ifdef USE_FAST_PINIO
typedef volatile ARDUINOGFX_PORT_t *PORTreg_t;
#endif
#if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM)
#define SPI_DEFAULT_FREQ 16000000
// Teensy 3.0, 3.1/3.2, 3.5, 3.6
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define SPI_DEFAULT_FREQ 40000000
// Teensy 4.x
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(__AVR__) || defined(TEENSYDUINO)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ARDUINO_ARCH_NRF52840)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ESP8266) || defined(ESP32)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(RTL8722DM)
#define SPI_DEFAULT_FREQ 20000000
#elif defined(RASPI)
#define SPI_DEFAULT_FREQ 80000000
#elif defined(ARDUINO_ARCH_STM32F1)
#define SPI_DEFAULT_FREQ 36000000
#elif defined(ARDUINO_BLACKPILL_F411CE)
#define SPI_DEFAULT_FREQ 50000000
#elif defined(F_CPU)
#define SPI_DEFAULT_FREQ (F_CPU / 4)
#else
#define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency
#endif
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#define ATTR_UNUSED __attribute__((unused))
#define MSB_16(val) (((val) & 0xFF00) >> 8) | (((val) & 0xFF) << 8)
#define MSB_16_SET(var, val) \
{ \
(var) = MSB_16(val); \
}
#define MSB_32_SET(var, val) \
{ \
uint8_t *v = (uint8_t *)&(val); \
(var) = v[3] | (v[2] << 8) | (v[1] << 16) | (v[0] << 24); \
}
#define MSB_32_16_16_SET(var, v1, v2) \
{ \
(var) = (((uint32_t)v2 & 0xff00) << 8) | (((uint32_t)v2 & 0xff) << 24) | ((v1 & 0xff00) >> 8) | ((v1 & 0xff) << 8); \
}
#define MSB_32_8_ARRAY_SET(var, a) \
{ \
(var) = ((uint32_t)a[0] << 8 | a[1] | a[2] << 24 | a[3] << 16); \
}
#if !defined(LITTLE_FOOT_PRINT)
#define GFX_INLINE __attribute__((always_inline)) inline
#else
#define GFX_INLINE inline
#endif // !defined(LITTLE_FOOT_PRINT)
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#if (!defined(ESP_ARDUINO_VERSION_MAJOR)) || (ESP_ARDUINO_VERSION_MAJOR < 3)
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_pm.h>
#include <esp_private/gdma.h>
#include <hal/dma_types.h>
#include <hal/lcd_hal.h>
#include <soc/dport_reg.h>
#include <soc/gpio_sig_map.h>
#include <soc/lcd_cam_reg.h>
#include <soc/lcd_cam_struct.h>
typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t;
typedef struct lcd_panel_io_i80_t lcd_panel_io_i80_t;
typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t;
struct esp_lcd_i80_bus_t
{
int bus_id; // Bus ID, index from 0
portMUX_TYPE spinlock; // spinlock used to protect i80 bus members(hal, device_list, cur_trans)
lcd_hal_context_t hal; // Hal object
size_t bus_width; // Number of data lines
intr_handle_t intr; // LCD peripheral interrupt handle
esp_pm_lock_handle_t pm_lock; // Power management lock
size_t num_dma_nodes; // Number of DMA descriptors
uint8_t *format_buffer; // The driver allocates an internal buffer for DMA to do data format transformer
size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source
gdma_channel_handle_t dma_chan; // DMA channel handle
size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM
size_t sram_trans_align; // DMA transfer alignment for data allocated from SRAM
lcd_i80_trans_descriptor_t *cur_trans; // Current transaction
lcd_panel_io_i80_t *cur_device; // Current working device
LIST_HEAD(i80_device_list, lcd_panel_io_i80_t)
device_list; // Head of i80 device list
struct
{
unsigned int exclusive : 1; // Indicate whether the I80 bus is owned by one device (whose CS GPIO is not assigned) exclusively
} flags;
dma_descriptor_t dma_nodes[]; // DMA descriptor pool, the descriptors are shared by all i80 devices
};
struct lcd_i80_trans_descriptor_t
{
lcd_panel_io_i80_t *i80_device; // i80 device issuing this transaction
int cmd_value; // Command value
uint32_t cmd_cycles; // Command cycles
const void *data; // Data buffer
uint32_t data_length; // Data buffer size
void *user_ctx; // private data used by trans_done_cb
esp_lcd_panel_io_color_trans_done_cb_t trans_done_cb; // transaction done callback
};
struct lcd_panel_io_i80_t
{
esp_lcd_panel_io_t base; // Base class of generic lcd panel io
esp_lcd_i80_bus_t *bus; // Which bus the device is attached to
int cs_gpio_num; // GPIO used for CS line
unsigned int pclk_hz; // PCLK clock frequency
size_t clock_prescale; // Prescaler coefficient, determined by user's configured PCLK frequency
QueueHandle_t trans_queue; // Transaction queue, transactions in this queue are pending for scheduler to dispatch
QueueHandle_t done_queue; // Transaction done queue, transactions in this queue are finished but not recycled by the caller
size_t queue_size; // Size of transaction queue
size_t num_trans_inflight; // Number of transactions that are undergoing (the descriptor not recycled yet)
int lcd_cmd_bits; // Bit width of LCD command
int lcd_param_bits; // Bit width of LCD parameter
void *user_ctx; // private data used when transfer color data
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // color data trans done callback
LIST_ENTRY(lcd_panel_io_i80_t)
device_list_entry; // Entry of i80 device list
struct
{
unsigned int dc_idle_level : 1; // Level of DC line in IDLE phase
unsigned int dc_cmd_level : 1; // Level of DC line in CMD phase
unsigned int dc_dummy_level : 1; // Level of DC line in DUMMY phase
unsigned int dc_data_level : 1; // Level of DC line in DATA phase
} dc_levels;
struct
{
unsigned int cs_active_high : 1; // Whether the CS line is active on high level
unsigned int reverse_color_bits : 1; // Reverse the data bits, D[N:0] -> D[0:N]
unsigned int swap_color_bytes : 1; // Swap adjacent two data bytes before sending out
unsigned int pclk_active_neg : 1; // The display will write data lines when there's a falling edge on WR line
unsigned int pclk_idle_low : 1; // The WR line keeps at low level in IDLE phase
} flags;
lcd_i80_trans_descriptor_t trans_pool[]; // Transaction pool
};
#endif // #if (!defined(ESP_ARDUINO_VERSION_MAJOR)) || (ESP_ARDUINO_VERSION_MAJOR < 3)
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
typedef enum
{
BEGIN_WRITE,
WRITE_COMMAND_8,
WRITE_COMMAND_16,
WRITE_COMMAND_BYTES,
WRITE_DATA_8,
WRITE_DATA_16,
WRITE_BYTES,
WRITE_C8_D8,
WRITE_C8_D16,
WRITE_C8_BYTES,
WRITE_C16_D16,
END_WRITE,
DELAY,
} spi_operation_type_t;
union
{
uint16_t value;
struct
{
uint8_t lsb;
uint8_t msb;
};
} _data16;
class Arduino_DataBus
{
public:
Arduino_DataBus();
void unused() { UNUSED(_data16); } // avoid compiler warning
virtual bool begin(int32_t speed = SPI_DEFAULT_FREQ, int8_t dataMode = GFX_NOT_DEFINED) = 0;
virtual void beginWrite() = 0;
virtual void endWrite() = 0;
virtual void writeCommand(uint8_t c) = 0;
virtual void writeCommand16(uint16_t c) = 0;
virtual void writeCommandBytes(uint8_t *data, uint32_t len) = 0;
virtual void write(uint8_t) = 0;
virtual void write16(uint16_t) = 0;
virtual void writeC8D8(uint8_t c, uint8_t d);
virtual void writeC16D16(uint16_t c, uint16_t d);
virtual void writeC8D16(uint8_t c, uint16_t d);
virtual void writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2);
virtual void writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2);
virtual void writeRepeat(uint16_t p, uint32_t len) = 0;
virtual void writeBytes(uint8_t *data, uint32_t len) = 0;
virtual void writePixels(uint16_t *data, uint32_t len) = 0;
void sendCommand(uint8_t c);
void sendCommand16(uint16_t c);
void sendData(uint8_t d);
void sendData16(uint16_t d);
#if !defined(LITTLE_FOOT_PRINT)
virtual void write16bitBeRGBBitmapR1(uint16_t *bitmap, int16_t w, int16_t h);
virtual void batchOperation(const uint8_t *operations, size_t len);
virtual void writePattern(uint8_t *data, uint8_t len, uint32_t repeat);
virtual void writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len);
virtual void writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len);
virtual void writeYCbCrPixels(uint8_t *yData, uint8_t *cbData, uint8_t *crData, uint16_t w, uint16_t h);
#else
void batchOperation(const uint8_t *operations, size_t len);
#endif // !defined(LITTLE_FOOT_PRINT)
protected:
int32_t _speed;
int8_t _dataMode;
};
#endif // _ARDUINO_DATABUS_H_