Files
lishanpi/app/main.cpp
T
hm 512a80aec8 feat(touch): 实现多点触控显示,5 点独立轨迹和坐标
- touch.h: 添加 TP_IS_ACTIVE / TP_ACTIVE_COUNT 辅助宏
- test_touch() 重写为多点触控模式:
  - 5 种颜色区分不同触控点 (黄/青/紫/绿/红)
  - LCD 左侧 5 行实时坐标显示
  - 5 条独立轨迹线 + 圆点追踪
  - 手指抬起自动清除对应圆点并显示 released
  - UART 输出全部活跃点坐标
2026-04-26 20:40:54 +08:00

603 lines
18 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 "gd32f4xx.h"
#include "hardware_init.h"
#include "led_driver.h"
#include "uart_driver.h"
#include "systick.h"
#include "sdram_manager.h"
#include "flash_manager.h"
#include "lcd.h"
#include "touch.h"
#include <cstdio>
#include <cstring>
// SDRAM 中分配的测试缓冲区
__attribute__((section(".sdram"))) uint8_t sdram_big_buffer[1024 * 1024];
// =============================================================
// 板级引脚定义
// =============================================================
#define LED1_PORT GPIOE
#define LED1_PIN GPIO_PIN_3
#define LED2_PORT GPIOD
#define LED2_PIN GPIO_PIN_7
#define LED3_PORT GPIOG
#define LED3_PIN GPIO_PIN_3
#define LED4_PORT GPIOA
#define LED4_PIN GPIO_PIN_5
// =============================================================
// 早期启动函数(16MHz,无 SysTick
// =============================================================
static void delay_16m(uint32_t ms)
{
for (volatile uint32_t i = 0; i < ms * 4000U; i++);
}
static void led_on(uint32_t port, uint32_t pin)
{
gpio_bit_set(port, pin);
}
static void led_off(uint32_t port, uint32_t pin)
{
gpio_bit_reset(port, pin);
}
static void led_pattern(uint8_t p)
{
led_off(LED1_PORT, LED1_PIN);
led_off(LED2_PORT, LED2_PIN);
led_off(LED3_PORT, LED3_PIN);
led_off(LED4_PORT, LED4_PIN);
if (p & 0x01) led_on(LED1_PORT, LED1_PIN);
if (p & 0x02) led_on(LED2_PORT, LED2_PIN);
if (p & 0x04) led_on(LED3_PORT, LED3_PIN);
if (p & 0x08) led_on(LED4_PORT, LED4_PIN);
}
static void init_leds(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOG);
rcu_periph_clock_enable(RCU_GPIOD);
gpio_mode_set(LED1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED1_PIN);
gpio_output_options_set(LED1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED1_PIN);
gpio_mode_set(LED2_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED2_PIN);
gpio_output_options_set(LED2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED2_PIN);
gpio_mode_set(LED3_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED3_PIN);
gpio_output_options_set(LED3_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED3_PIN);
gpio_mode_set(LED4_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED4_PIN);
gpio_output_options_set(LED4_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED4_PIN);
led_off(LED1_PORT, LED1_PIN);
led_off(LED2_PORT, LED2_PIN);
led_off(LED3_PORT, LED3_PIN);
led_off(LED4_PORT, LED4_PIN);
}
static void init_usart0(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9 | GPIO_PIN_10);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
usart_deinit(USART0);
usart_baudrate_set(USART0, 9600U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
}
static void uart_putchar(char c)
{
usart_data_transmit(USART0, (uint8_t)c);
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}
static void uart_puts(const char *s)
{
while (*s) uart_putchar(*s++);
}
static void uart_putdec(uint32_t val)
{
char buf[16];
int idx = 0;
if (val == 0) { uart_puts("0"); return; }
while (val > 0) { buf[idx++] = '0' + (val % 10); val /= 10; }
while (idx > 0) uart_putchar(buf[--idx]);
}
// 时钟切换到 168MHz 后重新配置 UART 波特率
static void reinit_usart0_168m(void)
{
usart_deinit(USART0);
usart_baudrate_set(USART0, 9600U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
}
// =============================================================
// 外设测试函数
// =============================================================
static void test_sdram_driver(void)
{
printf("SDRAM 驱动测试开始...\r\n");
SdramManager &sdram = SdramManager::instance();
RetCode ret = sdram.init();
if (ret != RET_OK) {
printf(" SDRAM 初始化失败: 错误码=%d\r\n", ret);
return;
}
printf(" 诊断1: 直接16位指针读写...\r\n");
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
for (uint32_t i = 0; i < 8; i++)
sram16[i] = (uint16_t)(0xAA00 + i);
__DSB();
delay_1ms(1);
bool diag1_ok = true;
for (uint32_t i = 0; i < 8; i++) {
uint16_t val = sram16[i];
uint16_t expected = (uint16_t)(0xAA00 + i);
if (val != expected) {
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
diag1_ok = false;
}
}
printf(" 诊断1: %s\r\n", diag1_ok ? "通过" : "失败");
printf(" 诊断2: 直接32位指针非零值测试...\r\n");
volatile uint32_t *sram32 = (volatile uint32_t *)0xC0000000;
sram32[0] = 0xDEADBEEF;
sram32[1] = 0xCAFEBABE;
sram32[2] = 0x12345678;
sram32[3] = 0x87654321;
__DSB();
delay_1ms(1);
bool diag2_ok = true;
for (uint32_t i = 0; i < 4; i++) {
uint32_t val = sram32[i];
uint32_t expected = (i == 0) ? 0xDEADBEEF : (i == 1) ? 0xCAFEBABE
: (i == 2) ? 0x12345678 : 0x87654321;
if (val != expected) {
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected, val);
diag2_ok = false;
}
}
printf(" 诊断2: %s\r\n", diag2_ok ? "通过" : "失败");
printf(" 诊断3: 驱动接口读写...\r\n");
uint32_t write_val = 0xA5A55A5A;
uint32_t read_val = 0;
ret = sdram.write(64, &write_val, sizeof(write_val));
if (ret != RET_OK) {
printf(" 驱动写入失败: %d\r\n", ret);
} else {
__DSB();
ret = sdram.read(64, &read_val, sizeof(read_val));
if (ret != RET_OK)
printf(" 驱动读取失败: %d\r\n", ret);
else
printf(" 写入=0x%08lX, 读取=0x%08lX, %s\r\n",
write_val, read_val,
(write_val == read_val) ? "通过" : "失败");
}
printf("SDRAM 驱动测试完成\r\n");
}
static void test_flash_driver(void)
{
printf("Flash 驱动测试开始...\r\n");
FlashManager &flash = FlashManager::instance();
RetCode ret = flash.init();
if (ret != RET_OK) {
printf(" Flash 初始化失败: %d\r\n", ret);
return;
}
printf(" Flash 信息: 总大小=%lu KB, 扇区大小=%lu KB\r\n",
flash.total_size() / 1024, flash.sector_size() / 1024);
uint32_t test_address = 0x08000000U + flash.total_size() - flash.sector_size();
printf(" 测试地址: 0x%08lX\r\n", test_address);
uint8_t write_buffer[256];
uint8_t read_buffer[256];
for (int i = 0; i < 256; i++)
write_buffer[i] = (uint8_t)((i + 0x80) & 0xFF);
printf(" 擦除 Flash 扇区...\r\n");
ret = flash.erase(test_address, flash.sector_size());
if (ret != RET_OK) { printf(" Flash 擦除失败: 错误码=%d\r\n", ret); return; }
printf(" Flash 擦除成功\r\n");
printf(" 写入 Flash 数据...\r\n");
ret = flash.write(test_address, write_buffer, sizeof(write_buffer));
if (ret != RET_OK) { printf(" Flash 写入失败: %d\r\n", ret); return; }
printf(" Flash 写入成功\r\n");
printf(" 读取 Flash 数据...\r\n");
ret = flash.read(test_address, read_buffer, sizeof(read_buffer));
if (ret != RET_OK) { printf(" Flash 读取失败: %d\r\n", ret); return; }
printf(" Flash 读取成功\r\n");
bool verify_ok = true;
for (int i = 0; i < 256; i++) {
if (read_buffer[i] != write_buffer[i]) {
verify_ok = false;
printf(" 数据错误 @ %d: 写入=%02X, 读取=%02X\r\n", i, write_buffer[i], read_buffer[i]);
break;
}
}
if (verify_ok) printf(" Flash 数据验证成功\r\n");
ret = flash.self_test(256);
if (ret == RET_OK) printf(" Flash 自测试通过\r\n");
else printf(" Flash 自测试失败: %d\r\n", ret);
printf("Flash 驱动测试完成\r\n");
}
static void test_lcd(void)
{
printf("\r\n===== LCD 功能测试 =====\r\n");
printf(" LCD_Init...\r\n");
LCD_Init();
printf(" LCD ID: %s\r\n", lcd_id);
delay_1ms(500);
uint16_t bands[4] = {RED, GREEN, BLUE, WHITE};
for (int i = 0; i < 4; i++) {
int y0 = i * 200;
int y1 = y0 + 199;
BlockWrite(0, 479, y0, y1);
LCD_WriteRAM_Prepare();
for (int p = 0; p < 480 * 200; p++)
LCD_WriteRAM(bands[i]);
__DSB();
}
delay_1ms(3000);
printf(" LCD_Clear(BLACK)\r\n");
LCD_Clear(BLACK);
delay_1ms(500);
printf(" LCD_Clear(RED)\r\n");
LCD_Clear(RED);
delay_1ms(500);
printf("LCD 测试完成\r\n");
delay_1ms(2000);
}
static void test_sdram_after_lcd(void)
{
printf("\r\n===== SDRAM 数据保持验证 (LCD 操作后) =====\r\n");
bool ok = true;
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
for (uint32_t i = 0; i < 8; i++) {
uint16_t val = sram16[i];
uint16_t expected = (uint16_t)(0xAA00 + i);
if (val != expected) {
printf(" 16位错误 @ [%lu]: 期望=0x%04X, 读取=0x%04X\r\n", i, expected, val);
ok = false;
}
}
volatile uint32_t *sram32 = (volatile uint32_t *)0xC0000000;
uint32_t expected_32[4] = {0xDEADBEEF, 0xCAFEBABE, 0x12345678, 0x87654321};
for (uint32_t i = 0; i < 4; i++) {
uint32_t val = sram32[i];
if (val != expected_32[i]) {
printf(" 32位错误 @ [%lu]: 期望=0x%08lX, 读取=0x%08lX\r\n", i, expected_32[i], val);
ok = false;
}
}
printf(" SDRAM 数据保持: %s\r\n", ok ? "通过 (LCD 未影响 SDRAM)" : "失败");
}
static void concurrent_loop(void)
{
printf("\r\n===== 全部外设并发运行 =====\r\n");
LCD_Clear(GREEN);
delay_1ms(500);
uint32_t counter = 0;
volatile uint16_t *sram16 = (volatile uint16_t *)0xC0000000;
for (int iter = 0; iter < 10; iter++) {
led_on(LED1_PORT, LED1_PIN);
led_off(LED2_PORT, LED2_PIN);
sram16[100 + iter] = (uint16_t)(iter * 0x1111);
__DSB();
uint16_t val = sram16[100 + iter];
printf("[并发] iter=%d, SDRAM[%d]=0x%04X, LED1=ON\r\n", iter, 100 + iter, val);
delay_1ms(500);
led_off(LED1_PORT, LED1_PIN);
led_on(LED2_PORT, LED2_PIN);
sram16[200 + iter] = (uint16_t)(iter * 0x2222);
__DSB();
val = sram16[200 + iter];
printf("[并发] iter=%d, SDRAM[%d]=0x%04X, LED2=ON\r\n", iter, 200 + iter, val);
delay_1ms(500);
counter += 2;
}
printf("\r\n===== 并发测试完成 =====\r\n");
LCD_Clear(BLUE);
delay_1ms(1000);
}
// =============================================================
// Touch 测试
// =============================================================
static void test_touch(void)
{
printf("\r\n===== Touch 测试 (多点触控) =====\r\n");
uint8_t ret = GT1151_Init();
if (ret != 0)
{
printf(" Touch 初始化失败 (ret=%d)\r\n", ret);
return;
}
printf(" Touch 初始化成功,等待触摸中断...\r\n");
static const uint16_t TP_COLORS[5] = {
0xFFE0, // YELLOW - point 0
0x07FF, // CYAN - point 1
0xF81F, // MAGENTA - point 2
0x07E0, // GREEN - point 3
0xF800 // RED - point 4
};
const uint16_t BG_COLOR = 0x0841;
LCD_Clear(BG_COLOR);
POINT_COLOR = CYAN;
LCD_ShowString(10, 10, 460, 24, 16, 0, (uint8_t *)"=== Multi-Touch (5pt) ===");
POINT_COLOR = WHITE;
LCD_ShowString(10, 30, 460, 24, 16, 0, (uint8_t *)"Touch with up to 5 fingers");
for (uint8_t i = 0; i < CT_MAX_TOUCH; i++)
{
POINT_COLOR = TP_COLORS[i];
char lbl[8];
sprintf(lbl, "P%d: --", i);
LCD_ShowString(10, 52 + i * 18, 200, 18, 16, 0, (uint8_t *)lbl);
}
uint16_t last_x[5];
uint16_t last_y[5];
bool was_active[5];
for (uint8_t i = 0; i < CT_MAX_TOUCH; i++)
{
last_x[i] = 0xFFFF;
last_y[i] = 0xFFFF;
was_active[i] = false;
}
uint32_t idle_counter = 0;
g_touch_irq_flag = 0;
while (1)
{
if (g_touch_irq_flag)
{
g_touch_irq_flag = 0;
delay_1ms(5);
GT1151_Scan(0);
idle_counter = 0;
uint8_t active_cnt = TP_ACTIVE_COUNT(tp_dev.sta);
uint8_t mask = tp_dev.sta & 0x1F;
for (uint8_t i = 0; i < CT_MAX_TOUCH; i++)
{
bool active = (mask & (1 << i)) != 0;
if (active)
{
uint16_t x = tp_dev.x[i];
uint16_t y = tp_dev.y[i];
if (x < lcddev.width && y < lcddev.height)
{
POINT_COLOR = TP_COLORS[i];
char buf[20];
sprintf(buf, "P%d: X:%-3d Y:%-3d", i, x, y);
LCD_FillRectangle(10, 52 + i * 18, 200, 52 + i * 18 + 17);
LCD_ShowString(10, 52 + i * 18, 200, 18, 16, 0, (uint8_t *)buf);
if (was_active[i] && last_x[i] != 0xFFFF)
{
POINT_COLOR = TP_COLORS[i];
LCD_DrawLine(last_x[i], last_y[i], x, y);
}
POINT_COLOR = TP_COLORS[i];
LCD_FillCircle(x, y, 5);
last_x[i] = x;
last_y[i] = y;
was_active[i] = true;
}
}
else
{
if (was_active[i])
{
POINT_COLOR = BG_COLOR;
LCD_FillCircle(last_x[i], last_y[i], 6);
POINT_COLOR = TP_COLORS[i];
LCD_FillRectangle(10, 52 + i * 18, 200, 52 + i * 18 + 17);
LCD_ShowString(10, 52 + i * 18, 200, 18, 16, 0, (uint8_t *)"released");
last_x[i] = 0xFFFF;
last_y[i] = 0xFFFF;
was_active[i] = false;
}
}
}
printf("[TOUCH] cnt=%d sta=0x%02X", active_cnt, tp_dev.sta);
for (uint8_t i = 0; i < CT_MAX_TOUCH; i++)
{
if (mask & (1 << i))
printf(" P%d(%u,%u)", i, tp_dev.x[i], tp_dev.y[i]);
}
printf("\r\n");
}
else
{
idle_counter++;
delay_1ms(10);
if (idle_counter > 500)
{
printf(" 无触摸超过 5 秒,退出 Touch 测试\r\n");
break;
}
}
}
LCD_Clear(BLUE);
printf(" Touch 测试完成\r\n");
delay_1ms(500);
}
// =============================================================
// 主函数
// =============================================================
int main(void)
{
// ---- 早期启动: 16MHz,原始寄存器操作 ----
init_leds();
led_pattern(0x01);
init_usart0();
led_pattern(0x03);
uart_puts("\r\n===== LSPi Board Bring-Up =====\r\n");
uart_puts("Early boot: LED + UART at 16MHz\r\n");
uint32_t cs = RCU_CFG0 & RCU_CFG0_SCS;
uart_puts("Clock source: ");
if (cs == RCU_SCSS_IRC16M) uart_puts("IRC16M (16MHz)\r\n");
else if (cs == RCU_SCSS_HXTAL) uart_puts("HXTAL (25MHz)\r\n");
else if (cs == RCU_SCSS_PLLP) uart_puts("PLL (168MHz)\r\n");
else uart_puts("UNKNOWN\r\n");
uart_puts("SystemCoreClock: ");
uart_putdec(SystemCoreClock);
uart_puts(" Hz\r\n");
// LED 闪烁验证
for (int i = 0; i < 3; i++) {
led_on(LED2_PORT, LED2_PIN);
delay_16m(200);
led_off(LED2_PORT, LED2_PIN);
delay_16m(200);
}
uart_puts("LED blink OK\r\n");
// ---- 硬件初始化: 切换到 168MHz ----
uart_puts("Initializing hardware...\r\n");
led_pattern(0x05);
hardware_init();
reinit_usart0_168m();
cs = RCU_CFG0 & RCU_CFG0_SCS;
uart_puts("Clock after init: ");
if (cs == RCU_SCSS_PLLP) uart_puts("PLL (168MHz)\r\n");
else uart_puts("UNKNOWN\r\n");
uart_puts("SystemCoreClock: ");
uart_putdec(SystemCoreClock);
uart_puts(" Hz\r\n");
// ---- C++ 驱动初始化 ----
led_pattern(0x07);
LedManager::instance().init_all();
LedManager::instance().led(1).on();
delay_16m(100);
LedManager::instance().led(1).off();
uart_puts("LedManager OK\r\n");
led_pattern(0x09);
{
UartConfig cfg;
cfg.baudrate = 9600;
UartBus::default_instance().init(cfg);
}
uart_puts("UartBus init OK\r\n");
// ---- SysTick 配置 ----
led_pattern(0x0B);
systick_config();
delay_1ms(500);
uart_puts("SysTick OK, delay_1ms available\r\n");
// ---- 外设测试 ----
led_pattern(0x0C);
printf("\r\n========================================\r\n");
printf(" LSPi 全外设测试\r\n");
printf("========================================\r\n");
test_sdram_driver();
delay_1ms(500);
test_flash_driver();
delay_1ms(500);
test_lcd();
delay_1ms(500);
test_sdram_after_lcd();
delay_1ms(500);
concurrent_loop();
delay_1ms(500);
test_touch();
delay_1ms(500);
// ---- 主循环 ----
led_pattern(0x0F);
printf("\r\n===== 所有外设测试完成 =====\r\n");
printf("系统运行于 168MHz, Flash/SDRAM/LCD/UART/LED 全部正常\r\n");
uint32_t tick = 0;
while (1) {
led_on(LED4_PORT, LED4_PIN);
delay_1ms(250);
led_off(LED4_PORT, LED4_PIN);
delay_1ms(250);
tick++;
if (tick % 4 == 0)
printf(".");
}
}