找回密码
 立即注册
查看: 1512|回复: 15

AI8051U_V1.2实验箱,实验驱动TFT彩屏 | 最终程序见3楼的 DMA 驱动

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-10-31 22:14:03 | 显示全部楼层 |阅读模式
基于AI8051U_V1.2实验箱_学习实验之驱动TFT彩屏
===最终程序见 3楼的 DMA 驱动

这是将原来在32G12K128_V6.92实验箱运行的实验程序移植到新的AI8051U_V1.2实验箱上来了,
虽说是旧话重提、老调重弹,其实过程并非一帆风顺。
先看看实验结果小视频吧:


使用40MHz,流畅度感觉已经不错了。
本实验使用的是模拟IO模式驱动,尚未加入LCM和DMA技术。
本人认为,这是必须先这样做的,这是最基本的方法,可以有助于理解控制指令的时序,程序可移植性较强。主要是可以先验证一下硬件是否没有问题了。
这套彩屏驱动的函数源码,已包括:使用小字库、实现中西文字符串显示、BMP小图片显示、画线、画矩形、下拉菜单制作等实用函数源码,可用于完成一般的项目需求的。


主程序就不贴出来了。基本相同于:

https://www.stcaimcu.com/forum.php?mod=viewthread&tid=8725

工程文件包供有兴趣的坛友下载参考、指正。

00-TestTFT9341_0.rar (131.73 KB, 下载次数: 89)


1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!

本帖被以下淘专辑推荐:

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-10-31 22:14:42 | 显示全部楼层
本帖最后由 浦江一水 于 2024-11-3 15:22 编辑

第二步,采用LCM模式的来了.

梳理一下,学习实验的思路:
LCM-i8080/M6800 是AI8051U单片机的特为
===驱动TFT/LCD等屏的硬件接口模式.
理论上比模拟IO方式速度快, 效果好.
实验改用LCM模式采取以下一些步骤:
① 在LCD9431.C源码文件中的开头部分,加入宏定义
    #define USE_LCM  1    //1:使用LCM模式 0:模拟IO模式
    保留原来模拟IO方式的代码, 在调试时可切换,这样可防新代码出错调试不通而回不来.
  
② 先搞清楚所用的显示屏是哪种类型,接口引脚定义.
    查数据手册, 配置LCM相关的寄存器,
    在LCD_Init()函数中,增加LCM初始化配置语句:
  #if (USE_LCM==1)
    LCMIFCFG = 0x80;   //bit7 1:Enable Interrupt, bit1 0:8bit mode; bit0 0:8080,1:6800 //选定显示屏接口类型//允许中断
    LCMIFCFG2= 0x29;  //RS:P45,RD:P37,WR:P36; Setup Time=2,HOLD Time=1   //配置切换到引脚(有限固定选择,不是随意的!)
    LCMIFSTA = 0x00;   //状态寄存器复零
    EA = 1;                  //开总中断 (注意:LCM模式需要用到中断服务机制,必须开)
  #endif

③ 在工程文件总加入 ISR.asm 文件,其内容为:  (是用汇编语言编写的)

    CSEG                AT 01D3H                 ;如果代码段地址是01D3H
    LJMP                006BH                      ;那么就长转移跳转到地址 006BH 代码段执行...
    CSEG                AT 01DBH                 ;如果代码段地址是01DBH
    LJMP                006BH                      ;那么也就长转移跳转到地址 006BH 代码段执行...
    END

    为什么要加入这个文件?  是因为根据AI8051U.H中的关于中断矢量表的定义:

    //Interrupt Vector  中断矢量表
    ......
    #define     USER_VECTOR           13       //006BH
   ......
    #define     DMA_LCM_VECTOR     58       //01D3H
    #define     LCM_VECTOR             59       //01DBH
    ......
    可见:LCM或DMA所触发的中断矢量编号已经超出标准32号, 则要强制转到保留的用户中断编号13号中来处理...

④ 由于启用的中断的原因, 也就要增加一个中断服务函数:
    void LCMIF_DMA_Interrupt(void) interrupt 13
   {
        if(LCMIFSTA & 0x01)           //如果是LCM所引发的中断, 查状态寄存器的bit0为是否为1...
        {
            LCMIFSTA = 0x00;          //状态寄存器复零
            LCD_CS=1;                    //LCD的片选置1, 不片选了, 也表示数据已经由硬件发出了...
        }
   }

