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

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

[复制链接]
  • TA的每日心情
    开心
    昨天 10:26
  • 签到天数: 105 天

    [LV.6]常住居民II

    28

    主题

    103

    回帖

    834

    积分

    高级会员

    积分
    834
    发表于 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的应用对例程的问题就无法理解了。
    回复 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 09:01
  • 签到天数: 122 天

    [LV.7]常住居民III

    26

    主题

    1242

    回帖

    3887

    积分

    论坛元老

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


    由于LCM、DMA中断向量号超过31,直接使用的话编译会报错,所以例程是借用13号中断向量地址作为LCM与DMA中断入口,这就需要添加中断入口映射指令:
    1.png
    至于j, width, height变量原本是用来计算需要显示的点数,这里已经不需要,可以全部删掉。

    该用户从未签到

    549

    主题

    9198

    回帖

    1万

    积分

    管理员

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

    将 KEIL C251 支持的中断号 拓展到 0 ~ 255
  • TA的每日心情
    开心
    昨天 10:26
  • 签到天数: 105 天

    [LV.6]常住居民II

    28

    主题

    103

    回帖

    834

    积分

    高级会员

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

    该用户从未签到

    549

    主题

    9198

    回帖

    1万

    积分

    管理员

    积分
    13999
    发表于 2022-12-13 12:13:42 | 显示全部楼层
    STC 的有 DMA 支持 TFT-i8080/M6800 接口的 MCU, 都可以设置 TFT-i8080/M6800 接口 是8位还是16位

    该用户从未签到

    549

    主题

    9198

    回帖

    1万

    积分

    管理员

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

    2.png
    3.png

  • TA的每日心情
    开心
    昨天 10:26
  • 签到天数: 105 天

    [LV.6]常住居民II

    28

    主题

    103

    回帖

    834

    积分

    高级会员

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


    999.jpg

    888.jpg

  • TA的每日心情
    奋斗
    昨天 09:01
  • 签到天数: 122 天

    [LV.7]常住居民III

    26

    主题

    1242

    回帖

    3887

    积分

    论坛元老

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

    [LV.2]偶尔看看I

    3

    主题

    28

    回帖

    331

    积分

    中级会员

    积分
    331
    发表于 2022-12-14 10:17:18 | 显示全部楼层
    各位大佬,有STC32的ADC-DMA的范本吗?我是模拟电子专业对编程只懂皮毛,项目需要以前都是用范本移植.谢谢!
  • TA的每日心情
    开心
    昨天 10:26
  • 签到天数: 105 天

    [LV.6]常住居民II

    28

    主题

    103

    回帖

    834

    积分

    高级会员

    积分
    834
     楼主| 发表于 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, 2024-4-25 01:52 , Processed in 0.074472 second(s), 67 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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