簡(jiǎn)介
根據(jù)安福萊的STM32H7教程,H7單片機(jī)的QSPI外設(shè)是直接連到芯片內(nèi)核上的,地址是0X90000000;那么就可以通過QSPI外設(shè),將外置flash內(nèi)存映射,并由此執(zhí)行代碼。
相關(guān)操作在keil5上比較簡(jiǎn)單,配置點(diǎn)東西就行;可以參考安福萊教程。
這里要介紹的是在linux環(huán)境下沒有keil5 IDE的情況下,如何使用clion+openocd實(shí)現(xiàn)
- 將大體積代碼下載到外置flash并執(zhí)行
- 對(duì)外置flash執(zhí)行的代碼進(jìn)行仿真
代碼配置
修改系統(tǒng)配置文件
STM32的代碼都是有起始地址的,每一句代碼,編譯為相關(guān)機(jī)器碼執(zhí)行時(shí),都有對(duì)應(yīng)地址的;對(duì)于一般情況的代碼,起始地址都是0X8000000;
該文件中詳細(xì)的配置了單片機(jī)所使用的flash大小,ram大小,地址等信息。
由于采用外置flash啟動(dòng),我們需要將flash地址配置為QSPI地址,并修改LENGTH為我們的flash芯片大小。
MEMORY
{
FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 8192K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
修改系統(tǒng)初始化函數(shù)
STM32單片機(jī)啟動(dòng)時(shí)會(huì)先執(zhí)行匯編啟動(dòng)文件,先定義中斷向量表,再執(zhí)行復(fù)位,設(shè)置棧頂指針,再執(zhí)行系統(tǒng)初始化函數(shù),再跳轉(zhuǎn)main函數(shù)。
其中系統(tǒng)初始化函數(shù)中需要修改SCB->VTOR的值。
SCB->VTOR為Cortex內(nèi)核的中斷向量表的基地址,一般為程序執(zhí)行的初始地址。 #12AA9C
關(guān)于該變量理解,參考鏈接
這里需要修改為我們程序啟動(dòng)的地址0X90000000。
編譯
點(diǎn)擊編譯,即可制作一個(gè)運(yùn)行在外部flash的代碼,下載到外置flash中,引導(dǎo)運(yùn)行即可。
那么現(xiàn)在出現(xiàn)兩個(gè)問題:
- 如何下載到外置flash
- 如何從外置flash中啟動(dòng)
代碼下載
使用CubeProgramer工具下載
使用ST提供的下載工具下載;
需要:
- 對(duì)應(yīng)板子的下載算法文件
- 燒錄器
- 能夠運(yùn)行在外置flash的代碼
剛才已經(jīng)成功編譯了外置執(zhí)行代碼,燒錄器咱也有,而燒錄算法呢,推薦看安福萊的相關(guān)教程。
相關(guān)教程
使用Clion下載
這個(gè)是我主要想講的,在一個(gè)編輯器里完成編譯、下載、調(diào)試,嘿嘿
先解決下載問題。
我們知道,STM32下載代碼時(shí)會(huì)先執(zhí)行一個(gè)配置程序,該程序運(yùn)行在RAM中,會(huì)初始化部分關(guān)于下載代碼的外設(shè)。
使用keil5時(shí),我們會(huì)使用一個(gè).flm文件下載代碼,該文件就是下載引導(dǎo)程序,其制作流程安福萊里講的有。
同樣,在正常下載的時(shí)候也會(huì)有一個(gè)keil5官方提供的.flm文件,這些文件就儲(chǔ)存在官方目錄里。
對(duì)于CubeMX而言,也有相應(yīng)的文件,
所以,我們使用的openocd工具也是有的,在我們的工程目錄里,有一些配置文件,都具有各自相應(yīng)的功能。
在stm32h750b-disco.cfg文件中,初始化了芯片時(shí)鐘,和部分必要的下載外設(shè);
在19行、23行:跳轉(zhuǎn)到了其他配置文件中,執(zhí)行具體的操作
# enable stmqspi
if {![info exists QUADSPI]} {
set QUADSPI 1
}
source [find target/stm32h7x.cfg]
reset_config srst_only
source [find board/stm32h7x_dual_qspi.cfg]
在這里,代碼定義了QUADSPI為1,即會(huì)在stm32h7x_dual_qspi.cfg中執(zhí)行該外設(shè)的初始化;
但是,這里該外設(shè)的初始化是以STM32官方出的板子的引腳定義的,不一定適合我們,而且實(shí)操下來,該文件改來改去效果不大,而且我覺得不建議跳到人家官方配置文件里修修改改,這里我們直接在該配置語句下面執(zhí)行我們板子的配置代碼;
# ART_Pi qspi.
# QUADSPI initialization
proc qspi_init { } {
global a
mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks)
mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock)
sleep 1 ;# Wait for clock startup
# PF10:AF09:H, PF09:AF10:H, PF08:AF10:H, PF07:AF09:H, PF06:AF09:H, PG06:AF10:H
# Port F: PF10:AF09:H, PF09:AF10:H, PF08:AF10:H, PF07:AF09:H, PF06:AF09:H
mmw 0x58021400 0x002AA000 0x00155000 ;# MODER
mmw 0x58021408 0x002AA000 0x00155000 ;# OSPEEDR
mmw 0x5802140C 0x00000000 0x003FF000 ;# PUPDR
mmw 0x58021420 0x99000000 0x66000000 ;# AFRL
mmw 0x58021424 0x000009AA 0x00000655 ;# AFRH
# Port G: PG06:AF10:H
mmw 0x58021800 0x00002000 0x00001000 ;# MODER
mmw 0x58021808 0x00002000 0x00001000 ;# OSPEEDR
mmw 0x5802180C 0x00000000 0x00003000 ;# PUPDR
mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL
# correct FSIZE is 0x16, however, this causes trouble when
# reading the last bytes at end of bank in *memory mapped* mode
# for single flash mode w25q64jv
;# 010101010000000000000 0 011000
mww 0x52005000 0x05500018 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=1, FSEL=0, DFM=0, SSHIFT=1, TCEN=1
mww 0x52005004 0x00160500 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x05, CKMODE=0
;# FSIZE flash的大小。
mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full
;# 11010000000000 10 010100000011
mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1
mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1
# Exit QPI mode
#mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
#mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI
sleep 1
# reset flash
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
mww 0x52005014 0x00000166 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=0x66
mww 0x52005014 0x00000199 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=0x99
# memory-mapped read mode with 3-byte addresses
mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1
;# 11 11 0 00100 00 11 10 11 01 11101011
mww 0x52005014 0x0F10EDEB ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0x4, ADSIZE=0x2, ADMODE=0x3, IMODE=0x1, INSTR=READ
;mww 0x52005014 0x0D002503
}
$_CHIPNAME.cpu0 configure -event reset-init {
global QUADSPI
mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK
mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on
mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock
mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1
mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2
mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2
mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI
mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide
mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24
mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1
sleep 1
mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock
sleep 1
adapter speed 24000
if { $QUADSPI } {
qspi_init
}
}
改代碼中主要就初始化了QSPI外設(shè)的GPIO,并配置了QSPI外設(shè),使用的板子是ART-Pi;
使用的GPIO是: PF10,PF09,PF08,PF07,PF06,PG06.
相關(guān)外設(shè)初始化主要時(shí)鐘匹配自己的芯片速度。
這里主要參考鏈接:
在CLion上實(shí)現(xiàn)STM32H750VBT6的Bootloader
使用openOCD擦寫ART_Pi外部qspi_flash
兩個(gè)教程都很全面,并且將代碼文件、配置文件都開源了,去點(diǎn)星星咯。
大家可以根據(jù)自己的板子的引腳定義進(jìn)行修改相關(guān)寄存器即可。
到這里,基本完成了配置,可以實(shí)現(xiàn)在clion中通過openocd實(shí)現(xiàn)向單片機(jī)外置flash下載代碼,并進(jìn)行仿真調(diào)試了。
從外置flash中啟動(dòng)代碼
不管上面如何下載代碼,都需要從外置flash啟動(dòng),前面也簡(jiǎn)略提到了——我們需要在單片機(jī)的內(nèi)置flash中下載一個(gè)bootloader代碼,用于從外置flash啟動(dòng)。
這個(gè)代碼比較簡(jiǎn)單,就初始化一點(diǎn)點(diǎn)外設(shè),主要還是QSPI,然后關(guān)閉Cache、MPU,對(duì)外置flash進(jìn)行內(nèi)存映射,并啟動(dòng)。具體內(nèi)容可以參考安福萊教程。
硬漢嵌入式的bootloader教程
我的是修改的反客科技的bootloader代碼,將其QSPI外設(shè)的引腳改成我的板子的就可以用了。是之前用keil5寫的,也可以自己用cubemx生成一個(gè),添加應(yīng)用代碼即可。比較簡(jiǎn)單。
適配ART-Pi的下載算法和bootloader
另外,從外置flash引導(dǎo)的代碼,受flash限制,運(yùn)行速度并不快,不如芯片內(nèi)部的flash,對(duì)此,我們參考安福萊教程,使用MPU配置外置flash內(nèi)存,用Cache預(yù)存取指令,提高代碼運(yùn)行速度。相關(guān)配置:
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x90000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_8MB;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
MPU配置代碼。
相關(guān)教程:
理論學(xué)習(xí),詳細(xì)好理解
硬漢哥的MPU教程
硬漢哥的實(shí)戰(zhàn)教程,超級(jí)好用
添加
在clion使用openocd仿真的話,為了查看各個(gè)寄存器的值,需要添加寄存器配置文件,一般keil5安裝目錄里有,我把我的上傳到Github上了,歡迎下載。
SVD文件文章來源:http://www.zghlxwxcb.cn/news/detail-792246.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-792246.html
到了這里,關(guān)于STM32H7使用QSPI外擴(kuò)flash(linux下使用openocd操作)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!