简介
根据安福莱的STM32H7教程,H7单片机的QSPI外设是直接连到芯片内核上的,地址是0X90000000;那么就可以通过QSPI外设,将外置flash内存映射,并由此执行代码。
相关操作在keil5上比较简单,配置点东西就行;可以参考安福莱教程。
这里要介绍的是在linux环境下没有keil5 IDE的情况下,如何使用clion+openocd实现
- 将大体积代码下载到外置flash并执行
- 对外置flash执行的代码进行仿真
代码配置
修改系统配置文件
STM32的代码都是有起始地址的,每一句代码,编译为相关机器码执行时,都有对应地址的;对于一般情况的代码,起始地址都是0X8000000;
该文件中详细的配置了单片机所使用的flash大小,ram大小,地址等信息。
由于采用外置flash启动,我们需要将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
}
修改系统初始化函数
STM32单片机启动时会先执行汇编启动文件,先定义中断向量表,再执行复位,设置栈顶指针,再执行系统初始化函数,再跳转main函数。
其中系统初始化函数中需要修改SCB->VTOR的值。
SCB->VTOR为Cortex内核的中断向量表的基地址,一般为程序执行的初始地址。 #12AA9C
关于该变量理解,参考链接
这里需要修改为我们程序启动的地址0X90000000。
编译
点击编译,即可制作一个运行在外部flash的代码,下载到外置flash中,引导运行即可。
那么现在出现两个问题:
- 如何下载到外置flash
- 如何从外置flash中启动
代码下载
使用CubeProgramer工具下载
使用ST提供的下载工具下载;
需要:
- 对应板子的下载算法文件
- 烧录器
- 能够运行在外置flash的代码
刚才已经成功编译了外置执行代码,烧录器咱也有,而烧录算法呢,推荐看安福莱的相关教程。
相关教程
使用Clion下载
这个是我主要想讲的,在一个编辑器里完成编译、下载、调试,嘿嘿
先解决下载问题。
我们知道,STM32下载代码时会先执行一个配置程序,该程序运行在RAM中,会初始化部分关于下载代码的外设。
使用keil5时,我们会使用一个.flm文件下载代码,该文件就是下载引导程序,其制作流程安福莱里讲的有。
同样,在正常下载的时候也会有一个keil5官方提供的.flm文件,这些文件就储存在官方目录里。
对于CubeMX而言,也有相应的文件,
所以,我们使用的openocd工具也是有的,在我们的工程目录里,有一些配置文件,都具有各自相应的功能。
在stm32h750b-disco.cfg文件中,初始化了芯片时钟,和部分必要的下载外设;
在19行、23行:跳转到了其他配置文件中,执行具体的操作
# 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,即会在stm32h7x_dual_qspi.cfg中执行该外设的初始化;
但是,这里该外设的初始化是以STM32官方出的板子的引脚定义的,不一定适合我们,而且实操下来,该文件改来改去效果不大,而且我觉得不建议跳到人家官方配置文件里修修改改,这里我们直接在该配置语句下面执行我们板子的配置代码;
# 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外设的GPIO,并配置了QSPI外设,使用的板子是ART-Pi;
使用的GPIO是: PF10,PF09,PF08,PF07,PF06,PG06.
相关外设初始化主要时钟匹配自己的芯片速度。
这里主要参考链接:
在CLion上实现STM32H750VBT6的Bootloader
使用openOCD擦写ART_Pi外部qspi_flash
两个教程都很全面,并且将代码文件、配置文件都开源了,去点星星咯。
大家可以根据自己的板子的引脚定义进行修改相关寄存器即可。
到这里,基本完成了配置,可以实现在clion中通过openocd实现向单片机外置flash下载代码,并进行仿真调试了。
从外置flash中启动代码
不管上面如何下载代码,都需要从外置flash启动,前面也简略提到了——我们需要在单片机的内置flash中下载一个bootloader代码,用于从外置flash启动。
这个代码比较简单,就初始化一点点外设,主要还是QSPI,然后关闭Cache、MPU,对外置flash进行内存映射,并启动。具体内容可以参考安福莱教程。
硬汉嵌入式的bootloader教程
我的是修改的反客科技的bootloader代码,将其QSPI外设的引脚改成我的板子的就可以用了。是之前用keil5写的,也可以自己用cubemx生成一个,添加应用代码即可。比较简单。
适配ART-Pi的下载算法和bootloader
另外,从外置flash引导的代码,受flash限制,运行速度并不快,不如芯片内部的flash,对此,我们参考安福莱教程,使用MPU配置外置flash内存,用Cache预存取指令,提高代码运行速度。相关配置:
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配置代码。
相关教程:
理论学习,详细好理解
硬汉哥的MPU教程
硬汉哥的实战教程,超级好用
添加
在clion使用openocd仿真的话,为了查看各个寄存器的值,需要添加寄存器配置文件,一般keil5安装目录里有,我把我的上传到Github上了,欢迎下载。
SVD文件文章来源:https://www.toymoban.com/news/detail-792246.html
文章来源地址https://www.toymoban.com/news/detail-792246.html
到了这里,关于STM32H7使用QSPI外扩flash(linux下使用openocd操作)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!