A39模拟器

This commit is contained in:
liulin
2024-03-07 11:03:18 +08:00
parent cb2cc0d66f
commit 33e6eb45b3
1008 changed files with 2222717 additions and 0 deletions

View File

@ -0,0 +1,579 @@
/**
* @file GC9A01.c
*
**/
/*********************
* INCLUDES
*********************/
#include "GC9A01.h"
#if USE_GC9A01
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define GC9A01_BAUD 2000000 /*< 2,5 MHz (400 ns)*/
#define GC9A01_CMD_MODE 0
#define GC9A01_DATA_MODE 1
#define GC9A01_HOR_RES 240
#define GC9A01_VER_RES 240
/* GC9A01 Commands that we know of. Limited documentation */
#define GC9A01_INVOFF 0x20
#define GC9A01_INVON 0x21
#define GC9A01_DISPON 0x29
#define GC9A01_CASET 0x2A
#define GC9A01_RASET 0x2B
#define GC9A01_RAMWR 0x2C
#define GC9A01_COLMOD 0x3A
#define GC9A01_MADCTL 0x36
#define GC9A01_MADCTL_MY 0x80
#define GC9A01_MADCTL_MX 0x40
#define GC9A01_MADCTL_MV 0x20
#define GC9A01_MADCTL_RGB 0x00
#define GC9A01_DISFNCTRL 0xB6
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void GC9A01_command(uint8_t cmd);
static void GC9A01_data(uint8_t data);
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
/**********************
* STATIC VARIABLES
**********************/
// Documentation on op codes for GC9A01 are very hard to find.
// Will document should they be found.
static struct GC9A01_function GC9A01_cfg_script[] = {
{ GC9A01_START, GC9A01_START},
{ GC9A01_CMD, 0xEF},
{ GC9A01_CMD, 0xEB},
{ GC9A01_DATA, 0x14},
{ GC9A01_CMD, 0xFE}, // Inter Register Enable1
{ GC9A01_CMD, 0xEF}, // Inter Register Enable2
{ GC9A01_CMD, 0xEB},
{ GC9A01_DATA, 0x14},
{ GC9A01_CMD, 0x84},
{ GC9A01_DATA, 0x40},
{ GC9A01_CMD, 0x85},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x86},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x87},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x88},
{ GC9A01_DATA, 0x0A},
{ GC9A01_CMD, 0x89},
{ GC9A01_DATA, 0x21},
{ GC9A01_CMD, 0x8A},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x8B},
{ GC9A01_DATA, 0x80},
{ GC9A01_CMD, 0x8C},
{ GC9A01_DATA, 0x01},
{ GC9A01_CMD, 0x8D},
{ GC9A01_DATA, 0x01},
{ GC9A01_CMD, 0x8E},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, 0x8F},
{ GC9A01_DATA, 0xFF},
{ GC9A01_CMD, GC9A01_DISFNCTRL}, // Display Function Control
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, GC9A01_MADCTL}, // Memory Access Control
{ GC9A01_DATA, 0x48}, // Set the display direction 0,1,2,3 four directions
{ GC9A01_CMD, GC9A01_COLMOD}, // COLMOD: Pixel Format Set
{ GC9A01_DATA, 0x05}, // 16 Bits per pixel
{ GC9A01_CMD, 0x90},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_CMD, 0xBD},
{ GC9A01_DATA, 0x06},
{ GC9A01_CMD, 0xBC},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0xFF},
{ GC9A01_DATA, 0x60},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0x04},
{ GC9A01_CMD, 0xC3}, // Power Control 2
{ GC9A01_DATA, 0x13},
{ GC9A01_CMD, 0xC4}, // Power Control 3
{ GC9A01_DATA, 0x13},
{ GC9A01_CMD, 0xC9}, // Power Control 4
{ GC9A01_DATA, 0x22},
{ GC9A01_CMD, 0xBE},
{ GC9A01_DATA, 0x11},
{ GC9A01_CMD, 0xE1},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x0E},
{ GC9A01_CMD, 0xDF},
{ GC9A01_DATA, 0x21},
{ GC9A01_DATA, 0x0C},
{ GC9A01_DATA, 0x02},
{ GC9A01_CMD, 0xF0}, // SET_GAMMA1
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x26},
{ GC9A01_DATA, 0x2A},
{ GC9A01_CMD, 0xF1}, // SET_GAMMA2
{ GC9A01_DATA, 0x43},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x72},
{ GC9A01_DATA, 0x36},
{ GC9A01_DATA, 0x37},
{ GC9A01_DATA, 0x6F},
{ GC9A01_CMD, 0xF2}, // SET_GAMMA3
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x26},
{ GC9A01_DATA, 0x2A},
{ GC9A01_CMD, 0xF3}, // SET_GAMMA4
{ GC9A01_DATA, 0x43},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x72},
{ GC9A01_DATA, 0x36},
{ GC9A01_DATA, 0x37},
{ GC9A01_DATA, 0x6F},
{ GC9A01_CMD, 0xED},
{ GC9A01_DATA, 0x1B},
{ GC9A01_DATA, 0x0B},
{ GC9A01_CMD, 0xAE},
{ GC9A01_DATA, 0x77},
{ GC9A01_CMD, 0xCD},
{ GC9A01_DATA, 0x63},
{ GC9A01_CMD, 0x70},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x04},
{ GC9A01_DATA, 0x0E},
{ GC9A01_DATA, 0x0F},
{ GC9A01_DATA, 0x09},
{ GC9A01_DATA, 0x07},
{ GC9A01_DATA, 0x08},
{ GC9A01_DATA, 0x03},
{ GC9A01_CMD, 0xE8},
{ GC9A01_DATA, 0x34},
{ GC9A01_CMD, 0x62},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x0D},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xED},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x0F},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xEF},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_CMD, 0x63},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x11},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x18},
{ GC9A01_DATA, 0x13},
{ GC9A01_DATA, 0x71},
{ GC9A01_DATA, 0xF3},
{ GC9A01_DATA, 0x70},
{ GC9A01_DATA, 0x70},
{ GC9A01_CMD, 0x64},
{ GC9A01_DATA, 0x28},
{ GC9A01_DATA, 0x29},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0xF1},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x07},
{ GC9A01_CMD, 0x66},
{ GC9A01_DATA, 0x3C},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0xCD},
{ GC9A01_DATA, 0x67},
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x45},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x67},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x3C},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x01},
{ GC9A01_DATA, 0x54},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x32},
{ GC9A01_DATA, 0x98},
{ GC9A01_CMD, 0x74},
{ GC9A01_DATA, 0x10},
{ GC9A01_DATA, 0x85},
{ GC9A01_DATA, 0x80},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x00},
{ GC9A01_DATA, 0x4E},
{ GC9A01_DATA, 0x00},
{ GC9A01_CMD, 0x98},
{ GC9A01_DATA, 0x3E},
{ GC9A01_DATA, 0x07},
{ GC9A01_CMD, 0x35}, // Tearing Effect Line ON
{ GC9A01_CMD, 0x21}, // Display Inversion ON
{ GC9A01_CMD, 0x11}, // Sleep Out Mode
{ GC9A01_DELAY, 120},
{ GC9A01_CMD, GC9A01_DISPON}, // Display ON
{ GC9A01_DELAY, 255},
{ GC9A01_END, GC9A01_END},
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Write a command to the GC9A01
* @param cmd the command
*/
static void GC9A01_command(uint8_t cmd)
{
LV_DRV_DISP_CMD_DATA(GC9A01_CMD_MODE);
LV_DRV_DISP_SPI_WR_BYTE(cmd);
}
/**
* Write data to the GC9A01
* @param data the data
*/
static void GC9A01_data(uint8_t data)
{
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
static int GC9A01_data_array(uint8_t *buf, uint32_t len)
{
uint8_t *pt = buf;
for (uint32_t lp = 0; lp < len; lp++, pt++)
{
LV_DRV_DISP_SPI_WR_BYTE(*pt);
}
return 0;
}
static int GC9A01_databuf(uint32_t len, uint8_t *buf)
{
uint32_t byte_left = len;
uint8_t *pt = buf;
while (byte_left)
{
if (byte_left > 64)
{
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, 64);
byte_left = byte_left - 64;
pt = pt + 64;
}
else
{
LV_DRV_DISP_SPI_WR_ARRAY((char*)pt, byte_left);
byte_left=0;
}
}
return 0;
}
// hard reset of the tft controller
// ----------------------------------------------------------
static void GC9A01_hard_reset( void )
{
LV_DRV_DISP_SPI_CS(0); // Low to listen to us
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
}
// Configuration of the tft controller
// ----------------------------------------------------------
static void GC9A01_run_cfg_script(void)
{
int i = 0;
int end_script = 0;
do {
switch (GC9A01_cfg_script[i].cmd)
{
case GC9A01_START:
break;
case GC9A01_CMD:
GC9A01_command( GC9A01_cfg_script[i].data & 0xFF );
break;
case GC9A01_DATA:
GC9A01_data( GC9A01_cfg_script[i].data & 0xFF );
break;
case GC9A01_DELAY:
LV_DRV_DELAY_MS(GC9A01_cfg_script[i].data);
break;
case GC9A01_END:
end_script = 1;
}
i++;
} while (!end_script);
}
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
// Rudimentary clipping
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((y+h-1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x, y + h - 1);
uint8_t hi = color >> 8, lo = color;
while (h--) {
GC9A01_data(hi);
GC9A01_data(lo);
}
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
// Rudimentary clipping
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((x+w-1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x + w - 1, y);
uint8_t hi = color >> 8, lo = color;
while (w--) {
GC9A01_data(hi);
GC9A01_data(lo);
}
LV_DRV_DISP_SPI_CS(1);
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
void GC9A01_invertDisplay(bool i)
{
GC9A01_command(i ? GC9A01_INVON : GC9A01_INVOFF);
}
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color)
{
if((x < 0) ||(x >= GC9A01_HOR_RES) || (y < 0) || (y >= GC9A01_VER_RES)) return;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x, y);
uint8_t hi = color >> 8, lo = color;
GC9A01_data(hi);
GC9A01_data(lo);
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_fillScreen(uint16_t color) {
GC9A01_fillRect(0, 0, GC9A01_HOR_RES, GC9A01_VER_RES, color);
}
// fill a rectangle
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
// rudimentary clipping (drawChar w/big text requires this)
if((x >= GC9A01_HOR_RES) || (y >= GC9A01_VER_RES)) return;
if((x + w - 1) >= GC9A01_HOR_RES) w = GC9A01_HOR_RES - x;
if((y + h - 1) >= GC9A01_VER_RES) h = GC9A01_VER_RES - y;
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(x, y, x + w - 1, y + h - 1);
uint8_t hi = color >> 8, lo = color;
for (y = h; y > 0; y--)
{
for (x = w; x > 0; x--)
{
GC9A01_data(hi);
GC9A01_data(lo);
}
}
LV_DRV_DISP_SPI_CS(1);
}
void GC9A01_setRotation(uint8_t m) {
GC9A01_command(GC9A01_MADCTL);
m %= 4; // can't be higher than 3
switch (m) {
case 0:
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MY | GC9A01_MADCTL_RGB);
// _xstart = _colstart;
// _ystart = _rowstart;
break;
case 1:
GC9A01_data(GC9A01_MADCTL_MY | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
// _ystart = _colstart;
// _xstart = _rowstart;
break;
case 2:
GC9A01_data(GC9A01_MADCTL_RGB);
// _xstart = _colstart;
// _ystart = _rowstart;
break;
case 3:
GC9A01_data(GC9A01_MADCTL_MX | GC9A01_MADCTL_MV | GC9A01_MADCTL_RGB);
// _ystart = _colstart;
// _xstart = _rowstart;
break;
}
}
/**
* Initialize the GC9A01
*/
int GC9A01_init(void)
{
LV_DRV_DISP_SPI_FREQ(GC9A01_SPI_BAUD);
LV_DRV_DISP_SPI_MODE(GC9A01_SPI_BITS, GC9A01_SPI_MODE);
GC9A01_hard_reset();
GC9A01_run_cfg_script();
// GC9A01_fillScreen(0x0000); // Black
// GC9A01_fillScreen(0xFFFF); // White
GC9A01_fillScreen(0xAAAA); // ?
return 0;
}
static void GC9A01_set_addr_win(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
uint16_t x_start = x0 + GC9A01_XSTART, x_end = x1 + GC9A01_XSTART;
uint16_t y_start = y0 + GC9A01_YSTART, y_end = y1 + GC9A01_YSTART;
GC9A01_command(GC9A01_CASET); // Column addr set
GC9A01_data(x_start >> 8);
GC9A01_data(x_start & 0xFF); // XSTART
GC9A01_data(x_end >> 8);
GC9A01_data(x_end & 0xFF); // XEND
GC9A01_command(GC9A01_RASET); // Row addr set
GC9A01_data(y_start >> 8);
GC9A01_data(y_start & 0xFF); // YSTART
GC9A01_data(y_end >> 8);
GC9A01_data(y_end & 0xFF); // YEND
GC9A01_command(GC9A01_RAMWR);
}
void GC9A01_flush(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t *color_p)
{
LV_DRV_DISP_SPI_CS(0); // Listen to us
GC9A01_set_addr_win(area->x1, area->y1, area->x2, area->y2);
int32_t len = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;
LV_DRV_DISP_CMD_DATA(GC9A01_DATA_MODE);
LV_DRV_DISP_SPI_WR_ARRAY((char*)color_p, len);
LV_DRV_DISP_SPI_CS(1);
lv_disp_flush_ready(disp_drv); /* Indicate you are ready with the flushing*/
}
#endif

