K1Guitar/device/LCD_ILI9341/Drv_ILI9341_Lcd_Dump.c

348 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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_TAP_CMD "TAP"
#define LCD_DUMP_RESET_CMD "sys reset"
#define LCD_DUMP_MAGIC "SCRN"
#define LCD_DUMP_FMT_RGB565 1
#define LCD_DUMP_CMD_BUF_SIZE 32
#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;
/* 烧录外部 UI 资源时占用 RTT0 down禁止此处吞字节 */
if (app_log_flash_busy()) {
return 0U;
}
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') {
if (s_cmd_len > 0U) {
s_cmd_buf[s_cmd_len] = '\0';
if (app_log_try_command(s_cmd_buf)) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
continue;
}
}
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';
/* 合成点击:验证 UI 命中路径(点万能按钮中心) */
if (strstr(s_cmd_buf, LCD_DUMP_TAP_CMD) != NULL) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
MainTask_Sendmsg(MSG_ID_TOUCH, 1, 120, 80);
SEGGER_RTT_WriteString(0, "TAP inject 120,80\n");
continue;
}
if (strstr(s_cmd_buf, LCD_DUMP_RESET_CMD) != NULL) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
(void)app_log_try_command(LCD_DUMP_RESET_CMD);
continue;
}
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 */