0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于MM32实现NOR FLASH运行应用程序的过程解析

Q4MP_gh_c472c21 来源:21ic论坛 作者:xld0932 2022-03-31 13:52 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

在项目开发之初,我们会根据设计需求来选择符合要求的芯片。其中,RAM决定了程序运行时的内存大小,ROM决定了应用程序的存储空间大小。但对于应用功能特别大的项目,MCU内部的FLASH(ROM)存储空间就无法满足要求了。这个时候就需要外扩程序存储空间,而NOR FLASH就是其中一种解决方案。

文结合涉及到的技术点一一做了详细介绍和说明,包含如下四大内容:

1. KEIL下载程序配置及说明2. MM32实现跳转到NOR FLASH运行程序3. 基于MM32的NOR FLASH下载算法实现4. MM32实现NOR FLASH应用程序编程,下载程序并运行

一、KEIL下载程序配置及说明

通过对项目工程的配置,在KEIL在编译完工程后,会生成相应的HEX或BIN格式的程序烧录文件,点击Download下载按键后,会将烧录文件烧录到芯片中。

点击Option for Target魔术棒按键,在弹出的Option for Target窗口中的Output选项卡中设置生成程序烧录文件名,并勾选Create HEX file选项,如下图所示:

2316602c-b0b4-11ec-aa7f-dac502259ad0.png

如果需要同时再生成BIN格式的程序烧录文件,我们可以在User选项卡中进行如下图的配置:

232ff0d2-b0b4-11ec-aa7f-dac502259ad0.png

接着,在Debug选项卡中选择相应的调试下载工具。

2351db2a-b0b4-11ec-aa7f-dac502259ad0.png

在Utilities选项卡中配置下载设置(使用与Debug相同的工具进行下载程序),如下图所示:

23676e4a-b0b4-11ec-aa7f-dac502259ad0.png

另外Utilities选项卡中,点击Settings按键,在弹出的窗口中Flash Download选项卡中进行如下配置:

237ea4de-b0b4-11ec-aa7f-dac502259ad0.png

下载功能设置:包括擦出选择、编程、校验和下载完成后复位芯片并运行应用程序。

编程(下载)算法选择:一般在创建工程选择相应的芯片后,这边的下载算法就默认了,如果没有我们可以点击ADD按键添加相对应的下载算法;下载算法列举了描述、设备存储空间大小、设备类型以及地址区间范围。

编程(下载)算法在RAM中的位置:这个一般是默认的,START表示芯片RAM的起始地址,这个是由芯片决定的;SIZE表示最大支持的编程(下载)算法的程序空间大小,这个可以修改,但不得小于下载算法程序大小。

待这些都配置完成后,我们编译工程代码,无错误警告后,点击Download下载按键,即可下载应用程序到芯片中。

那么,在点击了Download按键后,那KEIL是如何将烧录程序下载到芯片中去的呢?

简单来说,就是KEIL软件根据配置将编程(下载)算法加载到芯片指定的RAM空间去(这个空间就是上述的以START作为起始地址,SIZE大小的RAM空间),并运行下载算法,对下载文件进行解析,将需要写入的数据通过下载算法写到指定的存储地址上,完成上述编程的过程。

二、MM32实现跳转到NOR FLASH运行程序

MM32F3270系列MCU支持存储控制器FSMC功能,可配置的静态存储器包括SRAM、NOR FLASH;另外还支持80806800接口,可以应用到LCD显示上。

NOR FLASH之所以可以运行程序,主要是因为其内部地址/数据线是分开的,支持字节访问,符合CPU指令译码执行的要求(NOR FLASH上储存了指令代码,MCU给NOR FLASH一个地址,NOR FLASH就向MCU返回相应地址上的数据,让MCU执行,中间不需要额外的处理操作)。

那通过上述的描述,使用MM32实现跳转到NOR FLASH运行程序,我们就只需要在基于MM32内部FLASH运行的基础上实现NOR FLASH与MCU之间的FSMC初始化配置,以及程序跳转这两个操作步骤,具体参考代码如下所示:

FSMC初始化配置:

/*******************************************************************************
 * [url=home.php?mod=space&uid=288409]@file[/url]    NOR.c
 * [url=home.php?mod=space&uid=187600]@author[/url]  King
 * [url=home.php?mod=space&uid=895143]@version[/url] V1.00
 * [url=home.php?mod=space&uid=212281]@date[/url]    25-Jan-2021
 * [url=home.php?mod=space&uid=247401]@brief[/url]   ......
*******************************************************************************/




