目錄
在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燒錄演算法
實驗平臺:
硬體: RT-Thread官方ART-PI H750開發版,正點原子4.3寸RGBLCD屏(800*480)
軟體: 最新版本的STM32CubeH7韌體庫,TouchGFXDesigner v4.14和 STM32CubeMX V6.0.1,開發環境MDK v5.29

代碼下載:
CSDN:https://download.csdn.net/download/sinat_31039061/12849875
聯系作者:
關注公眾號,免費查看,回復“加群”,加入技術交流群

為什么需要QSPI-FLASH燒錄演算法下載到外部flash
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:
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,具體原理和上邊差不多,至于你想把哪部分代碼放到外部,可以有你自己決定,
可以參考一下正點原子的分散加載檔案:
#! 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的空間,至于超出的空間安全不安全就不知道了)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/70744.html
標籤:其他
上一篇:華為鴻蒙作業系統學習(1):查找學習資料,最重要的不是著急去買板子,這個關鍵在于軟體!這個關鍵在于軟體!這個關鍵在于軟體!準備直接在Linux上面進行編譯學習,就學習基礎的東西。
