找回密码
 立即注册
查看: 3779|回复: 18

求助!!DAM_LCM例程改编驱动并口TFT无法实现请求指点

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:441
  • 最近打卡:2025-05-02 09:05:39

45

主题

176

回帖

1735

积分

金牌会员

积分
1735
发表于 2022-12-10 16:46:52 | 显示全部楼层 |阅读模式
本帖最后由 乐此不疲 于 2022-12-10 21:25 编辑

最近一直在用STC32G屠龙刀的板子做驱动SSD1963-7寸TFT屏的测试,正常的硬件LCM接口应用程序已经完成调试,但DMA_LCM模式驱动却总是不能实现,现象为发送一包数据后就卡死了,请各位大神帮忙指点一下,先谢了!

部分例程如下:

  1. /*---------------------------------------------------------------------*/
  2. /* --- STC MCU Limited ------------------------------------------------*/
  3. /* --- STC 1T Series MCU Demo Programme -------------------------------*/
  4. /* --- Mobile: (86)13922805190 ----------------------------------------*/
  5. /* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
  6. /* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
  7. /* --- Web: www.STCMCU.com --------------------------------------------*/
  8. /* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
  9. /* --- QQ:  800003751 -------------------------------------------------*/
  10. /* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
  11. /*---------------------------------------------------------------------*/
  12. /*************  功能说明    **************
  13. 本例程基于STC32G为主控芯片的实验箱进行编写测试。
  14. 使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
  15. edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
  16. LCM接口+DMA驱动液晶屏程序
  17. 8bit I8080模式, P6口接D8~D15
  18. sbit LCD_RS = P4^5;      //数据/命令切换
  19. sbit LCD_WR = P4^2;      //写控制
  20. sbit LCD_RD = P4^4;      //读控制
  21. sbit LCD_CS = P3^4;      //片选
  22. sbit LCD_RESET = P4^3;   //复位
  23. LCM指令通过中断方式等待发送完成
  24. DMA设置长度256字节,通过中断方式判断传输完成
  25. 下载时, 选择时钟 24MHz (用户可自行修改频率).
  26. ******************************************/
  27. #include "..\..\comm\STC32G.h"
  28. #include "stdio.h"
  29. #include "intrins.h"
  30. #include "font.h"
  31. #define     MAIN_Fosc       24000000L   //定义主时钟
  32. typedef     unsigned char   u8;
  33. typedef     unsigned int    u16;
  34. typedef     unsigned long   u32;
  35. sbit LCD_RS = P4^5;      //数据/命令切换
  36. sbit LCD_WR = P4^2;      //写控制
  37. sbit LCD_RD = P4^4;      //读控制
  38. sbit LCD_CS = P3^4;      //片选
  39. sbit LCD_RESET = P4^3;   //复位
  40. //IO连接
  41. #define  LCD_DataPort P6     //8位数据口
  42. //支持横竖屏快速定义切换
  43. #define USE_HORIZONTAL            0   //定义液晶屏顺时针旋转方向         0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转
  44. //画笔颜色
  45. #define WHITE                  0xFFFF
  46. #define BLACK                  0x0000         
  47. #define BLUE             0x001F  
  48. #define BRED             0XF81F
  49. #define GRED             0XFFE0
  50. #define GBLUE            0X07FF
  51. #define RED                    0xF800
  52. #define MAGENTA                0xF81F
  53. #define GREEN                  0x07E0
  54. #define CYAN                   0x7FFF
  55. #define YELLOW                 0xFFE0
  56. #define BROWN            0XBC40 //棕色
  57. #define BRRED            0XFC07 //棕红色
  58. #define GRAY             0X8430 //灰色
  59. #define DARKBLUE               0X01CF        //深蓝色
  60. #define LIGHTBLUE               0X7D7C        //浅蓝色  
  61. #define GRAYBLUE                0X5458 //灰蓝色
  62. #define LIGHTGREEN              0X841F //浅绿色
  63. #define LGRAY            0XC618 //浅灰色(PANNEL),窗体背景色
  64. #define LGRAYBLUE        0XA651 //浅灰蓝色(中间层颜色)
  65. #define LBBLUE           0X2B12 //浅棕蓝色(选择条目的反色)
  66. //定义LCD的尺寸
  67. #define LCD_W 240
  68. #define LCD_H 320
  69. #define DMA_AMT_LEN  2047  //n+1
  70. u16 POINT_COLOR=0x0000;        //画笔颜色
  71. u16 index;
  72. //u16 xdata Buffer[8]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
  73. u16 xdata Color[DMA_AMT_LEN+1];
  74. bit DmaFlag;
  75. bit LcmFlag;
  76. typedef struct  
  77. {                                                                                    
  78.         u16 width;                        //LCD 宽度
  79.         u16 height;                        //LCD 高度
  80.         u16 id;                                //LCD ID
  81.         u8  dir;                        //横屏还是竖屏控制:0,竖屏;1,横屏。        
  82.         u8 wramcmd;                //开始写gram指令
  83.         u8 rramcmd;   //开始读gram指令
  84.         u8 setxcmd;                //设置x坐标指令
  85.         u8 setycmd;                //设置y坐标指令         
  86. }_lcd_dev;         
  87. _lcd_dev lcddev;
  88. void delay_ms(u16 ms);
  89. void GPIO_Init(void);
  90. void LCM_Config(void);
  91. void DMA_Config(void);
  92. void LCD_Init(void);
  93. void Test_Color(void);
  94. void LCD_WR_DATA_16Bit(u16 Data);
  95. void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);
  96. void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode);
  97. void LCD_direction(u8 direction);
  98. void main(void)
  99. {
  100.     WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
  101.     EAXFR = 1; //扩展寄存器(XFR)访问使能
  102.     CKCON = 0; //提高访问XRAM速度
  103.     P0M1 = 0x30;   P0M0 = 0x30;   //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
  104.     P1M1 = 0x32;   P1M0 = 0x32;   //设置P1.1、P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V), P1.1在PWM当DAC电路通过电阻串联到P2.3
  105.     P2M1 = 0x3c;   P2M0 = 0x3c;   //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V),设置开漏模式需要断开PWM当DAC电路中的R2电阻
  106.     P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  107.     P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  108.     P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  109.     P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
  110.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  111.         GPIO_Init();
  112.         LCM_Config();
  113.         DMA_Config();
  114.         EA = 1;
  115.         
  116.         LCD_Init(); //LCM初始化
  117.         while(1)
  118.         {
  119.                 Test_Color();
  120.         }
  121. }
  122. void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
  123. {         
  124.         u16 i,j;                        
  125.         u16 width=ex-sx+1;                 //得到填充的宽度
  126.         u16 height=ey-sy+1;                //高度
  127.         LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口
  128.         for(j=0,i=0;i<=DMA_AMT_LEN;i++)
  129.         {
  130.                 Color[i] = color;
  131.         }
  132.         index = 75;     //(320 * 240 * 2) / 2048 = 75
  133.         LCD_CS=0;
  134.         DMA_LCM_CR = 0xa0;        //Write dat
  135.         while(!LCD_CS);
  136. }
  137. void Test_Color(void)
  138. {
  139.         u8 buf[10] = {0};
  140.         LCD_Fill(0,0,lcddev.width,lcddev.height,WHITE);
  141.         Show_Str(20,30,BLUE,YELLOW,"LCM Test",16,1);delay_ms(800);
  142.         LCD_Fill(0,0,lcddev.width,lcddev.height,RED);
  143.         Show_Str(20,30,BLUE,YELLOW,"RED ",16,1);delay_ms(800);
  144.         LCD_Fill(0,0,lcddev.width,lcddev.height,GREEN);
  145.         Show_Str(20,30,BLUE,YELLOW,"GREEN ",16,1);delay_ms(800);
  146.         LCD_Fill(0,0,lcddev.width,lcddev.height,BLUE);
  147.         Show_Str(20,30,RED,YELLOW,"BLUE ",16,1);delay_ms(800);
  148. }
