2301_76906428 2024-06-02 21:39 采纳率: 0%
浏览 1156
已结题

stm32 lvgl+DMA,屏幕显示不全有条纹

现象:

img


stm32f103zet6 使用hal库开发,普中玄武的板子
本来用画点的方法没有问题,但是刷新太慢,于是尝试用DMA传输,就遇到了这个问题。
lv_port_disp.c

static void disp_init(void)
{
    /*You code here*/
    TFTLCD_Init();
    HAL_DMA_RegisterCallback(
            &hdma_memtomem_dma1_channel1,
            HAL_DMA_XFER_CPLT_CB_ID,
            LVGL_LCD_FSMC_DMA_pCallback);//注册LVGL_LCD_FSMC_DMA_pCallback函数,用于通知DMA传输完成
}
static void disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    if (disp_flush_enabled)
    {
        LCD_Address_Set(area->x1, area->y1, area->x2, area->y2);
        HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1, (uint32_t)color_p, (uint32_t)&(TFTLCD->LCD_DATA),
                                         ((area->x2 + 1) - area->x1) * ((area->y2 + 1) - area->y1));
    }
}
void LVGL_LCD_FSMC_DMA_pCallback(DMA_HandleTypeDef *_hdma)
{
    lv_disp_flush_ready(&disp_drv);
}
//TFT_LCD定义
typedef struct
{
    uint16_t LCD_CMD;
    uint16_t LCD_DATA;
} TFTLCD_TypeDef;

// 使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A10作为数据命令区分线
// 注意设置16位总线时STM32内部会右移一位对齐!
#define TFTLCD_BASE ((uint32_t)(0x6C000000 | 0x000007FE))
#define TFTLCD ((TFTLCD_TypeDef *)TFTLCD_BASE)

cubemx配置:

img


Data Width都试过了,按理说应该配置为Half word,但是显示却是这样的:

img


我放了一个方形的按钮部件在中间,设置为Byte勉强能看出来有个完整的按钮,设置为half word按钮直接裂开了(字面意思),如果改成word就什么都不显示了,我经过调试,y1,y2有在正常增加,没有跳过,也没看出来是不是DMA的问题,实在解决不了。

  • 写回答

22条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-06-02 21:39
    关注
    获得0.45元问题酬金

    引自免费微信小程序:皆我百晓生

    看起来你在使用STM32F103ZET6微控制器与普中玄武板上的LCD配合LVGL进行图形界面开发,并且尝试通过DMA来提高屏幕更新速度,但遇到了显示不全和条纹的问题。根据提供的信息,我将分析可能的原因并提供相应的解决方案。

    首先,确保你的硬件连接正确无误,包括电源、时钟、数据线、控制线等。接下来,我们将从软件方面进行排查。

    1. 检查LCD初始化和配置: 确保LCD的初始化函数TFTLCD_Init()已经正确设置了正确的参数,例如时钟频率、数据线宽度、接口模式等。同时确认LCD的数据线是否正确连接到FSMC的对应引脚。

    2. DMA设置: 你已经配置了正常的传输模式,地址递增,以及数据宽度为Byte。这一步看起来是正确的。然而,由于你提到当数据宽度设置为Half Word时出现了问题,这可能是DMA与LCD之间的数据对齐问题。检查一下你的LCD数据线宽度是否支持半字节访问,有些LCD可能只接受字节或字数据传输。

    3. DMA传输大小: 当你改变数据宽度时,记得调整每次传输的数据量。例如,如果你改为Half Word,则每个像素由两个字节组成,因此你需要乘以2来计算总传输量。确保HAL_DMA_Start_IT中的最后一个参数是正确的。

    4. 驱动程序配置: 在LVGL的驱动程序中,确保所有的回调函数都正确地被调用并且传递了正确的参数。特别关注disp_flush函数,确保它在正确的时机开始DMA传输,并且LVGL_LCD_FSMC_DMA_pCallback函数在DMA传输完成后被正确触发。

    5. 调试技巧: 可以在代码的关键部分添加日志输出,以便于跟踪DMA传输的状态和数据是否正确写入到LCD。另外,试着减缓DMA传输的速度,看看是否可以改善显示效果,这可以帮助确定是否是实时性问题。

    6. 检查中断处理: 确保中断处理程序没有阻塞或者导致其他问题。有时候,中断处理不当可能会干扰到DMA的工作。

    7. 代码示例: 这是一个简化版的示例代码,展示了如何根据颜色数组填充LCD缓冲区,然后使用DMA进行传输。这里假设你已经在初始化阶段设置了正确的数据线宽度(例如,对于16位宽的LCD,数据宽度应设为HAL_DMA_DATAWIDTH_HalfWord):

    // 假设lv_color_t 是一个16位的颜色类型
    void disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
    {
        if (disp_flush_enabled)
        {
            LCD_Address_Set(area->x1, area->y1, area->x2, area->y2);
    
            uint32_t buffer_size = ((area->x2 + 1) - area->x1) * ((area->y2 + 1) - area->y1) * sizeof(lv_color_t);
            uint32_t* buffer = (uint32_t*)malloc(buffer_size); // 创建临时缓冲区
            uint32_t i;
    
            for (i = 0; i < buffer_size / sizeof(uint32_t); ++i)
            {
                buffer[i] = color_p[i];
            }
    
            HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1, (uint32_t)buffer, (uint32_t)&(TFTLCD->LCD_DATA), buffer_size / sizeof(uint32_t));
    
            free(buffer); // 释放临时缓冲区
        }
    }
    
    void LVGL_LCD_FSMC_DMA_pCallback(DMA_HandleTypeDef *_hdma)
    {
        lv_disp_flush_ready(&disp_drv);
    }
    

    这个例子中,我们创建了一个临时的整数缓冲区,将lv_color_t类型的颜色转换成整数,然后使用DMA进行传输。这样做是为了确保数据的正确对齐,特别是对于16位宽的LCD。当然,这个方法可能不是最高效的,但在解决显示问题后,你可以考虑优化它。

    请按照上述步骤进行排查,并在必要的地方修改代码。如果问题仍然存在,可能需要进一步查看你的硬件设计或LVGL的配置细节。

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 6月10日
  • 创建了问题 6月2日