STM32F4标准库 DMA FSMC驱动TFT-LCD

背景

调试一个FSMC接口的TFT-LCD(9341驱动芯片),最开始使用的是LCD_DrawPoint方式,设一次坐标描一个像素点,效率极低,而且占用CPU。所以想使用DMA方式来处理像素数据,上一篇内容介绍了DMA MemoryToMemor,内存到内存数据拷贝功能。与上一篇不同的仅仅是一些配置而已

代码如下:

LCD外设驱动,可参考参考正点原子,代码。需要留意LCD_BASE的地址设置,硬件上我的LCD的CS接了FSMC_NE1,RS接了FSMC_A16。所以基地址设置为

#define LCD_BASE        ((u32)(0x60000000 | 0x0001FFFE))
//LCD地址结构体
typedef struct
{
  volatile uint16_t LCD_REG;
  volatile uint16_t LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11        	A6作为数据命令区分线((u32)(0x6C000000 | 0x0000007E))
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11       	A10作为数据命令区分线((u32)(0x6C000000 | 0x000007FE))
//使用NOR/SRAM的 Bank1.sector1,地址位HADDR[27,26]=00 			A16作为数据命令区分线((u32)(0x60000000 | 0x0001FFFE))
//注意设置时STM32内部会右移一位对其!
#define LCD_BASE        ((u32)(0x60000000 | 0x0001FFFE))
#define LCD             ((LCD_TypeDef *) LCD_BASE)

DMA配置:

#define LCD_DMA_Stream    DMA2_Stream3
#define LCD_DMA_Channel   DMA_Channel_0
#define LCD_DMA_IT_TCIFx  DMA_IT_TCIF3


/******************************************************************************
      函数说明:设置起始和结束地址
      入口数据:x1,x2 设置列的起始和结束地址
              y1,y2 设置行的起始和结束地址
      返回值:  无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
  LCD_WR_REG(0x2a);//列地址设置
  LCD_WR_DATA(x1>>8);
  LCD_WR_DATA(x1&0xff);
  LCD_WR_DATA(x2>>8);
  LCD_WR_DATA(x2&0xff);
  LCD_WR_REG(0x2b);//行地址设置
  LCD_WR_DATA(y1>>8);
  LCD_WR_DATA(y1&0xff);
  LCD_WR_DATA(y2>>8);
  LCD_WR_DATA(y2&0xff);
  LCD_WR_REG(0x2c);//储存器写(2C命令之后开始写颜色数据)
}


void LCD_DMA_Init_Core(void)
{
  DMA_InitTypeDef  DMA_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  if((uint32_t)LCD_DMA_Stream>(uint32_t)DMA2)//得到当前stream是属于DMA2还是DMA1
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能   
  }else 
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 
  }
  DMA_DeInit(LCD_DMA_Stream);

  while (DMA_GetCmdStatus(LCD_DMA_Stream) != DISABLE){}//等待DMA可配置 

  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = LCD_DMA_Channel;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0;//DMA外设地址(后续赋值)
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&LCD->LCD_RAM;//DMA 存储器0地址 
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;//存储器到外设模式
  DMA_InitStructure.DMA_BufferSize = 0;//数据传输量(后续赋值) 
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//外设增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//存储器非增量模式
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_HalfWord;//外设数据长度:8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:8位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 使用普通模式 
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
  DMA_Init(LCD_DMA_Stream, &DMA_InitStructure);//初始化DMA Stream

  DMA_ITConfig(LCD_DMA_Stream,DMA_IT_TC,ENABLE);
  //DMA NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  DMA_Cmd(LCD_DMA_Stream, DISABLE);
}

void LCD_Start_DMA_Transfer(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t *color)
{
  LCD_Address_Set(x1,y1,x2,y2);
  
  DMA_Cmd(LCD_DMA_Stream, DISABLE);                         //关闭DMA传输 
  while (DMA_GetCmdStatus(LCD_DMA_Stream) != DISABLE){}     //等待DMA可配置 
  LCD_DMA_Stream->NDTR = (uint16_t)((x2-x1+1)*(y2-y1+1)*2); //数据传输量  
  LCD_DMA_Stream->PAR  = (uint32_t)color;                   //传输数组
  DMA_Cmd(LCD_DMA_Stream, ENABLE);                          //开启DMA传输   
}

void DMA2_Stream3_IRQHandler(void)
{
  if(DMA_GetITStatus(LCD_DMA_Stream,LCD_DMA_IT_TCIFx)!=RESET)
  {
    DMA_ClearITPendingBit(LCD_DMA_Stream,LCD_DMA_IT_TCIFx);
  }
}

调用

LCD_Start_DMA_Transfer

即可开始一次DMA数据传输。
同理LVGL可将描点的方式替换为LCD_Start_DMA_Transfer让DMA自动传输Color数据,
中断回调可执行LVGL的lv_disp_flush_ready函数

在这里插入图片描述

  • 9
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值