赞
踩
根据安福莱的STM32H7教程,H7单片机的QSPI外设是直接连到芯片内核上的,地址是0X90000000;那么就可以通过QSPI外设,将外置flash内存映射,并由此执行代码。
相关操作在keil5上比较简单,配置点东西就行;可以参考安福莱教程。
这里要介绍的是在linux环境下没有keil5 IDE的情况下,如何使用clion+openocd实现
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中,引导运行即可。
那么现在出现两个问题:
使用ST提供的下载工具下载;
需要:
刚才已经成功编译了外置执行代码,烧录器咱也有,而烧录算法呢,推荐看安福莱的相关教程。
相关教程
这个是我主要想讲的,在一个编辑器里完成编译、下载、调试,嘿嘿
先解决下载问题。
我们知道,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
两个教程都很全面,并且将代码文件、配置文件都开源了,去点星星咯。
大家可以根据自己的板子的引脚定义进行修改相关寄存器即可。
到这里,基本完成了配置,可以实现在clion中通过openocd实现向单片机外置flash下载代码,并进行仿真调试了。
不管上面如何下载代码,都需要从外置flash启动,前面也简略提到了——我们需要在单片机的内置flash中下载一个bootloader代码,用于从外置flash启动。
这个代码比较简单,就初始化一点点外设,主要还是QSPI,然后关闭Cache、MPU,对外置flash进行内存映射,并启动。具体内容可以参考安福莱教程。
我的是修改的反客科技的bootloader代码,将其QSPI外设的引脚改成我的板子的就可以用了。是之前用keil5写的,也可以自己用cubemx生成一个,添加应用代码即可。比较简单。
另外,从外置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配置代码。
相关教程:
在clion使用openocd仿真的话,为了查看各个寄存器的值,需要添加寄存器配置文件,一般keil5安装目录里有,我把我的上传到Github上了,欢迎下载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。