硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1720|回复: 4
收起左侧

[技术讨论] fsmc+dma刷新lvgl失真,颜色错乱

[复制链接]

9

主题

25

回帖

52

积分

初级会员

积分
52
发表于 2024-12-5 14:28:44 | 显示全部楼层 |阅读模式
如题,板子是407,屏幕是8bits的并口屏,fsmc通讯,在使用fsmc打点/区域填充刷新时效果如图二,使用dma后反正失真了,如图一,请求下这是问什么?头文件:#define    LCD_DRI_FSMC                        1

#if LCD_DRI_FSMC
#define LCD_DRI_FSMC_DMA                    1   
#define FSMC_DMA_STREAM_IRQ                    DMA2_Stream7_IRQn   
#define FSMC_DMA_STREAM_IRQFun                DMA2_Stream7_IRQHandler
#endif

/*
            说明:ST77916驱动接口为8080时序,采用FSMC+DMA实现
2^26 =0X0400 0000 = 64MB,每个 BANK 有4*64MB = 256MB
64MB:FSMC_Bank1_NORSRAM1:0X6000 0000 ~ 0X63FF FFFF
64MB:FSMC_Bank1_NORSRAM2:0X6400 0000 ~ 0X67FF FFFF
64MB:FSMC_Bank1_NORSRAM3:0X6800 0000 ~ 0X6BFF FFFF
64MB:FSMC_Bank1_NORSRAM4:0X6C00 0000 ~ 0X6FFF FFFF

选择BANK1-BORSRAM4 连接 TFT,地址范围为0X6C00 0000 ~ 0X6FFF FFFF
使用FSMC地址线的A18 接LCD的DC(即Rs引脚,命令/数据选择)脚
寄存器基地址 = 0X6C00 0000
16位数据时: 16bits ==>> FSMC[24:0] == HADDR[25:1]
8位数据时:      8bits  ==>> FSMC[25:0] == HADDR[25:0]
16位数据FSMC_A18>> RAM BASE = 0x6C00 0000  + 2^18*2 = 0x6C080000
8位数据FSMC_A18>>     RAM BASE = 0x6C00 0000  + 2^18    = 0x6C040000
当选择不同的地址线时,地址要重新计算  
*/

/**************** ST77916 显示屏的 FSMC 参数定义 **********/
#define    FSMC_BANK1_NORSRAMX                    (0x6C000000)
#define FSMC_ST77916_BASE                     ((uint32)(FSMC_BANK1_NORSRAMX | 0x00000000))

//FSMC_Bank4_NORSRAM用于LCD命令操作的地址        
#define FSMC_Addr_ST77916_CMD                (FSMC_ST77916_BASE)         

//FSMC_Bank1_NORSRAM用于LCD数据操作的地址      
#define FSMC_Addr_ST77916_DATA                ((FSMC_ST77916_BASE +  (1 <<18)))  c文件dma配置:static void ST77916_DmaTranCfg(void)
{
    __HAL_RCC_DMA2_CLK_ENABLE();
   
    /* Configure DMA request hdma_memtomem_dma2_stream7 on DMA2_Stream7 */
    hdma_memtomem_dma2_stream7.Instance = DMA2_Stream7;
    hdma_memtomem_dma2_stream7.Init.Channel = DMA_CHANNEL_0;
    hdma_memtomem_dma2_stream7.Init.Direction = DMA_MEMORY_TO_MEMORY;
    hdma_memtomem_dma2_stream7.Init.PeriphInc = DMA_PINC_ENABLE;
    hdma_memtomem_dma2_stream7.Init.MemInc = DMA_MINC_ENABLE;
    hdma_memtomem_dma2_stream7.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_memtomem_dma2_stream7.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_memtomem_dma2_stream7.Init.Mode = DMA_NORMAL;
    hdma_memtomem_dma2_stream7.Init.Priority = DMA_PRIORITY_LOW;
    hdma_memtomem_dma2_stream7.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_memtomem_dma2_stream7.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_memtomem_dma2_stream7.Init.MemBurst = DMA_MBURST_INC8;
    hdma_memtomem_dma2_stream7.Init.PeriphBurst = DMA_PBURST_INC8;
    if (HAL_DMA_Init(&hdma_memtomem_dma2_stream7) != HAL_OK)
    {
        ERR_HANDLER();
    }

  /* DMA2_Stream7_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(FSMC_DMA_STREAM_IRQ, FSMC_DMA_MAIN_PRIO, FSMC_DMA_SUB_PRIO);
  HAL_NVIC_EnableIRQ(FSMC_DMA_STREAM_IRQ);

  /* 注册DMA传输完成中断 */
    HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream7, HAL_DMA_XFER_CPLT_CB_ID, lv_FsmcDmaCallBack);
}

