斑竹,帮忙解决一下DMA不能搬运数据到液晶屏
本帖最后由 liudingding 于 2022-9-13 11:40 编辑我属愚笨型人员,主控F407是用寄存器开发的,显示屏用TK499,例程都是库开发的,不懂库函数,写起程序很困难,照瓢画瓢从例程上抄了个DMA搬运数据显示的程序,不工作,求斑竹看看哪里错了,直接来个正确的程序,你要是说修改方法的话,我将是云里雾里的听不懂,这个帖子就看不懂:www.amobbs.com/forum.php?mod=viewthread&tid=5764784&highlight=DMA,
程序如下:
LCD_Fill_Pic(0, 0,320, 480, (u32*)gImage_MM_T035);//用DMA模式 显示一幅图片
/******************************************
函数名:Lcd图像填充
功能:向Lcd指定位置填充图像
入口参数:
(x,y): 图片左上角起始坐标
(pic_H,pic_V): 图片的宽高
pic指向存储图片数组的指针
******************************************/
void LCD_Fill_Pic(u16 x, u16 y,u16 pic_H, u16 pic_V, u32*pic)
{
//DMA 方式
BlockWrite(x,x+pic_H-1,y,y+pic_V-1); //开窗函数
TK80_DMA_Init((u32)pic, pic_H*pic_V*2);//DMA初始化
while((DMA2->ISR & 0x20)==0);
DMA2->IFCR |=1<<5;
}
void TK80_DMA_Init(u32 srcAdd ,u32 len) //TK80的DMA配置函数,srcAdd是源地址,len是数据长度,一次能搬运42亿点
{
RCC->AHB2ENR |= RCC_AHB2Periph_TK80;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
DMA2_Channel2->CCR = 0x3090; //0x3090==8位, 0x3590==16位, 0x3A90==32位,
DMA2_Channel2->CPAR = (u32)&(TK80->DINR);
TK80->CFGR1 = 0x05050102;
TK80->CFGR2 = 0x0501;
DMA2_Channel2->CMAR= srcAdd;//存储器地址(发送地址)
DMA2_Channel2->CNDTR = len; //数据传输长度
DMA2_Channel2->CCR|= 1; //通道开启
TK80->CR |= 1;
}
void WriteComm(unsigned int CMD) //写命令
{
TK80->CMDIR = CMD;
while(TK80->SR & 0x10000);
}
void WriteData(u32 dat) //写数据
{
TK80->DINR = dat;
while(TK80->SR & 0x10000);
}
/**********************************************
函数名:开窗函数
入口参数:XStart x方向的起点
Xend x方向的终点
YStart y方向的起点
Yend y方向的终点
这个函数的意义是:开一个矩形框,方便接下来往这个框填充数据
***********************************************/
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int
Yend)
{
WriteComm(0x2a);
WriteData(Xstart>>8);
WriteData(Xstart);
WriteData(Xend>>8);
WriteData(Xend);
WriteComm(0x2b);
WriteData(Ystart>>8);
WriteData(Ystart);
WriteData(Yend>>8);
WriteData(Yend);
WriteComm(0x2c);
}
已经帮你转告版主 你是用在7寸屏上吗?7寸屏这种属于线性显示器,你用这个DMA属于直接内存到内存copy,可以用在特例下面,就是搬运的数据刚好等于屏的分辨率,也就是全屏显了。或者还有一个特例情况,就是整行显示,这个用在LVGL界面上比较多,就只更新需要更新的行数,其它不动的行不更新显示,达到快速显示的效果。
只参考DMA例程中的M to M例程就行,如下函数,只需要更改目标地址M_addr_des及源地址M_addr_scr 两个参数就行。
原理是,线性显示器是从内存中顺序读取数据,发送到LTDC接口给显示器显示的,所以所有操作只有内存操作就行。
void DMA_m32tom32_test(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitStructure.DMA_PeripheralBaseAddr = M_addr_des;
DMA_InitStructure.DMA_MemoryBaseAddr = M_addr_scr;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 128;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel6, ENABLE);
AI_Responder_refresh();//refresh the AI Responder
}
本帖最后由 liudingding 于 2022-9-13 14:42 编辑
tiky 发表于 2022-9-13 12:27
你是用在7寸屏上吗?7寸屏这种属于线性显示器,你用这个DMA属于直接内存到内存copy,可以用在特例 ...
(引用自3楼)
谢谢斑竹答复,还有个问题不明白:
DMA_InitStructure.DMA_PeripheralBaseAddr = M_addr_des;
如果我要让源起始地址为:__align(4) const unsigned char gImage_MM_T035首地址,
或者u32cc首地址,应该怎么写?
可能是基础问题,基础不行,只会 ifelse
解决了,从寄存器来,一直用&取地址,用库不会了,基础不牢,不要笑话, 你定义变量时,gImage_MM_T035这个变量就已经是4字节对齐了,直接把这个地址递交给DMA就行
页:
[1]