/* Define to prevent recursive inclusion -------------------------------------*/
#define __NOR_C__




/* Includes ------------------------------------------------------------------*/
#include "NOR.h"




/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/




/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/




/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * [url=home.php?mod=space&uid=93590]@Attention[/url]   
*******************************************************************************/
void NOR_InitGPIO(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; 


    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD | RCC_AHBPeriph_GPIOE |
                          RCC_AHBPeriph_GPIOF | RCC_AHBPeriph_GPIOG , ENABLE);


    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_12);  /* FSMC_D0  */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_12);  /* FSMC_D1  */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0,  GPIO_AF_12);  /* FSMC_D2  */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1,  GPIO_AF_12);  /* FSMC_D3  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource7,  GPIO_AF_12);  /* FSMC_D4  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource8,  GPIO_AF_12);  /* FSMC_D5  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource9,  GPIO_AF_12);  /* FSMC_D6  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_12);  /* FSMC_D7  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_12);  /* FSMC_D8  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_12);  /* FSMC_D9  */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_12);  /* FSMC_D10 */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_12);  /* FSMC_D11 */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_12);  /* FSMC_D12 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8,  GPIO_AF_12);  /* FSMC_D13 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9,  GPIO_AF_12);  /* FSMC_D14 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_12);  /* FSMC_D15 */


    GPIO_PinAFConfig(GPIOF, GPIO_PinSource0,  GPIO_AF_12);  /* FSMC_A0  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource1,  GPIO_AF_12);  /* FSMC_A1  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource2,  GPIO_AF_12);  /* FSMC_A2  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource3,  GPIO_AF_12);  /* FSMC_A3  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource4,  GPIO_AF_12);  /* FSMC_A4  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource5,  GPIO_AF_12);  /* FSMC_A5  */


    GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_12);  /* FSMC_A6  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_12);  /* FSMC_A7  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_12);  /* FSMC_A8  */
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_12);  /* FSMC_A9  */


    GPIO_PinAFConfig(GPIOG, GPIO_PinSource0,  GPIO_AF_12);  /* FSMC_A10 */
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource1,  GPIO_AF_12);  /* FSMC_A11 */
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource2,  GPIO_AF_12);  /* FSMC_A12 */
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource3,  GPIO_AF_12);  /* FSMC_A13 */
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource4,  GPIO_AF_12);  /* FSMC_A14 */
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource5,  GPIO_AF_12);  /* FSMC_A15 */


    GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_12);  /* FSMC_A16 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_12);  /* FSMC_A17 */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_12);  /* FSMC_A18 */


    GPIO_PinAFConfig(GPIOE, GPIO_PinSource3,  GPIO_AF_12);  /* FSMC_A19 */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource4,  GPIO_AF_12);  /* FSMC_A20 */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource5,  GPIO_AF_12);  /* FSMC_A21 */
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource6,  GPIO_AF_12);  /* FSMC_A22 */


    GPIO_PinAFConfig(GPIOD, GPIO_PinSource4,  GPIO_AF_12);  /* FSMC_NOE  */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5,  GPIO_AF_12);  /* FSMC_NWE  */
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6,  GPIO_AF_12);  /* FSMC_NWAIT*/
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource9,  GPIO_AF_12);  /* FSMC_NE2  */


    /* D00 - D01 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure); 


    /* D02 - D03 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure); 


    /* D04 - D12 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7  | GPIO_Pin_8  | GPIO_Pin_9  |
                                    GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 |
                                    GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);


    /* D13 - D15 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure); 


    /* A00 - A05 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
                                    GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOF, &GPIO_InitStructure);


    /* A06 - A09 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12 | GPIO_Pin_13 | 
                                    GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOF, &GPIO_InitStructure);


    /* A10 - A15 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 |
                                    GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);


    /* A16 - A18 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);


    /* A19 - A22 */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_4 | 
                                    GPIO_Pin_5 | GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);


    /* NOE(PD4) NWE(PD5) configuration */  
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);


    /* NWAIT(PD6) configuration */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(GPIOD, &GPIO_InitStructure); 


    /* NE2(PG9) configuration */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
}




