版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第第页基于MM32F5微控制器的FSMC接口外接SRAM存储器的用法
用户实际开发application工程时,是不应该感受到这个附加的bootloader工程的,因此,bootloader的执行时间应尽量短,执行完毕后应尽量复原至芯片上电复位的状态。在本例中,为了尽量加速bootloader工程的运行,在BOARD_Init()函数中初始化启用的PLL,从芯片内部的8MHz时钟源倍频到120MHz,用最快速度执行完bootloader的语句后,在临跳转到application工程之前,又将系统时钟复原成原来上电缺省使用的8MHz内部时钟,尽量还原到芯片刚上电后进入用户程序的状态。但同外扩内存相关的外设资源(引脚、时钟等),则必须保持激活状态。
验证固件函数app_check_image()关于验证bootloader跳转的硬件环境,本例做得比较简单,仅在app_check_image()函数中检查即将在application中使用的栈顶指针值和复位向量入口(中断向量表的前两个表项)。如果希望做得更严谨一些,可以再把即将使用的外扩SRAM存储空间都遍历一遍,写入数据之后再读出来查看是否一致,以确认即将使用的SRAM也是有效的。本例创建的app_check_image()函数,见代码x。
代码x实现app_check_image()函数
voidapp_check_image(void*addr){uint32_t*vectorTable=(uint32_t*)addr;/*validatetheaddrforsp.*/if((vectorTable[0]BOARD_APP_EXEC_RAM_LIMIT)){return1u;/*unavailablesramarea.*/}/*validatetheaddrforpc.*/if((vectorTable[1]BOARD_APP_EXEC_ROM_LIMIT)){return2u;/*unavailablesramarea.*/}return0u;}跳转函数app_jump_to_image()
最关键的跳转函数app_jump_to_image(),见代码x。
代码x实现app_jump_to_image()函数
typedefvoid(*func_0_t)(void);volatileuint32_tsp_base;volatileuint32_tpc_base;voidapp_jump_to_image(void*addr){uint32_t*vectorTable=(uint32_t*)addr;sp_base=vectorTable[0];pc_base=vectorTable[1];/*setnewMSPandPSP.*whentheSPischanged,theaddressofvariablesinstackwouldberemappedaccordingtothenewSP.*/__set_MSP(sp_base);__set_PSP(sp_base);#if__VTOR_PRESENT==1SCB->VTOR=(uint32_t)addr;/*thefunc'sparamiskeptinR1register,whichwouldnotbechangedpertheSPupdate.*/#endif/*jumptoapplication.*/((func_0_t)(pc_base))();//pc_func();/*thecodeshouldneverreachhere.*/while(1){}}在app_jump_to_image()函数中,通过传入的即将跳转到可执行二进制代码区的首地址,提取位于可执行文件程序开始位置的中断向量表的前两个表项,分别为栈顶SP指针的初始值和PC指针的初始(复位中断服务程序入口地址),然后用各自不同的方法将它们赋值到硬件寄存器中生效:MSP和PSP寄存器可以直接使用汇编语句赋值,而PC指针不能由程序直接操作,但通过函数跳转命令实际可以载入新的PC值。
关于跳转之前是否重新配置SP指针(微控制器内核中的MSP和PSP寄存器),这里也有一些考虑:
如果在application工程的启动程序中,有重置栈指针的操作,那么在bootloader工程中就没必要从application工程的文件中提取栈地址并重置栈顶指针了。但实际上大多数工程的启动程序中都没有这个步骤,而是依赖于微控制内核硬件的自动行为,从中断向量表的第一个表项中提取栈顶地址作为内核栈指针的初值。从完全(模拟)芯片启动行为的角度上看,在进入application之前,仍然需要给application工程一个位于主内存空间中的缺省栈指针,就像bootloader工程中上电后执行的第一条指令时,硬件就已经自动从中断向量表的第一个表项中提取了栈顶地址赋给栈指针。从bootloader跳转到application的过程中,微控制器不会自动将application中断向量表的第一个存放栈顶地址值,硬件自动为栈指针赋值的操作仅仅,只好由bootloader预先准备好。关于重置SP指针的影响,这里也要特别说明。当在app_jump_to_image()函数中执行__set_MSP(sp_base)语句时,当前的栈指针就已经变了,此时,当前函数中使用的局部变量,还保存在原有的栈中,使用变化后的栈顶指针已经无法访问原有栈中的内容了。因此,之后再使用的sp_base和pc_base变量都被定义成全局变量,存放在外部内存(仍位于片内SRAM中),而不是栈中。至于addr变量,是来自于函数传参,被存放在内核的Rn寄存器中,不受栈指针变化的影响。
通过把pc_base赋值给PC寄存器,微控制器内核就转而执行新的PC指针指向的程序,从而完成了跳转到新程序的功能。
调试
改好代码之后,编译工程,就可以直接(下载)可执行文件到芯片中了。这个下载过程同正常下载工程没有任何区别,还是将可执行文件的二进制代码下载到片内FLASH存储器上。
此时,如果片内FLASH中还没有下载可用application文件到约定的地址上,有一定几率被app_check_image()函数检测为无效目标程序,直接卡在原地,并用指示灯常量警示用户。也可能碰巧通过了检测,bootloader工程最后跳转之后将会“跑飞”。
如果片内FLASH中已经下载了可用的application工程文件,例如后续重新调试bootloader添加新功能的开发过程,(处理器)内核执行了bootloader的跳转语句之后,就已经跳出了bootloader工程的控制范围,进入了application工程的执行序列,届时还需要配合application工程联合调试。
约定分配bootloader和application工程的存储空间
MM32F5微控制器内部存储空间分布,如表x所示。
bootloader工程和application工程的可执行文件都存放在片内FLASH存储器上。bootloader使用片内SRAM作为主SRAM,application使用外扩SRAM作为主SRAM,映射到FSMCBank3的0x68000000-0x68100000的1MB大小的空间上。
bootloader工程的链接命令文件bootloader工程和application工程的可执行文件都存放在片内FLASH存储器上。芯片上电后,缺省先执行bootloader工程,故bootloader工程的程序位于片内FLASH存储空间的首部,预留16KB。bootloader使用部分片内SRAM作为主SRAM,预留64KB,用户也可以根据实际需要调整。
在bootloader工程的链接命令文件中有关于存放程序文件地址空间的定义。见代码x。
代码xbootloader工程的链接命令文件
/*FLASHConfiguration;FLASHConfiguration;FLASHBaseAddress;FLASHSize(inBytes);**/#define__ROM_BASE0x08000000#define__ROM_SIZE0x00004000/*EmbeddedRAMConfiguration;RAMConfiguration;RAMBaseAddress;RAMSize(inBytes);**/#define__RAM_BASE0x30000000#define__RAM_SIZE0x00010000application工程的链接命令文件application工程的可执行文件也保存在片内FLASH上,位于bootloader程序文件之后。若在应用中没有特别的需要,application工程可占用剩余的所有FLASH存储空间。application使用外扩SRAM存储作为主SRAM,映射到FSMCBank3的0x68000000-0x68100000的1MB大小的空间上。
在application工程的链接命令文件中有关于存放程序文件地址空间的定义。见代码x。
代码xapplication工程的链接命令文件
/*FLASHConfiguration;FLASHConfiguration;FLASHBaseAddress;FLASHSize(inBytes);**/#define__ROM_BASE0x08004000#define__ROM_SIZE0x0003C000/*EmbeddedRAMConfiguration;RAMConfiguration;RAMBaseAddress;RAMSize(inBytes);**/#define__RAM_BASE0x68000000#define__RAM_SIZE0x00100000在application工程中开发应用
试验并查看分配在外扩SRAM的存储空间前文说到,用户在application工程中开发应用,不需要专门配置外扩SRAM相关硬件的操作,即可直接使用外扩SRAM存储作为主存储器。不过,在application工程中仍需要调整一下链接文件,将FLASH存储空间定义到片内FLASH存储器上除了bootloader已经在首部占用的其余空间,将RAM空间定义到外扩存储器映射的存储空间中。这部分操作,已经在application工程的链接命令文件中配置好了,不需要用户在代码层面做任何特殊的设置。
在样例工程application中定义全局变量uint8_tch;见代码x。
代码x在application工程中定义全局变量
#include"board_init.h"uint8_tch;intmain(void){BOARD_Init();printf("application.rn");while(1){ch=getchar();putchar(ch);}}编译项目后,可以查看其中的project.map文件中,编译器自动为全局变量分配的内存位于外扩存储的内存空间中。见代码x。
代码x编译application工程生成的project.map文件
GlobalSymbolsSymbolNameValueOvTypeSizeObject(Section)...__stdin0x68000000Data4stdin.o(.data)__stdout0x68000004Data4stdout.o(.data)ch0x68000008Data1main.o(.bss.ch)Image$$ARM_LIB_STACK$$ZI$$Base0x680ff000Number0anon$$obj.oABSOLUTEImage$$ARM_LIB_STACK$$ZI$$Limit0x68100000Number0anon$$obj.oABSOLUTE...ExecutionRegionRW_RAM(Execbase:0x68000000,Loadbase:0x08005724,Size:0x0000000c,Max:0x000fe000,ABSOLUTE)ExecAddrLoadAddrSizeTypeAttrIdxESectionNameObject0x680000000x080057240x00000004DataRW310.datamc_w.l(stdin.o)0x680000040x080057280x00000004DataRW311.datamc_w.l(stdout.o)0x68000008-0x00000001ZeroRW20.bss.chmain.oExecutionRegionARM_LIB_HEAP(Execbase:0x68000010,Loadbase:0x0800572c,Size:0x00001000,Max:0x00001000,ABSOLUTE)ExecAddrLoadAddrSizeTypeAttrIdxESectionNameObject0x68000010-0x00001000ZeroRW1ARM_LIB_HEAP.bssanon$$obj.oExecutionRegionARM_LIB_STACK(Execbase:0x680ff000,Loadbase:0x0800572c,Size:0x00001000,Max:0x00001000,ABSOLUTE)ExecAddrLoadAddrSizeTypeAttrIdxESectionNameObject0x680ff000-0x00001000ZeroRW2ARM_LIB_STACK.bssanon$$obj.o从代码x中也可以看到,application工程的运行时全局变量数据区(RW_RAW)、堆空间(ARM_LIB_HEAP)、栈空间(ARM_LIB_STACK)也都位于0x6800_0000开始的外扩内存区间。
clock_init()虽说在application工程中不需要用户为使用外扩SRAM做任何特殊的设置,但由于使用了SDK代码包,还是有一点编程要点要注意。SDK的编程规范里,有要求在芯片上电启动过程中,用户在使用硬件外设之前,要使用硬件复位操作复位将要使用外设模块,以确保每次进入main()函数时,硬件外设的状态都是从确定的初始状态开始工作的。但在本例中,是通过bootloader引导进入的application,有一些已经激活的外设必须保持工作状态,例如FSMC以及对应使用的GPIO等外设模块,是不能在application工程中复位硬件的,否则,之前bootloader的准备工作就白费了,整个工程也不能正常工作。这里务必要再次确认clock_init.c文件中BOARD_InitBootClocks()函数中,关闭对FSMC和GPIO外设的复位操作,或者不要额外操作亦可。见代码x。
代码xapplication工程的BOARD_InitBootClocks()函数
voidBOARD_InitBootClocks(void){CLOCK_ResetToDefault();CLOCK_BootToHSE120MHz();/*(UART)1.*/RCC_EnableAPB2Periphs(RCC_APB2_PERIPH_UART1,true);RCC_ResetAPB2Periphs(RCC_APB2_PERIPH_UART1);/*GPIOA.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA,true);//RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);/*GPIOB.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOB,true);//RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOB);/*GPIOC.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOC,true);//RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOC);/*GPIOD.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOD,true);//RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOD);/*GPIOE.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOE,true);//RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOE);/*GPIOF.*///RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOF,true);//RCC_ResetAHB1Periphs(RCC_A
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025曲靖职业技术学院教师招聘考试题目及答案
- 2025江西师范高等专科学校教师招聘考试题目及答案
- 2026贵州省物资集团国际贸易有限公司招聘7人建设笔试备考试题及答案解析
- 2026河南洛阳市西苑初级中学招聘建设笔试参考题库及答案解析
- 2026北京航空航天大学宇航学院聘用编研发工程师招聘1人建设考试备考题库及答案解析
- 2025年安徽省池州市城管协管招聘笔试试题及答案解析
- 宜宾三江新区主导产业企业(含民营企业)2026年第二季度人才引进(招聘)岗位需求建设考试备考试题及答案解析
- 2026武汉工程大学招聘非事业编制工作人员1人(二)建设笔试模拟试题及答案解析
- 2026年上半年黑龙江中医药大学附属第二医院哈南分院暨黑龙江省老年医院 公开招聘工作人员30人(人事代理)建设考试备考题库及答案解析
- 2026南昌市劳动保障事务代理中心招聘外包人员2人建设笔试参考题库及答案解析
- JJF 2380-2026检验医学定量检测项目基于患者数据的质量控制算法溯源方法
- 2026年离婚协议(标准版)
- 产妇生产陪伴制度
- 药剂科“十五五”发展规划(2026-2030年)
- 基于PLC的自动售货机控制系统设计
- 《船舶结构与货运(大副)》-第5章 船舶货运基础知识
- 灵活就业人员劳动合同范本及说明
- 自我认知课件
- 肺功能康复指南
- (2025年标准)设备预定协议书
- 公司向个人无偿租赁汽车合同(2025版)
评论
0/150
提交评论