View File

@ -0,0 +1,88 @@
/**
* @file GC9A01.h
*
**/
#ifndef GC9A01_H
#define GC9A01_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_GC9A01
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
// #include "../../lv_drv_conf.h"
// #if USE_GC9A01 != 0
// #include <stdint.h>
// #include "lvgl/lv_misc/lv_color.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/* Init script function */
struct GC9A01_function {
uint16_t cmd;
uint16_t data;
};
/* Init script commands */
enum GC9A01_cmd {
GC9A01_START,
GC9A01_END,
GC9A01_CMD,
GC9A01_DATA,
GC9A01_DELAY
};
/**********************
* GLOBAL PROTOTYPES
**********************/
int GC9A01_init(void);
void GC9A01_flush(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void GC9A01_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void GC9A01_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t * color_p);
void GC9A01_setRotation(uint8_t m);
void GC9A01_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void GC9A01_fillScreen(uint16_t color);
uint16_t GC9A01_Color565(uint8_t r, uint8_t g, uint8_t b);
void GC9A01_invertDisplay(bool i);
void GC9A01_drawPixel(int16_t x, int16_t y, uint16_t color);
void GC9A01_drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void GC9A01_drawFastVLine(int16_t x, int16_t y, int16_t w, uint16_t color);
/**********************
* MACROS
**********************/
#endif /* USE_GC9A01 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* GC9A01_H */

View File