/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void NOR_InitFSMC(void)
{
    FSMC_InitTypeDef              FSMC_InitStructure;
    FSMC_NORSRAM_Bank_InitTypeDef FSMC_BankInitStructure;


    RCC_AHB3PeriphClockCmd(RCC_AHB3ENR_FSMC, ENABLE);


    FSMC_NORSRAM_BankStructInit(&FSMC_BankInitStructure);
    FSMC_BankInitStructure.FSMC_SMReadPipe      = 0;
    FSMC_BankInitStructure.FSMC_ReadyMode       = 0;
    FSMC_BankInitStructure.FSMC_WritePeriod     = 5;    /* W:WE Pulse Width         : [0, 63] */
    FSMC_BankInitStructure.FSMC_WriteHoldTime   = 3;    /* W:Address/Data Hold Time : [0,  3] */
    FSMC_BankInitStructure.FSMC_AddrSetTime     = 3;    /* W:Address Setup Time     : [0,  3] */
    FSMC_BankInitStructure.FSMC_ReadPeriod      = 8;    /* R:Read Cycle Time        : [0, 63] */
    FSMC_BankInitStructure.FSMC_DataWidth       = FSMC_DataWidth_16bits;
    FSMC_NORSRAM_Bank_Init(&FSMC_BankInitStructure, FSMC_NORSRAM_BANK1);


    FSMC_NORSRAMStructInit(&FSMC_InitStructure);
    FSMC_InitStructure.FSMC_Mode                = FSMC_Mode_NorFlash;
    FSMC_InitStructure.FSMC_TimingRegSelect     = FSMC_TimingRegSelect_1;
    FSMC_InitStructure.FSMC_MemSize             = FSMC_MemSize_64MB;
    FSMC_InitStructure.FSMC_MemType             = FSMC_MemType_FLASH;
    FSMC_InitStructure.FSMC_AddrDataMode        = FSMC_AddrDataDeMUX;
    FSMC_NORSRAMInit(&FSMC_InitStructure);
}




/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
void NOR_Init(void)
{
    NOR_InitGPIO();


    NOR_InitFSMC();
}




/******************* (C) COPYRIGHT 2022 *************************END OF FILE***/


程序跳转代码:

/*******************************************************************************
 * @file    main.c
 * @author  King
 * @version V1.00
 * @date    25-Jan-2021
 * @brief   ......
*******************************************************************************/




/* Define to prevent recursive inclusion -------------------------------------*/
#define __MAIN_C__




/* Includes ------------------------------------------------------------------*/
#include "main.h"




/* Private typedef -----------------------------------------------------------*/
typedef void (*pFunction)(void);




/* Private define ------------------------------------------------------------*/
#define ApplicationAddress      ((uint32_t)0x64000000)




/* Private macro -------------------------------------------------------------*/




/* Private variables ---------------------------------------------------------*/
uint32_t  JumpAddress  =  0;
pFunction JumpToApplication;




/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/




/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/




/*******************************************************************************
 * @brief       
 * @param       
 * @retval      
 * @attention   
*******************************************************************************/
int main(void)
{
    NOR_Init();


    /* Jump to code loaded in NOR memory and execute it ***********************/
    JumpAddress = *(volatile uint32_t *)(ApplicationAddress + 4);
    JumpToApplication = (pFunction)JumpAddress;


    /* Initialize user application's Stack Pointer */
    __set_MSP(*(volatile uint32_t *)ApplicationAddress); 
    JumpToApplication();


    while(1);
}




/******************* (C) COPYRIGHT 2022 *************************END OF FILE***/


KEIL工程的相关配置:

2394b882-b0b4-11ec-aa7f-dac502259ad0.png

23a9d4ce-b0b4-11ec-aa7f-dac502259ad0.png

三、基于MM32的NOR FLASH下载算法实现

在能够成功跳转到NOR FLASH运行程序后,我们就需要将应用程序下载到NOR FLASH就可以了。

结合第一小结,一般MCU自带的下载算法只是将程序下载到自身内部的FLASH存储空间,如果需要将程序下载到外扩的NOR FLASH,我们可以使用烧录工具,将程序烧录进NOR FLASH。但在开发调试过程中,这显然不太方便,所以我们就需要自行编写下载算法,来实现MM32与NOR FLASH之间的程序编程。