复制代码

  1. /*****************************************************************************
  2. * @name       :void LCM_Config(void)
  3. * @date       :2018-11-13
  4. * @function   :Config LCM
  5. * @parameters :None
  6. * @retvalue   :None
  7. ******************************************************************************/        
  8. void LCM_Config(void)
  9. {
  10.         LCMIFCFG = 0x84;        //bit7 1:Enable Interrupt, bit1 0:8bit mode; bit0 0:8080,1:6800
  11.         LCMIFCFG2 = 0x09;        //RS:P45,RD:P44,WR:P42; Setup Time=2,HOLD Time=1
  12.         LCMIFSTA = 0x00;
  13. }
  14. /*****************************************************************************
  15. * @name       :void DMA_Config(void)
  16. * @date       :2020-12-09
  17. * @function   :Config DMA
  18. * @parameters :None
  19. * @retvalue   :None
  20. ******************************************************************************/        
  21. void DMA_Config(void)
  22. {
  23.         DMA_LCM_AMT = (u8)DMA_AMT_LEN;                                //设置传输总字节数(低8位):n+1
  24.         DMA_LCM_AMTH = (u8)(DMA_AMT_LEN>>8);        //设置传输总字节数(高8位):n+1
  25.         DMA_LCM_TXAH = (u8)((u16)&Color >> 8);
  26.         DMA_LCM_TXAL = (u8)((u16)&Color);
  27. //        DMA_LCM_RXAH = (u8)((u16)&Buffer >> 8);
  28. //        DMA_LCM_RXAL = (u8)((u16)&Buffer);
  29.         DMA_LCM_STA = 0x00;
  30.         DMA_LCM_CFG = 0x82;
  31.         DMA_LCM_CR = 0x00;
  32. }