@ -0,0 +1,432 @@
/**
* @file ILI9341.c
*
* ILI9341.pdf [ILI9341_DS_V1.13_20110805]
*
* [references]
* - https://www.newhavendisplay.com/app_notes/ILI9341.pdf
* - Linux Source [v5.9-rc4] "drivers/staging/fbtft/fb_ili9341.c"
* - https://github.com/adafruit/Adafruit_ILI9341/blob/master/Adafruit_ILI9341.cpp
* - https://os.mbed.com/users/dreschpe/code/SPI_TFT_ILI9341
*
*/
/*********************
* INCLUDES
*********************/
#include "ILI9341.h"
#if USE_ILI9341 != 0
#include <stdio.h>
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define ILI9341_CMD_MODE 0
#define ILI9341_DATA_MODE 1
#define ILI9341_TFTWIDTH 240
#define ILI9341_TFTHEIGHT 320
/* Level 1 Commands -------------- [section] Description */
#define ILI9341_NOP 0x00 /* [8.2.1 ] No Operation / Terminate Frame Memory Write */
#define ILI9341_SWRESET 0x01 /* [8.2.2 ] Software Reset */
#define ILI9341_RDDIDIF 0x04 /* [8.2.3 ] Read Display Identification Information */
#define ILI9341_RDDST 0x09 /* [8.2.4 ] Read Display Status */
#define ILI9341_RDDPM 0x0A /* [8.2.5 ] Read Display Power Mode */
#define ILI9341_RDDMADCTL 0x0B /* [8.2.6 ] Read Display MADCTL */
#define ILI9341_RDDCOLMOD 0x0C /* [8.2.7 ] Read Display Pixel Format */
#define ILI9341_RDDIM 0x0D /* [8.2.8 ] Read Display Image Mode */
#define ILI9341_RDDSM 0x0E /* [8.2.9 ] Read Display Signal Mode */
#define ILI9341_RDDSDR 0x0F /* [8.2.10] Read Display Self-Diagnostic Result */
#define ILI9341_SLPIN 0x10 /* [8.2.11] Enter Sleep Mode */
#define ILI9341_SLPOUT 0x11 /* [8.2.12] Leave Sleep Mode */
#define ILI9341_PTLON 0x12 /* [8.2.13] Partial Display Mode ON */
#define ILI9341_NORON 0x13 /* [8.2.14] Normal Display Mode ON */
#define ILI9341_DINVOFF 0x20 /* [8.2.15] Display Inversion OFF */
#define ILI9341_DINVON 0x21 /* [8.2.16] Display Inversion ON */
#define ILI9341_GAMSET 0x26 /* [8.2.17] Gamma Set */
#define ILI9341_DISPOFF 0x28 /* [8.2.18] Display OFF*/
#define ILI9341_DISPON 0x29 /* [8.2.19] Display ON*/
#define ILI9341_CASET 0x2A /* [8.2.20] Column Address Set */
#define ILI9341_PASET 0x2B /* [8.2.21] Page Address Set */
#define ILI9341_RAMWR 0x2C /* [8.2.22] Memory Write */
#define ILI9341_RGBSET 0x2D /* [8.2.23] Color Set (LUT for 16-bit to 18-bit color depth conversion) */
#define ILI9341_RAMRD 0x2E /* [8.2.24] Memory Read */
#define ILI9341_PTLAR 0x30 /* [8.2.25] Partial Area */
#define ILI9341_VSCRDEF 0x33 /* [8.2.26] Veritcal Scrolling Definition */
#define ILI9341_TEOFF 0x34 /* [8.2.27] Tearing Effect Line OFF */
#define ILI9341_TEON 0x35 /* [8.2.28] Tearing Effect Line ON */
#define ILI9341_MADCTL 0x36 /* [8.2.29] Memory Access Control */
#define MADCTL_MY 0x80 /* MY row address order */
#define MADCTL_MX 0x40 /* MX column address order */
#define MADCTL_MV 0x20 /* MV row / column exchange */
#define MADCTL_ML 0x10 /* ML vertical refresh order */
#define MADCTL_MH 0x04 /* MH horizontal refresh order */
#define MADCTL_RGB 0x00 /* RGB Order [default] */
#define MADCTL_BGR 0x08 /* BGR Order */
#define ILI9341_VSCRSADD 0x37 /* [8.2.30] Vertical Scrolling Start Address */
#define ILI9341_IDMOFF 0x38 /* [8.2.31] Idle Mode OFF */
#define ILI9341_IDMON 0x39 /* [8.2.32] Idle Mode ON */
#define ILI9341_PIXSET 0x3A /* [8.2.33] Pixel Format Set */
#define ILI9341_WRMEMCONT 0x3C /* [8.2.34] Write Memory Continue */
#define ILI9341_RDMEMCONT 0x3E /* [8.2.35] Read Memory Continue */
#define ILI9341_SETSCANTE 0x44 /* [8.2.36] Set Tear Scanline */
#define ILI9341_GETSCAN 0x45 /* [8.2.37] Get Scanline */
#define ILI9341_WRDISBV 0x51 /* [8.2.38] Write Display Brightness Value */
#define ILI9341_RDDISBV 0x52 /* [8.2.39] Read Display Brightness Value */
#define ILI9341_WRCTRLD 0x53 /* [8.2.40] Write Control Display */
#define ILI9341_RDCTRLD 0x54 /* [8.2.41] Read Control Display */
#define ILI9341_WRCABC 0x55 /* [8.2.42] Write Content Adaptive Brightness Control Value */
#define ILI9341_RDCABC 0x56 /* [8.2.43] Read Content Adaptive Brightness Control Value */
#define ILI9341_WRCABCMIN 0x5E /* [8.2.44] Write CABC Minimum Brightness */
#define ILI9341_RDCABCMIN 0x5F /* [8.2.45] Read CABC Minimum Brightness */
#define ILI9341_RDID1 0xDA /* [8.2.46] Read ID1 - Manufacturer ID (user) */
#define ILI9341_RDID2 0xDB /* [8.2.47] Read ID2 - Module/Driver version (supplier) */
#define ILI9341_RDID3 0xDC /* [8.2.48] Read ID3 - Module/Driver version (user) */
/* Level 2 Commands -------------- [section] Description */
#define ILI9341_IFMODE 0xB0 /* [8.3.1 ] Interface Mode Control */
#define ILI9341_FRMCTR1 0xB1 /* [8.3.2 ] Frame Rate Control (In Normal Mode/Full Colors) */
#define ILI9341_FRMCTR2 0xB2 /* [8.3.3 ] Frame Rate Control (In Idle Mode/8 colors) */
#define ILI9341_FRMCTR3 0xB3 /* [8.3.4 ] Frame Rate control (In Partial Mode/Full Colors) */
#define ILI9341_INVTR 0xB4 /* [8.3.5 ] Display Inversion Control */
#define ILI9341_PRCTR 0xB5 /* [8.3.6 ] Blanking Porch Control */
#define ILI9341_DISCTRL 0xB6 /* [8.3.7 ] Display Function Control */
#define ILI9341_ETMOD 0xB7 /* [8.3.8 ] Entry Mode Set */
#define ILI9341_BLCTRL1 0xB8 /* [8.3.9 ] Backlight Control 1 - Grayscale Histogram UI mode */
#define ILI9341_BLCTRL2 0xB9 /* [8.3.10] Backlight Control 2 - Grayscale Histogram still picture mode */
#define ILI9341_BLCTRL3 0xBA /* [8.3.11] Backlight Control 3 - Grayscale Thresholds UI mode */
#define ILI9341_BLCTRL4 0xBB /* [8.3.12] Backlight Control 4 - Grayscale Thresholds still picture mode */
#define ILI9341_BLCTRL5 0xBC /* [8.3.13] Backlight Control 5 - Brightness Transition time */
#define ILI9341_BLCTRL7 0xBE /* [8.3.14] Backlight Control 7 - PWM Frequency */
#define ILI9341_BLCTRL8 0xBF /* [8.3.15] Backlight Control 8 - ON/OFF + PWM Polarity*/
#define ILI9341_PWCTRL1 0xC0 /* [8.3.16] Power Control 1 - GVDD */
#define ILI9341_PWCTRL2 0xC1 /* [8.3.17] Power Control 2 - step-up factor for operating voltage */
#define ILI9341_VMCTRL1 0xC5 /* [8.3.18] VCOM Control 1 - Set VCOMH and VCOML */
#define ILI9341_VMCTRL2 0xC7 /* [8.3.19] VCOM Control 2 - VCOM offset voltage */
#define ILI9341_NVMWR 0xD0 /* [8.3.20] NV Memory Write */
#define ILI9341_NVMPKEY 0xD1 /* [8.3.21] NV Memory Protection Key */
#define ILI9341_RDNVM 0xD2 /* [8.3.22] NV Memory Status Read */
#define ILI9341_RDID4 0xD3 /* [8.3.23] Read ID4 - IC Device Code */
#define ILI9341_PGAMCTRL 0xE0 /* [8.3.24] Positive Gamma Control */
#define ILI9341_NGAMCTRL 0xE1 /* [8.3.25] Negative Gamma Correction */
#define ILI9341_DGAMCTRL1 0xE2 /* [8.3.26] Digital Gamma Control 1 */
#define ILI9341_DGAMCTRL2 0xE3 /* [8.3.27] Digital Gamma Control 2 */
#define ILI9341_IFCTL 0xF6 /* [8.3.28] 16bits Data Format Selection */
/* Extended Commands --------------- [section] Description*/
#define ILI9341_PWCTRLA 0xCB /* [8.4.1] Power control A */
#define ILI9341_PWCTRLB 0xCF /* [8.4.2] Power control B */
#define ILI9341_TIMECTRLA_INT 0xE8 /* [8.4.3] Internal Clock Driver timing control A */
#define ILI9341_TIMECTRLA_EXT 0xE9 /* [8.4.4] External Clock Driver timing control A */
#define ILI9341_TIMECTRLB 0xEA /* [8.4.5] Driver timing control B (gate driver timing control) */
#define ILI9341_PWSEQCTRL 0xED /* [8.4.6] Power on sequence control */
#define ILI9341_GAM3CTRL 0xF2 /* [8.4.7] Enable 3 gamma control */
#define ILI9341_PUMPRATIO 0xF7 /* [8.4.8] Pump ratio control */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void ili9341_write(int mode, uint8_t data);
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the ILI9341 display controller
*/
void ili9341_init(void)
{
uint8_t data[15];
/* hardware reset */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_CMD_DATA(ILI9341_DATA_MODE);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_US(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(5);
/* software reset */
ili9341_write(ILI9341_CMD_MODE, ILI9341_SWRESET);
LV_DRV_DELAY_MS(5);
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPOFF);
/* startup sequence */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLB);
data[0] = 0x00;
data[1] = 0x83;
data[2] = 0x30;
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWSEQCTRL);
data[0] = 0x64;
data[1] = 0x03;
data[2] = 0x12;
data[3] = 0x81;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLA_INT);
data[0] = 0x85;
data[1] = 0x01;
data[2] = 0x79;
ili9341_write_array(ILI9341_DATA_MODE, data, 3);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRLA);
data[0] = 0x39;
data[1] = 0x2c;
data[2] = 0x00;
data[3] = 0x34;
data[4] = 0x02;
ili9341_write_array(ILI9341_DATA_MODE, data, 5);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PUMPRATIO);
ili9341_write(ILI9341_DATA_MODE, 0x20);
ili9341_write(ILI9341_CMD_MODE, ILI9341_TIMECTRLB);
data[0] = 0x00;
data[1] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
/* power control */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL1);
ili9341_write(ILI9341_DATA_MODE, 0x26);
ili9341_write(ILI9341_CMD_MODE, ILI9341_PWCTRL2);
ili9341_write(ILI9341_DATA_MODE, 0x11);
/* VCOM */
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL1);
data[0] = 0x35;
data[1] = 0x3e;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
ili9341_write(ILI9341_CMD_MODE, ILI9341_VMCTRL2);
ili9341_write(ILI9341_DATA_MODE, 0xbe);
/* set orientation */
ili9341_rotate(0, ILI9341_BGR);
/* 16 bit pixel */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PIXSET);
ili9341_write(ILI9341_DATA_MODE, 0x55);
/* frame rate */
ili9341_write(ILI9341_CMD_MODE, ILI9341_FRMCTR1);
data[0] = 0x00;
data[1] = 0x1b;
ili9341_write_array(ILI9341_DATA_MODE, data, 2);
#if ILI9341_GAMMA
/* gamma curve set */
ili9341_write(ILI9341_CMD_MODE, ILI9341_GAMSET);
ili9341_write(ILI9341_DATA_MODE, 0x01);
/* positive gamma correction */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PGAMCTRL);
data[0] = 0x1f;
data[1] = 0x1a;
data[2] = 0x18;
data[3] = 0x0a;
data[4] = 0x0f;
data[5] = 0x06;
data[6] = 0x45;
data[7] = 0x87;
data[8] = 0x32;
data[9] = 0x0a;
data[10] = 0x07;
data[11] = 0x02;
data[12] = 0x07;
data[13] = 0x05;
data[14] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
/* negative gamma correction */
ili9341_write(ILI9341_CMD_MODE, ILI9341_NGAMCTRL);
data[0] = 0x00;
data[1] = 0x25;
data[2] = 0x27;
data[3] = 0x05;
data[4] = 0x10;
data[5] = 0x09;
data[6] = 0x3a;
data[7] = 0x78;
data[8] = 0x4d;
data[9] = 0x05;
data[10] = 0x18;
data[11] = 0x0d;
data[12] = 0x38;
data[13] = 0x3a;
data[14] = 0x1f;
ili9341_write_array(ILI9341_DATA_MODE, data, 15);
#endif
/* window horizontal */
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
data[0] = 0;
data[1] = 0;
data[2] = (ILI9341_HOR_RES - 1) >> 8;
data[3] = (ILI9341_HOR_RES - 1);
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* window vertical */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
data[0] = 0;
data[1] = 0;
data[2] = (ILI9341_VER_RES - 1) >> 8;
data[3] = (ILI9341_VER_RES - 1);
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
#if ILI9341_TEARING
/* tearing effect off */
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEOFF);
/* tearing effect on */
ili9341_write(ILI9341_CMD_MODE, ILI9341_TEON);
#endif
/* entry mode set */
ili9341_write(ILI9341_CMD_MODE, ILI9341_ETMOD);
ili9341_write(ILI9341_DATA_MODE, 0x07);
/* display function control */
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISCTRL);
data[0] = 0x0a;
data[1] = 0x82;
data[2] = 0x27;
data[3] = 0x00;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* exit sleep mode */
ili9341_write(ILI9341_CMD_MODE, ILI9341_SLPOUT);
LV_DRV_DELAY_MS(100);
/* display on */
ili9341_write(ILI9341_CMD_MODE, ILI9341_DISPON);
LV_DRV_DELAY_MS(20);
}
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, const lv_color_t * color_p)
{
if(area->x2 < 0 || area->y2 < 0 || area->x1 > (ILI9341_HOR_RES - 1) || area->y1 > (ILI9341_VER_RES - 1)) {
lv_disp_flush_ready(drv);
return;
}
/* Truncate the area to the screen */
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > ILI9341_HOR_RES - 1 ? ILI9341_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > ILI9341_VER_RES - 1 ? ILI9341_VER_RES - 1 : area->y2;
int32_t y;
uint8_t data[4];
int32_t len = len = (act_x2 - act_x1 + 1) * 2;
lv_coord_t w = (area->x2 - area->x1) + 1;
/* window horizontal */
ili9341_write(ILI9341_CMD_MODE, ILI9341_CASET);
data[0] = act_x1 >> 8;
data[1] = act_x1;
data[2] = act_x2 >> 8;
data[3] = act_x2;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
/* window vertical */
ili9341_write(ILI9341_CMD_MODE, ILI9341_PASET);
data[0] = act_y1 >> 8;
data[1] = act_y1;
data[2] = act_y2 >> 8;
data[3] = act_y2;
ili9341_write_array(ILI9341_DATA_MODE, data, 4);
ili9341_write(ILI9341_CMD_MODE, ILI9341_RAMWR);
for(y = act_y1; y <= act_y2; y++) {
ili9341_write_array(ILI9341_DATA_MODE, (uint8_t *)color_p, len);
color_p += w;
}
lv_disp_flush_ready(drv);
}
void ili9341_rotate(int degrees, bool bgr)
{
uint8_t color_order = MADCTL_RGB;
if(bgr)
color_order = MADCTL_BGR;
ili9341_write(ILI9341_CMD_MODE, ILI9341_MADCTL);
switch(degrees) {
case 270:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MV | color_order);
break;
case 180:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MY | color_order);
break;
case 90:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | MADCTL_MY | MADCTL_MV | color_order);
break;
case 0:
/* fall-through */
default:
ili9341_write(ILI9341_DATA_MODE, MADCTL_MX | color_order);
break;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Write byte
* @param mode sets command or data mode for write
* @param byte the byte to write
*/
static inline void ili9341_write(int mode, uint8_t data)
{
LV_DRV_DISP_CMD_DATA(mode);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
/**
* Write byte array
* @param mode sets command or data mode for write
* @param data the byte array to write
* @param len the length of the byte array
*/
static inline void ili9341_write_array(int mode, uint8_t *data, uint16_t len)
{
LV_DRV_DISP_CMD_DATA(mode);
LV_DRV_DISP_SPI_WR_ARRAY(data, len);
}
#endif

View File

@ -0,0 +1,67 @@
/**
* @file ILI9341.h
*
*/
#ifndef ILI9341_H
#define ILI9341_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdbool.h>
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_ILI9341
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#if LV_COLOR_DEPTH != 16
#error "ILI9341 currently supports 'LV_COLOR_DEPTH == 16'. Set it in lv_conf.h"
#endif
#if LV_COLOR_16_SWAP != 1
#error "ILI9341 SPI requires LV_COLOR_16_SWAP == 1. Set it in lv_conf.h"
#endif
/*********************
* DEFINES
*********************/
#define ILI9341_BGR true
#define ILI9341_RGB false
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void ili9341_init(void);
void ili9341_flush(lv_disp_drv_t * drv, const lv_area_t * area, const lv_color_t * color_p);
void ili9341_rotate(int degrees, bool bgr);
/**********************
* MACROS
**********************/
#endif /* USE_ILI9341 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ILI9341_H */

View File

@ -0,0 +1,425 @@
/**
* @file R61581.c
*
*/
/*********************
* INCLUDES
*********************/
#include "R61581.h"
#if USE_R61581 != 0
#include <stdbool.h>
#include "lvgl/lv_core/lv_vdb.h"
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define R61581_CMD_MODE 0
#define R61581_DATA_MODE 1
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void r61581_io_init(void);
static void r61581_reset(void);
static void r61581_set_tft_spec(void);
static inline void r61581_cmd_mode(void);
static inline void r61581_data_mode(void);
static inline void r61581_cmd(uint8_t cmd);
static inline void r61581_data(uint8_t data);
/**********************
* STATIC VARIABLES
**********************/
static bool cmd_mode = true;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the R61581 display controller
* @return HW_RES_OK or any error from hw_res_t enum
*/
void r61581_init(void)
{
r61581_io_init();
/*Slow mode until the PLL is not started in the display controller*/
LV_DRV_DISP_PAR_SLOW;
r61581_reset();
r61581_set_tft_spec();
r61581_cmd(0x13); //SET display on
r61581_cmd(0x29); //SET display on
LV_DRV_DELAY_MS(30);
/*Parallel to max speed*/
LV_DRV_DISP_PAR_FAST;
}
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
int16_t i;
uint16_t full_w = x2 - x1 + 1;
r61581_data_mode();
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
color_p += full_w;
}
}
#endif
lv_flush_ready();
}
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
r61581_data_mode();
uint16_t color16 = lv_color_to16(color);
uint32_t size = (act_x2 - act_x1 + 1) * (act_y2 - act_y1 + 1);
uint32_t i;
for(i = 0; i < size; i++) {
LV_DRV_DISP_PAR_WR_WORD(color16);
}
}
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > R61581_HOR_RES - 1) return;
if(y1 > R61581_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > R61581_HOR_RES - 1 ? R61581_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > R61581_VER_RES - 1 ? R61581_VER_RES - 1 : y2;
//Set the rectangular area
r61581_cmd(0x002A);
r61581_data(act_x1 >> 8);
r61581_data(0x00FF & act_x1);
r61581_data(act_x2 >> 8);
r61581_data(0x00FF & act_x2);
r61581_cmd(0x002B);
r61581_data(act_y1 >> 8);
r61581_data(0x00FF & act_y1);
r61581_data(act_y2 >> 8);
r61581_data(0x00FF & act_y2);
r61581_cmd(0x2c);
int16_t i;
uint16_t full_w = x2 - x1 + 1;
r61581_data_mode();
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(lv_color_to16(color_p[j]));
color_p += full_w;
}
}
#endif
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Io init
*/
static void r61581_io_init(void)
{
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
cmd_mode = true;
}
/**
* Reset
*/
static void r61581_reset(void)
{
/*Hardware reset*/
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
/*Chip enable*/
LV_DRV_DISP_PAR_CS(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_PAR_CS(0);
LV_DRV_DELAY_MS(5);
/*Software reset*/
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
r61581_cmd(0x01);
LV_DRV_DELAY_MS(20);
}
/**
* TFT specific initialization
*/
static void r61581_set_tft_spec(void)
{
r61581_cmd(0xB0);
r61581_data(0x00);
r61581_cmd(0xB3);
r61581_data(0x02);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x10);
r61581_cmd(0xB4);
r61581_data(0x00);//0X10
r61581_cmd(0xB9); //PWM
r61581_data(0x01);
r61581_data(0xFF); //FF brightness
r61581_data(0xFF);
r61581_data(0x18);
/*Panel Driving Setting*/
r61581_cmd(0xC0);
r61581_data(0x02);
r61581_data(0x3B);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(0x01);
r61581_data(0x00);//NW
r61581_data(0x43);
/*Display Timing Setting for Normal Mode */
r61581_cmd(0xC1);
r61581_data(0x08);
r61581_data(0x15); //CLOCK
r61581_data(R61581_VFP);
r61581_data(R61581_VBP);
/*Source/VCOM/Gate Driving Timing Setting*/
r61581_cmd(0xC4);
r61581_data(0x15);
r61581_data(0x03);
r61581_data(0x03);
r61581_data(0x01);
/*Interface Setting*/
r61581_cmd(0xC6);
r61581_data((R61581_DPL << 0) |
(R61581_EPL << 1) |
(R61581_HSPL << 4) |
(R61581_VSPL << 5));
/*Gamma Set*/
r61581_cmd(0xC8);
r61581_data(0x0c);
r61581_data(0x05);
r61581_data(0x0A);
r61581_data(0x6B);
r61581_data(0x04);
r61581_data(0x06);
r61581_data(0x15);
r61581_data(0x10);
r61581_data(0x00);
r61581_data(0x31);
r61581_cmd(0x36);
if(R61581_ORI == 0) r61581_data(0xE0);
else r61581_data(0x20);
r61581_cmd(0x0C);
r61581_data(0x55);
r61581_cmd(0x3A);
r61581_data(0x55);
r61581_cmd(0x38);
r61581_cmd(0xD0);
r61581_data(0x07);
r61581_data(0x07);
r61581_data(0x14);
r61581_data(0xA2);
r61581_cmd(0xD1);
r61581_data(0x03);
r61581_data(0x5A);
r61581_data(0x10);
r61581_cmd(0xD2);
r61581_data(0x03);
r61581_data(0x04);
r61581_data(0x04);
r61581_cmd(0x11);
LV_DRV_DELAY_MS(10);
r61581_cmd(0x2A);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(((R61581_HOR_RES - 1) >> 8) & 0XFF);
r61581_data((R61581_HOR_RES - 1) & 0XFF);
r61581_cmd(0x2B);
r61581_data(0x00);
r61581_data(0x00);
r61581_data(((R61581_VER_RES - 1) >> 8) & 0XFF);
r61581_data((R61581_VER_RES - 1) & 0XFF);
LV_DRV_DELAY_MS(10);
r61581_cmd(0x29);
LV_DRV_DELAY_MS(5);
r61581_cmd(0x2C);
LV_DRV_DELAY_MS(5);
}
/**
* Command mode
*/
static inline void r61581_cmd_mode(void)
{
if(cmd_mode == false) {
LV_DRV_DISP_CMD_DATA(R61581_CMD_MODE)
cmd_mode = true;
}
}
/**
* Data mode
*/
static inline void r61581_data_mode(void)
{
if(cmd_mode != false) {
LV_DRV_DISP_CMD_DATA(R61581_DATA_MODE);
cmd_mode = false;
}
}
/**
* Write command
* @param cmd the command
*/
static inline void r61581_cmd(uint8_t cmd)
{
r61581_cmd_mode();
LV_DRV_DISP_PAR_WR_WORD(cmd);
}
/**
* Write data
* @param data the data
*/
static inline void r61581_data(uint8_t data)
{
r61581_data_mode();
LV_DRV_DISP_PAR_WR_WORD(data);
}
#endif

View File

@ -0,0 +1,57 @@
/**
* @file R61581.h
*
*/
#ifndef R61581_H
#define R61581_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_R61581
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void r61581_init(void);
void r61581_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
void r61581_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void r61581_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_R61581 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* R61581_H */

View File