应该怎么去编写这个下载算法呢?

首先,在KEIL的安装路径下:C:Keil_v5ARMFlash有一个_Template的下载算法工程模板,我们将其直接拷贝一份,重命名为MM32F3270_NOR_FLM;打开KEIL工程,里面主要有两个文件FlashDev.c和FlashPrg.c

FlashDev.c主要是用来描述存储特性的,包括Device Name、Device Type、Device Start Address、Device Size in Bytes等等,这些特性的值,我们可以根据NOR FLASH的特性值来填写,编程超时时间和擦出超时时间可以尽量长一些,做些冗余,具体参考如下所示:

23c3372a-b0b4-11ec-aa7f-dac502259ad0.png

FlashPrg.c就是用来实现编程下载算法的接口函数,其中有些函数是必须实现的,有些函数则是可选择的,如下所示:

23d64586-b0b4-11ec-aa7f-dac502259ad0.png

我们需要实现的就是通过对这些函数的补充实现,来达到NOR FLASH的读写操作,实现将程序下载到NOR FLASH。

在第一小节,我们知道下载算法是需要先加载到RAM中运行,再去进行编程操作的,对于这个加载到RAM空间的下载算法程序空间大小其实是有大小限制有,根据每个芯片的RAM大小而定,但最大也不能超过0x10000。

所以,我们在实现自己定义的下载算法的时候就尤其需要注意,尽量的不去使用库函数,以使用寄存器或者是直接操作芯片内部地址最佳,这样可以最大程序的节省程序空间。

不过,这也会使代码的阅读理解变得有些困难。因为下载算法运行的程序不能够实现的在线调试,所以对于NOR FLASH操作的这些函数功能,最好在其它工程上先进行验证,确认功能正常后,再移植到下载算法的工程当中来。

接下来,就是点击KEIL工程魔术棒按键对工程进行设置。在Target选项卡中选择芯片型号为MM32F3277G9P,在C/C++选项卡中根据需要进行宏定义(因为这个下载算法,支持多个NOR FLASH,所以我这边有相应的宏定义),在添加好NOR FLASH的相关函数,并补全接口函数后,进行编译。

此时工程目录中就会生成一个FLM文件(因为在User选项卡中有一个命令:cmd.exe /C copy "Objects\%L" ".@L.FLM",它会将编译后的文件转换成FLM格式)

24023376-b0b4-11ec-aa7f-dac502259ad0.png

241b757a-b0b4-11ec-aa7f-dac502259ad0.png

242d48ea-b0b4-11ec-aa7f-dac502259ad0.png

我们将这个生成的FLM下载算法文件拷贝到C:Keil_v5ARMFlash目录下,在后面工程使用到的时候就可以添加进来了。

四、MM32实现NOR FLASH应用程序编程,下载程序并运行

对于运行在NOR FLASH中的MM32程序来说,程序编写并没有特殊的要求,唯一不同的就是对于KEIL工程的设置。例程中,我们只实现了LED灯的闪烁功能,功能比较简单。对于KEIL工程的设置,如下图所示:

将默认的程序空间和程序启动空间设置为NOR FLASH的起始地址作为开始:

2446c48c-b0b4-11ec-aa7f-dac502259ad0.png

根据DEBUG调试工具进行对应的选择:

246206ac-b0b4-11ec-aa7f-dac502259ad0.png

下载工具与调试工具相同:

2475f14e-b0b4-11ec-aa7f-dac502259ad0.png

将编程(下载)算法选择为第三小节生成的FLM算法,在添加进来的时候,就会自动显示相应的描述信息:

248dbd1a-b0b4-11ec-aa7f-dac502259ad0.png

这样配置完成后,编译后点击下载按键,程序就被下载到NOR FLASH外部存储空间了。因为勾选了RESET AND RUN,下载完成后会复位MCU,此时MCU FLASH中已经存在了跳转程序,这个时候就会跳转到NOR FLASH执行LED闪烁程序。此时LED灯若能够正常运行,就说明程序功能已经正常运行了。

另外,有些小伙伴可能会问,在Option for Target窗口Utilities选项卡中,有看到Init File会配置一个INI文件,我上述的工程配置中却没有,这是怎么回事呢?

