chore: migrate project into clean repository

This commit is contained in:
yuuux
2026-08-13 16:50:52 +08:00
commit d1d25a09e7
27405 changed files with 9422808 additions and 0 deletions

View File

@@ -0,0 +1,614 @@
/*
* Copyright (c) 2025, LISTENAI
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <string.h>
#include "lisa_device.h"
#include "lisa_rgb.h"
#include "Driver_RGB.h"
#include "Driver_GPDMA.h"
#include "lisa_semaphore.h"
#include "lisa_mutex.h"
#include "lisa_mem.h"
#include "sysheap.h"
#include "board.h"
#define LOG_TAG "lisa_rgb"
#include "lisa_log.h"
/* ========================================================================
* 私有数据结构
* ======================================================================== */
typedef struct {
void *hal_rgb; /**< HAL RGB 驱动句柄 */
lisa_mutex_t *lock; /**< 互斥锁 */
lisa_semaphore_t *done_sem; /**< 传输完成信号量 */
lisa_semaphore_t *write_sem; /**< 写入信号量(防止重复写入) */
/* GPDMA 配置 */
csk_gpdma_ch_t gpdma_ch; /**< GPDMA 通道号 */
/* 帧缓冲配置 */
uint8_t *fb_buf[2]; /**< 双缓冲:[0]=写缓冲, [1]=显示缓冲(或反之) */
uint32_t fb_size; /**< 单个帧缓冲区大小(字节) */
/* Bounce Buffer 配置 */
uint8_t *bounce_buffer[2]; /**< 内部RAM bounce bufferPing/Pong */
uint32_t bb_size; /**< 单个bounce buffer大小字节 */
uint32_t bounce_pos; /**< 当前在帧缓冲中的位置(字节) */
/* 双缓冲管理 */
volatile uint8_t display_idx; /**< 当前DMA正在显示的帧缓冲索引 (0 or 1) */
volatile uint8_t write_idx; /**< 当前应用层写入的帧缓冲索引 (0 or 1) */
volatile uint8_t swap_pending; /**< 是否有新帧待切换 (0 or 1) */
/* 传输状态 */
bool is_running; /**< 是否正在运行 */
} lisa_rgb_priv_t;
/* ========================================================================
* 辅助宏定义
* ======================================================================== */
#define RGB_LOCK(priv) \
do { \
if ((priv)->lock) { \
lisa_mutex_lock((priv)->lock, LISA_OS_WAIT_FOREVER); \
} \
} while (0)
#define RGB_UNLOCK(priv) \
do { \
if ((priv)->lock) { \
lisa_mutex_unlock((priv)->lock); \
} \
} while (0)
/* ========================================================================
* HAL 层映射函数
* ======================================================================== */
static inline int hal_status_to_err(int status)
{
return (status == CSK_DRIVER_OK) ? LISA_DEVICE_OK : LISA_DEVICE_ERR_IO;
}
static rgb_emFormatIn to_hal_input_format(lisa_rgb_input_format_t fmt)
{
switch (fmt) {
case LISA_RGB_INPUT_FORMAT_RGB888:
return RGB_INPUT_FORMAT_RGB888;
case LISA_RGB_INPUT_FORMAT_XRGB8888:
return RGB_INPUT_FORMAT_XRGB8888;
case LISA_RGB_INPUT_FORMAT_RGB565:
default:
return RGB_INPUT_FORMAT_RGB565;
}
}
static rgb_emFormatOut to_hal_output_format(lisa_rgb_output_format_t fmt)
{
switch (fmt) {
case LISA_RGB_OUTPUT_FORMAT_RGB888:
return RGB_OUTPUT_FORMAT_RGB888;
case LISA_RGB_OUTPUT_FORMAT_RGB666:
return RGB_OUTPUT_FORMAT_RGB666;
case LISA_RGB_OUTPUT_FORMAT_BGR888:
return RGB_OUTPUT_FORMAT_BGR888;
case LISA_RGB_OUTPUT_FORMAT_BGR666:
return RGB_OUTPUT_FORMAT_BGR666;
case LISA_RGB_OUTPUT_FORMAT_BGR565:
return RGB_OUTPUT_FORMAT_BGR565;
case LISA_RGB_OUTPUT_FORMAT_RGB565:
default:
return RGB_OUTPUT_FORMAT_RGB565;
}
}
static rgb_emPol to_hal_polarity(lisa_rgb_polarity_t pol)
{
return (pol == LISA_RGB_POLARITY_POSITIVE) ? RGB_POLARITY_POSITIVE : RGB_POLARITY_NEGATIVE;
}
/* ========================================================================
* Bounce Buffer 管理
* ======================================================================== */
/**
* @brief 填充bounce buffer
* 从当前显示的帧缓冲拷贝数据到指定的bounce buffer
* @param priv 私有数据指针
* @param bb_idx bounce buffer索引 (0 或 1)
* @return 是否完成一帧传输 (1=完成, 0=未完成)
*/
static int bounce_buffer_fill(lisa_rgb_priv_t *priv, uint8_t bb_idx)
{
// 从当前显示的帧缓冲读取数据
uint8_t *src = priv->fb_buf[priv->display_idx];
uint8_t *dst = priv->bounce_buffer[bb_idx];
uint32_t copy_size = priv->bb_size;
// 检查是否到帧末尾,调整拷贝大小
if (priv->bounce_pos + copy_size > priv->fb_size) {
copy_size = priv->fb_size - priv->bounce_pos;
}
// 从帧缓冲拷贝到bounce buffer
memcpy(dst, src + priv->bounce_pos, copy_size);
#if CONFIG_DCACHE_ENABLE
// 刷新cache确保DMA能读到最新数据
extern void HAL_FlushDCache_by_Addr(uint32_t *addr, uint32_t len);
HAL_FlushDCache_by_Addr((uint32_t*)dst, copy_size);
#endif
priv->bounce_pos += copy_size;
// 检查是否完成一帧
if (priv->bounce_pos >= priv->fb_size) {
priv->bounce_pos = 0;
return 1; // 一帧完成
}
return 0;
}
/* ========================================================================
* RGB 事件回调
* ======================================================================== */
static void rgb_event_handler(uint32_t event, void *workspace)
{
(void)workspace;
switch (event) {
case RGB_IRQ_EVENT_SOF:
// 帧开始事件
break;
case RGB_IRQ_EVENT_EOF:
// 帧结束事件
LISA_LOGD(LOG_TAG, "RGB_IRQ_EVENT_EOF");
break;
case RGB_IRQ_EVENT_FIFO_RD_EMPTY:
// FIFO 读空事件 - 可能需要补充数据
LISA_LOGW(LOG_TAG, "RGB_IRQ_EVENT_FIFO_RD_EMPTY");
break;
case RGB_IRQ_EVENT_FIFO_RD_FULL:
// FIFO 读满事件
LISA_LOGW(LOG_TAG, "RGB_IRQ_EVENT_FIFO_RD_FULL");
break;
default:
break;
}
}
/* ========================================================================
* DMA 事件回调
* ======================================================================== */
static void gpdma_event_callback(uint32_t event, void *workspace)
{
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)workspace;
if (!priv) {
return;
}
int frame_done = 0;
uint8_t completed_bb = 0;
// 确定刚完成传输的bounce buffer索引
if (event & CSK_GPDMA_EVENT_PIPO0_DONE) {
completed_bb = 0;
} else if (event & CSK_GPDMA_EVENT_PIPO1_DONE) {
completed_bb = 1;
} else {
// 其他事件处理
LOGW("gpdma_event_callback event:%x", event);
return;
}
// 填充刚完成的bounce buffer为下一次传输准备
frame_done = bounce_buffer_fill(priv, completed_bb);
// 一帧传输完成,检查是否需要切换到新的帧缓冲
if (frame_done) {
if (priv->swap_pending) {
// 有新帧待显示:切换显示缓冲区
priv->display_idx = priv->write_idx;
priv->swap_pending = 0;
// 释放写入信号量,允许应用层写入新帧
if (priv->write_sem) {
lisa_semaphore_give(priv->write_sem);
}
// bounce_pos 已在 bounce_buffer_fill 中重置为 0
}
// 如果没有新帧,继续显示当前帧(自动重复)
}
// 重新加载DMA传输即使地址相同也需要reload
GPDMA_PiPo_Reload(priv->gpdma_ch, priv->bounce_buffer[completed_bb], NULL);
}
/* ========================================================================
* RGB API 实现
* ======================================================================== */
static int arcs_rgb_start(lisa_device_t *dev)
{
if (!dev || !dev->priv_data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)dev->priv_data;
RGB_LOCK(priv);
if (priv->is_running) {
LISA_LOGW(LOG_TAG, "RGB already running, stop first");
RGB_UNLOCK(priv);
return LISA_DEVICE_ERR_BUSY;
}
// 预填充两个 bounce buffer
bounce_buffer_fill(priv, 0);
bounce_buffer_fill(priv, 1);
// 启动 Ping-Pong DMA使用 bounce buffer
int ret = GPDMA_Start_PiPo(priv->gpdma_ch,
priv->bounce_buffer[0],
priv->bounce_buffer[1],
(void *)RGB0_Buf(),
(void *)RGB0_Buf(),
priv->bb_size / 4); // 以 WORD 为单位
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "GPDMA_Start_PiPo failed (%d)", ret);
RGB_UNLOCK(priv);
return LISA_DEVICE_ERR_IO;
}
LISA_LOGI(LOG_TAG, "GPDMA Ping-Pong started (bounce mode, bb_size: %lu words)",
(unsigned long)(priv->bb_size / 4));
// 启动 RGB 传输
ret = RGB_Start(priv->hal_rgb);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "RGB_Start failed (%d)", ret);
RGB_UNLOCK(priv);
return LISA_DEVICE_ERR_IO;
}
priv->is_running = true;
LISA_LOGI(LOG_TAG, "RGB transmission started");
RGB_UNLOCK(priv);
return LISA_DEVICE_OK;
}
static int arcs_rgb_stop(lisa_device_t *dev)
{
if (!dev || !dev->priv_data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)dev->priv_data;
RGB_LOCK(priv);
if (!priv->is_running) {
RGB_UNLOCK(priv);
return LISA_DEVICE_OK;
}
// 停止 RGB 传输
int ret = RGB_Stop(priv->hal_rgb);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "RGB_Stop failed (%d)", ret);
RGB_UNLOCK(priv);
return LISA_DEVICE_ERR_IO;
}
priv->is_running = false;
RGB_UNLOCK(priv);
return LISA_DEVICE_OK;
}
static int arcs_rgb_wait_done(lisa_device_t *dev, uint32_t timeout_ms)
{
if (!dev || !dev->priv_data) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)dev->priv_data;
if (!priv->done_sem) {
return LISA_DEVICE_ERR_NOT_SUPPORT;
}
if (lisa_semaphore_take(priv->done_sem, timeout_ms) != LISA_DEVICE_OK) {
LISA_LOGE(LOG_TAG, "wait_done timeout");
return LISA_DEVICE_ERR_TIMEOUT;
}
return LISA_DEVICE_OK;
}
/**
* @brief 更新图像数据Bounce Buffer 模式专用)
* @param dev 设备实例
* @param buf 图像数据缓冲区
* @param size 数据大小(字节)
* @return 0=成功,负数=错误码
*
* @note 此函数用于 Bounce Buffer 模式,将新图像数据拷贝到写缓冲区
* @note 函数会等待上一帧显示完成后才允许写入
*/
static int arcs_rgb_update_framebuffer(lisa_device_t *dev, const void *buf, uint32_t size)
{
if (!dev || !dev->priv_data || !buf || size == 0) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)dev->priv_data;
if (size > priv->fb_size) {
LISA_LOGW(LOG_TAG, "input size %lu exceeds fb size %lu", (unsigned long)size, (unsigned long)priv->fb_size);
size = priv->fb_size;
}
// 1. 等待写入信号量(确保不与上一次写入冲突)
if (!priv->write_sem || lisa_semaphore_take(priv->write_sem, 1000) != LISA_DEVICE_OK) {
LISA_LOGE(LOG_TAG, "write_sem timeout");
return LISA_DEVICE_ERR_TIMEOUT;
}
// 2. 选择写缓冲区(非显示缓冲区)
uint8_t write_idx = 1 - priv->display_idx;
// 3. 拷贝数据到写缓冲区LVGL buf -> framebuffer
memcpy(priv->fb_buf[write_idx], buf, size);
// 4. 标记待切换(中断中会检测并切换)
priv->write_idx = write_idx;
priv->swap_pending = 1;
return LISA_DEVICE_OK;
}
/* ========================================================================
* 设备初始化
* ======================================================================== */
static int arcs_rgb_setup(lisa_device_t *dev, const lisa_display_bus_rgb_config_t *config)
{
if (!dev || !config) {
return LISA_DEVICE_ERR_INVALID;
}
lisa_rgb_priv_t *priv = (lisa_rgb_priv_t *)dev->priv_data;
// 配置 RGB 初始化参数
RGB_InitTypeDef rgb_init = {0};
rgb_init.frms = RGB_FRAME_CONTINUE;
rgb_init.wires = RGB_OUTPUT_WIRES_24;
rgb_init.sync = RGB_SYNC_MODE_SYNC_DE;
rgb_init.de_continue = true;
rgb_init.format_in = to_hal_input_format(config->input_format);
rgb_init.format_out = to_hal_output_format(config->output_format);
rgb_init.out_lsb = config->output_lsb_first;
// 时序参数
rgb_init.img_width = config->timings.h_res;
rgb_init.img_height = config->timings.v_res;
rgb_init.h_pulse_width = config->timings.h_pulse_width;
rgb_init.v_pulse_width = config->timings.v_pulse_width;
rgb_init.h_front_blanking = config->timings.h_front_blanking;
rgb_init.h_back_blanking = config->timings.h_back_blanking;
rgb_init.v_front_blanking = config->timings.v_front_blanking;
rgb_init.v_back_blanking = config->timings.v_back_blanking;
// 信号极性
rgb_init.VSPolarity = to_hal_polarity(config->vsync_polarity);
rgb_init.HSPolarity = to_hal_polarity(config->hsync_polarity);
rgb_init.DEPolarity = to_hal_polarity(config->de_polarity);
rgb_init.CLKPolarity = to_hal_polarity(config->pclk_polarity);
// 时钟频率
rgb_init.clk_hz = config->pclk_hz;
// 初始化 RGB 外设
int ret = RGB_Initialize(priv->hal_rgb, rgb_event_handler, &rgb_init);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "RGB_Initialize failed (%d)", ret);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_INIT_FAIL;
}
// 启用时钟输出
ret = RGB_EnableClockout(config->pclk_hz);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "RGB_EnableClockout failed (%d)", ret);
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_INIT_FAIL;
}
// 初始化 GPDMA用于数据传输
ret = GPDMA_Initialize();
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "GPDMA_Initialize failed (%d)", ret);
RGB_DisableClockout();
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_INIT_FAIL;
}
// 配置 GPDMA
csk_gpdma_init_t gpdma_cfg = {
.dma_ch = priv->gpdma_ch,
.burst_len = gpdma_burst_len_8spl,
.sample_unit = gpdma_sample_unit_word,
.src_mode = address_mode_pipo,
.dst_mode = address_mode_pipo,
.tfr_mode = tfr_mode_m2p,
.src_inc_mode = inc_mode_increase,
.dst_inc_mode = inc_mode_fix,
.prio_lvl = prio_mode_vhigh,
.handshake = qspi_hs_num0,
};
ret = GPDMA_Config(&gpdma_cfg, gpdma_event_callback, priv);
if (ret != CSK_DRIVER_OK) {
LISA_LOGE(LOG_TAG, "GPDMA_Config failed (%d)", ret);
RGB_DisableClockout();
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->write_sem);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_INIT_FAIL;
}
// 计算帧缓冲区大小
uint32_t bpp = (config->input_format == LISA_RGB_INPUT_FORMAT_RGB565) ? 16 : 24;
uint32_t w = config->timings.h_res;
uint32_t h = config->timings.v_res;
priv->fb_size = (w * h * bpp) / 8;
// ========== Bounce Buffer 模式初始化 ==========
priv->bb_size = config->bounce_buffer_size * bpp / 8;
// 确保 bounce buffer 大小是帧缓冲大小的整数因子
if (priv->fb_size % priv->bb_size != 0) {
LISA_LOGE(LOG_TAG, "fb_size(%lu) must be multiple of bb_size(%lu)",
(unsigned long)priv->fb_size, (unsigned long)priv->bb_size);
RGB_DisableClockout();
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->write_sem);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_INVALID;
}
LISA_LOGI(LOG_TAG, "Bounce buffer mode enabled: bb_size=%lu, transfers_per_frame=%lu",
(unsigned long)priv->bb_size, (unsigned long)(priv->fb_size / priv->bb_size));
// 分配帧缓冲PSRAM- 双缓冲机制
for (int i = 0; (i < 2) && (priv->bb_size > 0); i++) {
priv->fb_buf[i] = (uint8_t *)lisa_mem_align_alloc(32, priv->fb_size);
if (!priv->fb_buf[i]) {
LISA_LOGE(LOG_TAG, "alloc fb %d failed (%lu bytes)", i, (unsigned long)priv->fb_size);
// 清理
for (int j = 0; j < i; j++) {
lisa_mem_free(priv->fb_buf[j]);
}
RGB_DisableClockout();
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->write_sem);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_NO_MEM;
}
// 初始化为白色测试图案
memset(priv->fb_buf[i], 0xFF, priv->fb_size);
LISA_LOGI(LOG_TAG, "alloc fb%d addr: %p (PSRAM)", i, priv->fb_buf[i]);
}
// 初始化双缓冲索引
priv->display_idx = 0; // 初始显示 fb_buf[0]
priv->write_idx = 0; // 尚未写入
priv->swap_pending = 0; // 无待切换帧
// 分配 bounce buffer内部RAM
for (int i = 0; i < 2; i++) {
priv->bounce_buffer[i] = (uint8_t *)inram_malloc(32, priv->bb_size);
if (!priv->bounce_buffer[i]) {
LISA_LOGE(LOG_TAG, "alloc bounce buffer %d failed (%lu bytes)", i, (unsigned long)priv->bb_size);
// 清理
for (int j = 0; j < i; j++) {
inram_free(priv->bounce_buffer[j]);
}
for (int j = 0; j < 2; j++) {
lisa_mem_free(priv->fb_buf[j]);
}
RGB_DisableClockout();
RGB_Uninitialize(priv->hal_rgb);
lisa_semaphore_delete(priv->write_sem);
lisa_semaphore_delete(priv->done_sem);
lisa_mutex_delete(priv->lock);
return LISA_DEVICE_ERR_NO_MEM;
}
memset(priv->bounce_buffer[i], 0x00, priv->bb_size);
LISA_LOGI(LOG_TAG, "alloc bounce_buffer[%d] addr: %p (Internal RAM)", i, priv->bounce_buffer[i]);
}
priv->bounce_pos = 0;
LISA_LOGI(LOG_TAG, "Bounce buffer initialized (fb_size: %lu, bb_size: %lu)",
(unsigned long)priv->fb_size, (unsigned long)priv->bb_size);
LISA_LOGI(LOG_TAG, "RGB device initialized (resolution: %dx%d, pclk: %lu Hz)",
config->timings.h_res, config->timings.v_res, (unsigned long)config->pclk_hz);
return LISA_DEVICE_OK;
}
/* ========================================================================
* 设备 API 和注册
* ======================================================================== */
static const lisa_rgb_api_t arcs_rgb_api = {
.stop = arcs_rgb_stop,
.setup = arcs_rgb_setup,
.start = arcs_rgb_start,
.wait_done = arcs_rgb_wait_done,
.update_framebuffer = arcs_rgb_update_framebuffer,
};
static lisa_rgb_priv_t rgb_priv;
/**
* @brief RGB 设备初始化入口函数
*/
int lisa_rgb0_init(void)
{
memset(&rgb_priv, 0, sizeof(rgb_priv));
lisa_rgb_pinmux();
rgb_priv.hal_rgb = RGB0();
rgb_priv.gpdma_ch = CONFIG_LISA_RGB_GPDMA_CH;
// 创建互斥锁
rgb_priv.lock = lisa_mutex_create();
if (!rgb_priv.lock) {
LISA_LOGE(LOG_TAG, "Failed to create mutex");
return LISA_DEVICE_ERR_NO_MEM;
}
// 创建信号量
rgb_priv.done_sem = lisa_semaphore_create(1);
if (!rgb_priv.done_sem) {
LISA_LOGE(LOG_TAG, "Failed to create semaphore");
lisa_mutex_delete(rgb_priv.lock);
return LISA_DEVICE_ERR_NO_MEM;
}
// 创建写入信号量(用于 Bounce Buffer 模式)
rgb_priv.write_sem = lisa_semaphore_create(1);
if (!rgb_priv.write_sem) {
LISA_LOGE(LOG_TAG, "Failed to create write semaphore");
lisa_semaphore_delete(rgb_priv.done_sem);
lisa_mutex_delete(rgb_priv.lock);
return LISA_DEVICE_ERR_NO_MEM;
}
lisa_semaphore_give(rgb_priv.write_sem); // 初始化为可用状态
return LISA_DEVICE_OK;
}
LISA_DEVICE_REGISTER(rgb0, &arcs_rgb_api, &rgb_priv, NULL, &lisa_rgb0_init, LISA_DEVICE_PRIORITY_NORMAL);