硬汉嵌入式论坛

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

[STM32CubeF4] 通过DMA将显示数据传入到LCD的GRAM中

[复制链接]

1

主题

8

回帖

11

积分

新手上路

积分
11
发表于 2024-5-15 20:50:12 | 显示全部楼层 |阅读模式
在用F407做LVGL的学习,正点原子的那个LCD_Color_Fill()效率太低了。于是想出这个方法,但不知道这种方法是否可行。我尝试过将dma方向设为内存到外设,设置了一个超时检测,结果总是超时,数据一个也没传入过去。又试了M2M,虽然不超时了,但LCD屏幕上还是什么都没有。搞不清楚问题在哪
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-5-15 21:17:52 | 显示全部楼层
dma设置的代码和lcd_color_fill代码如下:
void DMA_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

    DMA_DeInit(DMA2_Stream0);
    DMA_InitStructure.DMA_Channel = DMA_Channel_1;
    // DMA_InitStructure.DMA_PeripheralBaseAddr = 0;//(uint32_t)(0x6C000000); // LCD RAM address
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (LCD->LCD_RAM); // LCD RAM address

    DMA_InitStructure.DMA_Memory0BaseAddr    = 0;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize         = 0; // Will be configured later
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;

    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream1, DISABLE);

    // Enable transfer complete interrupt
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);

    // Configure and enable DMA interrupt
    NVIC_InitStructure.NVIC_IRQChannel                   = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void DMA_StartTransfer(uint32_t *src, uint32_t *dst, uint32_t length)
{
    // Disable the DMA stream before configuring it
    DMA_Cmd(DMA2_Stream0, DISABLE);
    // Wait until the DMA stream is disabled
    while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE) {}

    // Configure the source and destination addresses and the number of data items
    DMA2_Stream0->M0AR = (uint32_t)src;
    DMA2_Stream0->PAR  = (uint32_t)dst;
    DMA2_Stream0->NDTR = length;
    // 清除所有 DMA 中断标志
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);

    // 启用传输完成中断
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
    // Enable the DMA stream
    DMA_Cmd(DMA2_Stream0, ENABLE);
}

// DMA interrupt handler
void DMA2_Stream0_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) {
        // Clear DMA interrupt flag
        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
    }
}
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-5-15 21:18:22 | 显示全部楼层
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 *color)
{
    u16 width            = ex - sx + 1;
    u16 height           = ey - sy + 1;
    u32 total_pixels     = width * height;
    u32 remaining_pixels = total_pixels;
    u32 current_offset   = 0;

    // 准备写入GRAM
    LCD_WriteRAM_Prepare();

    // 设置光标位置
    LCD_SetCursor(sx, sy);

    while (remaining_pixels > 0) {
        u32 transfer_size = (remaining_pixels > DMA_MAX_TRANSFER) ? DMA_MAX_TRANSFER : remaining_pixels;

        // 启动 DMA 传输,注意目标地址的计算
        DMA_StartTransfer((uint32_t *)(color + current_offset), (uint32_t *)&LCD->LCD_RAM + current_offset, transfer_size);

        // 等待 DMA 传输完成并增加超时机制
        uint32_t timeout = DMA_TIMEOUT;
        while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE && --timeout > 0) {}

        if (timeout == 0) {
            // 处理超时情况
            LED0 = 0;
            // 输出剩余像素数
            printf("DMA transfer timed out, remaining pixels: %d\n", remaining_pixels);
            break;
        }

        current_offset += transfer_size;
        remaining_pixels -= transfer_size;
    }
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107970
QQ
发表于 2024-5-16 09:19:28 | 显示全部楼层
有做DMA加速,供参考。

基于V5,V6和V7的LVGL模板,驱动支持单缓冲,双缓冲和配合硬件消隐的双缓冲,以及电容和电阻触摸全支持(2023-07-19)
https://www.armbbs.cn/forum.php? ... 0161&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-5-16 18:14:29 来自手机 | 显示全部楼层
eric2013 发表于 2024-5-16 09:19
有做DMA加速,供参考。

基于V5,V6和V7的LVGL模板,驱动支持单缓冲,双缓冲和配合硬件消隐的双缓冲,以 ...

我看到ra8875中的划线函数有个dma版本,但没找到这个dma的配置函数
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-5-16 21:51:56 来自手机 | 显示全部楼层
找到原因了:使用m2m模式时,没有把内存地址和外设地址设反了。但又发现另一个问题:通过dma将数组中的图像数据传到LCD->RAM时,一次似乎只能传几十个,但如果传到另一个数组中,却能全部传完
回复

使用道具 举报

1

主题

8

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-5-16 22:43:58 来自手机 | 显示全部楼层
又尝试了用dma将数据传到fsmc上的一个外部sram上,dma能够把全部数据都传过去。难道是因为nt35510的LCD->RAM不能够那么快地接收数据?
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-6-21 03:25 , Processed in 0.183281 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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