Sry for the longer delay.
This sounds like a good idea.
Is there a way to check if a used transaction hadle that was queued is finished?
I tried to use the post_transmission_callback where I set the user field of the handle back to NULL.
On function side I loop through all of the 12 and check whenever the user field is NUL or not.
If it is NULL I reuse it instantly and increment a counter to remember how much transmission are up for beeing finished.
If it is not NULL I wait for it beeing finished and use it afterwards. In this case the counter will be decremented by one.
If everything is queued the code will wait for all transmission to be finished.
Howerver using this method ends in an abort() on the core the driver is running on.
Does someone know what this means?
Code:
Header:
Code: Select all
#ifndef _TFT_ILI9163CLIB_H_
#define _TFT_ILI9163CLIB_H_
//
// include section
//
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "TFT_ILI9163C_settings.h"
#include "TFT_ILI9163C_registers.h"
//
// define section
//
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define swapbyte(num) (((num) >> 8)|((num) << 8))
#define swap(a, b) { int16_t t = a; a = b; b = t; }
#define bitClear(num, bit) ((num) &= ~(1 << (bit)))
#define bitSet(num, bit) ((num) |= (1 << (bit)))
//
// typedef section
//
// display init sequence
typedef struct {
uint8_t cmd;
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
uint8_t data[16];
} init_cmd_t;
// struct for the displays
typedef struct ili9163c_t{
// spi stuff
spi_host_device_t spiHost; // storing spi host pheripheral
spi_device_interface_config_t devcfg; // storing the spi device configuration
spi_device_handle_t spiDevice; // storing the spi device handler
// spi transaction buffer
spi_transaction_t dmaBuffer[12];
// non spi pins
gpio_num_t pinDC; // pin to select if spi data is data or a command
gpio_num_t pinRst; // pin for resetting the tft controller
gpio_num_t pinBckLight; // pin for the backlight
// settings
uint8_t rotation;
uint8_t maCtrlData;
uint8_t colorSpaceData;
uint16_t width;
uint16_t height;
uint8_t sem;
} ili9163c_t;
//
// var section
//
const static init_cmd_t init_cmds[] = {
{0x01, 0, {}}, // Software reset
{0x11, 0, {}}, // Exit sleep mode
{0x3A, 1, {0x05}}, // Set pixel format
{0x26, 1, {0x04}}, // Set Gamma curve
{0xF2, 1, {0x01}}, // Gamma adjustment enabled
{0xE0, 15, {0x3F, 0x25, 0x1C, 0x1E, 0x20, 0x12, 0x2A, 0x90, 0x24, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}}, // Positive Gamma
{0xE1, 15, {0x20, 0x20, 0x20, 0x20, 0x05, 0x00, 0x15, 0xA7, 0x3D, 0x18, 0x25, 0x2A, 0x2B, 0x2B, 0x3A}}, // Negative Gamma
{0xB1, 2, {17,20}}, // Frame rate control 1 0x08, 0x08
{0xB4, 1, {0x07}}, // Display inversion
{0xC0, 2, {0x0A, 0x02}}, // Power control 1
{0xC1, 1, {0x02}}, // Power control 2
{0xC5, 2, {0x50, 0x5B}}, // Vcom control 1
{0xC7, 1, {0x40}}, // Vcom offset
{0x2A, 5, {0x00, 0x00, 0x00, 0x7F, 250}}, // Set column address
{0x2B, 4, {0x00, 0x00, 0x00, 0x9F}}, // Set page address
{0x36, 1, {0xC8}}, // Set address mode
{0x13, 0, {}}, // Set display on
{0x29, 0, {}}, // Set display on
{0, 0xff, {}}
};
//
// function section
//
// regular functions
ili9163c_t ili9163c_createDisplay(spi_host_device_t hostspi, gpio_num_t cspin, gpio_num_t dcpin, gpio_num_t rstpin, gpio_num_t bcklightpin);
void ili9163c_init(ili9163c_t *display);
// clear screen
void ili9163c_clearScreen_dma(ili9163c_t *display, uint16_t color);
// rect
void ili9163c_fillRect_dma(ili9163c_t *display, uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color);
// color code
uint16_t ili9163c_color565(uint8_t r, uint8_t g, uint8_t b);
#endif // _TFT_ILI9163CLIB_H_
C File:
Code: Select all
#include "TFT_ILI9163C.h"
//---------------------------------------------------------------------------------------------------------------------------
//
// helper functions
//
//---------------------------------------------------------------------------------------------------------------------------
// send a command to the LCD
static void ili9163c_send_cmd(ili9163c_t *display, const uint8_t cmd) {
uint8_t info[] = {display->pinDC, 0};
spi_transaction_t t;
memset(&t, 0, sizeof(t)); // zero out the transaction
t.tx_data[0] = cmd; // the data is the cmd itself
t.length = 8; // command is 8 bits
t.user = (void*)info;
t.flags = SPI_TRANS_USE_TXDATA;
assert(spi_device_transmit(display->spiDevice, &t) == ESP_OK); //Should have had no issues.
}
static void ili9163c_send_cmd_dma(ili9163c_t *display, const uint8_t transNr, uint8_t *buffer, const uint8_t cmd) {
buffer[0] = display->pinDC;
buffer[1] = 0;
display->dmaBuffer[transNr].tx_data[0] = cmd;
display->dmaBuffer[transNr].length = 8; // Data length, in bits
display->dmaBuffer[transNr].user = (void*)(buffer);
display->dmaBuffer[transNr].flags = SPI_TRANS_USE_TXDATA; // undo SPI_TRANS_USE_TXDATA flag
assert(spi_device_queue_trans(display->spiDevice, &(display->dmaBuffer[transNr]), portMAX_DELAY) == ESP_OK); //portMAX_DELAY
}
// send data to the LCD
static void ili9163c_send_data(ili9163c_t *display, const uint8_t *data, int len) {
uint8_t info[] = {display->pinDC, 1};
spi_transaction_t t;
if (len == 0) return;
memset(&t, 0, sizeof(t)); // zero out the transaction
t.length = len*8; // len is in bytes, transaction length is in bits.
t.tx_buffer = data; // data
t.user = (void*)info;
assert(spi_device_transmit(display->spiDevice, &t) == ESP_OK); // Should have had no issues.
}
static void ili9163c_send_data_dma(ili9163c_t *display, const uint8_t transNr, uint8_t *data, uint16_t len) {
data[0] = display->pinDC;
data[1] = 1;
display->dmaBuffer[transNr].tx_buffer = (data + 2);
display->dmaBuffer[transNr].length = len*8; // Data length, in bits
display->dmaBuffer[transNr].user = (void*)(data);
display->dmaBuffer[transNr].flags = 0; // undo SPI_TRANS_USE_TXDATA flag
assert(spi_device_queue_trans(display->spiDevice, &(display->dmaBuffer[transNr]), portMAX_DELAY) == ESP_OK); //portMAX_DELAY
}
static void ili9163c_pre_transfer_callback_dma(spi_transaction_t *t) {
gpio_set_level(((uint8_t*)(t->user))[0], ((uint8_t*)(t->user))[1]);
}
static void ili9163c_post_transfer_callback_dma(spi_transaction_t *t) {
t->user = NULL;
}
static void ili9163c_setAddr(ili9163c_t *display, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
ili9163c_send_cmd(display, CMD_CLMADRS); // Column
if (display->rotation == 0 || display->rotation > 1){
uint32_t tx = (swapbyte(x1) << 16) | swapbyte(x0);
ili9163c_send_data(display, (uint8_t*)(&tx), 4); // (uint8_t*)(&x0)
} else {
uint32_t tx = (swapbyte(x1 + __OFFSET) << 16) | swapbyte(x0 + __OFFSET);
ili9163c_send_data(display, (uint8_t*)(&tx), 4);
}
ili9163c_send_cmd(display, CMD_PGEADRS); // Page
if (display->rotation == 0){
uint32_t ty = (swapbyte(y1 + __OFFSET) << 16) | swapbyte(y0 + __OFFSET);
ili9163c_send_data(display, (uint8_t*)(&ty), 4); //
} else {
uint32_t ty = (swapbyte(y1) << 16) | swapbyte(y0);
ili9163c_send_data(display, (uint8_t*)(&ty), 4);
}
ili9163c_send_cmd(display, CMD_RAMWR); //Into RAM
}
static void ili9163c_setAddr_dma(ili9163c_t *display, const uint8_t transNr, uint8_t *data, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
// 0 byte offset
ili9163c_send_cmd_dma(display, transNr, data, CMD_CLMADRS); // Column
if (display->rotation == 0 || display->rotation > 1) {
uint16_t *data16 = (uint16_t*)(data + 2);
data16[1] = swapbyte(x0);
data16[2] = swapbyte(x1);
// +2 byte offset cause of userdata from command before
ili9163c_send_data_dma(display, transNr + 1, (data + 2), sizeof(uint32_t));
} else {
uint16_t *data16 = (uint16_t*)(data + 2);
data16[1] = swapbyte(x0 + __OFFSET);
data16[2] = swapbyte(x1 + __OFFSET);
// +2 byte offset cause of userdata from command before
ili9163c_send_data_dma(display, transNr + 1, (data + 2), sizeof(uint32_t));
}
// +2 byte additional offset cause of userdata from data command before
// +4 byte additional offset cause of data from data command before
ili9163c_send_cmd_dma(display, transNr + 2, (data + (4 + sizeof(uint32_t))), CMD_PGEADRS); // Page
if (display->rotation == 0){
uint16_t *data16 = (uint16_t*)(data + (6 + sizeof(uint32_t)));
data16[1] = swapbyte(y0 + __OFFSET);
data16[2] = swapbyte(y1 + __OFFSET);
// +2 byte offset cause of userdata from command before
ili9163c_send_data_dma(display, transNr + 3, (data + (6 + sizeof(uint32_t))), sizeof(uint32_t));
} else {
uint16_t *data16 = (uint16_t*)(data + (6 + sizeof(uint32_t)));
data16[1] = swapbyte(y0);
data16[2] = swapbyte(y1);
// +2 byte offset cause of userdata from command before
ili9163c_send_data_dma(display, transNr + 3, (data + (6 + sizeof(uint32_t))), sizeof(uint32_t));
}
// +2 byte additional offset cause of userdata from command before
// +4 byte additional offset cause of data from data command before
ili9163c_send_cmd_dma(display, transNr + 4, (data + (8 + 2*sizeof(uint32_t))), CMD_RAMWR); //Into RAM
}
//---------------------------------------------------------------------------------------------------------------------------
//
// regular functions
//
//---------------------------------------------------------------------------------------------------------------------------
ili9163c_t ili9163c_createDisplay(spi_host_device_t hostspi, gpio_num_t cspin, gpio_num_t dcpin, gpio_num_t rstpin, gpio_num_t bcklightpin) {
ili9163c_t display;
memset(&display, 0, sizeof(ili9163c_t));
// spi stuff
display.spiHost = hostspi;
display.devcfg.clock_speed_hz = 26000000; // clock out at 26 MHz
display.devcfg.mode = 0; // spi mode 0
display.devcfg.spics_io_num = cspin; // cs pin
display.devcfg.queue_size = 13; // we want to be able to queue 7 transactions at a time
display.devcfg.pre_cb = ili9163c_pre_transfer_callback_dma; // specify pre-transfer callback to handle D/C line
display.devcfg.post_cb = ili9163c_post_transfer_callback_dma; // specify post-transfer callback to give the transaction handle free
display.devcfg.flags = SPI_DEVICE_HALFDUPLEX;
assert(spi_bus_add_device(hostspi, &display.devcfg, &display.spiDevice) == ESP_OK);
for(int i = 0; i < 12; i++) memset(&(display.dmaBuffer[i]), 0, sizeof(spi_transaction_t));
// non spi pins
display.pinDC = dcpin;
display.pinRst = rstpin;
display.pinBckLight = bcklightpin;
gpio_set_direction(display.pinDC , GPIO_MODE_OUTPUT);
gpio_set_direction(display.pinRst, GPIO_MODE_OUTPUT);
gpio_set_direction(display.pinBckLight, GPIO_MODE_OUTPUT);
// general stuff
display.maCtrlData = 0x00;
display.colorSpaceData = __COLORSPC; //start with default data;
display.width = _TFTWIDTH;
display.height = _TFTHEIGHT;
return display;
}
void ili9163c_init(ili9163c_t *display) {
uint8_t cmd = 0;
// reset display
gpio_set_level(display->pinRst, 0);
vTaskDelay(100 / portTICK_RATE_MS);
gpio_set_level(display->pinRst, 1);
vTaskDelay(100 / portTICK_RATE_MS);
// send init sequence
while (init_cmds[cmd].databytes != 0xff)
{
ili9163c_send_cmd (display, init_cmds[cmd].cmd);
ili9163c_send_data(display, init_cmds[cmd].data, init_cmds[cmd].databytes&0x1F);
if (init_cmds[cmd].databytes&0x80) {
vTaskDelay(100 / portTICK_RATE_MS);
}
cmd ++;
}
gpio_set_level(display->pinBckLight, 0);
}
// clear the screen
void ili9163c_clearScreen_dma(ili9163c_t *display, uint16_t color) {
ili9163c_fillRect_dma(display, 0, 0, display->width, display->height, color);
}
// draw a rect on the screen
void ili9163c_fillRect_dma(ili9163c_t *display, uint16_t x0, uint16_t y0, uint16_t w, uint16_t h, uint16_t color) {
uint8_t *databuffer = (uint8_t*)heap_caps_malloc(18 + 2 + 2*w*2 + 2, MALLOC_CAP_DMA);
uint16_t *data16 = (uint16_t*)(databuffer + 18 + 2);
color = swapbyte(color);
for(int i = 0; i <= w*2; i++) data16[i] = color;
// 5 transactions are queued here
ili9163c_setAddr_dma(display, 0, databuffer, x0, y0, x0 + w - 1, y0 + h - 1); // go home
uint8_t totalTransactions = 5;
uint8_t currentSlot = 5;
ESP_LOGI("tft driver", "Sending data");
while(h > 0) {
while (display->dmaBuffer[currentSlot].user != NULL) {
spi_transaction_t *rtrans;
assert(spi_device_get_trans_result(display->spiDevice, &rtrans, portMAX_DELAY) == ESP_OK);
totalTransactions --;
ESP_LOGI("tft driver", "Freed transaction %d", currentSlot);
}
if(h > 2) {
ESP_LOGI("tft driver", "Use transaction %d", currentSlot);
ili9163c_send_data_dma(display, currentSlot, (databuffer + 20), 2*w*2);
h -= 2;
} else {
ESP_LOGI("tft driver", "Use transaction %d", currentSlot);
ili9163c_send_data_dma(display, currentSlot, (databuffer + 20), w*2);
h --;
}
totalTransactions ++;
ESP_LOGI("tft driver", "Transactions to wait for after %d", totalTransactions);
currentSlot = (currentSlot + 1)%12;
}
// clear remaining transactions
spi_transaction_t *rtrans;
for(int i = 0; i < totalTransactions; i ++) {
ESP_LOGI("tft driver", "Wait for Transaction %d to be finished", i);
assert(spi_device_get_trans_result(display->spiDevice, &rtrans, portMAX_DELAY) == ESP_OK);
}
free(databuffer);
}
// get color code
uint16_t ili9163c_color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
//1552
Settings:
Code: Select all
#ifndef _TFT_ILI9163C_USETT_H_
#define _TFT_ILI9163C_USETT_H_
#if defined(__144_RED_PCB__)
#define _TFTWIDTH 128//the REAL W resolution of the TFT
#define _TFTHEIGHT 128//the REAL H resolution of the TFT
#define _GRAMWIDTH 128
#define _GRAMHEIGH 160//160
#define _GRAMSIZE _GRAMWIDTH * _GRAMHEIGH//*see note 1
#define __COLORSPC 1// 1:GBR - 0:RGB
#define __GAMMASET3 //uncomment for another gamma
#define __OFFSET 32//*see note 2
//Tested!
#elif defined (__144_BLACK_PCB__)
#define _TFTWIDTH 128//the REAL W resolution of the TFT
#define _TFTHEIGHT 160//128//the REAL H resolution of the TFT
#define _GRAMWIDTH 128
#define _GRAMHEIGH 160//128
#define _GRAMSIZE _GRAMWIDTH * _GRAMHEIGH//*see note 1
#define __COLORSPC 1// 1:GBR - 0:RGB
#define __GAMMASET1 //uncomment for another gamma
#define __OFFSET 0
//not tested
#elif defined (__22_RED_PCB__)
#define _TFTWIDTH 240//the REAL W resolution of the TFT
#define _TFTHEIGHT 320//the REAL H resolution of the TFT
#define _GRAMWIDTH 240
#define _GRAMHEIGH 320
#define _GRAMSIZE _GRAMWIDTH * _GRAMHEIGH
#define __COLORSPC 1// 1:GBR - 0:RGB
#define __GAMMASET1 //uncomment for another gamma
#define __OFFSET 0
#else
#define _TFTWIDTH 128//128
#define _TFTHEIGHT 160//160
#define _GRAMWIDTH 128
#define _GRAMHEIGH 160
#define _GRAMSIZE _GRAMWIDTH * _GRAMHEIGH
#define __COLORSPC 1// 1:GBR - 0:RGB
#define __GAMMASET1
#define __OFFSET 0
#endif
//#if defined(__GAMMASET1)
// const uint8_t pGammaSet[15]= {0x36,0x29,0x12,0x22,0x1C,0x15,0x42,0xB7,0x2F,0x13,0x12,0x0A,0x11,0x0B,0x06};
// const uint8_t nGammaSet[15]= {0x09,0x16,0x2D,0x0D,0x13,0x15,0x40,0x48,0x53,0x0C,0x1D,0x25,0x2E,0x34,0x39};
//#elif defined(__GAMMASET2)
// const uint8_t pGammaSet[15]= {0x3F,0x21,0x12,0x22,0x1C,0x15,0x42,0xB7,0x2F,0x13,0x02,0x0A,0x01,0x00,0x00};
// const uint8_t nGammaSet[15]= {0x09,0x18,0x2D,0x0D,0x13,0x15,0x40,0x48,0x53,0x0C,0x1D,0x25,0x2E,0x24,0x29};
//#elif defined(__GAMMASET3)
// const uint8_t pGammaSet[15]= {0x3F,0x26,0x23,0x30,0x28,0x10,0x55,0xB7,0x40,0x19,0x10,0x1E,0x02,0x01,0x00};
// const uint8_t nGammaSet[15]= {0x09,0x18,0x2D,0x0D,0x13,0x15,0x40,0x48,0x53,0x0C,0x1D,0x25,0x2E,0x24,0x29};
//#else
// const uint8_t pGammaSet[15]= {0x3F,0x25,0x1C,0x1E,0x20,0x12,0x2A,0x90,0x24,0x11,0x00,0x00,0x00,0x00,0x00};
// const uint8_t nGammaSet[15]= {0x20,0x20,0x20,0x20,0x05,0x15,0x00,0xA7,0x3D,0x18,0x25,0x2A,0x2B,0x2B,0x3A};
//#endif
/*
Note 1: The __144_RED_PCB__ display has hardware addressing of 128 x 160
but the tft resolution it's 128 x 128 so the dram should be set correctly
Note 2: This is the offset between image in RAM and TFT. In that case 160 - 128 = 32;
*/
#endif // _TFT_ILI9163C_USETT_H_
Registers
Code: Select all
#ifndef _TFT_ILI9163C_REG_H_
#define _TFT_ILI9163C_REG_H_
//ILI9163C registers-----------------------
#define CMD_NOP 0x00//Non operation
#define CMD_SWRESET 0x01//Soft Reset
#define CMD_SLPIN 0x10//Sleep ON
#define CMD_SLPOUT 0x11//Sleep OFF
#define CMD_PTLON 0x12//Partial Mode ON
#define CMD_NORML 0x13//Normal Display ON
#define CMD_DINVOF 0x20//Display Inversion OFF
#define CMD_DINVON 0x21//Display Inversion ON
#define CMD_GAMMASET 0x26//Gamma Set (0x01[1],0x02[2],0x04[3],0x08[4])
#define CMD_DISPOFF 0x28//Display OFF
#define CMD_DISPON 0x29//Display ON
#define CMD_IDLEON 0x39//Idle Mode ON
#define CMD_IDLEOF 0x38//Idle Mode OFF
#define CMD_CLMADRS 0x2A//Column Address Set
#define CMD_PGEADRS 0x2B//Page Address Set
#define CMD_RAMWR 0x2C//Memory Write
#define CMD_RAMRD 0x2E//Memory Read
#define CMD_CLRSPACE 0x2D//Color Space : 4K/65K/262K
#define CMD_PARTAREA 0x30//Partial Area
#define CMD_VSCLLDEF 0x33//Vertical Scroll Definition
#define CMD_TEFXLON 0x35//Tearing Effect Line ON
#define CMD_TEFXLOF 0x34//Tearing Effect Line OFF
#define CMD_MADCTL 0x36//Memory Access Control
#define CMD_VSSTADRS 0x37//Vertical Scrolling Start address
#define CMD_PIXFMT 0x3A//Interface Pixel Format
#define CMD_FRMCTR1 0xB1//Frame Rate Control (In normal mode/Full colors)
#define CMD_FRMCTR2 0xB2//Frame Rate Control(In Idle mode/8-colors)
#define CMD_FRMCTR3 0xB3//Frame Rate Control(In Partial mode/full colors)
#define CMD_DINVCTR 0xB4//Display Inversion Control
#define CMD_RGBBLK 0xB5//RGB Interface Blanking Porch setting
#define CMD_DFUNCTR 0xB6//Display Fuction set 5
#define CMD_SDRVDIR 0xB7//Source Driver Direction Control
#define CMD_GDRVDIR 0xB8//Gate Driver Direction Control
#define CMD_PWCTR1 0xC0//Power_Control1
#define CMD_PWCTR2 0xC1//Power_Control2
#define CMD_PWCTR3 0xC2//Power_Control3
#define CMD_PWCTR4 0xC3//Power_Control4
#define CMD_PWCTR5 0xC4//Power_Control5
#define CMD_VCOMCTR1 0xC5//VCOM_Control 1
#define CMD_VCOMCTR2 0xC6//VCOM_Control 2
#define CMD_VCOMOFFS 0xC7//VCOM Offset Control
#define CMD_PGAMMAC 0xE0//Positive Gamma Correction Setting
#define CMD_NGAMMAC 0xE1//Negative Gamma Correction Setting
#define CMD_GAMRSEL 0xF2//GAM_R_SEL
#endif