K1Guitar/device/LCD_ILI9341/Drv_ILI9341_Lcd_Dump.c

317 lines
7.9 KiB
C

#include "Drv_ILI9341_Lcd_Dump.h"
#if DEBUG_LCD_DUMP
#include "SEGGER_RTT.h"
#define LCD_DUMP_RTT_UP_CH 1
#define LCD_DUMP_RTT_DOWN_CH 0
#define LCD_DUMP_CMD "DUMP"
#define LCD_DUMP_MAGIC "SCRN"
#define LCD_DUMP_FMT_RGB565 1
#define LCD_DUMP_CMD_BUF_SIZE 16
#pragma pack(1)
typedef struct {
char magic[4];
uint16_t width;
uint16_t height;
uint16_t format;
uint16_t reserved;
} lcd_dump_header_t;
#pragma pack()
static uint8_t s_dump_busy;
static uint8_t s_rtt_ready;
static char s_rtt_up_buf[1024];
static char s_cmd_buf[LCD_DUMP_CMD_BUF_SIZE];
static uint8_t s_cmd_len;
static uint8_t s_row565[LCD_W * 2U];
static struct rt_thread s_dump_thread;
ALIGN(RT_ALIGN_SIZE) static rt_uint8_t s_dump_stack[1024];
static uint8_t LCD_SPI_Transceive(uint8_t tx)
{
uint32_t timeout = 200000U;
while (!(SPI2->sts & SPI_I2S_TDBE_FLAG) && --timeout) {}
spi_i2s_data_transmit(SPI2, tx);
timeout = 200000U;
while (!(SPI2->sts & SPI_I2S_RDBF_FLAG) && --timeout) {}
if (timeout == 0U) {
return 0xFF;
}
return (uint8_t)spi_i2s_data_receive(SPI2);
}
static void LCD_SPI_FlushRx(void)
{
while (SPI2->sts & SPI_I2S_RDBF_FLAG) {
(void)spi_i2s_data_receive(SPI2);
}
}
static void LCD_SPI_EnableMisoMux(void)
{
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_14;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
static void LCD_SPI_CsGpioLow(void)
{
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_12;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
gpio_bits_reset(GPIOB, GPIO_PINS_12);
}
static void LCD_SPI_CsHwRestore(void)
{
gpio_init_type gpio_init_struct;
gpio_bits_set(GPIOB, GPIO_PINS_12);
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_12;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
static void LCD_SPI_SetBaud(spi_mclk_freq_div_type div)
{
spi_enable(SPI2, FALSE);
SPI2->ctrl1 &= ~(0x7U << 3);
/* Standard div 2..256 live in CTRL1[5:3]; AT32 maps enum 0..7 there. */
SPI2->ctrl1 |= (uint16_t)(((uint16_t)div & 0x7U) << 3);
spi_enable(SPI2, TRUE);
}
static uint16_t LCD_RGB888To565(uint8_t r, uint8_t g, uint8_t b)
{
return (uint16_t)(((uint16_t)(r & 0xF8) << 8) |
((uint16_t)(g & 0xFC) << 3) |
(b >> 3));
}
static void LCD_RTT_WriteBlocking(const void *data, uint32_t len)
{
const uint8_t *p = (const uint8_t *)data;
uint32_t sent = 0U;
uint32_t spin = 0U;
while (sent < len) {
unsigned wrote = SEGGER_RTT_Write(LCD_DUMP_RTT_UP_CH, p + sent, len - sent);
if (wrote == 0U) {
if ((++spin & 0x3FU) == 0U) {
rt_thread_mdelay(1);
}
continue;
}
spin = 0U;
sent += wrote;
}
}
/* Soft-CS byte helpers (CS already held low by caller). */
static void LCD_Soft_WR_REG(uint8_t reg)
{
LCD_DC_Clr();
(void)LCD_SPI_Transceive(reg);
}
static void LCD_Soft_WR_DATA16(uint16_t data)
{
LCD_DC_Set();
(void)LCD_SPI_Transceive((uint8_t)(data >> 8));
(void)LCD_SPI_Transceive((uint8_t)(data & 0xFF));
}
/* Set CASET/RASET only — do NOT send 0x2C (memory write). */
static void LCD_Soft_SetAddr(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
LCD_Soft_WR_REG(0x2A);
LCD_Soft_WR_DATA16(x1);
LCD_Soft_WR_DATA16(x2);
LCD_Soft_WR_REG(0x2B);
LCD_Soft_WR_DATA16(y1);
LCD_Soft_WR_DATA16(y2);
}
static void LCD_ReadFrameRGB565(void)
{
uint16_t x, y;
register rt_base_t level;
LCD_SPI_FlushRx();
LCD_Soft_SetAddr(0, 0, (uint16_t)(LCD_W - 1), (uint16_t)(LCD_H - 1));
LCD_Soft_WR_REG(0x2E);
LCD_DC_Set();
(void)LCD_SPI_Transceive(0xFF); /* dummy */
for (y = 0; y < LCD_H; y++) {
level = rt_hw_interrupt_disable();
for (x = 0; x < LCD_W; x++) {
uint8_t r = LCD_SPI_Transceive(0xFF);
uint8_t g = LCD_SPI_Transceive(0xFF);
uint8_t b = LCD_SPI_Transceive(0xFF);
uint16_t color = LCD_RGB888To565(r, g, b);
s_row565[(x * 2U)] = (uint8_t)(color >> 8);
s_row565[(x * 2U) + 1] = (uint8_t)(color & 0xFF);
}
rt_hw_interrupt_enable(level);
LCD_RTT_WriteBlocking(s_row565, (uint32_t)(LCD_W * 2U));
}
}
static uint8_t LCD_Dump_CommandPending(void)
{
char rx[8];
unsigned read_len;
unsigned i;
read_len = SEGGER_RTT_Read(LCD_DUMP_RTT_DOWN_CH, rx, sizeof(rx));
if (read_len == 0U) {
return 0U;
}
for (i = 0; i < read_len; i++) {
char c = rx[i];
if (c == '\r' || c == '\n' || c == '\0') {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
continue;
}
if (s_cmd_len + 1U >= LCD_DUMP_CMD_BUF_SIZE) {
s_cmd_len = 0U;
}
s_cmd_buf[s_cmd_len++] = c;
s_cmd_buf[s_cmd_len] = '\0';
if (c == 0x01 || strstr(s_cmd_buf, LCD_DUMP_CMD) != NULL) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
return 1U;
}
}
return 0U;
}
static void LCD_Dump_ThreadEntry(void *parameter)
{
(void)parameter;
SEGGER_RTT_WriteString(0, "LCDDump ready\n");
while (1) {
LCD_Dump_Poll();
rt_thread_mdelay(5);
}
}
void LCD_Dump_Init(void)
{
if (s_rtt_ready) {
return;
}
SEGGER_RTT_ConfigUpBuffer(LCD_DUMP_RTT_UP_CH,
"LCDDump",
s_rtt_up_buf,
(uint32_t)sizeof(s_rtt_up_buf),
SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
s_rtt_ready = 1;
}
void LCD_Dump_StartPoller(void)
{
static uint8_t started;
if (!s_rtt_ready) {
LCD_Dump_Init();
}
if (started) {
return;
}
started = 1;
rt_thread_init(&s_dump_thread,
"lcd_dump",
LCD_Dump_ThreadEntry,
RT_NULL,
s_dump_stack,
sizeof(s_dump_stack),
8,
10);
rt_thread_startup(&s_dump_thread);
}
void LCD_DumpScreen_RTT(void)
{
lcd_dump_header_t header;
if (!s_rtt_ready) {
LCD_Dump_Init();
}
SEGGER_RTT_WriteString(0, "LCDDump start\n");
LCD_SPI_EnableMisoMux();
header.magic[0] = LCD_DUMP_MAGIC[0];
header.magic[1] = LCD_DUMP_MAGIC[1];
header.magic[2] = LCD_DUMP_MAGIC[2];
header.magic[3] = LCD_DUMP_MAGIC[3];
header.width = LCD_W;
header.height = LCD_H;
header.format = LCD_DUMP_FMT_RGB565;
header.reserved = 0;
LCD_RTT_WriteBlocking(&header, (uint32_t)sizeof(header));
/* Slow clock; hold CS for one full-frame RAMRD burst. */
LCD_SPI_SetBaud(SPI_MCLK_DIV_64);
LCD_SPI_CsGpioLow();
LCD_ReadFrameRGB565();
LCD_SPI_CsHwRestore();
LCD_SPI_SetBaud(SPI_MCLK_DIV_4);
SEGGER_RTT_WriteString(LCD_DUMP_RTT_UP_CH, "DONE");
SEGGER_RTT_WriteString(0, "LCDDump done\n");
}
void LCD_Dump_Poll(void)
{
if (s_dump_busy) {
return;
}
if (!LCD_Dump_CommandPending()) {
return;
}
s_dump_busy = 1;
LCD_DumpScreen_RTT();
s_dump_busy = 0;
}
#endif /* DEBUG_LCD_DUMP */