复制代码

  1. /*****************************************************************************
  2. * @name       :void LCM_Interrupt(void)
  3. * @date       :2018-11-13
  4. * @function   :None
  5. * @parameters :None
  6. * @retvalue   :
  7. ******************************************************************************/
  8. void LCMIF_DMA_Interrupt(void) interrupt 13
  9. {
  10.         if(LCMIFSTA & 0x01)
  11.         {
  12.                 LCMIFSTA = 0x00;
  13.                 LcmFlag = 0;
  14.         }
  15.         
  16.         if(DMA_LCM_STA & 0x01)
  17.         {
  18.                 if(DmaFlag)
  19.                 {
  20.                         DmaFlag = 0;
  21.                         DMA_LCM_CR = 0;
  22.                 }
  23.                 else
  24.                 {
  25.                         index--;
  26.                         if(index == 0)
  27.                         {
  28.                                 DMA_LCM_CR = 0;
  29.                                 LCD_CS=1;
  30.                         }
  31.                         else
  32.                         {
  33.                                 DMA_LCM_CR = 0xa0;        //Write dat
  34.                         }
  35.                 }
  36.                 DMA_LCM_STA = 0;
  37.         }
  38. }
复制代码


1234.jpg
问题现象为调用Test_Color()函数后就卡在了函数LCD_Fill(0,0,lcddev.width,lcddev.height,WHITE);这里了。
问题一:想知道上述现象的原因,卡死的问题怎样解决
问题二:我感觉这个函数有些问题,但作为玩51单片机的菜鸟第一次学习DMA的应用对例程的问题就无法理解了。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:415
  • 最近打卡:2025-04-30 09:58:34
已绑定手机

39

主题

2006

回帖

6843

积分

论坛元老

积分
6843
发表于 2022-12-12 16:23:59 | 显示全部楼层


由于LCM、DMA中断向量号超过31,直接使用的话编译会报错,所以例程是借用13号中断向量地址作为LCM与DMA中断入口,这就需要添加中断入口映射指令:
1.png
至于j, width, height变量原本是用来计算需要显示的点数,这里已经不需要,可以全部删掉。
  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-02 08:32:59

718

主题

1万

回帖

1万

积分

管理员

积分
15626
发表于 2022-12-12 22:48:44 | 显示全部楼层
1.png https://www.stcai.com/filedownload/609391

将 KEIL C251 支持的中断号 拓展到 0 ~ 255
  • 打卡等级:以坛为家II
  • 打卡总天数:441
  • 最近打卡:2025-05-02 09:05:39

45

主题

176

回帖

1735

积分

金牌会员

积分
1735
发表于 2022-12-13 10:52:13 | 显示全部楼层
多谢楼上二位朋友的指点,在安装keilC251时就根据STC手册提示通过软件做了拓展,而且在不使用DMA时硬件LCM驱动通过中断输出也是正常的并且已经也可以正常刷屏的,只是DMA传输不正常,显示现象为只传输了2048K(程序设定一包数据量)后就卡住了。我的代码是根据8bitLCM输出的代码改编的,我不知道STC的DMA传输数据宽度是否需要设定为16bit才能和LCM的16bit输出接口匹配,如果需要的话貌似STC的DMA无法设定数据宽度,刚刚接触DMA很多不懂。
  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-02 08:32:59

718

主题

1万

回帖

1万

积分

管理员

积分
15626
发表于 2022-12-13 12:13:42 | 显示全部楼层
STC 的有 DMA 支持 TFT-i8080/M6800 接口的 MCU, 都可以设置 TFT-i8080/M6800 接口 是8位还是16位
  • 打卡等级:偶尔看看III
  • 打卡总天数:55
  • 最近打卡:2025-05-02 08:32:59

718

主题

1万

回帖

1万

积分

管理员

积分
15626
发表于 2022-12-13 12:21:38 | 显示全部楼层
1.png

2.png
3.png

  • 打卡等级:以坛为家II
  • 打卡总天数:441
  • 最近打卡:2025-05-02 09:05:39