@ -0,0 +1,182 @@
/**
* @file SHARP_MIP.c
*
*/
/*-------------------------------------------------------------------------------------------------
* SHARP memory in pixel monochrome display series
* LS012B7DD01 (184x38 pixels.)
* LS013B7DH03 (128x128 pixels.)
* LS013B7DH05 (144x168 pixels.)
* LS027B7DH01 (400x240 pixels.) (tested)
* LS032B7DD02 (336x536 pixels.)
* LS044Q7DH01 (320x240 pixels.)
*
* These displays need periodic com inversion, there are two ways :
* - software com inversion :
* define SHARP_MIP_SOFT_COM_INVERSION 1 and set EXTMODE display pin LOW,
* call sharp_mip_com_inversion() periodically
* - hardware com inversion with EXTCOMIN display pin :
* define SHARP_MIP_SOFT_COM_INVERSION 0,
* set EXTMODE display pin HIGH and handle
* EXTCOMIN waveform (for example with mcu pwm output),
* see datasheet pages 8-12 for details
*
* draw_buf size : (LV_VER_RES / X) * (2 + LV_HOR_RES / 8) + 2 bytes, structure :
* [FRAME_HEADER (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 1st line
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] 2nd line
* ...........................................................................................
* [DUMMY (1 byte)] [GATE_ADDR (1 byte )] [LINE_DATA (LV_HOR_RES / 8 bytes)] last line
* [DUMMY (2 bytes)]
*
* Since extra bytes (dummy, addresses, header) are stored in draw_buf, we need to use
* an "oversized" draw_buf. Buffer declaration in "lv_port_disp.c" becomes for example :
* static lv_disp_buf_t disp_buf;
* static uint8_t buf[(LV_VER_RES_MAX / X) * (2 + (LV_HOR_RES_MAX / 8)) + 2];
* lv_disp_buf_init(&disp_buf, buf, NULL, LV_VER_RES_MAX * LV_HOR_RES_MAX / X);
*-----------------------------------------------------------------------------------------------*/
/*********************
* INCLUDES
*********************/
#include "SHARP_MIP.h"
#if USE_SHARP_MIP
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define SHARP_MIP_HEADER 0
#define SHARP_MIP_UPDATE_RAM_FLAG (1 << 7) /* (M0) Mode flag : H -> update memory, L -> maintain memory */
#define SHARP_MIP_COM_INVERSION_FLAG (1 << 6) /* (M1) Frame inversion flag : relevant when EXTMODE = L, */
/* H -> outputs VCOM = H, L -> outputs VCOM = L */
#define SHARP_MIP_CLEAR_SCREEN_FLAG (1 << 5) /* (M2) All clear flag : H -> clear all pixels */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if SHARP_MIP_SOFT_COM_INVERSION
static bool_t com_output_state = false;
#endif
/**********************
* MACROS
**********************/
/*
* Return the draw_buf byte index corresponding to the pixel
* relatives coordinates (x, y) in the area.
* The area is rounded to a whole screen line.
*/
#define BUFIDX(x, y) (((x) >> 3) + ((y) * (2 + (SHARP_MIP_HOR_RES >> 3))) + 2)
/*
* Return the byte bitmask of a pixel bit corresponding
* to draw_buf arrangement (8 pixels per byte on lines).
*/
#define PIXIDX(x) SHARP_MIP_REV_BYTE(1 << ((x) & 7))
/**********************
* GLOBAL FUNCTIONS
**********************/
void sharp_mip_init(void) {
/* These displays have nothing to initialize */
}
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
/*Return if the area is out the screen*/
if(area->y2 < 0) return;
if(area->y1 > SHARP_MIP_VER_RES - 1) return;
/*Truncate the area to the screen*/
uint16_t act_y1 = area->y1 < 0 ? 0 : area->y1;
uint16_t act_y2 = area->y2 > SHARP_MIP_VER_RES - 1 ? SHARP_MIP_VER_RES - 1 : area->y2;
uint8_t * buf = (uint8_t *) color_p; /*Get the buffer address*/
uint16_t buf_h = (act_y2 - act_y1 + 1); /*Number of buffer lines*/
uint16_t buf_size = buf_h * (2 + SHARP_MIP_HOR_RES / 8) + 2; /*Buffer size in bytes */
/* Set lines to flush dummy byte & gate address in draw_buf*/
for(uint16_t act_y = 0 ; act_y < buf_h ; act_y++) {
buf[BUFIDX(0, act_y) - 1] = SHARP_MIP_REV_BYTE((act_y1 + act_y + 1));
buf[BUFIDX(0, act_y) - 2] = 0;
}
/* Set last dummy two bytes in draw_buf */
buf[BUFIDX(0, buf_h) - 1] = 0;
buf[BUFIDX(0, buf_h) - 2] = 0;
/* Set frame header in draw_buf */
buf[0] = SHARP_MIP_HEADER |
SHARP_MIP_UPDATE_RAM_FLAG;
/* Write the frame on display memory */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
LV_DRV_DISP_SPI_CS(0);
lv_disp_flush_ready(disp_drv);
}
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
(void) disp_drv;
(void) buf_w;
(void) opa;
if (lv_color_to1(color) != 0) {
buf[BUFIDX(x, y)] |= PIXIDX(x); /*Set draw_buf pixel bit to 1 for other colors than BLACK*/
} else {
buf[BUFIDX(x, y)] &= ~PIXIDX(x); /*Set draw_buf pixel bit to 0 for BLACK color*/
}
}
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area) {
(void) disp_drv;
/* Round area to a whole line */
area->x1 = 0;
area->x2 = SHARP_MIP_HOR_RES - 1;
}
#if SHARP_MIP_SOFT_COM_INVERSION
void sharp_mip_com_inversion(void) {
uint8_t inversion_header[2] = {0};
/* Set inversion header */
if (com_output_state) {
com_output_state = false;
} else {
inversion_header[0] |= SHARP_MIP_COM_INVERSION_FLAG;
com_output_state = true;
}
/* Write inversion header on display memory */
LV_DRV_DISP_SPI_CS(1);
LV_DRV_DISP_SPI_WR_ARRAY(inversion_header, 2);
LV_DRV_DISP_SPI_CS(0);
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -0,0 +1,63 @@
/**
* @file SHARP_MIP.h
*
*/
#ifndef SHARP_MIP_H
#define SHARP_MIP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_SHARP_MIP
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void sharp_mip_init(void);
void sharp_mip_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void sharp_mip_rounder(lv_disp_drv_t * disp_drv, lv_area_t * area);
void sharp_mip_set_px(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
#if SHARP_MIP_SOFT_COM_INVERSION
void sharp_mip_com_inversion(void);
#endif
/**********************
* MACROS
**********************/
#endif /* USE_SHARP_MIP */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SHARP_MIP_H */

View File

@ -0,0 +1,292 @@
/**
* @file SSD1963.c
*
*/
/*********************
* INCLUDES
*********************/
#include "SSD1963.h"
#if USE_SSD1963
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define SSD1963_CMD_MODE 0
#define SSD1963_DATA_MODE 1
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static inline void ssd1963_cmd_mode(void);
static inline void ssd1963_data_mode(void);
static inline void ssd1963_cmd(uint8_t cmd);
static inline void ssd1963_data(uint8_t data);
static void ssd1963_io_init(void);
static void ssd1963_reset(void);
static void ssd1963_set_clk(void);
static void ssd1963_set_tft_spec(void);
static void ssd1963_init_bl(void);
/**********************
* STATIC VARIABLES
**********************/
static bool cmd_mode = true;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void ssd1963_init(void)
{
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
LV_DRV_DELAY_MS(250);
ssd1963_cmd(0x00E2); //PLL multiplier, set PLL clock to 120M
ssd1963_data(0x0023); //N=0x36 for 6.5M, 0x23 for 10M crystal
ssd1963_data(0x0002);
ssd1963_data(0x0004);
ssd1963_cmd(0x00E0); // PLL enable
ssd1963_data(0x0001);
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x00E0);
ssd1963_data(0x0003); // now, use PLL output as system clock
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x0001); // software reset
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x00E6); //PLL setting for PCLK, depends on resolution
ssd1963_data(0x0001); //HX8257C
ssd1963_data(0x0033); //HX8257C
ssd1963_data(0x0033); //HX8257C
ssd1963_cmd(0x00B0); //LCD SPECIFICATION
ssd1963_data(0x0020);
ssd1963_data(0x0000);
ssd1963_data(((SSD1963_HOR_RES - 1) >> 8) & 0X00FF); //Set HDP
ssd1963_data((SSD1963_HOR_RES - 1) & 0X00FF);
ssd1963_data(((SSD1963_VER_RES - 1) >> 8) & 0X00FF); //Set VDP
ssd1963_data((SSD1963_VER_RES - 1) & 0X00FF);
ssd1963_data(0x0000);
LV_DRV_DELAY_MS(1);//Delay10us(5);
ssd1963_cmd(0x00B4); //HSYNC
ssd1963_data((SSD1963_HT >> 8) & 0X00FF); //Set HT
ssd1963_data(SSD1963_HT & 0X00FF);
ssd1963_data((SSD1963_HPS >> 8) & 0X00FF); //Set HPS
ssd1963_data(SSD1963_HPS & 0X00FF);
ssd1963_data(SSD1963_HPW); //Set HPW
ssd1963_data((SSD1963_LPS >> 8) & 0X00FF); //SetLPS
ssd1963_data(SSD1963_LPS & 0X00FF);
ssd1963_data(0x0000);
ssd1963_cmd(0x00B6); //VSYNC
ssd1963_data((SSD1963_VT >> 8) & 0X00FF); //Set VT
ssd1963_data(SSD1963_VT & 0X00FF);
ssd1963_data((SSD1963_VPS >> 8) & 0X00FF); //Set VPS
ssd1963_data(SSD1963_VPS & 0X00FF);
ssd1963_data(SSD1963_VPW); //Set VPW
ssd1963_data((SSD1963_FPS >> 8) & 0X00FF); //Set FPS
ssd1963_data(SSD1963_FPS & 0X00FF);
ssd1963_cmd(0x00B8);
ssd1963_data(0x000f); //GPIO is controlled by host GPIO[3:0]=output GPIO[0]=1 LCD ON GPIO[0]=1 LCD OFF
ssd1963_data(0x0001); //GPIO0 normal
ssd1963_cmd(0x00BA);
ssd1963_data(0x0001); //GPIO[0] out 1 --- LCD display on/off control PIN
ssd1963_cmd(0x0036); //rotation
ssd1963_data(0x0008); //RGB=BGR
ssd1963_cmd(0x003A); //Set the current pixel format for RGB image data
ssd1963_data(0x0050); //16-bit/pixel
ssd1963_cmd(0x00F0); //Pixel Data Interface Format
ssd1963_data(0x0003); //16-bit(565 format) data
ssd1963_cmd(0x00BC);
ssd1963_data(0x0040); //contrast value
ssd1963_data(0x0080); //brightness value
ssd1963_data(0x0040); //saturation value
ssd1963_data(0x0001); //Post Processor Enable
LV_DRV_DELAY_MS(1);
ssd1963_cmd(0x0029); //display on
ssd1963_cmd(0x00BE); //set PWM for B/L
ssd1963_data(0x0006);
ssd1963_data(0x0080);
ssd1963_data(0x0001);
ssd1963_data(0x00f0);
ssd1963_data(0x0000);
ssd1963_data(0x0000);
ssd1963_cmd(0x00d0);
ssd1963_data(0x000d);
//DisplayBacklightOn();
LV_DRV_DELAY_MS(30);
}
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(area->x2 < 0) return;
if(area->y2 < 0) return;
if(area->x1 > SSD1963_HOR_RES - 1) return;
if(area->y1 > SSD1963_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > SSD1963_HOR_RES - 1 ? SSD1963_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > SSD1963_VER_RES - 1 ? SSD1963_VER_RES - 1 : area->y2;
//Set the rectangular area
ssd1963_cmd(0x002A);
ssd1963_data(act_x1 >> 8);
ssd1963_data(0x00FF & act_x1);
ssd1963_data(act_x2 >> 8);
ssd1963_data(0x00FF & act_x2);
ssd1963_cmd(0x002B);
ssd1963_data(act_y1 >> 8);
ssd1963_data(0x00FF & act_y1);
ssd1963_data(act_y2 >> 8);
ssd1963_data(0x00FF & act_y2);
ssd1963_cmd(0x2c);
int16_t i;
uint16_t full_w = area->x2 - area->x1 + 1;
ssd1963_data_mode();
LV_DRV_DISP_PAR_CS(0);
#if LV_COLOR_DEPTH == 16
uint16_t act_w = act_x2 - act_x1 + 1;
for(i = act_y1; i <= act_y2; i++) {
LV_DRV_DISP_PAR_WR_ARRAY((uint16_t *)color_p, act_w);
color_p += full_w;
}
LV_DRV_DISP_PAR_CS(1);
#else
int16_t j;
for(i = act_y1; i <= act_y2; i++) {
for(j = 0; j <= act_x2 - act_x1 + 1; j++) {
LV_DRV_DISP_PAR_WR_WORD(color_p[j]);
color_p += full_w;
}
}
#endif
lv_disp_flush_ready(disp_drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void ssd1963_io_init(void)
{
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
}
static void ssd1963_reset(void)
{
/*Hardware reset*/
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(50);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(50);
/*Chip enable*/
LV_DRV_DISP_PAR_CS(0);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_PAR_CS(1);
LV_DRV_DELAY_MS(5);
/*Software reset*/
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
ssd1963_cmd(0x01);
LV_DRV_DELAY_MS(20);
}
/**
* Command mode
*/
static inline void ssd1963_cmd_mode(void)
{
if(cmd_mode == false) {
LV_DRV_DISP_CMD_DATA(SSD1963_CMD_MODE);
cmd_mode = true;
}
}
/**
* Data mode
*/
static inline void ssd1963_data_mode(void)
{
if(cmd_mode != false) {
LV_DRV_DISP_CMD_DATA(SSD1963_DATA_MODE);
cmd_mode = false;
}
}
/**
* Write command
* @param cmd the command
*/
static inline void ssd1963_cmd(uint8_t cmd)
{
LV_DRV_DISP_PAR_CS(0);
ssd1963_cmd_mode();
LV_DRV_DISP_PAR_WR_WORD(cmd);
LV_DRV_DISP_PAR_CS(1);
}
/**
* Write data
* @param data the data
*/
static inline void ssd1963_data(uint8_t data)
{
LV_DRV_DISP_PAR_CS(0);
ssd1963_data_mode();
LV_DRV_DISP_PAR_WR_WORD(data);
LV_DRV_DISP_PAR_CS(1);
}
#endif

View File

@ -0,0 +1,150 @@
/**
* @file SSD1963.h
*
*/
#ifndef SSD1963_H
#define SSD1963_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_SSD1963
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
// SSD1963 command table
#define CMD_NOP 0x00 //No operation
#define CMD_SOFT_RESET 0x01 //Software reset
#define CMD_GET_PWR_MODE 0x0A //Get the current power mode
#define CMD_GET_ADDR_MODE 0x0B //Get the frame memory to the display panel read order
#define CMD_GET_PIXEL_FORMAT 0x0C //Get the current pixel format
#define CMD_GET_DISPLAY_MODE 0x0D //Returns the display mode
#define CMD_GET_SIGNAL_MODE 0x0E //
#define CMD_GET_DIAGNOSTIC 0x0F
#define CMD_ENT_SLEEP 0x10
#define CMD_EXIT_SLEEP 0x11
#define CMD_ENT_PARTIAL_MODE 0x12
#define CMD_ENT_NORMAL_MODE 0x13
#define CMD_EXIT_INVERT_MODE 0x20
#define CMD_ENT_INVERT_MODE 0x21
#define CMD_SET_GAMMA 0x26
#define CMD_BLANK_DISPLAY 0x28
#define CMD_ON_DISPLAY 0x29
#define CMD_SET_COLUMN 0x2A
#define CMD_SET_PAGE 0x2B
#define CMD_WR_MEMSTART 0x2C
#define CMD_RD_MEMSTART 0x2E
#define CMD_SET_PARTIAL_AREA 0x30
#define CMD_SET_SCROLL_AREA 0x33
#define CMD_SET_TEAR_OFF 0x34 //synchronization information is not sent from the display
#define CMD_SET_TEAR_ON 0x35 //sync. information is sent from the display
#define CMD_SET_ADDR_MODE 0x36 //set fram buffer read order to the display panel
#define CMD_SET_SCROLL_START 0x37
#define CMD_EXIT_IDLE_MODE 0x38
#define CMD_ENT_IDLE_MODE 0x39
#define CMD_SET_PIXEL_FORMAT 0x3A //defines how many bits per pixel is used
#define CMD_WR_MEM_AUTO 0x3C
#define CMD_RD_MEM_AUTO 0x3E
#define CMD_SET_TEAR_SCANLINE 0x44
#define CMD_GET_SCANLINE 0x45
#define CMD_RD_DDB_START 0xA1
#define CMD_RD_DDB_AUTO 0xA8
#define CMD_SET_PANEL_MODE 0xB0
#define CMD_GET_PANEL_MODE 0xB1
#define CMD_SET_HOR_PERIOD 0xB4
#define CMD_GET_HOR_PERIOD 0xB5
#define CMD_SET_VER_PERIOD 0xB6
#define CMD_GET_VER_PERIOD 0xB7
#define CMD_SET_GPIO_CONF 0xB8
#define CMD_GET_GPIO_CONF 0xB9
#define CMD_SET_GPIO_VAL 0xBA
#define CMD_GET_GPIO_STATUS 0xBB
#define CMD_SET_POST_PROC 0xBC
#define CMD_GET_POST_PROC 0xBD
#define CMD_SET_PWM_CONF 0xBE
#define CMD_GET_PWM_CONF 0xBF
#define CMD_SET_LCD_GEN0 0xC0
#define CMD_GET_LCD_GEN0 0xC1
#define CMD_SET_LCD_GEN1 0xC2
#define CMD_GET_LCD_GEN1 0xC3
#define CMD_SET_LCD_GEN2 0xC4
#define CMD_GET_LCD_GEN2 0xC5
#define CMD_SET_LCD_GEN3 0xC6
#define CMD_GET_LCD_GEN3 0xC7
#define CMD_SET_GPIO0_ROP 0xC8
#define CMD_GET_GPIO0_ROP 0xC9
#define CMD_SET_GPIO1_ROP 0xCA
#define CMD_GET_GPIO1_ROP 0xCB
#define CMD_SET_GPIO2_ROP 0xCC
#define CMD_GET_GPIO2_ROP 0xCD
#define CMD_SET_GPIO3_ROP 0xCE
#define CMD_GET_GPIO3_ROP 0xCF
#define CMD_SET_ABC_DBC_CONF 0xD0
#define CMD_GET_ABC_DBC_CONF 0xD1
#define CMD_SET_DBC_HISTO_PTR 0xD2
#define CMD_GET_DBC_HISTO_PTR 0xD3
#define CMD_SET_DBC_THRES 0xD4
#define CMD_GET_DBC_THRES 0xD5
#define CMD_SET_ABM_TMR 0xD6
#define CMD_GET_ABM_TMR 0xD7
#define CMD_SET_AMB_LVL0 0xD8
#define CMD_GET_AMB_LVL0 0xD9
#define CMD_SET_AMB_LVL1 0xDA
#define CMD_GET_AMB_LVL1 0xDB
#define CMD_SET_AMB_LVL2 0xDC
#define CMD_GET_AMB_LVL2 0xDD
#define CMD_SET_AMB_LVL3 0xDE
#define CMD_GET_AMB_LVL3 0xDF
#define CMD_PLL_START 0xE0 //start the PLL
#define CMD_PLL_STOP 0xE1 //disable the PLL
#define CMD_SET_PLL_MN 0xE2
#define CMD_GET_PLL_MN 0xE3
#define CMD_GET_PLL_STATUS 0xE4 //get the current PLL status
#define CMD_ENT_DEEP_SLEEP 0xE5
#define CMD_SET_PCLK 0xE6 //set pixel clock (LSHIFT signal) frequency
#define CMD_GET_PCLK 0xE7 //get pixel clock (LSHIFT signal) freq. settings
#define CMD_SET_DATA_INTERFACE 0xF0
#define CMD_GET_DATA_INTERFACE 0xF1
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void ssd1963_init(void);
void ssd1963_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_SSD1963 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SSD1963_H */

View File

@ -0,0 +1,289 @@
/**
* @file ST7565.c
*
*/
/*********************
* INCLUDES
*********************/
#include "ST7565.h"
#if USE_ST7565
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "lvgl/lv_core/lv_vdb.h"
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define ST7565_BAUD 2000000 /*< 2,5 MHz (400 ns)*/
#define ST7565_CMD_MODE 0
#define ST7565_DATA_MODE 1
#define ST7565_HOR_RES 128
#define ST7565_VER_RES 64
#define CMD_DISPLAY_OFF 0xAE
#define CMD_DISPLAY_ON 0xAF
#define CMD_SET_DISP_START_LINE 0x40
#define CMD_SET_PAGE 0xB0
#define CMD_SET_COLUMN_UPPER 0x10
#define CMD_SET_COLUMN_LOWER 0x00
#define CMD_SET_ADC_NORMAL 0xA0
#define CMD_SET_ADC_REVERSE 0xA1
#define CMD_SET_DISP_NORMAL 0xA6
#define CMD_SET_DISP_REVERSE 0xA7
#define CMD_SET_ALLPTS_NORMAL 0xA4
#define CMD_SET_ALLPTS_ON 0xA5
#define CMD_SET_BIAS_9 0xA2
#define CMD_SET_BIAS_7 0xA3
#define CMD_RMW 0xE0
#define CMD_RMW_CLEAR 0xEE
#define CMD_INTERNAL_RESET 0xE2
#define CMD_SET_COM_NORMAL 0xC0
#define CMD_SET_COM_REVERSE 0xC8
#define CMD_SET_POWER_CONTROL 0x28
#define CMD_SET_RESISTOR_RATIO 0x20
#define CMD_SET_VOLUME_FIRST 0x81
#define CMD_SET_VOLUME_SECOND 0x00
#define CMD_SET_STATIC_OFF 0xAC
#define CMD_SET_STATIC_ON 0xAD
#define CMD_SET_STATIC_REG 0x00
#define CMD_SET_BOOSTER_FIRST 0xF8
#define CMD_SET_BOOSTER_234 0x00
#define CMD_SET_BOOSTER_5 0x01
#define CMD_SET_BOOSTER_6 0x03
#define CMD_NOP 0xE3
#define CMD_TEST 0xF0
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2);
static void st7565_command(uint8_t cmd);
static void st7565_data(uint8_t data);
/**********************
* STATIC VARIABLES
**********************/
static uint8_t lcd_fb[ST7565_HOR_RES * ST7565_VER_RES / 8] = {0xAA, 0xAA};
static uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the ST7565
*/
void st7565_init(void)
{
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_RST(0);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_RST(1);
LV_DRV_DELAY_MS(10);
LV_DRV_DISP_SPI_CS(0);
st7565_command(CMD_SET_BIAS_7);
st7565_command(CMD_SET_ADC_NORMAL);
st7565_command(CMD_SET_COM_NORMAL);
st7565_command(CMD_SET_DISP_START_LINE);
st7565_command(CMD_SET_POWER_CONTROL | 0x4);
LV_DRV_DELAY_MS(50);
st7565_command(CMD_SET_POWER_CONTROL | 0x6);
LV_DRV_DELAY_MS(50);
st7565_command(CMD_SET_POWER_CONTROL | 0x7);
LV_DRV_DELAY_MS(10);
st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); // Defaulted to 0x26 (but could also be between 0x20-0x27 based on display's specs)
st7565_command(CMD_DISPLAY_ON);
st7565_command(CMD_SET_ALLPTS_NORMAL);
/*Set brightness*/
st7565_command(CMD_SET_VOLUME_FIRST);
st7565_command(CMD_SET_VOLUME_SECOND | (0x18 & 0x3f));
LV_DRV_DISP_SPI_CS(1);
memset(lcd_fb, 0x00, sizeof(lcd_fb));
}
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
/*Set the first row in */
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(lv_color_to1(*color_p) != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
}
color_p ++;
}
color_p += x2 - act_x2; /*Next row*/
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
lv_flush_ready();
}
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
uint8_t white = lv_color_to1(color);
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(white != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
}
}
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
}
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
/*Return if the area is out the screen*/
if(x2 < 0) return;
if(y2 < 0) return;
if(x1 > ST7565_HOR_RES - 1) return;
if(y1 > ST7565_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = x1 < 0 ? 0 : x1;
int32_t act_y1 = y1 < 0 ? 0 : y1;
int32_t act_x2 = x2 > ST7565_HOR_RES - 1 ? ST7565_HOR_RES - 1 : x2;
int32_t act_y2 = y2 > ST7565_VER_RES - 1 ? ST7565_VER_RES - 1 : y2;
int32_t x, y;
/*Set the first row in */
/*Refresh frame buffer*/
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
if(lv_color_to1(*color_p) != 0) {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] &= ~(1 << (7 - (y % 8)));
} else {
lcd_fb[x + (y / 8)*ST7565_HOR_RES] |= (1 << (7 - (y % 8)));
}
color_p ++;
}
color_p += x2 - act_x2; /*Next row*/
}
st7565_sync(act_x1, act_y1, act_x2, act_y2);
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Flush a specific part of the buffer to the display
* @param x1 left coordinate of the area to flush
* @param y1 top coordinate of the area to flush
* @param x2 right coordinate of the area to flush
* @param y2 bottom coordinate of the area to flush
*/
static void st7565_sync(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
{
LV_DRV_DISP_SPI_CS(0);
uint8_t c, p;
for(p = y1 / 8; p <= y2 / 8; p++) {
st7565_command(CMD_SET_PAGE | pagemap[p]);
st7565_command(CMD_SET_COLUMN_LOWER | (x1 & 0xf));
st7565_command(CMD_SET_COLUMN_UPPER | ((x1 >> 4) & 0xf));
st7565_command(CMD_RMW);
for(c = x1; c <= x2; c++) {
st7565_data(lcd_fb[(ST7565_HOR_RES * p) + c]);
}
}
LV_DRV_DISP_SPI_CS(1);
}
/**
* Write a command to the ST7565
* @param cmd the command
*/
static void st7565_command(uint8_t cmd)
{
LV_DRV_DISP_CMD_DATA(ST7565_CMD_MODE);
LV_DRV_DISP_SPI_WR_BYTE(cmd);
}
/**
* Write data to the ST7565
* @param data the data
*/
static void st7565_data(uint8_t data)
{
LV_DRV_DISP_CMD_DATA(ST7565_DATA_MODE);
LV_DRV_DISP_SPI_WR_BYTE(data);
}
#endif

View File

@ -0,0 +1,58 @@
/**
* @file ST7565.h
*
*/
#ifndef ST7565_H
#define ST7565_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_ST7565
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void st7565_init(void);
void st7565_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
void st7565_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color);
void st7565_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_ST7565 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ST7565_H */