/**
* @brief  LCD     DMA传输完成中断函数
* @param  无
* @retval 无
*/
void FSMC_DMA_STREAM_IRQFun(void)
{
    HAL_DMA_IRQHandler(&hdma_memtomem_dma2_stream7);   
}void ST77916_DispFill(uint16 usX1, uint16 usY1, uint16 usX2, uint16 usY2,const uint16 *pData)
{
#if LCD_DRI_FSMC_DMA
    uint32 temp = ((usX2 +1 -usX1) * (usY2 +1 -usY1));
    ST77916_WriteCmd(CMD_SetCoordinateX);
    ST77916_WriteData(usX1 >> 8);            
    ST77916_WriteData(usX1 & 0xFF);            
    ST77916_WriteData(usX2 >>8);            
    ST77916_WriteData(usX2 & 0xFF);            
    ST77916_WriteCmd(CMD_SetCoordinateY);  
    ST77916_WriteData(usY1 >> 8);            
    ST77916_WriteData(usY1 & 0xFF);            
    ST77916_WriteData(usY2 >> 8);            
    ST77916_WriteData(usY2 & 0xFF);   
    ST77916_WriteCmd(CMD_SetPixel);

    HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream7, (uint32)pData, FSMC_Addr_ST77916_DATA, temp);
#else
    for (uint16 y_start = usY1;y_start <=usY2;y_start++)  // 逐行显示
    {
        ST77916_WriteCmd(CMD_SetCoordinateX);     
        ST77916_WriteData(usX1 >> 8);            
        ST77916_WriteData(usX1 & 0xFF);
        ST77916_WriteCmd(CMD_SetCoordinateY);
        ST77916_WriteData(y_start >> 8);            
        ST77916_WriteData(y_start & 0xFF);
        ST77916_WriteCmd(CMD_SetPixel);
        for (uint16 x_start = usX1; x_start <= usX2; x_start++)    //1行中从左到右逐个像素
        {
            ST77916_WriteData((*pData) >> 0x08);
            ST77916_WriteData((*pData)  & 0xFF);   
            pData++;
        }
    }
#endif   
}static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(disp_flush_enabled) {
        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
#if 0  // 打点
        int32_t x;
        int32_t y;
        for(y = area->y1; y <= area->y2; y++) {
            for(x = area->x1; x <= area->x2; x++) {
                /*Put a pixel to the display. For example:*/
                /*put_px(x, y, *color_p)*/
                ST77916_DrawPoint(x,y,color_p->full);
                color_p++;
               
            }
        }
#else  // 区域填充
        ST77916_DispFill(area->x1,area->y1,area->x2,area->y2,(uint16 *)color_p);
#endif        
    }

    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
#if !LCD_DRI_FSMC_DMA     
    lv_disp_flush_ready(disp_drv);
#endif
}

#if LCD_DRI_FSMC_DMA
/* DMA 传输完成中断回调函数 */
void lv_FsmcDmaCallBack(DMA_HandleTypeDef *_Hdma)
{
    //lv_disp_flush_ready(&disp_drv);   
    lv_disp_flush_ready(lv_disp_get_default()->driver);
}
#endif


使用fsmc+DMA刷新

使用fsmc+DMA刷新

使用fsmc刷新

使用fsmc刷新
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2024-12-5 15:38:21 | 显示全部楼层
和你的不同的地方是,我这个是16bit的,其它都用了,可以参考,

STM32F407+LVGL8+RA8875+外部SRAM,视频展示800*480做滑动效果流畅度也不错(2023-07-18)
https://forum.anfulai.cn/forum.p ... 0162&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

9

主题

25

回帖

52

积分

初级会员

积分
52
 楼主| 发表于 2024-12-6 12:04:31 | 显示全部楼层
eric2013 发表于 2024-12-5 15:38
和你的不同的地方是,我这个是16bit的,其它都用了,可以参考,

STM32F407+LVGL8+RA8875+外部SRAM,视频 ...

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
        /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
        int32_t x;
        int32_t y;
        x = area->x2- area->x1 + 1;
        for(y = area->y1; y <= area->y2; y++) {
                RA8875_DrawHColorLine( area->x1 , y, x, (const uint16_t *)color_p);
                color_p = color_p + x;
        }

    /*IMPORTANT!!!
     *Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}
void RA8875_DrawHColorLine(uint16_t _usX1 , uint16_t _usY1, uint16_t _usWidth, const uint16_t *_pColor)
{
       

        s_ucRA8875Busy = 1;
       
        RA8875_REG = 0x46; RA8875_RAM = _usX1;
        RA8875_REG = 0x47; RA8875_RAM = _usX1 >> 8;
        RA8875_REG = 0x48; RA8875_RAM = _usY1;
        RA8875_REG = 0x49; RA8875_RAM = _usY1 >> 8;

        RA8875_REG = 0x02;                 /* 用于设定RA8875 进入内存(DDRAM或CGRAM)读取/写入模式 */

