当前位置:   article > 正文

STM32H7使用QSPI外扩flash(linux下使用openocd操作)_stm32h7 qspi

stm32h7 qspi

简介

根据安福莱的STM32H7教程,H7单片机的QSPI外设是直接连到芯片内核上的,地址是0X90000000;那么就可以通过QSPI外设,将外置flash内存映射,并由此执行代码。

STM3H7单片机矩阵架构
相关操作在keil5上比较简单,配置点东西就行;可以参考安福莱教程。

这里要介绍的是在linux环境下没有keil5 IDE的情况下,如何使用clion+openocd实现

  • 将大体积代码下载到外置flash并执行
  • 对外置flash执行的代码进行仿真

代码配置

修改系统配置文件

STM32的代码都是有起始地址的,每一句代码,编译为相关机器码执行时,都有对应地址的;对于一般情况的代码,起始地址都是0X8000000;

工程FLASH配置文件
该文件中详细的配置了单片机所使用的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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

修改系统初始化函数

STM32单片机启动时会先执行汇编启动文件,先定义中断向量表,再执行复位,设置栈顶指针,再执行系统初始化函数,再跳转main函数。

其中系统初始化函数中需要修改SCB->VTOR的值。
SCB->VTOR为Cortex内核的中断向量表的基地址,一般为程序执行的初始地址。 #12AA9C
关于该变量理解,参考链接

这里需要修改为我们程序启动的地址0X90000000。
SCB->VTOR地址修改

编译

点击编译,即可制作一个运行在外部flash的代码,下载到外置flash中,引导运行即可。

那么现在出现两个问题:

  • 如何下载到外置flash
  • 如何从外置flash中启动

代码下载

使用CubeProgramer工具下载

使用ST提供的下载工具下载;
需要:

  • 对应板子的下载算法文件
  • 烧录器
  • 能够运行在外置flash的代码

刚才已经成功编译了外置执行代码,烧录器咱也有,而烧录算法呢,推荐看安福莱的相关教程。
相关教程

使用Clion下载

这个是我主要想讲的,在一个编辑器里完成编译、下载、调试,嘿嘿

先解决下载问题。

我们知道,STM32下载代码时会先执行一个配置程序,该程序运行在RAM中,会初始化部分关于下载代码的外设。

使用keil5时,我们会使用一个.flm文件下载代码,该文件就是下载引导程序,其制作流程安福莱里讲的有。

反客的keil5下载教程

同样,在正常下载的时候也会有一个keil5官方提供的.flm文件,这些文件就储存在官方目录里。

对于CubeMX而言,也有相应的文件,

所以,我们使用的openocd工具也是有的,在我们的工程目录里,有一些配置文件,都具有各自相应的功能。

clion工程目录
在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]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这里,代码定义了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
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

改代码中主要就初始化了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预存取指令,提高代码运行速度。相关配置:
Cubemx配置

  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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

MPU配置代码。

相关教程:

理论学习,详细好理解

硬汉哥的MPU教程

硬汉哥的实战教程,超级好用

添加

在clion使用openocd仿真的话,为了查看各个寄存器的值,需要添加寄存器配置文件,一般keil5安装目录里有,我把我的上传到Github上了,欢迎下载。

SVD文件

仿真视图

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号