View File

@ -0,0 +1,206 @@
/**
* @file UC1610.c
*
*/
/*********************
* INCLUDES
*********************/
#include "UC1610.h"
#if USE_UC1610
#include <stdbool.h>
#include LV_DRV_DISP_INCLUDE
#include LV_DRV_DELAY_INCLUDE
/*********************
* DEFINES
*********************/
#define UC1610_CMD_MODE 0
#define UC1610_DATA_MODE 1
#define UC1610_RESET_MODE 0
#define UC1610_SET_MODE 1
/* hardware control commands */
#define UC1610_SYSTEM_RESET 0xE2 /* software reset */
#define UC1610_NOP 0xE3
#define UC1610_SET_TEMP_COMP 0x24 /* set temperature compensation, default -0.05%/°C */
#define UC1610_SET_PANEL_LOADING 0x29 /* set panel loading, default 16~21 nF */
#define UC1610_SET_PUMP_CONTROL 0x2F /* default internal Vlcd (8x pump) */
#define UC1610_SET_LCD_BIAS_RATIO 0xEB /* default 11 */
#define UC1610_SET_VBIAS_POT 0x81 /* 1 byte (0~255) to follow setting the contrast, default 0x81 */
#define UC1610_SET_LINE_RATE 0xA0 /* default 12,1 Klps */
#define UC1610_SET_DISPLAY_ENABLE 0xAE /* + 1 / 0 : exit sleep mode / entering sleep mode */
#define UC1610_SET_LCD_GRAY_SHADE 0xD0 /* default 24% between the two gray shade levels */
#define UC1610_SET_COM_END 0xF1 /* set the number of used com electrodes (lines number -1) */
/* ram address control */
#define UC1610_SET_AC 0x88 /* set ram address control */
#define UC1610_AC_WA_FLAG 1 /* automatic column/page increment wrap around (1 : cycle increment) */
#define UC1610_AC_AIO_FLAG (1 << 1) /* auto increment order (0/1 : column/page increment first) */
#define UC1610_AC_PID_FLAG (1 << 2) /* page address auto increment order (0/1 : +1/-1) */
/* set cursor ram address */
#define UC1610_SET_CA_LSB 0x00 /* + 4 LSB bits */
#define UC1610_SET_CA_MSB 0x10 /* + 4 MSB bits // MSB + LSB values range : 0~159 */
#define UC1610_SET_PA 0x60 /* + 5 bits // values range : 0~26 */
/* display control commands */
#define UC1610_SET_FIXED_LINES 0x90 /* + 4 bits = 2xFL */
#define UC1610_SET_SCROLL_LINES_LSB 0x40 /* + 4 LSB bits scroll up display by N (7 bits) lines */
#define UC1610_SET_SCROLL_LINES_MSB 0x50 /* + 3 MSB bits */
#define UC1610_SET_ALL_PIXEL_ON 0xA4 /* + 1 / 0 : set all pixel on, reverse */
#define UC1610_SET_INVERSE_DISPLAY 0xA6 /* + 1 / 0 : inverse all data stored in ram, reverse */
#define UC1610_SET_MAPPING_CONTROL 0xC0 /* control mirorring */
#define UC1610_SET_MAPPING_CONTROL_LC_FLAG 1
#define UC1610_SET_MAPPING_CONTROL_MX_FLAG (1 << 1)
#define UC1610_SET_MAPPING_CONTROL_MY_FLAG (1 << 2)
/* window program mode */
#define UC1610_SET_WINDOW_PROGRAM_ENABLE 0xF8 /* + 1 / 0 : enable / disable window programming mode, */
/* reset before changing boundaries */
#define UC1610_SET_WP_STARTING_CA 0xF4 /* 1 byte to follow for column address */
#define UC1610_SET_WP_ENDING_CA 0xF6 /* 1 byte to follow for column address */
#define UC1610_SET_WP_STARTING_PA 0xF5 /* 1 byte to follow for page address */
#define UC1610_SET_WP_ENDING_PA 0xF7 /* 1 byte to follow for page address */
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
static uint8_t cmd_buf[12];
/**********************
* MACROS
**********************/
/* Return the byte bitmask of a pixel color corresponding to draw_buf arrangement */
#define PIXIDX(y, c) ((c) << (((y) & 3) << 1))
/**********************
* GLOBAL FUNCTIONS
**********************/
void uc1610_init(void) {
LV_DRV_DELAY_MS(12);
/* initialization sequence */
#if UC1610_INIT_HARD_RST
LV_DRV_DISP_RST(UC1610_RESET_MODE); /* hardware reset */
LV_DRV_DELAY_MS(1);
LV_DRV_DISP_RST(UC1610_SET_MODE);
#else
cmd_buf[0] = UC1610_SYSTEM_RESET; /* software reset */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 1);
LV_DRV_DISP_SPI_CS(1);
#endif
LV_DRV_DELAY_MS(2);
cmd_buf[0] = UC1610_SET_COM_END; /* set com end value */
cmd_buf[1] = UC1610_VER_RES - 1;
cmd_buf[2] = UC1610_SET_PANEL_LOADING;
cmd_buf[3] = UC1610_SET_LCD_BIAS_RATIO;
cmd_buf[4] = UC1610_SET_VBIAS_POT; /* set contrast */
cmd_buf[5] = (UC1610_INIT_CONTRAST * 255) / 100;
#if UC1610_TOP_VIEW
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL | /* top view */
UC1610_SET_MAPPING_CONTROL_MY_FLAG |
UC1610_SET_MAPPING_CONTROL_MX_FLAG;
#else
cmd_buf[6] = UC1610_SET_MAPPING_CONTROL; /* bottom view */
#endif
cmd_buf[7] = UC1610_SET_SCROLL_LINES_LSB | 0; /* set scroll line on line 0 */
cmd_buf[8] = UC1610_SET_SCROLL_LINES_MSB | 0;
cmd_buf[9] = UC1610_SET_AC | UC1610_AC_WA_FLAG; /* set auto increment wrap around */
cmd_buf[10] = UC1610_SET_INVERSE_DISPLAY | 1; /* invert colors to complies lv color system */
cmd_buf[11] = UC1610_SET_DISPLAY_ENABLE | 1; /* turn display on */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 12);
LV_DRV_DISP_SPI_CS(1);
}
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {
/*Return if the area is out the screen*/
if(area->x2 < 0) return;
if(area->y2 < 0) return;
if(area->x1 > UC1610_HOR_RES - 1) return;
if(area->y1 > UC1610_VER_RES - 1) return;
/*Truncate the area to the screen*/
uint8_t act_x1 = area->x1 < 0 ? 0 : area->x1;
uint8_t act_y1 = area->y1 < 0 ? 0 : area->y1;
uint8_t act_x2 = area->x2 > UC1610_HOR_RES - 1 ? UC1610_HOR_RES - 1 : area->x2;
uint8_t act_y2 = area->y2 > UC1610_VER_RES - 1 ? UC1610_VER_RES - 1 : area->y2;
uint8_t * buf = (uint8_t *) color_p;
uint16_t buf_size = (act_x2 - act_x1 + 1) * (((act_y2 - act_y1) >> 2) + 1);
/*Set display window to fill*/
cmd_buf[0] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 0; /* before changing boundaries */
cmd_buf[1] = UC1610_SET_WP_STARTING_CA;
cmd_buf[2] = act_x1;
cmd_buf[3] = UC1610_SET_WP_ENDING_CA;
cmd_buf[4] = act_x2;
cmd_buf[5] = UC1610_SET_WP_STARTING_PA;
cmd_buf[6] = act_y1 >> 2;
cmd_buf[7] = UC1610_SET_WP_ENDING_PA;
cmd_buf[8] = act_y2 >> 2;
cmd_buf[9] = UC1610_SET_WINDOW_PROGRAM_ENABLE | 1; /* entering window programming */
LV_DRV_DISP_CMD_DATA(UC1610_CMD_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(cmd_buf, 10);
LV_DRV_DISP_SPI_CS(1);
/*Flush draw_buf on display memory*/
LV_DRV_DISP_CMD_DATA(UC1610_DATA_MODE);
LV_DRV_DISP_SPI_CS(0);
LV_DRV_DISP_SPI_WR_ARRAY(buf, buf_size);
LV_DRV_DISP_SPI_CS(1);
lv_disp_flush_ready(disp_drv);
}
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa) {
(void) disp_drv;
(void) opa;
uint16_t idx = x + buf_w * (y >> 2);
/* Convert color to depth 2 */
#if LV_COLOR_DEPTH == 1
uint8_t color2 = color.full * 3;
#else
uint8_t color2 = color.full >> (LV_COLOR_DEPTH - 2);
#endif
buf[idx] &= ~PIXIDX(y, 3); /* reset pixel color */
buf[idx] |= PIXIDX(y, color2); /* write new color */
}
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area) {
(void) disp_drv;
/* Round y window to display memory page size */
area->y1 = (area->y1 & (~3));
area->y2 = (area->y2 & (~3)) + 3;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -0,0 +1,58 @@
/**
* @file UC1610.h
*
*/
#ifndef UC1610_H
#define UC1610_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_UC1610
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void uc1610_init(void);
void uc1610_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void uc1610_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area);
void uc1610_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
/**********************
* MACROS
**********************/
#endif /* USE_UC1610 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UC1610_H */

