#include "AXS15231B.h" #include "SPI.h" #include "Arduino.h" #include "driver/spi_master.h" static volatile bool lcd_spi_dma_write = false; extern void my_print(const char *buf); uint32_t transfer_num = 0; size_t lcd_PushColors_len = 0; const static lcd_cmd_t axs15231b_qspi_init[] = { {0x28, {0x00}, 0x40}, {0x10, {0x00}, 0x20}, {0x11, {0x00}, 0x80}, {0x29, {0x00}, 0x00}, }; const static lcd_cmd_t axs15231b_qspi_init_new[] = { {0x28, {0x00}, 0x40}, {0x10, {0x00}, 0x80}, {0xbb, {0x00,0x00,0x00,0x00,0x00,0x00,0x5a,0xa5}, 0x08}, {0xa0, {0x00,0x30,0x00,0x02,0x00,0x00,0x05,0x3f,0x30,0x05,0x3f,0x3f,0x00,0x00,0x00,0x00,0x00}, 0x11}, {0xa2, {0x30,0x04,0x14,0x50,0x80,0x30,0x85,0x80,0xb4,0x28,0xff,0xff,0xff,0x20,0x50,0x10,0x02,0x06,0x20,0xd0,0xc0,0x01,0x12,0xa0,0x91,0xc0,0x20,0x7f,0xff,0x00,0x06}, 0x1F}, {0xd0, {0x80,0xb4,0x21,0x24,0x08,0x05,0x10,0x01,0xf2,0x02,0xc2,0x02,0x22,0x22,0xaa,0x03,0x10,0x12,0xc0,0x10,0x10,0x40,0x04,0x00,0x30,0x10,0x00,0x03,0x0d,0x12}, 0x1E}, {0xa3, {0xa0,0x06,0xaa,0x00,0x08,0x02,0x0a,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x55,0x55}, 0x16}, {0xc1, {0x33,0x04,0x02,0x02,0x71,0x05,0x24,0x55,0x02,0x00,0x01,0x01,0x53,0xff,0xff,0xff,0x4f,0x52,0x00,0x4f,0x52,0x00,0x45,0x3b,0x0b,0x04,0x0d,0x00,0xff,0x42}, 0x1E}, {0xc4, {0x00,0x24,0x33,0x80,0x66,0xea,0x64,0x32,0xc8,0x64,0xc8,0x32,0x90,0x90,0x11,0x06,0xdc,0xfa,0x00,0x00,0x80,0xfe,0x10,0x10,0x00,0x0a,0x0a,0x44,0x50}, 0x1D}, {0xc5, {0x18,0x00,0x00,0x03,0xfe,0xe8,0x3b,0x20,0x30,0x10,0x88,0xde,0x0d,0x08,0x0f,0x0f,0x01,0xe8,0x3b,0x20,0x10,0x10,0x00}, 0x17}, {0xc6, {0x05,0x0a,0x05,0x0a,0x00,0xe0,0x2e,0x0b,0x12,0x22,0x12,0x22,0x01,0x03,0x00,0x02,0x6a,0x18,0xc8,0x22}, 0x14}, {0xc7, {0x50,0x36,0x28,0x00,0xa2,0x80,0x8f,0x00,0x80,0xff,0x07,0x11,0x9c,0x6f,0xff,0x24,0x0c,0x0d,0x0e,0x0f,0x01,0x01,0x01,0x01,0x3f,0x07,0x00}, 0x1B}, {0xc9, {0x33,0x44,0x44,0x01}, 0x04}, {0xcf, {0x2c,0x1e,0x88,0x58,0x13,0x18,0x56,0x18,0x1e,0x68,0xf7,0x00,0x66,0x0d,0x22,0xc4,0x0c,0x77,0x22,0x44,0xaa,0x55,0x04,0x04,0x12,0xa0,0x08}, 0x1B}, {0xd5, {0x30,0x30,0x8a,0x00,0x44,0x04,0x4a,0xe5,0x02,0x4a,0xe5,0x02,0x04,0xd9,0x02,0x47,0x03,0x03,0x03,0x03,0x83,0x00,0x00,0x00,0x80,0x52,0x53,0x50,0x50,0x00}, 0x1E}, {0xd6, {0x10,0x32,0x54,0x76,0x98,0xba,0xdc,0xfe,0x34,0x02,0x01,0x83,0xff,0x00,0x20,0x50,0x00,0x30,0x03,0x03,0x50,0x13,0x00,0x00,0x00,0x04,0x50,0x20,0x01,0x00}, 0x1E}, {0xd7, {0x03,0x01,0x09,0x0b,0x0d,0x0f,0x1e,0x1f,0x18,0x1d,0x1f,0x19,0x30,0x30,0x04,0x00,0x20,0x20,0x1f}, 0x13}, {0xd8, {0x02,0x00,0x08,0x0a,0x0c,0x0e,0x1e,0x1f,0x18,0x1d,0x1f,0x19}, 0x0C}, {0xdf, {0x44,0x33,0x4b,0x69,0x00,0x0a,0x02,0x90}, 0x06}, {0xe0, {0x1f,0x20,0x10,0x17,0x0d,0x09,0x12,0x2a,0x44,0x25,0x0c,0x15,0x13,0x31,0x36,0x2f,0x02}, 0x11}, {0xe1, {0x3f,0x20,0x10,0x16,0x0c,0x08,0x12,0x29,0x43,0x25,0x0c,0x15,0x13,0x32,0x36,0x2f,0x27}, 0x11}, {0xe2, {0x3b,0x07,0x12,0x18,0x0e,0x0d,0x17,0x35,0x44,0x32,0x0c,0x14,0x14,0x36,0x3a,0x2f,0x0d}, 0x11}, {0xe3, {0x37,0x07,0x12,0x18,0x0e,0x0d,0x17,0x35,0x44,0x32,0x0c,0x14,0x14,0x36,0x32,0x2f,0x0f}, 0x11}, {0xe4, {0x3b,0x07,0x12,0x18,0x0e,0x0d,0x17,0x39,0x44,0x2e,0x0c,0x14,0x14,0x36,0x3a,0x2f,0x0d}, 0x11}, {0xe5, {0x37,0x07,0x12,0x18,0x0e,0x0d,0x17,0x39,0x44,0x2e,0x0c,0x14,0x14,0x36,0x3a,0x2f,0x0f}, 0x11}, {0xbb, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 0x06}, {0x28, {0x00}, 0x40}, {0x10, {0x00}, 0x80}, {0x11, {0x00}, 0x80}, {0x29, {0x00}, 0x00}, }; bool get_lcd_spi_dma_write(void) { return lcd_spi_dma_write; } static spi_device_handle_t spi; static void WriteComm(uint8_t data) { TFT_CS_L; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); SPI.write(0x00); SPI.write(data); SPI.write(0x00); SPI.endTransaction(); TFT_CS_H; } static void WriteData(uint8_t data) { TFT_CS_L; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); SPI.write(data); SPI.endTransaction(); TFT_CS_H; } static void lcd_send_cmd(uint32_t cmd, uint8_t *dat, uint32_t len) { #if LCD_USB_QSPI_DREVER == 1 TFT_CS_L; spi_transaction_t t; memset(&t, 0, sizeof(t)); t.flags = (SPI_TRANS_MULTILINE_CMD | SPI_TRANS_MULTILINE_ADDR); #ifdef LCD_SPI_DMA if(cmd == 0xff && len == 0x1f) { t.cmd = 0x02; t.addr = 0xffff; len = 0; } else if(cmd == 0x00) { t.cmd = 0X00; t.addr = 0X0000; len = 4; } else { t.cmd = 0x02; t.addr = cmd << 8; } #else t.cmd = 0x02; t.addr = cmd << 8; #endif if (len != 0) { t.tx_buffer = dat; t.length = 8 * len; } else { t.tx_buffer = NULL; t.length = 0; } spi_device_polling_transmit(spi, &t); TFT_CS_H; if(0) { WriteComm(cmd); if (len != 0) { for (int i = 0; i < len; i++) WriteData(dat[i]); } } #else WriteComm(cmd); if (len != 0) { for (int i = 0; i < len; i++) WriteData(dat[i]); } #endif } static void IRAM_ATTR spi_dma_cd(spi_transaction_t *trans) { if(transfer_num > 0) { transfer_num--; } if(lcd_PushColors_len <= 0 && transfer_num <= 0) { if(lcd_spi_dma_write) { lcd_spi_dma_write = false; lv_disp_t * disp = _lv_refr_get_disp_refreshing(); if(disp != NULL) lv_disp_flush_ready(disp->driver); TFT_CS_H; } } } void lcd_send_data8(uint8_t dat) { unsigned char i; for (i = 0; i < 8; i++) { if (dat & 0x80) { digitalWrite(TFT_QSPI_D0, 1); } else { digitalWrite(TFT_QSPI_D0, 0); } dat <<= 1; digitalWrite(TFT_QSPI_SCK, 0); digitalWrite(TFT_QSPI_SCK, HIGH); } } void axs15231_init(void) { pinMode(TFT_QSPI_CS, OUTPUT); pinMode(TFT_QSPI_RST, OUTPUT); TFT_RES_H; delay(130); TFT_RES_L; delay(130); TFT_RES_H; delay(300); #if LCD_USB_QSPI_DREVER == 1 esp_err_t ret; spi_bus_config_t buscfg = { .data0_io_num = TFT_QSPI_D0, .data1_io_num = TFT_QSPI_D1, .sclk_io_num = TFT_QSPI_SCK, .data2_io_num = TFT_QSPI_D2, .data3_io_num = TFT_QSPI_D3, .max_transfer_sz = (SEND_BUF_SIZE * 16) + 8, .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS /* | SPICOMMON_BUSFLAG_QUAD */ , }; spi_device_interface_config_t devcfg = { .command_bits = 8, .address_bits = 24, .mode = TFT_SPI_MODE, .clock_speed_hz = SPI_FREQUENCY, .spics_io_num = -1, // .spics_io_num = TFT_QSPI_CS, .flags = SPI_DEVICE_HALFDUPLEX, .queue_size = 17, .post_cb = spi_dma_cd, }; ret = spi_bus_initialize(TFT_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO); ESP_ERROR_CHECK(ret); ret = spi_bus_add_device(TFT_SPI_HOST, &devcfg, &spi); ESP_ERROR_CHECK(ret); #else SPI.begin(TFT_SCK, -1, TFT_MOSI, TFT_CS); SPI.setFrequency(SPI_FREQUENCY); pinMode(TFT_DC, OUTPUT); #endif // Initialize the screen multiple times to prevent initialization failure int i = 1; while (i--) { #if LCD_USB_QSPI_DREVER == 1 const lcd_cmd_t *lcd_init = axs15231b_qspi_init; for (int i = 0; i < sizeof(axs15231b_qspi_init) / sizeof(lcd_cmd_t); i++) #else const lcd_cmd_t *lcd_init = axs15231_spi_init; for (int i = 0; i < sizeof(axs15231_spi_init) / sizeof(lcd_cmd_t); i++) #endif { lcd_send_cmd(lcd_init[i].cmd, (uint8_t *)lcd_init[i].data, lcd_init[i].len & 0x3f); if (lcd_init[i].len & 0x80) delay(200); if (lcd_init[i].len & 0x40) delay(20); } } } void lcd_setRotation(uint8_t r) { uint8_t gbr = TFT_MAD_RGB; switch (r) { case 0: // Portrait // WriteData(gbr); break; case 1: // Landscape (Portrait + 90) gbr = TFT_MAD_MX | TFT_MAD_MV | gbr; break; case 2: // Inverter portrait gbr = TFT_MAD_MX | TFT_MAD_MY | gbr; break; case 3: // Inverted landscape gbr = TFT_MAD_MV | TFT_MAD_MY | gbr; break; } lcd_send_cmd(TFT_MADCTL, &gbr, 1); } void lcd_address_set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { lcd_cmd_t t[3] = { {0x2a, {(uint8_t)(x1 >> 8), (uint8_t)x1, uint8_t(x2 >> 8), (uint8_t)(x2)}, 0x04}, {0x2b, {(uint8_t)(y1 >> 8), (uint8_t)(y1), (uint8_t)(y2 >> 8), (uint8_t)(y2)}, 0x04}, }; for (uint32_t i = 0; i < 2; i++) { lcd_send_cmd(t[i].cmd, t[i].data, t[i].len); } } void lcd_fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color) { uint16_t w = xend - xsta; uint16_t h = yend - ysta; uint16_t *color_p = (uint16_t *)heap_caps_malloc(w * h * 2, MALLOC_CAP_INTERNAL); int i = 0; for(i = 0; i < w * h ; i+=1) { color_p[i] = color; } lcd_PushColors(xsta, ysta, w, h, color_p); free(color_p); } void lcd_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { lcd_address_set(x, y, x + 1, y + 1); lcd_PushColors(&color, 1); } void spi_device_queue_trans_fun(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait) { ESP_ERROR_CHECK(spi_device_queue_trans(spi, (spi_transaction_t *)trans_desc, portMAX_DELAY)); } #ifdef LCD_SPI_DMA spi_transaction_ext_t t = {0}; void lcd_PushColors(uint16_t x, uint16_t y, uint16_t width, uint16_t high, uint16_t *data) { static bool first_send = 1; static uint16_t *p = (uint16_t *)data; static uint32_t transfer_num_old = 0; if(data != NULL && (width != 0) && (high != 0)) { lcd_PushColors_len = width * high; p = (uint16_t *)data; first_send = 1; transfer_num = 0; lcd_address_set(x, y, x + width - 1, y + high - 1); TFT_CS_L; } for (int x = 0; x < (transfer_num_old - (transfer_num_old-(transfer_num_old-transfer_num))); x++) { spi_transaction_t *rtrans; esp_err_t ret = spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); if (ret != ESP_OK) { // ESP_LOGW(TAG, "1. transfer_num = %d", transfer_num_old); } assert(ret == ESP_OK); } transfer_num_old -= (transfer_num_old - (transfer_num_old-(transfer_num_old-transfer_num))); do { if(transfer_num >= 3 || ESP.getFreeHeap() <= 70000) { break; } size_t chunk_size = lcd_PushColors_len; memset(&t, 0, sizeof(t)); if (first_send) { t.base.flags = SPI_TRANS_MODE_QIO ;// | SPI_TRANS_MODE_DIOQIO_ADDR t.base.cmd = 0x32 ;// 0x12 t.base.addr = 0x002C00; first_send = 0; } else { t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; t.command_bits = 0; t.address_bits = 0; t.dummy_bits = 0; } if (chunk_size > SEND_BUF_SIZE) { chunk_size = SEND_BUF_SIZE; } t.base.tx_buffer = p; t.base.length = chunk_size * 16; lcd_spi_dma_write = true; transfer_num++; transfer_num_old++; lcd_PushColors_len -= chunk_size; esp_err_t ret; ESP_ERROR_CHECK(spi_device_queue_trans(spi, (spi_transaction_t *)&t, portMAX_DELAY)); assert(ret == ESP_OK); p += chunk_size; } while (lcd_PushColors_len > 0); } #if 0 void lcd_PushColors(uint16_t x, uint16_t y, uint16_t width, uint16_t high, uint16_t *data) { bool first_send = 1; lcd_PushColors_len = width * high; uint16_t *p = (uint16_t *)data; spi_transaction_t *rtrans; for (int x = 0; x < transfer_num; x++) { esp_err_t ret = spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); if (ret != ESP_OK) { ESP_LOGW(TAG, "1. transfer_num = %d", transfer_num); } assert(ret == ESP_OK); } transfer_num = 0; lcd_address_set(x, y, x + width - 1, y + high - 1); TFT_CS_L; do { size_t chunk_size = lcd_PushColors_len; spi_transaction_ext_t t = {0}; memset(&t, 0, sizeof(t)); if (first_send) { t.base.flags = SPI_TRANS_MODE_QIO /* | SPI_TRANS_MODE_DIOQIO_ADDR */; t.base.cmd = 0x32 /* 0x12 */; t.base.addr = 0x002C00; first_send = 0; } else { t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; t.command_bits = 0; t.address_bits = 0; t.dummy_bits = 0; } if (chunk_size > SEND_BUF_SIZE) { chunk_size = SEND_BUF_SIZE; } t.base.tx_buffer = p; t.base.length = chunk_size * 16; lcd_spi_dma_write = true; transfer_num++; lcd_PushColors_len -= chunk_size; spi_device_queue_trans_fun(spi, (spi_transaction_t *)&t, portMAX_DELAY); p += chunk_size; } while (lcd_PushColors_len > 0); } #endif #else void lcd_PushColors(uint16_t x, uint16_t y, uint16_t width, uint16_t high, uint16_t *data) { #if LCD_USB_QSPI_DREVER == 1 bool first_send = 1; size_t len = width * high; uint16_t *p = (uint16_t *)data; lcd_address_set(x, y, x + width - 1, y + high - 1); do { TFT_CS_L; size_t chunk_size = len; spi_transaction_ext_t t = {0}; memset(&t, 0, sizeof(t)); if (1) { t.base.flags = SPI_TRANS_MODE_QIO /* | SPI_TRANS_MODE_DIOQIO_ADDR */; t.base.cmd = 0x32 /* 0x12 */; if(first_send) { t.base.addr = 0x002C00; } else t.base.addr = 0x003C00; first_send = 0; } else { t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; t.command_bits = 0; t.address_bits = 0; t.dummy_bits = 0; } if (chunk_size > SEND_BUF_SIZE) { chunk_size = SEND_BUF_SIZE; } t.base.tx_buffer = p; t.base.length = chunk_size * 16; int aaa = 0; aaa = aaa>>1; aaa = aaa>>1; aaa = aaa>>1; if(!first_send) TFT_CS_H; aaa = aaa>>1; aaa = aaa>>1; aaa = aaa>>1; aaa = aaa>>1; aaa = aaa>>1; TFT_CS_L; aaa = aaa>>1; aaa = aaa>>1; aaa = aaa>>1; spi_device_polling_transmit(spi, (spi_transaction_t *)&t); len -= chunk_size; p += chunk_size; } while (len > 0); TFT_CS_H; #else lcd_address_set(x, y, x + width - 1, y + high - 1); TFT_CS_L; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); SPI.writeBytes((uint8_t *)data, width * high * 2); SPI.endTransaction(); TFT_CS_H; #endif } #endif void lcd_PushColors(uint16_t *data, uint32_t len) { #if LCD_USB_QSPI_DREVER == 1 bool first_send = 1; uint16_t *p = (uint16_t *)data; TFT_CS_L; do { size_t chunk_size = len; spi_transaction_ext_t t = {0}; memset(&t, 0, sizeof(t)); if (first_send) { t.base.flags = SPI_TRANS_MODE_QIO /* | SPI_TRANS_MODE_DIOQIO_ADDR */; t.base.cmd = 0x32 /* 0x12 */; t.base.addr = 0x002C00; first_send = 0; } else { t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; t.command_bits = 0; t.address_bits = 0; t.dummy_bits = 0; } if (chunk_size > SEND_BUF_SIZE) { chunk_size = SEND_BUF_SIZE; } t.base.tx_buffer = p; t.base.length = chunk_size * 16; spi_device_polling_transmit(spi, (spi_transaction_t *)&t); len -= chunk_size; p += chunk_size; } while (len > 0); TFT_CS_H; #else TFT_CS_L; SPI.beginTransaction(SPISettings(SPI_FREQUENCY, MSBFIRST, TFT_SPI_MODE)); SPI.writeBytes((uint8_t *)data, len * 2); SPI.endTransaction(); TFT_CS_H; #endif } void lcd_sleep() { lcd_send_cmd(0x10, NULL, 0); }