45

主题

176

回帖

1735

积分

金牌会员

积分
1735
发表于 2022-12-13 13:02:59 | 显示全部楼层
多谢临帖指点,或许我的测试存在的问题应该与DMA总线宽度无关,你说的寄存器配置是LCM与TFT之间的总线配置,我的代码不用DMA时已经能够驱动TFT了,这些寄存器配置也没问题的,我对DMA的理解如下图,很愿意和你继续探讨。


999.jpg

888.jpg

  • 打卡等级:以坛为家II
  • 打卡总天数:415
  • 最近打卡:2025-04-30 09:58:34
已绑定手机

39

主题

2006

回帖

6843

积分

论坛元老

积分
6843
发表于 2022-12-13 20:37:58 | 显示全部楼层
DMA只是一个数据缓冲区,需要根据屏的分辨率计算出刷屏所需的数据量,然后除以DMA缓冲区设置长度,最好能够得到一个整数,这就是刷一整屏需要DMA搬运的次数。DMA每次完成传输后会停止传输并产生中断事件,判断搬运的次数如果没有刷完的话需要手动再启动下一次的DMA传输。
楼主传输了2048K(程序设定一包数据量)后就卡住了。其实不是卡住,而是DMA完成了一次传输后停止了,需要再次启动DMA才能继续下一次的传输。
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2024-05-02 21:48:56

6

主题

48

回帖

614

积分

高级会员

积分
614
发表于 2022-12-14 10:17:18 | 显示全部楼层
各位大佬,有STC32的ADC-DMA的范本吗?我是模拟电子专业对编程只懂皮毛,项目需要以前都是用范本移植.谢谢!
  • 打卡等级:以坛为家II
  • 打卡总天数:441
  • 最近打卡:2025-05-02 09:05:39

45

主题

176

回帖

1735

积分

金牌会员

积分
1735
发表于 2022-12-14 12:22:21 | 显示全部楼层
本帖最后由 乐此不疲 于 2022-12-14 12:28 编辑
乘风*** 发表于 2022-12-13 20:37
DMA只是一个数据缓冲区,需要根据屏的分辨率计算出刷屏所需的数据量,然后除以DMA缓冲区设置长度,最好能够 ...

执行函数中有启动传输的代码的。我目前只是在验证例程,所不同的是例程驱动的是8位并口TFT,而我是通过修改例程来驱动16位并口TFT,想必例程是应该能够实现8位并口屏的验证功能的(我没有8位屏所以无法验证),而我的改编也已经实现了硬件LCM16位接口的应用,只是不能实现DMA_LCM功能,从现象来看,DMA在初次启动时确实完成了2K数据的发送,屏幕上也显示了1024个色点(一个色点2个字节),例程详见1楼:

  1. void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
  2. {
  3.     u16 i;
  4.     LCD_SetWindows(sx,sy,ex-1,ey-1);//设置显示窗口
  5.     for(i=0; i<=DMA_AMT_LEN; i++)
  6.     {
  7.         Color = color;
  8.     }
  9.     LCD_CS=0;
  10.     DMA_LCM_CR = 0xa0;
  11.     while(!LCD_CS);
  12. }
  13. /***************************************/
  14. void LCMIF_DMA_Interrupt(void) interrupt 13
  15. {
  16.         if(LCMIFSTA & 0x01)
  17.         {
  18.                 LCMIFSTA = 0x00;
  19.                 LcmFlag = 0;
  20.         }
  21.         if(DMA_LCM_STA & 0x01)
  22.         {
  23.         DmaFlag = 0;
  24.         index--;
  25.         if(index == 0)
  26.         {
  27.             DMA_LCM_CR = 0;
  28.             LCD_CS=1;
  29.         }
  30.                 DMA_LCM_STA = 0;
  31.         }
  32. }      
复制代码

以下是我对例程的解读,如有问题诚请指正!
首先执行函数准备了一包数据 Color = color;而后使能目标设备 LCD_CS=0;而后 DMA_LCM_CR = 0xa0;使能DMA中断并触发DMA传送,此后执行函数停在while(!LCD_CS);处等待数据传输完成,当中断函数查询到DMA_LCM_STA的B0位为1时说明此包数据已经传输完毕,此后清除标志 DmaFlag = 0; 结束写数据函数的工作,index--递减发送计数次数, DMA_LCM_CR = 0;取消DMA中断, LCD_CS=1;打断阻塞恢复执行函数的运行,DMA_LCM_STA = 0;清除中断标志开始下一包数据的传输。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2025-5-2 15:42 , Processed in 0.168873 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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