这边的INI文件包含的是对MCU内部地址配置相应参数值的数据,是在下载程序前先对MCU进行设置的操作。一般看到的就是对MCU与NOR FLASH的FSMC相关寄存器进行配置,好让下载算法能够正常的去操作NOR FLASH。但我的配置截图中却没有,是因为在实现下载算法时的INIT函数,已经实现了对FSMC的初始化配置,所以在INIT FILE的位置就不需要再重复操作了。

五、后续

有了这个下载算法,我们可以将部分程序或数据指令到外部存储空间;如果当我们通过LCD显示图片数据时,图片数据是一个很大的数组,我们就可以将这些数据指定到NOR FLASH中,而应用程序还是在MCU内部的FLASH中运行,操作如下图所示:

芯片有两个ROM空间,但默认的和启动的为MCU内部FLASH:

24a402aa-b0b4-11ec-aa7f-dac502259ad0.png

下载算法有两个,这两个的地址是不一样的,一个是MCU内部FLASH,一个是外扩的NOR FLASH:

24b9eeb2-b0b4-11ec-aa7f-dac502259ad0.png

将程序指定到NOR FLASH的方法,右击.C文件,选择Options for File”IMAGE1.c”...

24d3db6a-b0b4-11ec-aa7f-dac502259ad0.png

在弹出的窗口中将CODE/CONST指令到ROM1,如下图所示:

24e85c0c-b0b4-11ec-aa7f-dac502259ad0.png

然后在程序中再调用IMAGE1.c文件中的数据,这样在编译后下载程序的时候,会先下载程序到MCU的FLASH,再下载图片数据到MCU扩展的NOR FLASH。

24fbc9f4-b0b4-11ec-aa7f-dac502259ad0.png

本文中的硬件是基本神舟III开发板实现的,MCU使用的是灵动微电子的MM32F3277G9P,NOR FLASH使用的是M29W128FH。

至此分享就结束了,希望能对各位小伙伴有所帮助!另外,如果有需要查看原图和代码的小伙伴,请点击底部“阅读原文”进行下载。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    462

    文章

    53552

    浏览量

    459292
  • 应用程序
    +关注

    关注

    38

    文章

    3342

    浏览量

    59929
  • 存储空间
    +关注

    关注

    0

    文章

    55

    浏览量

    10991
  • MM32
    +关注

    关注

    1

    文章

    108

    浏览量

    1318