⑤  使用LCM模式发送的主要语句是写命令和写数据两条: (其它语句不需要改编)

      写命令字节函数:
      LCMIFDATL = CMD; //将命令字节写入数据寄存器的字节(低8位)
      LCD_CS=0;            //LCD片选上...
      LCMIFCR = 0x84;          //Enable interface, write command out 触发中断写命令//控制寄存器的CMD[]位=100
      while(!LCD_CS);     //等待中断返回标志

      写数据字节函数:
      LCMIFDATL = CMD; //将命令字节写入数据寄存器的字节(低8位)
      LCD_CS=0;            //LCD片选上...
      LCMIFCR = 0x85;          //Enable interface, write command out 触发中断写命令//控制寄存器的CMD[]位=101
      while(!LCD_CS);     //等待中断返回标志

      这样,原来模拟IO方式写命令或数据时, 要考虑的时序控制IO跳变, 现在只要将数据放入寄存器,其它由硬件去控制完成发送了。
      因此效率提高了。
      调试时可改写宏定义
      #define USE_LCM  0    //1:使用LCM模式 0:模拟IO模式
      重新编译运行, 来观察比较两种模式的显示效果。

工程文件包在此,供有兴趣的坛友下载参考和指正。
00-TestTFT9341_1.rar (99.73 KB, 下载次数: 75)



点评

请教下,这个ISR.asm文件是不是没生效呢。 因为代码中用的是interrupt 13 而不是interrupt DMA_LCM_VECTOR  详情 回复 发表于 2024-11-18 00:26
也上个视频  发表于 2024-11-1 20:22
2 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-10-31 22:15:04 | 显示全部楼层
本学习实验课题的移植到AI8051U实验箱来运行,
经过了三个步骤,在此前的基础上又增加了DMA手段


从视频中可见, 程序稍有小改动,增加了32*32小图标的显示, 是实验用DMA方式显示BMP图片的方法.
由于本课题除了清屏和图标显示以外,没有大量数据传输的需求,因此DMA手段仅仅用在这两个函数上。
稍稍添加注释解析,以供初学、同学者参考理解。

//清屏函数
void LCD_CLS(u8 Color)
{ u16 i,j;
  LCD_SetWindow(0,0,LCD_W-1,LCD_H-1);  
#if (USE_DMA==1)          //若使用DMA方式  
  j=0;
  for(i=0;i<=DMA_AMT_LEN;i++)LCD_Buf= COLOR[Color];   //先向缓存区填颜色字
  DMA_TxCount = 75;      //确定发送次数: 总字节数/缓存区大小=循环次数 (320*240*2) /2048=75
  LCD_CS=0;                   //显示屏片选中,让DMA向显示屏发送数据...
  DMAFlag=0;                  //设DMA完成标志初为0
  DMA_LCM_CR = 0xA0;   //(Write dat 写数据) 使能LCM_DMA / 启动发送数据模式操作 / 引发中断
  while(!DMAFlag);           //等待中断操作完成...
  LCD_CS=1;                   //片选中,让DMA向显示屏发送数据...
#else
  for(i=0;i<LCD_W;i++)   //不使用DMA方式的原写数据循环方式
  { for (j=0;j<LCD_H;j++)
    { LCD_WR_DATA(COLOR[Color]); }
  }
#endif  
}
//使用DMA方式的BMP图标显示函数
#if (USE_DMA==1)
/*****************************************************************************
* 函数:void LCD_BMP_DMA(u16 X, u16 Y,u16 W,u16 H,u8 Color) //显示图片
* 参数: X起点 Y起点 W宽度 H高度 Color: 色号
* 注意:因目前缓存区LCD_Buf[]为2048字节,故仅仅支持32*32图标DMA模式显示
*      若缓存区扩为4608字节,可显示48*48图标
*      若缓存区扩为8192字节,可显示64*64图标 (算法暂留,有待完善)  
******************************************************************************/
void LCD_BMP_DMA(u16 X,u16 Y,u8 W,u8 H,u8* pic)
{  u16 i,Col; u8 h,l;
   LCD_SetWindow(X,Y,X+W-1,Y+H-1); //设置显示窗口
   for(i=0;i<W*H; i++)
  { l=pic[2*i]; h=pic[2*i+1];  //BMP图像数据:低位在前/高位在后
    Col=256*h+l;                   //转换为: 高位在前/低位在后
    LCD_Buf = Col;             //先送入缓存区
  }  
//DMA_TxCount=W*H*2/(DMA_AMT_LEN+1); //计算发送次数:总字节数/缓存区大小=循环次数.图标(32*32*2)/2048=1
  DMA_TxCount=1;               //计算发送次数:总字节数/缓存区大小=循环次数. 图标(32*32*2)/2048=1
  LCD_CS=0;                        //显示屏片选中,让DMA向显示屏发送数据...
  DMAFlag=0;                       //设DMA完成标志初为0
  DMA_LCM_CR = 0xA0;        //(Write dat 写数据) 使能LCM_DMA / 启动发送数据模式操作 / 引发中断
  while(!DMAFlag);                //等待中断操作完成...
  LCD_CS=1;                        //片选中,让DMA向显示屏发送数据...
  LCD_SetWindow(0,0,LCD_W,LCD_H); //恢复全屏显示区域
}
#endif

