615 lines
20 KiB
C
615 lines
20 KiB
C
/*
|
||
* 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 buffer(Ping/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);
|