原文标题:实战!基于MM32实现NOR FLASH运行应用程序的过程解析

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    3D NOR FLASH技术、AI服务器动能,多家厂商预估2026全年上涨

    电子发烧友网报道(文/黄晶晶)继DRAM和NAND的价格不断上涨之后,日前NOR Flash也出现了惊人的高达30%涨幅。NOR Flash在AI服务器、手机、平板电脑、可穿戴等领域呈
    的头像 发表于 11-17 07:53 9034次阅读
    3D <b class='flag-5'>NOR</b> <b class='flag-5'>FLASH</b>技术、AI服务器动能,多家厂商预估2026全年上涨

    NOR Flash到NAND Flash和SD NAND,从底层结构到应用差异

    在嵌入式系统开发中,“存储选型”是经常会遇到的问题,特别是许多曾长期使用 NOR   Flash 的工程师,在切换到 NAND Flash 时常常感到疑惑:   为什么 NAND Flash
    发表于 12-08 17:54

    FLASH中的代码是如何得到运行的呢

    以ARM为例: ARM-cortex-M3/4的单片机(比如STM32 等):该类单片机的代码在nor flash中,cortex内核可以直接运行,不需要将代码加载到ram中运行
    发表于 12-04 08:06

    高性能SPI NOR FLASH芯片ZB25VQ系列推荐

    在嵌入式系统、物联网设备及各类存储应用中,SPI NOR FLASH芯片因其接口简单、功耗低、读写速度快等特点,成为代码存储与数据缓存的常见选择。SPI NOR FLASH是一种基于S
    的头像 发表于 12-01 14:52 202次阅读

    华邦高性能NOR Flash用于学习平板

    华邦电子(Winbond)的NOR Flash以其卓越性能成为学习平板理想的存储解决方案。其芯片内执行(XIP)特性可实现系统秒级快速启动,高可靠性确保固件和核心代码安全,低功耗特性则有效延长设备续航,为流畅稳定的学习体验奠定坚
    的头像 发表于 11-10 09:48 278次阅读
    华邦高性能<b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>用于学习平板

    博雅NOR Flash 液晶电视核心存储方案优选​

    博雅BOYA BY25Q32BSSIG是一款32Mbit SPI NOR Flash芯片,支持133MHz高速读取与XIP技术,能显著提升液晶电视的启动速度与系统响应。其工业级温度范围与低功耗特性保障了电视在长期高温环境下的稳定运行
    的头像 发表于 10-31 09:16 163次阅读
    博雅<b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b> 液晶电视核心存储方案优选​

    博雅NOR FLASH XIP技术实现电力仪表毫秒级快速启动​

    博雅128Mbit NOR Flash BY25Q128ESSIG为智能电力仪表提供高可靠存储方案,133MHz读取速度与-40℃~105℃宽温保障数据实时性与稳定性。
    的头像 发表于 09-08 09:55 718次阅读
    博雅<b class='flag-5'>NOR</b> <b class='flag-5'>FLASH</b> XIP技术<b class='flag-5'>实现</b>电力仪表毫秒级快速启动​

    SPI NOR FLASH是什么,与SPI NAND Flash的区别

    存储一位数据 (0或1) ,可以直接寻址,寻址速度非常快。SPI NOR FLASH支持全双工、单工以及半双工传输方式,被广泛应用于嵌入式系统中,如Bootloader、操作系统内核等程序的存储。由于它的读写速度和寻址方式类似于
    的头像 发表于 08-21 09:26 1119次阅读

    华邦电子W25Q-RV系列NOR Flash的四大本领

    在汽车、物联网和工业自动化等应用场景中,存储器是否能够稳定运行直接影响产品的可靠性。华邦推出的 W25Q-RV 系列 NOR Flash,成功通过 105°C 的工业级高温循环测试和储能测试,以超越 JEDEC 标准的性能,在严
    的头像 发表于 08-16 17:14 1358次阅读

    嵌入式系统中,FLASH 中的程序代码必须搬到 RAM 中运行吗?

    嵌入式系统里,FLASH 中的程序代码并非必须搬到 RAM 中运行,这得由硬件配置、实际性能需求和应用场景共同决定。就像很多低端单片机,无论是依赖片内 Flash 还是外挂的 SPI
    的头像 发表于 08-06 10:19 1143次阅读
    嵌入式系统中,<b class='flag-5'>FLASH</b> 中的<b class='flag-5'>程序</b>代码必须搬到 RAM 中<b class='flag-5'>运行</b>吗?

    普冉NOR FLASH助力IPC摄像头高效运行

    Puya 普冉 64 Mbit NOR Flash P25Q64SH-SUH 以宽压、高速 SPI、毫秒级擦写和低功耗特性,为 IPC 摄像头提供固件、配置与算法的可靠存储。适用于安防监控、智能家居及电池供电场景,助力终端小型化、低功耗与持续在线。
    的头像 发表于 08-01 10:05 691次阅读
    普冉<b class='flag-5'>NOR</b> <b class='flag-5'>FLASH</b>助力IPC摄像头高效<b class='flag-5'>运行</b>

    如何将Flash刷写程序放到SRAM中运行

    客户要求Flash driver不能存储在Flash中,需要在升级的时候,由CAN FBL发送到SRAM中,再运行SRAM中的Flash driver 我应该如何
    发表于 07-15 07:22

    MCU片上Flash

    保留能力,支持多次擦写操作,是MCU程序存储的核心介质。 主要类型‌ NOR Flash‌:支持随机访问,可直接运行代码,适用于实时性要求高的场景。 NAND
    的头像 发表于 05-06 14:26 868次阅读

    在OpenVINO™中运行应用程序失败怎么解决?

    尝试在 OpenVINO™ 中运行我的推理应用程序失败,并出现以下错误: RuntimeError: Check \'false\' failed at src/core/src/runtime/ov_tensor.cpp:67: Dims and format are
    发表于 03-05 10:29

    罗彻斯特电子为传统应用提供卓越的内存支持 为并行NOR Flash提供持续供货支持

    为并行NOR Flash提供持续供货支持 凭借罗彻斯特电子的生产能力,能够持续供应并行NOR Flash。不论是传统还是成熟产品对于此类产品都有持续需求。通过战略性安排,罗彻斯特电子购
    发表于 12-17 10:33 482次阅读