这两函数的区别在于:
清屏函数在一次性初始化发送缓存区数据后, 启动DMA发送要循环75次才完成全屏一色. 每次循环不必重载缓存区数据, 所以期间不需要MCU参与.
而显示BMP函数, 如果图像数据量大于缓存的话, 即要分多次循环的话, 那么在期间要重载新数据, 则需要MCU参与, 所以先不考虑大图片, 否则就失去使用DMA的意义了.
(虽说有双缓存的手段,可开两个缓存,启用两个DMA, 交替使用, 但目前看是用于从外部Flash存储器读取数据的. 故暂不作深入考虑.)

AI8051U实验箱还有丰富的新知识点, 有待开发挖掘、学习研究.  

至此,初篇移植作业暂告段落, 还有提升完善的空间, 日后再换课题: 比如图片数据放在外部QSPI_Flash中, 再做全屏图片的显示实验.

工程文件包, 供有兴趣的爱好者参考和指正:
00-TestTFT9341_2.rar (136.64 KB, 下载次数: 87)



1 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-11-2 09:37:53 | 显示全部楼层
本帖最后由 浦江一水 于 2024-11-3 15:25 编辑

感谢 autopccopy 版主鲜花鼓励。
感谢 神农鼎  管理员  鲜花鼓励。
两位都5朵鲜花支持,太给力、厚爱了。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:162
  • 最近打卡:2025-05-01 06:56:44
已绑定手机

56

主题

1319

回帖

2938

积分

荣誉版主

无情的代码机器

积分
2938
发表于 2024-11-18 00:26:33 | 显示全部楼层
浦江*** 发表于 2024-10-31 22:14
第二步,采用LCM模式的来了.

梳理一下,学习实验的思路:

请教下,这个ISR.asm文件是不是没生效呢。

===因为代码中用的是interrupt 13
       而不是interrupt DMA_LCM_VECTOR

点评

感谢这位坛友对本贴的关注、浏览和留言。 关于所提的问题, 我是这样理解的: 程序中用了: interrupt 13 这是等价于 : interrupt USER_VECTOR DMA_LCM 所触发的中断是 DMA_LCM_VECTOR 根据Ai8051U.H中  详情 回复 发表于 2024-11-18 09:35
感谢这位坛友对本贴的关注、浏览和留言。 关于所提的问题, 我是这样理解的: 程序中用了: interrupt 13 这是等价于 : interrupt USER_VECTOR DMA_LCM 所触发的中断是 DMA_LCM_VECTOR 根据Ai8051U.H  详情 回复 发表于 2024-11-18 09:33
感谢这位坛友对本贴的关注、浏览和留言。 关于所提的问题, 我是这样理解的: 程序中用了: interrupt 13 这是等价于 : interrupt USER_VECTOR DMA_LCM 所触发的中断是 DMA_LCM_VECTOR 根据Ai8051U.H  详情 回复 发表于 2024-11-18 09:33
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-11-18 09:33:58 | 显示全部楼层
erci*** 发表于 2024-11-18 00:26
请教下,这个ISR.asm文件是不是没生效呢。