View File

@ -0,0 +1,796 @@
/**
* @file drm.c
*
*/
/*********************
* INCLUDES
*********************/
#include "drm.h"
#if USE_DRM
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <inttypes.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#define DBG_TAG "drm"
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define print(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__);
#define err(msg, ...) print("error: " msg "\n", ##__VA_ARGS__)
#define info(msg, ...) print(msg "\n", ##__VA_ARGS__)
#define dbg(msg, ...) {} //print(DBG_TAG ": " msg "\n", ##__VA_ARGS__)
struct drm_buffer {
uint32_t handle;
uint32_t pitch;
uint32_t offset;
unsigned long int size;
void * map;
uint32_t fb_handle;
};
struct drm_dev {
int fd;
uint32_t conn_id, enc_id, crtc_id, plane_id, crtc_idx;
uint32_t width, height;
uint32_t mmWidth, mmHeight;
uint32_t fourcc;
drmModeModeInfo mode;
uint32_t blob_id;
drmModeCrtc *saved_crtc;
drmModeAtomicReq *req;
drmEventContext drm_event_ctx;
drmModePlane *plane;
drmModeCrtc *crtc;
drmModeConnector *conn;
uint32_t count_plane_props;
uint32_t count_crtc_props;
uint32_t count_conn_props;
drmModePropertyPtr plane_props[128];
drmModePropertyPtr crtc_props[128];
drmModePropertyPtr conn_props[128];
struct drm_buffer drm_bufs[2]; /* DUMB buffers */
struct drm_buffer *cur_bufs[2]; /* double buffering handling */
} drm_dev;
static uint32_t get_plane_property_id(const char *name)
{
uint32_t i;
dbg("Find plane property: %s", name);
for (i = 0; i < drm_dev.count_plane_props; ++i)
if (!strcmp(drm_dev.plane_props[i]->name, name))
return drm_dev.plane_props[i]->prop_id;
dbg("Unknown plane property: %s", name);
return 0;
}
static uint32_t get_crtc_property_id(const char *name)
{
uint32_t i;
dbg("Find crtc property: %s", name);
for (i = 0; i < drm_dev.count_crtc_props; ++i)
if (!strcmp(drm_dev.crtc_props[i]->name, name))
return drm_dev.crtc_props[i]->prop_id;
dbg("Unknown crtc property: %s", name);
return 0;
}
static uint32_t get_conn_property_id(const char *name)
{
uint32_t i;
dbg("Find conn property: %s", name);
for (i = 0; i < drm_dev.count_conn_props; ++i)
if (!strcmp(drm_dev.conn_props[i]->name, name))
return drm_dev.conn_props[i]->prop_id;
dbg("Unknown conn property: %s", name);
return 0;
}
static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
unsigned int tv_usec, void *user_data)
{
dbg("flip");
}
static int drm_get_plane_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.plane_id,
DRM_MODE_OBJECT_PLANE);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u plane props", props->count_props);
drm_dev.count_plane_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.plane_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added plane prop %u:%s", drm_dev.plane_props[i]->prop_id, drm_dev.plane_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_get_crtc_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u crtc props", props->count_props);
drm_dev.count_crtc_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.crtc_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added crtc prop %u:%s", drm_dev.crtc_props[i]->prop_id, drm_dev.crtc_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_get_conn_props(void)
{
uint32_t i;
drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.conn_id,
DRM_MODE_OBJECT_CONNECTOR);
if (!props) {
err("drmModeObjectGetProperties failed");
return -1;
}
dbg("Found %u connector props", props->count_props);
drm_dev.count_conn_props = props->count_props;
for (i = 0; i < props->count_props; i++) {
drm_dev.conn_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
dbg("Added connector prop %u:%s", drm_dev.conn_props[i]->prop_id, drm_dev.conn_props[i]->name);
}
drmModeFreeObjectProperties(props);
return 0;
}
static int drm_add_plane_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_plane_property_id(name);
if (!prop_id) {
err("Couldn't find plane prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.plane_id, get_plane_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_add_crtc_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_crtc_property_id(name);
if (!prop_id) {
err("Couldn't find crtc prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.crtc_id, get_crtc_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_add_conn_property(const char *name, uint64_t value)
{
int ret;
uint32_t prop_id = get_conn_property_id(name);
if (!prop_id) {
err("Couldn't find conn prop %s", name);
return -1;
}
ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.conn_id, get_conn_property_id(name), value);
if (ret < 0) {
err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
return ret;
}
return 0;
}
static int drm_dmabuf_set_plane(struct drm_buffer *buf)
{
int ret;
static int first = 1;
uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
drm_dev.req = drmModeAtomicAlloc();
/* On first Atomic commit, do a modeset */
if (first) {
drm_add_conn_property("CRTC_ID", drm_dev.crtc_id);
drm_add_crtc_property("MODE_ID", drm_dev.blob_id);
drm_add_crtc_property("ACTIVE", 1);
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
first = 0;
}
drm_add_plane_property("FB_ID", buf->fb_handle);
drm_add_plane_property("CRTC_ID", drm_dev.crtc_id);
drm_add_plane_property("SRC_X", 0);
drm_add_plane_property("SRC_Y", 0);
drm_add_plane_property("SRC_W", drm_dev.width << 16);
drm_add_plane_property("SRC_H", drm_dev.height << 16);
drm_add_plane_property("CRTC_X", 0);
drm_add_plane_property("CRTC_Y", 0);
drm_add_plane_property("CRTC_W", drm_dev.width);
drm_add_plane_property("CRTC_H", drm_dev.height);
ret = drmModeAtomicCommit(drm_dev.fd, drm_dev.req, flags, NULL);
if (ret) {
err("drmModeAtomicCommit failed: %s", strerror(errno));
drmModeAtomicFree(drm_dev.req);
return ret;
}
return 0;
}
static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
{
drmModePlaneResPtr planes;
drmModePlanePtr plane;
unsigned int i;
unsigned int j;
int ret = 0;
unsigned int format = fourcc;
planes = drmModeGetPlaneResources(drm_dev.fd);
if (!planes) {
err("drmModeGetPlaneResources failed");
return -1;
}
dbg("drm: found planes %u", planes->count_planes);
for (i = 0; i < planes->count_planes; ++i) {
plane = drmModeGetPlane(drm_dev.fd, planes->planes[i]);
if (!plane) {
err("drmModeGetPlane failed: %s", strerror(errno));
break;
}
if (!(plane->possible_crtcs & (1 << crtc_idx))) {
drmModeFreePlane(plane);
continue;
}
for (j = 0; j < plane->count_formats; ++j) {
if (plane->formats[j] == format)
break;
}
if (j == plane->count_formats) {
drmModeFreePlane(plane);
continue;
}
*plane_id = plane->plane_id;
drmModeFreePlane(plane);
dbg("found plane %d", *plane_id);
break;
}
if (i == planes->count_planes)
ret = -1;
drmModeFreePlaneResources(planes);
return ret;
}
static int drm_find_connector(void)
{
drmModeConnector *conn = NULL;
drmModeEncoder *enc = NULL;
drmModeRes *res;
int i;
if ((res = drmModeGetResources(drm_dev.fd)) == NULL) {
err("drmModeGetResources() failed");
return -1;
}
if (res->count_crtcs <= 0) {
err("no Crtcs");
goto free_res;
}
/* find all available connectors */
for (i = 0; i < res->count_connectors; i++) {
conn = drmModeGetConnector(drm_dev.fd, res->connectors[i]);
if (!conn)
continue;
#if DRM_CONNECTOR_ID >= 0
if (conn->connector_id != DRM_CONNECTOR_ID) {
drmModeFreeConnector(conn);
continue;
}
#endif
if (conn->connection == DRM_MODE_CONNECTED) {
dbg("drm: connector %d: connected", conn->connector_id);
} else if (conn->connection == DRM_MODE_DISCONNECTED) {
dbg("drm: connector %d: disconnected", conn->connector_id);
} else if (conn->connection == DRM_MODE_UNKNOWNCONNECTION) {
dbg("drm: connector %d: unknownconnection", conn->connector_id);
} else {
dbg("drm: connector %d: unknown", conn->connector_id);
}
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
break;
drmModeFreeConnector(conn);
conn = NULL;
};
if (!conn) {
err("suitable connector not found");
goto free_res;
}
drm_dev.conn_id = conn->connector_id;
dbg("conn_id: %d", drm_dev.conn_id);
drm_dev.mmWidth = conn->mmWidth;
drm_dev.mmHeight = conn->mmHeight;
memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
&drm_dev.blob_id)) {
err("error creating mode blob");
goto free_res;
}
drm_dev.width = conn->modes[0].hdisplay;
drm_dev.height = conn->modes[0].vdisplay;
for (i = 0 ; i < res->count_encoders; i++) {
enc = drmModeGetEncoder(drm_dev.fd, res->encoders[i]);
if (!enc)
continue;
dbg("enc%d enc_id %d conn enc_id %d", i, enc->encoder_id, conn->encoder_id);
if (enc->encoder_id == conn->encoder_id)
break;
drmModeFreeEncoder(enc);
enc = NULL;
}
if (enc) {
drm_dev.enc_id = enc->encoder_id;
dbg("enc_id: %d", drm_dev.enc_id);
drm_dev.crtc_id = enc->crtc_id;
dbg("crtc_id: %d", drm_dev.crtc_id);
drmModeFreeEncoder(enc);
} else {
/* Encoder hasn't been associated yet, look it up */
for (i = 0; i < conn->count_encoders; i++) {
int crtc, crtc_id = -1;
enc = drmModeGetEncoder(drm_dev.fd, conn->encoders[i]);
if (!enc)
continue;
for (crtc = 0 ; crtc < res->count_crtcs; crtc++) {
uint32_t crtc_mask = 1 << crtc;
crtc_id = res->crtcs[crtc];
dbg("enc_id %d crtc%d id %d mask %x possible %x", enc->encoder_id, crtc, crtc_id, crtc_mask, enc->possible_crtcs);
if (enc->possible_crtcs & crtc_mask)
break;
}
if (crtc_id > 0) {
drm_dev.enc_id = enc->encoder_id;
dbg("enc_id: %d", drm_dev.enc_id);
drm_dev.crtc_id = crtc_id;
dbg("crtc_id: %d", drm_dev.crtc_id);
break;
}
drmModeFreeEncoder(enc);
enc = NULL;
}
if (!enc) {
err("suitable encoder not found");
goto free_res;
}
drmModeFreeEncoder(enc);
}
drm_dev.crtc_idx = -1;
for (i = 0; i < res->count_crtcs; ++i) {
if (drm_dev.crtc_id == res->crtcs[i]) {
drm_dev.crtc_idx = i;
break;
}
}
if (drm_dev.crtc_idx == -1) {
err("drm: CRTC not found");
goto free_res;
}
dbg("crtc_idx: %d", drm_dev.crtc_idx);
return 0;
free_res:
drmModeFreeResources(res);
return -1;
}
static int drm_open(const char *path)
{
int fd, flags;
uint64_t has_dumb;
int ret;
fd = open(path, O_RDWR);
if (fd < 0) {
err("cannot open \"%s\"", path);
return -1;
}
/* set FD_CLOEXEC flag */
if ((flags = fcntl(fd, F_GETFD)) < 0 ||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
err("fcntl FD_CLOEXEC failed");
goto err;
}
/* check capability */
ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
if (ret < 0 || has_dumb == 0) {
err("drmGetCap DRM_CAP_DUMB_BUFFER failed or doesn't have dumb "
"buffer");
goto err;
}
return fd;
err:
close(fd);
return -1;
}
static int drm_setup(unsigned int fourcc)
{
int ret;
drm_dev.fd = drm_open(DRM_CARD);
if (drm_dev.fd < 0)
return -1;
ret = drmSetClientCap(drm_dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
if (ret) {
err("No atomic modesetting support: %s", strerror(errno));
goto err;
}
ret = drm_find_connector();
if (ret) {
err("available drm devices not found");
goto err;
}
ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
if (ret) {
err("Cannot find plane");
goto err;
}
drm_dev.plane = drmModeGetPlane(drm_dev.fd, drm_dev.plane_id);
if (!drm_dev.plane) {
err("Cannot get plane");
goto err;
}
drm_dev.crtc = drmModeGetCrtc(drm_dev.fd, drm_dev.crtc_id);
if (!drm_dev.crtc) {
err("Cannot get crtc");
goto err;
}
drm_dev.conn = drmModeGetConnector(drm_dev.fd, drm_dev.conn_id);
if (!drm_dev.conn) {
err("Cannot get connector");
goto err;
}
ret = drm_get_plane_props();
if (ret) {
err("Cannot get plane props");
goto err;
}
ret = drm_get_crtc_props();
if (ret) {
err("Cannot get crtc props");
goto err;
}
ret = drm_get_conn_props();
if (ret) {
err("Cannot get connector props");
goto err;
}
drm_dev.drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
drm_dev.drm_event_ctx.page_flip_handler = page_flip_handler;
drm_dev.fourcc = fourcc;
info("drm: Found plane_id: %u connector_id: %d crtc_id: %d",
drm_dev.plane_id, drm_dev.conn_id, drm_dev.crtc_id);
info("drm: %dx%d (%dmm X% dmm) pixel format %c%c%c%c",
drm_dev.width, drm_dev.height, drm_dev.mmWidth, drm_dev.mmHeight,
(fourcc>>0)&0xff, (fourcc>>8)&0xff, (fourcc>>16)&0xff, (fourcc>>24)&0xff);
return 0;
err:
close(drm_dev.fd);
return -1;
}
static int drm_allocate_dumb(struct drm_buffer *buf)
{
struct drm_mode_create_dumb creq;
struct drm_mode_map_dumb mreq;
uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
int ret;
/* create dumb buffer */
memset(&creq, 0, sizeof(creq));
creq.width = drm_dev.width;
creq.height = drm_dev.height;
creq.bpp = LV_COLOR_DEPTH;
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
if (ret < 0) {
err("DRM_IOCTL_MODE_CREATE_DUMB fail");
return -1;
}
buf->handle = creq.handle;
buf->pitch = creq.pitch;
dbg("pitch %d", buf->pitch);
buf->size = creq.size;
dbg("size %d", buf->size);
/* prepare buffer for memory mapping */
memset(&mreq, 0, sizeof(mreq));
mreq.handle = creq.handle;
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) {
err("DRM_IOCTL_MODE_MAP_DUMB fail");
return -1;
}
buf->offset = mreq.offset;
/* perform actual memory mapping */
buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
if (buf->map == MAP_FAILED) {
err("mmap fail");
return -1;
}
/* clear the framebuffer to 0 (= full transparency in ARGB8888) */
memset(buf->map, 0, creq.size);
/* create framebuffer object for the dumb-buffer */
handles[0] = creq.handle;
pitches[0] = creq.pitch;
offsets[0] = 0;
ret = drmModeAddFB2(drm_dev.fd, drm_dev.width, drm_dev.height, drm_dev.fourcc,
handles, pitches, offsets, &buf->fb_handle, 0);
if (ret) {
err("drmModeAddFB fail");
return -1;
}
return 0;
}
static int drm_setup_buffers(void)
{
int ret;
/* Allocate DUMB buffers */
ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
if (ret)
return ret;
ret = drm_allocate_dumb(&drm_dev.drm_bufs[1]);
if (ret)
return ret;
/* Set buffering handling */
drm_dev.cur_bufs[0] = NULL;
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
return 0;
}
void drm_wait_vsync(lv_disp_drv_t *disp_drv)
{
int ret;
fd_set fds;
FD_ZERO(&fds);
FD_SET(drm_dev.fd, &fds);
do {
ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL);
} while (ret == -1 && errno == EINTR);
if (ret < 0) {
err("select failed: %s", strerror(errno));
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
return;
}
if (FD_ISSET(drm_dev.fd, &fds))
drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
}
void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
struct drm_buffer *fbuf = drm_dev.cur_bufs[1];
lv_coord_t w = (area->x2 - area->x1 + 1);
lv_coord_t h = (area->y2 - area->y1 + 1);
int i, y;
dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h);
/* Partial update */
if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0])
memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size);
for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) {
memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i),
(uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
w * (LV_COLOR_SIZE/8));
}
if (drm_dev.req)
drm_wait_vsync(disp_drv);
/* show fbuf plane */
if (drm_dmabuf_set_plane(fbuf)) {
err("Flush fail");
return;
}
else
dbg("Flush done");
if (!drm_dev.cur_bufs[0])
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
else
drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
drm_dev.cur_bufs[0] = fbuf;
lv_disp_flush_ready(disp_drv);
}
#if LV_COLOR_DEPTH == 32
#define DRM_FOURCC DRM_FORMAT_ARGB8888
#elif LV_COLOR_DEPTH == 16
#define DRM_FOURCC DRM_FORMAT_RGB565
#else
#error LV_COLOR_DEPTH not supported
#endif
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
{
if (width)
*width = drm_dev.width;
if (height)
*height = drm_dev.height;
if (dpi && drm_dev.mmWidth)
*dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
}
void drm_init(void)
{
int ret;
ret = drm_setup(DRM_FOURCC);
if (ret) {
close(drm_dev.fd);
drm_dev.fd = -1;
return;
}
ret = drm_setup_buffers();
if (ret) {
err("DRM buffer allocation failed");
close(drm_dev.fd);
drm_dev.fd = -1;
return;
}
info("DRM subsystem and buffer mapped successfully");
}
void drm_exit(void)
{
close(drm_dev.fd);
drm_dev.fd = -1;
}
#endif

