在ART-Pi H750上移植TouchGFX(一)——使用STM32CUBMX生成TouchGFX工程
在ART-Pi H750上移植TouchGFX(二)——制做MDK的外部QSPI-FLASH烧录算法
在ART-Pi H750上移植TouchGFX(三)——移植TouchGFX到RT-Thread系统
在ART-Pi H750上移植TouchGFX(四)——使用RT-Thread Studio移植TouchGFX
在ART-Pi H750上移植TouchGFX(五)——制做ST-LINK的外部QSPI-FLASH烧录算法html
硬件: RT-Thread官方ART-PI H750开发版,正点原子4.3寸RGBLCD屏(800*480)
软件: 最新版本的STM32CubeH7固件库,TouchGFXDesigner v4.14和 STM32CubeMX V6.0.1,开发环境MDK v5.29
web
CSDN:https://download.csdn.net/download/sinat_31039061/12849875算法
关注公众号,免费查看,回复“加群”,加入技术交流群
数组
1.在实际的UI设计中每每须要大量的图片和字体,而TouchGFX Designer是把所使用的图片和字体自动转换成了静态数组,这些大数组在内部flash中通常是放不下的,因此须要把这些占用资源比较大的数组放在外部flash中,而后经过QSPI地址映射的方式访问。
打开上个工程的TouchGFX Designer,导入一个带图片的例程:
Edit->import GUI
安全
从新打开MDK工程,能够发现generated 分类下多了不少资源,经过以下宏定义能够知道该数组会优先存放在名为“ExtFlashSection”的内存区域中:
MDK的分散加载文件默认是没有“ExtFlashSection”区域的,咱们须要经过编写分散加载文件来配置“ExtFlashSection”段:
经过Edit按钮打开KEIL本身生成的sct文件,而后进行改写:
经过以上配置后,再编译代码,就不会出现flash不足的错误提示了,可是这时候还不能下载代码,由于没有为该段区域配置下载算法,下载会出现“No Algorithm found for: 90000000H - 9000FFFFH”等错误。
查看map文件,能够发现以上资源的地址已经被分配到了0x90000000:svg
MDK的STM32H7升级包升级至V2.6.0版本后,对ST全部板子的外置Flash下载算法提供了HAL库版本的源码,能够在这个源码的基础上改为你须要的。
下载地址:https://www.cnblogs.com/armfly/p/12564643.html函数
安装完成后,找到安装目录,经过如下地址,能够找到源代码:
(提醒一点:默认文件夹的属性是只读类型,因此打开工程后,全部文件都是加锁的,若是想要修改代码,须要把文件夹的属性取消只读)
因为我在更新最新的V2.6.0软件包以前,已经制做了寄存器版本的烧录算法,因此再也不使用HAL库版本的了,感兴趣的能够自行修改。
修改烧录算法的思路其实很简单,只须要修改FlashDev.c里边的外部flash大小,而后根据FlashPrg.c模板所须要的接口,添加你的外部flash驱动就好了,由于ART-PI使用的是W25Q128,和正点原子板子所使用的同样,因此直接把正点原子W25Q128的驱动移植过来就能够了。
工程模板默认已经作好了生成.FLM文件的配置,编译后会自动生成.FLM文件,而后把STM32H7_W25QXX.FLM拷贝到你MDK的安装目录…Keil_v5\ARM\Flash下。
测试
添加完下载算法,最后在MDK里修改一下配置,就能够把程序下载到板子里了:
还差一步:虽然你把图片和字体资源下载到了外部flash,可是这个时候尚未配置地址映射,因此你的程序依然是读不到数据的,须要添加qspi地址映射的代码。我这里依然借用了正点原子的代码:字体
//QSPI进入内存映射模式(执行QSPI代码必备前提,为了减小引入的文件, //除了GPIO驱动外,其余的外设驱动均采用寄存器形式) void QSPI_Enable_Memmapmode(void) { uint32_t tempreg=0; __IO uint32_t *data_reg=&QUADSPI->DR; GPIO_InitTypeDef qspi_gpio; RCC->AHB4ENR|=1<<6; //使能PORTG时钟 RCC->AHB4ENR|=1<<5; //使能PORTF时钟 RCC->AHB3ENR|=1<<14; //QSPI时钟使能 qspi_gpio.Pin=GPIO_PIN_6; //PG6 AF10 qspi_gpio.Mode=GPIO_MODE_AF_PP; qspi_gpio.Speed=GPIO_SPEED_FREQ_VERY_HIGH; qspi_gpio.Pull=GPIO_NOPULL; qspi_gpio.Alternate=GPIO_AF10_QUADSPI; HAL_GPIO_Init(GPIOG,&qspi_gpio); qspi_gpio.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_10; //PF6,7,10 AF9 qspi_gpio.Alternate=GPIO_AF9_QUADSPI; HAL_GPIO_Init(GPIOF,&qspi_gpio); qspi_gpio.Pin=GPIO_PIN_8|GPIO_PIN_9; //PF8,9 AF10 qspi_gpio.Alternate=GPIO_AF10_QUADSPI; HAL_GPIO_Init(GPIOF,&qspi_gpio); //QSPI设置,参考QSPI实验的QSPI_Init函数 RCC->AHB3RSTR|=1<<14; //复位QSPI RCC->AHB3RSTR&=~(1<<14); //中止复位QSPI while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 QUADSPI->CR=0X01000310; //设置CR寄存器,这些值怎么来的,请参考QSPI实验/看H750参考手册寄存器描述分析 QUADSPI->DCR=0X00160401; //设置DCR寄存器 QUADSPI->CR|=1<<0; //使能QSPI //注意:QSPI QE位的使能,在QSPI烧写算法里面,就已经设置了 //因此,这里能够不用设置QE位,不然须要加入对QE位置1的代码 //不过,代码必须经过仿真器下载,直接烧录到外部QSPI FLASH,是不可用的 //若是想直接烧录到外部QSPI FLASH也能够用,则须要在这里添加QE位置1的代码 //W25QXX进入QPI模式(0X38指令) while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 QUADSPI->CCR=0X00000138; //发送0X38指令,W25QXX进入QPI模式 while((QUADSPI->SR&(1<<1))==0); //等待指令发送完成 QUADSPI->FCR|=1<<1; //清除发送完成标志位 //W25QXX写使能(0X06指令) while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 QUADSPI->CCR=0X00000106; //发送0X06指令,W25QXX写使能 while((QUADSPI->SR&(1<<1))==0); //等待指令发送完成 QUADSPI->FCR|=1<<1; //清除发送完成标志位 //W25QXX设置QPI相关读参数(0XC0) while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 QUADSPI->CCR=0X030003C0; //发送0XC0指令,W25QXX读参数设置 QUADSPI->DLR=0; while((QUADSPI->SR&(1<<2))==0); //等待FTF *(__IO uint8_t *)data_reg=3<<4; //设置P4&P5=11,8个dummy clocks,104M QUADSPI->CR|=1<<2; //终止传输 while((QUADSPI->SR&(1<<1))==0); //等待数据发送完成 QUADSPI->FCR|=1<<1; //清除发送完成标志位 while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 //MemroyMap 模式设置 while(QUADSPI->SR&(1<<5)); //等待BUSY位清零 QUADSPI->ABR=0; //交替字节设置为0,实际上就是W25Q 0XEB指令的,M0~M7=0 tempreg=0XEB; //INSTRUCTION[7:0]=0XEB,发送0XEB指令(Fast Read QUAD I/O) tempreg|=3<<8; //IMODE[1:0]=3,四线传输指令 tempreg|=3<<10; //ADDRESS[1:0]=3,四线传输地址 tempreg|=2<<12; //ADSIZE[1:0]=2,24位地址长度 tempreg|=3<<14; //ABMODE[1:0]=3,四线传输交替字节 tempreg|=0<<16; //ABSIZE[1:0]=0,8位交替字节(M0~M7) tempreg|=6<<18; //DCYC[4:0]=6,6个dummy周期 tempreg|=3<<24; //DMODE[1:0]=3,四线传输数据 tempreg|=3<<26; //FMODE[1:0]=3,内存映射模式 QUADSPI->CCR=tempreg; //设置CCR寄存器 //设置QSPI FLASH空间的MPU保护 SCB->SHCSR&=~(1<<16); //禁止MemManage MPU->CTRL&=~(1<<0); //禁止MPU MPU->RNR=0; //设置保护区域编号为0(1~7能够给其余内存用) MPU->RBAR=0X90000000; //基地址为0X9000 000,即QSPI的起始地址 MPU->RASR=0X0303002D; //设置相关保护参数(禁止共用,容许cache,容许缓冲),详见MPU实验的解析 MPU->CTRL=(1<<2)|(1<<0); //使能PRIVDEFENA,使能MPU SCB->SHCSR|=1<<16; //使能MemManage }
烧录验证:
2.STM32H750XBH6的官方指导手册说明内部flash只要128K,这个空间对于作项目来讲是远远不够,因此也须要将部分代码下载到外部flash,具体原理和上边差很少,至于你想把哪部分代码放到外部,能够有你本身决定。
能够参考一下正点原子的分散加载文件:ui
#! armcc -E // //STM32H750分散加载文件(.scf文件) //ALIENTEK STM32开发板 //正点原子@ALIENTEK //技术论坛:www.openedv.com //建立日期:2019/4/21 //版本:V1.0 //版权全部,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved //******************************************************************************** //修改说明 //无 // #define m_stmflash_start 0X08000000 //m_stmflash(STM32内部FLASH)域起始地址 #define m_stmflash_size 0X20000 //m_stmflash(STM32内部FLASH)大小,H750是128KB #define m_qspiflash_start 0X90000000 //m_qspiflash(外扩QSPI FLASH)域起始地址 #define m_qspiflash_size 0X800000 //m_qspiflash(外扩QSPI FLASH)大小,W25Q64是8MB #define m_stmsram_start 0X24000000 //m_stmsram(STM32内部RAM)域起始地址,定义在D1,AXI SRAM #define m_stmsram_size 0X80000 //m_stmsram(STM32内部RAM)大小,AXI SRAM共512KB LR_m_stmflash m_stmflash_start m_stmflash_size { //LR_m_stmflash加载域 ER_m_stmflash m_stmflash_start m_stmflash_size { //ER_m_stmfalsh运行域,起始地址为:m_stmflash_start,大小为:m_stmflash_size *.o (RESET, +First) //优先(+FIRST)将RESET(中断向量表)段放这个域,实际上就是把中断向量表拷贝到m_stmflash_start //RESET是一个段名,表示中断向量表(在.s文件定义);+FIRST表示时第一个要加载的. * (InRoot$$Sections) //将全部的库段(C/C++标准库)放在root region.如__main.o,__scatter*.o等 * (Veneer$$Code) libinit.o libinit2.o libshutdown.o libshutdown2.o __rtentry.o __rtentry2.o __rtentry4.o rtexit.o rtexit2.o use_no_semi_2.o heapauxi.o use_no_semi.o sys_stackheap_outer.o exit.o libspace.o fpinit.o lludivv7m.o startup_stm32h750xx.o rt_locale_intlibspace.o lc_numeric_c.o lc_ctype_c.o startup_stm32h750xx.o system_stm32h7xx.o stm32h7xx_hal.o stm32h7xx_hal_cortex.o stm32h7xx_hal_rcc.o stm32h7xx_hal_gpio.o stm32h7xx_hal_msp.o main.o sys.o usart.o delay.o } RW_m_stmsram m_stmsram_start m_stmsram_size { //RW_m_stmsram运行域,起始地址为:m_stmsram_start,大小为:m_stmsram_size. .ANY (+RW +ZI) //将全部用到的RAM都放在这个区域 } } LR_m_qspiflash m_qspiflash_start m_qspiflash_size { //LR_m_qspiflash加载域 ER_m_qspiflash m_qspiflash_start m_qspiflash_size { //ER_m_qspiflash加载域,起始地址为:m_qspiflash_start,大小为:m_qspiflash_size .ANY (+RO) //将只读数据(+RO)放这个域,任意分配.至关于程序就是存放在这个域的. } }
(悄悄告诉你,虽然官方手册上说明内部flash只有128k的大小,可是通过实际测试,能够用到2M的空间,至于超出的空间安全不安全就不知道了)