===因为代码中用的是interrupt 13

感谢这位坛友对本贴的关注、浏览和留言。

关于所提的问题, 我是这样理解的:
程序中用了:    interrupt  13
这是等价于 :     interrupt    USER_VECTOR
DMA_LCM 所触发的中断是  DMA_LCM_VECTOR


根据Ai8051U.H中的中断矢量表来看:
USER_VECTOR         定义的中断序号   13     其入口地址是   006BH
DMA_LCM_VECTOR  定义的中断序号   58     其入口地址是   01D3H

那么DMA_LCM触发的中断如何转到USER_VECTOR来执行中断服务程序呢?
再看:  ISR.asm  中的代码...
      CSEG     AT 01D3H
      LJMP     006BH
      CSEG     AT 01DBH
      LJMP     006BH
      END
意思是:  一旦中断入口到地址 01D3H  那就长转移到地址 006BH 之处去执行...
             也就是转移到了 interrupt  13 去执行了。
这说明  ISR.asm 中的代码还是起作用、有效的。

那么,为什么不直接用  interrupt   DMA_LCM_VECTOR  呢?
因为 DMA_LCM_VECTOR 中断序号是 58,是扩展号, 超出传统的 32 的范畴,
通过ISR.asm 这是一种兼容传统8051的手段。

而 Ai8051U是新型强大的CPU,不同于传统的8051,
程序一开始就加了  EAXFR = 1; //扩展寄存器(XFR)访问使能
估计还会有新的手段变化。
有待进一步学习、体会...
谢谢。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-11-18 09:33:58 | 显示全部楼层
本帖最后由 浦江一水 于 2024-11-26 07:26 编辑

无意间重复了。

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-11-18 09:35:51 | 显示全部楼层
本帖最后由 浦江一水 于 2024-11-26 07:26 编辑

谢谢。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:162
  • 最近打卡:2025-05-01 06:56:44
已绑定手机

56

主题

1319

回帖

2938

积分

荣誉版主

无情的代码机器

积分
2938
发表于 2024-11-18 10:51:28 | 显示全部楼层
感谢回复,那应该是对中断DMA_LCM_VECTOR的寻址是芯片内部的事,流程上:
1.用户代码LCMIFCFG  = LCMIFIE 开中断
2.芯片内部寻址DMA_LCM_VECTOR
3.汇编映射DMA_LCM_VECTOR到USER_VECTOR
4.通过USER_VECTOR跳转到interrupt    USER_VECTOR对应的函数
上面是8bit,32bit使用拓展中断号之后应该直接用DMA_LCM_VECTOR可以省去汇编映射而且不占用USER_VECTOR。
屏还没到手,等到了验证下对不对。

点评

好像在哪里见到过,直接用DMA_LCM_VECTOR的,或可省去ISR.asm汇编文件参与。 不过这个转换手段也给人编程思路方面有一点启示,有点意思,也不算啥麻烦事。 目前看到的很多代码都在这样用ISR.asm,包括官方例程。  详情 回复 发表于 2024-11-18 12:27
三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:493
  • 最近打卡:2025-05-01 08:31:58

30

主题

347

回帖

3476

积分

荣誉版主

积分
3476
发表于 2024-11-18 12:27:34 | 显示全部楼层
erci*** 发表于 2024-11-18 10:51
感谢回复,那应该是对中断DMA_LCM_VECTOR的寻址是芯片内部的事,流程上:
1.用户代码LCMIFCFG  = LCMIFIE  ...

好像在哪里见到过,直接用DMA_LCM_VECTOR的,或可省去ISR.asm汇编文件参与。
不过这个转换手段也给人编程思路方面有一点启示,有点意思,也不算啥麻烦事。
目前看到的很多代码都在这样用ISR.asm,包括官方例程。

回复 支持 0 反对 1

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 19:39 , Processed in 0.248500 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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