AT32F425-R8T7-7开发板移植2.4寸ILI9341液晶显示屏测试 一、开箱的仪式感 春节假期块结束的时候,看到21ic.com论坛的评测活动又开始了,机会很是难得,写了申请材料,就盼望着。 盼望着,后来有工程师联系我,询问是否需要样品,等等。还谈了一些特别的工具之类。我想应该会有配备调试器的。当然,作为初学者,我接触过的单片机,最早是stc89c52,那时候买了一个套件,自己焊接的,还学了protel99se 来画板子,终于了解PCB是怎么一回事。已经是12年前了。后来出现了Arduino热潮,感觉驱动啥的都做好了,太方便了,只要关心你需要做的工作的流程就行了,渐渐的就不再静心来学习新知识了,或者是因为有些害怕困难了。使用Keil u2开发51,使用Arduino IDE 写Arduino代码,好多年过去了,keil已经升级为MDK,然后中国芯越来越多了,感到很振奋。可惜精力不如以前了,要是搞一个Arduino的BSP包也是极好的,因为这可以方便打入教育市场。还是基本功不扎实,需要认真的啃代码。 这样子参加测评活动,一开始定的目标挺高的。眼高手低,不想点灯来作为发帖子的主题,因为高手们已经发过了。打开论坛,满眼都是测评,有熟悉的FFT测试。我前一阵子也做了FFT算法的学习,也打算跑在arm32上,其实真的很合适,因为AT32F425-R8T7-8这颗芯片是有FPU,有浮点运算单元的。可以做很好的数字信号处理。这也是一个Flag吧。 过了一阵,收到了公司从北京发来的开发板。我以为所谓的工具是很奇特的,也是可以支持 MDK开发环境的。而且开发板有AT-Link,可以做仿真调试用,很方便做原创性开发。 看看漂亮而富有冬奥会主题的包装设计把。有点冰墩墩的萌。 图 1 AT-START-F425开发板 图 2 AT32F425-R8T7-7 这块开发板设计时很讲究的,有一个标准的Arduino Uno 接口。我的科技实验室的学生黄同学痴迷Arduino,留在实验室里有一块彩色液晶屏,已经吃灰很久了。让它点亮发挥它的真本事那该有多好。于是开始寻找合适的代码。某宝上的商家有一块一样的屏,有资料链接,下载下来,是stm32f103的驱动代码。我感到有压力。习惯了Arduino那种标准化的库的学习使用,觉得找不到方向。但是受到论坛上大家的移植的作品的鼓励,我觉得应该是可以在原有驱动代码的基础上,适配到AT32F425的。只是要先了解驱动代码的实现原理和关键的部分。先实现对液晶显示部分功能的移植。里面还有sdcard驱动和touch触摸屏的驱动部分。 图 3 带有UNO接口的液晶模块的正面 图 4 ILI9341的液晶模块,接口是arduino uno 二、ILI9341液晶屏的自带驱动 资料里面的驱动,Arduino Uno的驱动差距实在太大,是atmega8的gcc代码。和at32F425比较接近的应该是 stm32的代码包。而且还是mdk4版本的。折腾了一番,上网看了一些资料,需要下载pack,还有legacy support 包。我弄好了,Rebuild一遍,没有问题。 Stm32我没有学过,但是基本上很像arm 核的风格。Cmis, drvier, board, peripheral等代码结构里面,从启动到时钟设置,到延迟,到各种外设。 最重要的差异就是时钟。Stm32F103一般时钟是72 Mhz ,到GPIO的时钟频率被分配了为50MHz ,AT32F425是96MHz,是8Mhz * 12,倍频来的。不知道咋整。 驱动液晶屏的关键就是对GPIO的学习和理解。通用的GPIO的设置,参考各种支持包的例程,基本都包含了时钟设置,输入输出模式设置,数字模拟设置,更复杂的是复用,驱动液晶基本上是最简单的数字输出模式。参考标准例程gpio,心里还是有谱的。 三、AT32F425 的 UNO兼容接口 先把硬件连接好,接好后当然只是亮起了白屏。 图 5 ILI9341液晶模块的引脚数据 需要认真的记录下接线的gpio口,在代码移植中,这是极其重要的。 图 6 AT-START-F425v1.0 开发板的Uno接口。 四、移植的代码修改 1.延时函数 在和液晶通信时,关键的是接线要对,还有时序一定要对。所以延时函数很重要。AT32F425的BSP支持包中,已经有很好的延时函数了。 把原来的 #include ”delay.h” 更换为 #include "at32f425_board.h" 就可以了。这样就有了delay_us()和delay_ms()可以供其它控制逻辑使用了。 2.控制线和数据线 在芯片和芯片的通信中,有控制信号,也有数字信号。这些信号线的连接,是个精细活需要认真记录。 在lcd.h中重新定义控制总线和数据总线的位操作代码。 #define LCD_CS_SET GPIOB->scr = GPIO_PINS_0 //片选端口 PB0
#define LCD_RS_SET GPIOA->scr = GPIO_PINS_4 //数据/命令 PA4
#define LCD_WR_SET GPIOA->scr = GPIO_PINS_1 //写数据 PA1
#define LCD_RD_SET GPIOA->scr = GPIO_PINS_0 //读数据 PA0
#define LCD_RST_SET GPIOC->scr = GPIO_PINS_1 //复位 PC1
#define LCD_D0_SET GPIOA->scr = GPIO_PINS_9 //D0 set PA9
#define LCD_D1_SET GPIOC->scr = GPIO_PINS_7 //D1 set PC7
#define LCD_D2_SET GPIOA->scr = GPIO_PINS_10 //D2 set PA10
#define LCD_D3_SET GPIOB->scr = GPIO_PINS_3 //D3 set PB3
#define LCD_D4_SET GPIOB->scr = GPIO_PINS_5 //D4 set PB5
#define LCD_D5_SET GPIOB->scr = GPIO_PINS_4 //D5 set PB4
#define LCD_D6_SET GPIOB->scr = GPIO_PINS_10 //D6 set PB10
#define LCD_D7_SET GPIOA->scr = GPIO_PINS_8 //D7 set PA8
#define LCD_CS_CLR GPIOB->clr = GPIO_PINS_0 //片选端口 PB0
#define LCD_RS_CLR GPIOA->clr = GPIO_PINS_4 //数据/命令 PA4
#define LCD_WR_CLR GPIOA->clr = GPIO_PINS_1 //写数据 PA1
#define LCD_RD_CLR GPIOA->clr = GPIO_PINS_0 //读数据 PA0
#define LCD_RST_CLR GPIOC->clr = GPIO_PINS_1 //复位 PC1
#define LCD_D0_CLR GPIOA->clr = GPIO_PINS_9 //D0 CLR PA9
#define LCD_D1_CLR GPIOC->clr = GPIO_PINS_7 //D1 CLR PC7
#define LCD_D2_CLR GPIOA->clr = GPIO_PINS_10 //D2 CLR PA10
#define LCD_D3_CLR GPIOB->clr = GPIO_PINS_3 //D3 CLR PB3
#define LCD_D4_CLR GPIOB->clr = GPIO_PINS_5 //D4 CLR PB5
#define LCD_D5_CLR GPIOB->clr = GPIO_PINS_4 //D5 CLR PB4
#define LCD_D6_CLR GPIOB->clr = GPIO_PINS_10 //D6 CLR PB10
#define LCD_D7_CLR GPIOA->clr = GPIO_PINS_8 //D7 CLR PA8
//AT-START-F425 v1.0 data port
// LCD_D7 -- PA8
// LCD_D6 -- PB10
// LCD_D5 -- PB4
// LCD_D4 -- PB5
// LCD_D3 -- PB3
// LCD_D2 -- PA10
// LCD_D1 -- PC7
// LCD_D0 -- PA9
数据总线的操作比较麻烦。为了更快操作,可以使用某一组端口,比如GPIOB的8个脚,比如GPIOB8~GPIOB15来和D0~D7通信。但是因为要方便使用UNO接口,而AT32-F425开发板上的对应接口没有这么刚好。所以需要定义位操作,对需要送到数据按位来设定。从而每一次传输,都需要判断位,然后进行位设置或位清零。这个方法可以,但是费时间。为了更高速,可以尝试应用接线来做。 有一个很重要的数据口操作宏实现。 #if LCD_USE8BIT_MODEL==1 //8bits pararell mode,8bits data in high 8bits of u16t
#define DATAOUT(x){\
if((x)&0x0100){\
LCD_D0_SET;\
}\
else{\
LCD_D0_CLR;\
}\
if((x)&0x0200){\
LCD_D1_SET;\
}\
else{\
LCD_D1_CLR;\
}\
if((x)&0x0400){\
LCD_D2_SET;\
}\
else{\
LCD_D2_CLR;\
}\
if((x)&0x0800){\
LCD_D3_SET;\
}\
else{\
LCD_D3_CLR;\
}\
if((x)&0x1000){\
LCD_D4_SET;\
}\
else{\
LCD_D4_CLR;\
}\
if((x)&0x2000){\
LCD_D5_SET;\
}\
else{\
LCD_D5_CLR;\
}\
if((x)&0x4000){\
LCD_D6_SET;\
}\
else{\
LCD_D6_CLR;\
}\
if((x)&0x8000){\
LCD_D7_SET;\
}\
else{\
LCD_D7_CLR;\
}\
}
#else
#define DATAOUT(x) {}; //16位模式 没有实现
#endif
3.用于控制线和数据线的GPIO设置 我们知道必须对控制总线和数据总线用到的GPIO口进行设置。 认真学习led_toggle 例程,也参考了论坛上的教程。发现进行GPIO设置,最好是同一个Port的几个引脚一起设置。分为时钟使能、输入输出模式设定、上拉下拉状态设定等。这个函数中就定义好了控制总线和8位数据总线。要注意的是,AT32F425开发板是信号的发送方,所以设定为数字输出,而且是推挽输出。而液晶模块整个过程中只简单的负责接收信号,没有反馈给开发板。这个对于速度要求不高的情况是简单可行的。 void LCD_GPIOInit(void)
{
//stm32 libraries
/*
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5; //GPIO_Pin_10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure); //GPIOC
GPIO_SetBits(GPIOC,GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8|GPIO_Pin_7|GPIO_Pin_6|GPIO_Pin_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //
GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIOB
GPIO_SetBits(GPIOB,GPIO_Pin_All);
*/
//stm32 libraries
//at32f425 lib
gpio_init_type gpio_init_struct;
/* configure the DATA and CTRL gpio Port A */
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
//gpio A 0 1 4 5 7 15 9 8 10
gpio_init_struct.gpio_pins = (GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_7|GPIO_PINS_15 |GPIO_PINS_9 |GPIO_PINS_8 |GPIO_PINS_10 );
gpio_init(GPIOA, &gpio_init_struct);
/* configure the DATA and CTRL gpio Port B */
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
//gpio B 0 10 4 5 3
gpio_init_struct.gpio_pins = (GPIO_PINS_0|GPIO_PINS_10|GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_3 );
gpio_init(GPIOB, &gpio_init_struct);
/* configure the DATA and CTRL gpio Port C */
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
/* set default parameter */
gpio_default_para_init(&gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
//gpio C 1 7
gpio_init_struct.gpio_pins = (GPIO_PINS_1|GPIO_PINS_7);
gpio_init(GPIOC, &gpio_init_struct);
}
五、移植的结果 图 7测试的最终结果 六、致谢 感谢21ic.com论坛,感谢ARTERY雅特力科技,感谢论坛上无私分享实验成果的伙伴们,希望这微小的探索,可以有点用。 参考文献来源 www.arterytek.com www.taobao.com
|