#if 1
        {
                uint16_t i;
                for (i = 0; i < _usWidth; i++)
                {
                        RA8875_RAM = *_pColor++;
                        //RA8875_WriteData16(*_pColor++);
                }
        }
#else
        DMA2_Stream7->PAR = (uint32_t )_pColor;
        DMA2_Stream7->NDTR =_usWidth;
        DMA2_Stream7->CR |= 1<<0;       
       
        while(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) == RESET);
        DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);
#endif
       
        s_ucRA8875Busy = 0;
}
哥,这只是开启dma传输而已吧,然后死等传输结束;开启dma传输的话,bsp初始化不需要配置DMA2_STRAM的时钟和寄存器配置吗,我没看到有的
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2024-12-6 13:01:55 | 显示全部楼层
cv_master 发表于 2024-12-6 12:04
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
...


1、这个例子测试的时候有加入,整理发布的版本里面忘了整理进来了,初始化在bsp.c里面。参考此贴移植过去即可。

【原创开源应用第4期】给ili9488,RA8875等类显示屏的emWin底层增加DMA加速,提供RTX,uCOS和FreeRTOS版本
https://forum.anfulai.cn/forum.php? ... id=87501&fromuid=58
(出处: 硬汉嵌入式论坛)

2、然后就是死等问题。正确理解GUI的DMA加速玩法

【深入探讨】DMA到底能不能起到加速程序执行的作用,DMA死等操作是否合理,多个DMA数据流同时刷是否处理过来
https://forum.anfulai.cn/forum.php? ... d=109765&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

9

主题

25

回帖

52

积分

初级会员

积分
52
 楼主| 发表于 2024-12-6 20:47:10 | 显示全部楼层
void ST77916_DispFill(uint16 usX1, uint16 usY1, uint16 usX2, uint16 usY2, uint16 *pData)
{
#if LCD_DRI_FSMC_DMA
        uint32 temp = ((usX2 +1 -usX1) * (usY2 +1 -usY1));
        ST77916_WriteCmd(CMD_SetCoordinateX);
        ST77916_WriteData(usX1 >> 8);            
        ST77916_WriteData(usX1 & 0xFF);            
        ST77916_WriteData(usX2 >>8);            
        ST77916_WriteData(usX2 & 0xFF);            
        ST77916_WriteCmd(CMD_SetCoordinateY);  
        ST77916_WriteData(usY1 >> 8);            
        ST77916_WriteData(usY1 & 0xFF);            
        ST77916_WriteData(usY2 >> 8);            
        ST77916_WriteData(usY2 & 0xFF);   
        ST77916_WriteCmd(CMD_SetPixel);
       
        #if LCD_DRI_FSMC_8080_8BIT
        for(uint32 i=0;i<temp;i++)
        {
                pData[i] = (pData[i] & 0xFF << 8) | pData[i] >>8;
        }
        #endif
       
        #if 0   // DMA传输,不开启完成中断
        DMA_SetConfig(&hdma_memtomem_dma2_stream7, (uint32)pData, FSMC_Addr_ST77916_DATA, temp);
        hdma_memtomem_dma2_stream7.Instance->CR |= 1<<0;
        while(__HAL_DMA_GET_FLAG(&hdma_memtomem_dma2_stream7,DMA_FLAG_TCIF3_7) == RESET);
        __HAL_DMA_CLEAR_FLAG(&hdma_memtomem_dma2_stream7,DMA_FLAG_TCIF3_7);       
        #else
        HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream7, (uint32)pData, FSMC_Addr_ST77916_DATA, temp);
        #endif
       
#else
        for (uint16 y_start = usY1;y_start <=usY2;y_start++)  // 逐行显示
        {
                ST77916_WriteCmd(CMD_SetCoordinateX);        
                ST77916_WriteData(usX1 >> 8);            
                ST77916_WriteData(usX1 & 0xFF);
                ST77916_WriteCmd(CMD_SetCoordinateY);
                ST77916_WriteData(y_start >> 8);            
                ST77916_WriteData(y_start & 0xFF);
                ST77916_WriteCmd(CMD_SetPixel);
                for (uint16 x_start = usX1; x_start <= usX2; x_start++)        //1行中从左到右逐个像素
                {
                        ST77916_WriteData((*pData) >> 0x08);
                        ST77916_WriteData((*pData)  & 0xFF);       
                        pData++;
                }
        }
#endif       
}
已解决,大小端的问题;但第三个圈颜色还是不对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 06:07 , Processed in 0.041841 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表