View File

@ -0,0 +1,60 @@
/**
* @file drm.h
*
*/
#ifndef DRM_H
#define DRM_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_DRM
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void drm_init(void);
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi);
void drm_exit(void);
void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void drm_wait_vsync(lv_disp_drv_t * drv);
/**********************
* MACROS
**********************/
#endif /*USE_DRM*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*DRM_H*/

View File

@ -0,0 +1,251 @@
/**
* @file fbdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "fbdev.h"
#if USE_FBDEV || USE_BSD_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#if USE_BSD_FBDEV
#include <sys/fcntl.h>
#include <sys/time.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else /* USE_BSD_FBDEV */
#include <linux/fb.h>
#endif /* USE_BSD_FBDEV */
/*********************
* DEFINES
*********************/
#ifndef FBDEV_PATH
#define FBDEV_PATH "/dev/fb0"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STRUCTURES
**********************/
struct bsd_fb_var_info{
uint32_t xoffset;
uint32_t yoffset;
uint32_t xres;
uint32_t yres;
int bits_per_pixel;
};
struct bsd_fb_fix_info{
long int line_length;
long int smem_len;
};
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if USE_BSD_FBDEV
static struct bsd_fb_var_info vinfo;
static struct bsd_fb_fix_info finfo;
#else
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
#endif /* USE_BSD_FBDEV */
static char *fbp = 0;
static long int screensize = 0;
static int fbfd = 0;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void fbdev_init(void)
{
// Open the file for reading and writing
fbfd = open(FBDEV_PATH, O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
return;
}
printf("The framebuffer device was opened successfully.\n");
#if USE_BSD_FBDEV
struct fbtype fb;
unsigned line_length;
//Get fb type
if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) {
perror("ioctl(FBIOGTYPE)");
return;
}
//Get screen width
if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
perror("ioctl(FBIO_GETLINEWIDTH)");
return;
}
vinfo.xres = (unsigned) fb.fb_width;
vinfo.yres = (unsigned) fb.fb_height;
vinfo.bits_per_pixel = fb.fb_depth;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
finfo.line_length = line_length;
finfo.smem_len = finfo.line_length * vinfo.yres;
#else /* USE_BSD_FBDEV */
// Get fixed screen information
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
return;
}
// Get variable screen information
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
return;
}
#endif /* USE_BSD_FBDEV */
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
// Figure out the size of the screen in bytes
screensize = finfo.smem_len; //finfo.line_length * vinfo.yres;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if((intptr_t)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
return;
}
memset(fbp, 0, screensize);
printf("The framebuffer device was mapped to memory successfully.\n");
}
void fbdev_exit(void)
{
close(fbfd);
}
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(fbp == NULL ||
area->x2 < 0 ||
area->y2 < 0 ||
area->x1 > (int32_t)vinfo.xres - 1 ||
area->y1 > (int32_t)vinfo.yres - 1) {
lv_disp_flush_ready(drv);
return;
}
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;
lv_coord_t w = (act_x2 - act_x1 + 1);
long int location = 0;
long int byte_location = 0;
unsigned char bit_location = 0;
/*32 or 24 bit per pixel*/
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {
uint32_t * fbp32 = (uint32_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 4;
memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
color_p += w;
}
}
/*16 bit per pixel*/
else if(vinfo.bits_per_pixel == 16) {
uint16_t * fbp16 = (uint16_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2;
memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2);
color_p += w;
}
}
/*8 bit per pixel*/
else if(vinfo.bits_per_pixel == 8) {
uint8_t * fbp8 = (uint8_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length;
memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1));
color_p += w;
}
}
/*1 bit per pixel*/
else if(vinfo.bits_per_pixel == 1) {
uint8_t * fbp8 = (uint8_t *)fbp;
int32_t x;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
for(x = act_x1; x <= act_x2; x++) {
location = (x + vinfo.xoffset) + (y + vinfo.yoffset) * vinfo.xres;
byte_location = location / 8; /* find the byte we need to change */
bit_location = location % 8; /* inside the byte found, find the bit we need to change */
fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location);
fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location;
color_p++;
}
color_p += area->x2 - act_x2;
}
} else {
/*Not supported bit per pixel*/
}
//May be some direct update command is required
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
lv_disp_flush_ready(drv);
}
void fbdev_get_sizes(uint32_t *width, uint32_t *height) {
if (width)
*width = vinfo.xres;
if (height)
*height = vinfo.yres;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@ -0,0 +1,59 @@
/**
* @file fbdev.h
*
*/
#ifndef FBDEV_H
#define FBDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_FBDEV || USE_BSD_FBDEV
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void fbdev_init(void);
void fbdev_exit(void);
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void fbdev_get_sizes(uint32_t *width, uint32_t *height);
/**********************
* MACROS
**********************/
#endif /*USE_FBDEV*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*FBDEV_H*/

View File

@ -0,0 +1,388 @@
/**
* @file monitor.c
*
*/
/*********************
* INCLUDES
*********************/
#include "monitor.h"
#if USE_MONITOR
#ifndef MONITOR_SDL_INCLUDE_PATH
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
#endif
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include MONITOR_SDL_INCLUDE_PATH
#include "../indev/mouse.h"
#include "../indev/keyboard.h"
#include "../indev/mousewheel.h"
/*********************
* DEFINES
*********************/
#define SDL_REFR_PERIOD 50 /*ms*/
#ifndef MONITOR_ZOOM
#define MONITOR_ZOOM 1
#endif
#ifndef MONITOR_HOR_RES
#define MONITOR_HOR_RES LV_HOR_RES
#endif
#ifndef MONITOR_VER_RES
#define MONITOR_VER_RES LV_VER_RES
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * texture;
volatile bool sdl_refr_qry;
#if MONITOR_DOUBLE_BUFFERED
uint32_t * tft_fb_act;
#else
uint32_t * tft_fb;
#endif
}monitor_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void window_create(monitor_t * m);
static void window_update(monitor_t * m);
int quit_filter(void * userdata, SDL_Event * event);
static void monitor_sdl_clean_up(void);
static void monitor_sdl_init(void);
static void sdl_event_handler(lv_timer_t * t);
static void monitor_sdl_refr(lv_timer_t * t);
/***********************
* GLOBAL PROTOTYPES
***********************/
/**********************
* STATIC VARIABLES
**********************/
monitor_t monitor;
#if MONITOR_DUAL
monitor_t monitor2;
#endif
static volatile bool sdl_inited = false;
static volatile bool sdl_quit_qry = false;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the monitor
*/
void monitor_init(void)
{
monitor_sdl_init();
lv_timer_create(sdl_event_handler, 10, NULL);
}
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t hres = disp_drv->hor_res;
lv_coord_t vres = disp_drv->ver_res;
// printf("x1:%d,y1:%d,x2:%d,y2:%d\n", area->x1, area->y1, area->x2, area->y2);
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if MONITOR_DOUBLE_BUFFERED
monitor.tft_fb_act = (uint32_t *)color_p;
#else /*MONITOR_DOUBLE_BUFFERED*/
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
for(x = area->x1; x <= area->x2; x++) {
monitor.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p);
color_p++;
}
}
#else
uint32_t w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
memcpy(&monitor.tft_fb[y * MONITOR_HOR_RES + area->x1], color_p, w * sizeof(lv_color_t));
color_p += w;
}
#endif
#endif /*MONITOR_DOUBLE_BUFFERED*/
monitor.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor_sdl_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
}
#if MONITOR_DUAL
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t hres = disp_drv->hor_res;
lv_coord_t vres = disp_drv->ver_res;
/*Return if the area is out the screen*/
if(area->x2 < 0 || area->y2 < 0 || area->x1 > hres - 1 || area->y1 > vres - 1) {
lv_disp_flush_ready(disp_drv);
return;
}
#if MONITOR_DOUBLE_BUFFERED
monitor2.tft_fb_act = (uint32_t *)color_p;
monitor2.sdl_refr_qry = true;
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#else
int32_t y;
#if LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 /*32 is valid but support 24 for backward compatibility too*/
int32_t x;
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
for(x = area->x1; x <= area->x2; x++) {
monitor2.tft_fb[y * disp_drv->hor_res + x] = lv_color_to32(*color_p);
color_p++;
}
}
#else
uint32_t w = lv_area_get_width(area);
for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
memcpy(&monitor2.tft_fb[y * disp_drv->hor_res + area->x1], color_p, w * sizeof(lv_color_t));
color_p += w;
}
#endif
monitor2.sdl_refr_qry = true;
/* TYPICALLY YOU DO NOT NEED THIS
* If it was the last part to refresh update the texture of the window.*/
if(lv_disp_flush_is_last(disp_drv)) {
monitor_sdl_refr(NULL);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_disp_flush_ready(disp_drv);
#endif
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void sdl_event_handler(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
SDL_Event event;
while(SDL_PollEvent(&event)) {
#if USE_MOUSE != 0
mouse_handler(&event);
#endif
#if USE_MOUSEWHEEL != 0
mousewheel_handler(&event);
#endif
#if USE_KEYBOARD
keyboard_handler(&event);
#endif
if((&event)->type == SDL_WINDOWEVENT) {
switch((&event)->window.event) {
#if SDL_VERSION_ATLEAST(2, 0, 5)
case SDL_WINDOWEVENT_TAKE_FOCUS:
#endif
case SDL_WINDOWEVENT_EXPOSED:
window_update(&monitor);
#if MONITOR_DUAL
window_update(&monitor2);
#endif
break;
default:
break;
}
}
}
/*Run until quit event not arrives*/
if(sdl_quit_qry) {
monitor_sdl_clean_up();
exit(0);
}
}
/**
* SDL main thread. All SDL related task have to be handled here!
* It initializes SDL, handles drawing and the mouse.
*/
static void monitor_sdl_refr(lv_timer_t * t)
{
(void)t;
/*Refresh handling*/
if(monitor.sdl_refr_qry != false) {
monitor.sdl_refr_qry = false;
window_update(&monitor);
}
#if MONITOR_DUAL
if(monitor2.sdl_refr_qry != false) {
monitor2.sdl_refr_qry = false;
window_update(&monitor2);
}
#endif
}
int quit_filter(void * userdata, SDL_Event * event)
{
(void)userdata;
if(event->type == SDL_WINDOWEVENT) {
if(event->window.event == SDL_WINDOWEVENT_CLOSE) {
sdl_quit_qry = true;
}
}
else if(event->type == SDL_QUIT) {
sdl_quit_qry = true;
}
return 1;
}
static void monitor_sdl_clean_up(void)
{
SDL_DestroyTexture(monitor.texture);
SDL_DestroyRenderer(monitor.renderer);
SDL_DestroyWindow(monitor.window);
#if MONITOR_DUAL
SDL_DestroyTexture(monitor2.texture);
SDL_DestroyRenderer(monitor2.renderer);
SDL_DestroyWindow(monitor2.window);
#endif
SDL_Quit();
}
static void monitor_sdl_init(void)
{
/*Initialize the SDL*/
SDL_Init(SDL_INIT_VIDEO);
SDL_SetEventFilter(quit_filter, NULL);
window_create(&monitor);
#if MONITOR_DUAL
window_create(&monitor2);
int x, y;
SDL_GetWindowPosition(monitor2.window, &x, &y);
SDL_SetWindowPosition(monitor.window, x + (MONITOR_HOR_RES * MONITOR_ZOOM) / 2 + 10, y);
SDL_SetWindowPosition(monitor2.window, x - (MONITOR_HOR_RES * MONITOR_ZOOM) / 2 - 10, y);
#endif
sdl_inited = true;
}
static void window_create(monitor_t * m)
{
m->window = SDL_CreateWindow("TFT Simulator",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
MONITOR_HOR_RES * MONITOR_ZOOM, MONITOR_VER_RES * MONITOR_ZOOM, 0); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/
m->renderer = SDL_CreateRenderer(m->window, -1, SDL_RENDERER_SOFTWARE);
m->texture = SDL_CreateTexture(m->renderer,
SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, MONITOR_HOR_RES, MONITOR_VER_RES);
SDL_SetTextureBlendMode(m->texture, SDL_BLENDMODE_BLEND);
/*Initialize the frame buffer to gray (77 is an empirical value) */
#if MONITOR_DOUBLE_BUFFERED
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t));
#else
m->tft_fb = (uint32_t *)malloc(sizeof(uint32_t) * MONITOR_HOR_RES * MONITOR_VER_RES);
memset(m->tft_fb, 0x44, MONITOR_HOR_RES * MONITOR_VER_RES * sizeof(uint32_t));
#endif
m->sdl_refr_qry = true;
}
static void window_update(monitor_t * m)
{
#if MONITOR_DOUBLE_BUFFERED == 0
SDL_UpdateTexture(m->texture, NULL, m->tft_fb, MONITOR_HOR_RES * sizeof(uint32_t));
#else
if(m->tft_fb_act == NULL) return;
SDL_UpdateTexture(m->texture, NULL, m->tft_fb_act, MONITOR_HOR_RES * sizeof(uint32_t));
#endif
SDL_RenderClear(m->renderer);
#if LV_COLOR_SCREEN_TRANSP
SDL_SetRenderDrawColor(m->renderer, 0xff, 0, 0, 0xff);
SDL_Rect r;
r.x = 0; r.y = 0; r.w = MONITOR_HOR_RES; r.w = MONITOR_VER_RES;
SDL_RenderDrawRect(m->renderer, &r);
#endif
/*Update the renderer with the texture containing the rendered image*/
SDL_RenderCopy(m->renderer, m->texture, NULL, NULL);
SDL_RenderPresent(m->renderer);
}
#endif /*USE_MONITOR*/

View File

@ -0,0 +1,57 @@
/**
* @file monitor.h
*
*/
#ifndef MONITOR_H
#define MONITOR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_MONITOR
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void monitor_init(void);
void monitor_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
void monitor_flush2(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
/**********************
* MACROS
**********************/
#endif /* USE_MONITOR */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* MONITOR_H */