在多次尝试修改 boot_serial 工程并使用汇编启动代码提供的失败后; 虽然看到了许多奇怪的行为,例如使用编译器优化级别更改行为、奇怪的 sp 和 LR 地址,但更改 GPIO 强制更新分配会在以后的另一个点中断程序,有时变量/指针只是在单步执行语句后不设置--
这是我最近尝试创建尽可能简单且易于理解的 SD 卡引导加载程序。
这在理论上似乎是正确的、也应该对其他人有用...
启动脚本没有什么特别之处、只是通过 Keil 提供的脚本。 fatfs 文件是包含在 TivaWare 中的文件。
使用此构建:
当我单步执行 f_mount (0、&fatf)时、我看到 SP 已更改为0x1fff60;
然后、我将以下内容移至全局区域:
FATFSFatFs; FILFileObject; FRESULTfResult;
这样、就不会使用栈来分配它们、而只是为了查看发生了什么、因为此数据不应首先导致栈溢出或任何问题。 我看不到不稳定的堆栈指针。 但在某些任意点、lr 设置 为0xfffffff9、程序进入 HardFault_Handler。
我真的无法以任何方式解释这种行为。
实际上、app_start_address 0x2800是使用另一个程序使用 boot_demo2进行刷写的。 我能够从 boot_demo2跳回引导加载程序... 但出于某种原因进入 fatfs 函数、会发生奇怪的情况。 我知道问题不在于 fatfs 代码、它可以处理其他项目。
//
//
//// bl_main.c -文件保存引导加载程序的主控制循环。
//
//版权所有(c) 2006-2016 Texas Instruments Incorporated。 保留所有权利。
//软件许可协议
//
//德州仪器(TI)提供此软件仅供
和//仅供 TI 的微控制器产品使用。 软件归
// TI 和/或其供应商所有,并受适用的版权
//法律保护。 您不能将此软件与"病毒"开源
//软件组合在一起以形成更大的程序。
//
//此软件按“原样”提供,且存在所有故障。
//对于
本软件,不作任何明示、暗示或法定的保证,包括但不限于对适销性和适用性的暗示保证//特定用途。 在任何
//情况下、TI 不对任何
原因造成的特殊、意外或必然//损害负责。
//
//这是 Tiva 固件开发包版本2.1.3.156的一部分。
////
*****************
//
//
//转换为 SD 引导加载程序并使用引导演示1和2进行测试
//
//*********
#include
#include
#include "inc/hw_gpio.h"
#include "iptit/hw_nvic.h"
#include "inc/hw_sysctl.h"
#include
"inc/hw_memmap.h"
#include "fatfs/conf/ff.h"
#include "fatfs/src="/src/ffio.io"
#include "#/driverc/#include "#/drivers/fs/fs/notes/src/#/ffic/now/now/notes/sr.pnings.c/#/now/notes/snings./#/#/#/notes/snow/nings./#/#/#/ff/now/nings.c/now/nings./#/#/#/#/notes/sr.pnings.c/nings.c/now/notes/snings./#/#/#/#/ffics/notes/snings.
//
//确保应用程序的起始地址位于闪存页边界
//
//*********
#if (APP_START_ADDRESS &(FLASH_PAGE_SIZE - 1)
)#ERROR 错误:APP_START_ADDRESS 必须是 FLASH_PAGE_SIZE 字节的倍数!
#endif
//*********
//
//确保闪存保留空间是闪存页的倍数。
////
*****************
#if (FLASH_RSVD_SPACE &(FLASH_PAGE_SIZE - 1))
#ERROR 错误:FLASH_RSVD_SPACE 必须是 FLASH_PAGE_SIZE 字节的倍数!
#endif
//*********
//
//应用程序的起始地址。 这必须是1024
//字节的倍数(使其与页边界对齐)。 在
//这个位置应该有一个矢量表、而矢量表(位于
SRAM 中的堆栈、位于闪存中的复位矢量)的感知有效性被用作
应用程序映像的//有效性的指示。
//
//启动加载程序的闪存映像不得大于此值。
//
//取决于:无
//不包括:无
//要求:无
//
//*********
#define APP_START_ADDRESS 0x2800
//*********
//
//应用程序查找其异常向量表的地址。
//这必须是1024字节的倍数(使其与页//
边界对齐)。 通常、应用程序将从其矢量表开始、
//此值应设置为 APP_START_ADDRESS。 提供此选项的目的
是//满足从外部存储器运行的应用程序的需要,
NVIC 可能无法访问这些应用程序(矢量表偏移寄存器仅为30位
//长)。
//
//取决于:无
//不包括:无
//要求:无
//
//*********
#define VTABLE vstart_address 0x2800
//*********
//
//闪存中单个可擦除页的大小。 这必须是电源
//为2。
//
//取决于:无
//不包括:无
//要求:无
//
//*********
#define FLASH_PAGE_SIZE 0x00000400
//*********
//
//要启用 GPIO 模块以检查强制更新。 这将
//成为 SYSCTL_RCGC2_GPIOx 值之一,其中"x"将替换为端口
//名称(如 B)。 "x"的值应与
// forced_update_port 的"x"的值匹配。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
//#define Forced_update_Periph sysctl_RCGC2_GPIOB
#define Forced_update_Periph 0x00000800 //对于 GPIO//
*********
//
// GPIO 端口检查强制更新。 这将是
// GPIO_Portx_BASE 值之一,其中"x"替换为端口名称(如
// B)。 "x"的值应与
// Forced_update_Periph 的"x"的值匹配。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
#define Forced_update_port GPIO_PORTM_BASE
//*********
//
//检查强制更新的引脚。 这是一个介于0和7之间的值。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
#define Forced_update_pin 0
//*****************
//
//导致强制更新的 GPIO 引脚的极性。 如果
引脚应该为低电平、这个值//应该为0;如果引脚应该为高电平、这个值应该为1。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
#define Forced_update_polarity 0
//*********
//
//这为强制
//更新中使用的 GPIO 引脚启用弱上拉或下拉。
只应//定义其中一个 forced_update_wpu 或 forced_update_wpd、如果不需要弱上拉或下拉、则不应这样做。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
#define Forced_update_WPU
//#define Forced_update_WPD
//*********
//
//这使得能够使用 GPIO_LOCK 机制来配置
//受保护的 GPIO 引脚(例如 JTAG 引脚)。 如果未定义此值、
//将不使用锁定机制。 此
//功能的唯一合法值是 Fury 器件的 GPIO_LOCK_KEY 和不
支持此功能的 Sandstorm 器件以外的所有//其他器件的 GPIO_LOCK_KEY_DD。
//
//取决于:enable_update_check
//不包括:none
// requss: none
//
//*********
//#define forced_update_key GPIO_LOCK_KEY
//#define Forced_update_key GPIO_LOCK_KEY_DD
#define delay (n) ROM_SysCtlDelay ((ROM_SysCtlClockGet ()/3000000)*n)
//extern void CallApplication ();
uint32_t g_ui32Forced = 0;
//*********
//
//! 检查 GPIO 是否有强制更新。
//!
//! 此函数检查 GPIO 的状态以确定是否正在进行更新
//! 已申请。
//!
//! 如果正在请求更新、则返回非零值、并且为零
//! 否则。
////
*****************
uint32_t
CheckGPIOForceUpdate (void)
{
//
//启用所需的 GPIO 模块。
//
HWREG (SYSCTL_RCGCGPIO)|= Forced_update_Periph;
//
//在访问外设之前等待一段时间。
//
延迟(3);
#ifdef Forced_update_key
//
//解锁 GPIO 访问。
//
HWREG (Forced_update_port + GPIO_lock)= Forced_update_key;
HWREG (Forced_update_port + GPIO_CR)= 1 << Forced_update_PIN;
#endif
//
//启用用于查看是否正在请求更新的引脚。
//
HWREG (Forced_update_port + GPIO_DEN)|= 1 << Forced_update_PIN;
#ifdef Forced_update_WPU
//
//设置输出驱动强度。
//
HWREG (Forced_update_port + GPIO_DR2R)|= 1 << Forced_update_PIN;
//
//启用弱上拉。
//
HWREG (Forced_update_port + GPIO_PUR)|= 1 << Forced_update_PIN;
//
//确保该引脚的模拟模式选择寄存器是清零的。
//
HWREG (Forced_update_port + GPIO_AMSEL)&=~(1 << Forced_update_pin);
#endif
#ifdef Forced_update_wpd
//
//设置输出驱动强度。
//
HWREG (Forced_update_port + GPIO_DR2R)|= 1 << Forced_update_PIN;
//
//启用弱下拉。
//
HWREG (Forced_update_port + GPIO_PDR)|= 1 << Forced_update_PIN;
//
//确保该引脚的模拟模式选择寄存器是清零的。
//该寄存器只出现在 DustDevil 类(及更高版本)设备中,但是
//是对 Sandstorm 和 Fury 级设备的无害写入。
//
HWREG (Forced_update_port + GPIO_AMSEL)&=~(1 << Forced_update_PIN);
#endif
#ifdef Forced_update_key
//
//解锁 GPIO 访问。
//
HWREG (Forced_update_port + GPIO_lock)= Forced_update_key;
HWREG (Forced_update_port + GPIO_CR)= 0;
#endif
//
//在读取引脚之前等待一段时间。
//
延迟(1000);
//
//检查引脚以查看是否正在请求更新。
//
if (HWREG (Forced_update_port +(1 <<(Forced_update_PIN + 2)))=
(Forced_update_polarity << Forced_update_PIN)
{
//
//请记住这是强制更新。
//
G_ui32 Forced = 1;
返回(1);
}
//
//未请求更新,因此返回0。
//
退货(0);
}
//*********
//
//! 检查是否需要或正在请求更新。
//!
//! 此函数检测是否请求更新或是否没有
//! 当前位于微控制器上的有效代码。 这用于告诉
//! 是否进入更新模式。
//!
//! 如果需要更新或正在
进行//、\返回返回非零值! 而不是0。
////
*****************
uint32_t
CheckForceUpdate (void)
{
uint32_t * pui32App;
//
//查看第一个位置是0xffffffffff 还是不是这样的位置
//看起来像堆栈指针,或者第二个位置是0xffffffff 或
//看起来不像复位矢量的内容。
//
pui32App =(uint32_t *) app_start_address;
if ((pui32App[0]= 0xffffffff)||
((pui32App[0]& 0xFF00000)!= 0x20000000)||
(pui32App[1]=0xffffffff)||
((pui32App[1]和0xfff00001)!= 0x00000001))
{
返回(1);
}
//
//如果配置了简单的 GPIO 检查,则确定是否强制执行
//更新。
//
return (CheckGPIOForceUpdate());
}
//*********
//
//! 配置微控制器。
//!
//! 此函数用于配置微控制器的外设和 GPIO、
//! 准备供引导加载程序使用。 已经//
!的接口 因为更新端口将被配置、自动波特率将为
//! 必要时执行。
//!
//! \无返回。
////
*****************
void
ConfigureDevice (void)
{
//
//由于指定了晶振频率,因此启用主振荡器
//并从它为处理器计时。
//
// HWREG (SYSCTL_RCC)&&~(SYSCTL_RCC_MOSCDIS);
//延迟(524288);
// HWREG (SYSCTL_RCC)=((HWREG (SYSCTL_RCC)&~(SYSCTL_RCC_OSCSRC_M)))|
// SYSCTL_RCC_OSCSRC_MAIN);
//ROM_SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_INT | SYSCTL_MAIN_OSC_DIS);//为 ROM_SysCtlDelay 启用
int nStatus;
HWREG (SYSCTL_RCGCGPIO)&=~Forced_update_Periph;
ROM_SysCtlClockSet (SYSCTL_USE_OSC | SYSCTL_OSC_INT);
nStatus = ROM_SysCtlClockGet ();
//
//为100Hz 中断配置 SysTick。 FatFs 驱动程序需要10ms
//勾选。
//
ROM_SysTickPeriodSet (ROM_SysCtlClockGet ()/ 100);
ROM_SysTickEnable();
ROM_SysTickIntEnable();
ROM_IntMasterEnable();
}//
*********
//
//! 此函数对所选端口执行更新。
//!
//! 此函数由引导加载程序直接调用或作为
//! 应用程序更新请求的结果。
//!
//! 返回但不返回。
////
*****************
void
Updater (void)
{
FATFSFatFs;
FILFileObject;
FRESULTfResult;
uint32_t addr、count、 data、temp;
fResult = f_mount (0、&fatf);
//fResult = pf_mount (&fatf);
if (fResult = FR_OK)
{
fResult = f_open (&FileObject、"boot2.bin"、FA_read);
//fResult = pf_open ("boot2.bin");
//temp = 0;
//do
//
fResult = pf_open ("boot2.bin");//
fresult
=
/+
!/fresult = temp =/f_start_addr (针对文件启动);/fif_file=/f <+!/fr =/f 文件启动);/fr =/f 文件启动!(针对文件启动) ADDR += FLASH_PAGE_SIZE)
//for (addr = app_start_address;addr < app_start_address + fatfs.fsize;addr += flash_page_size)
{
//
擦除此块。
//
rom_FlashErase (addr);
}
for (addr = app_start_address;addr < app_start_address + FileObject.fsize;addr += 4)
// for (addr = app_start_address;addr < app_start_address + fatdr.fsize;adfs += 4)
{
//
//////将
数据写入到闪存中(4个字节
)、写入数据(4)、写入数据(4)、写入数据(4)、写入数据(4个字节)、数据(4)、写入数据(4个数据)、数据(4个数据) 4、&count);
ROM_FlashProgram (&data、addr、4);
}
}
//
HWREG (NVIC_APINT)=(NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ);
while (1);
}
//*********
//
//这是该 SysTick 中断的处理程序。 FatFs 需要一个计时器节拍
//每10ms 用于内部计时。
////
*****************
void
SysTickHandler (void)
{
//
//调用 FatFs tick 计时器。
//
Disk_timerproC();
}
void SVC_Handler (void)
{
ConfigureDevice();
Updater ();
while (1);
}
int
main (void)
{
uint32_t t = 213;
t = ROM_SysCtlClockGet ();
if (CheckForceUpdate())
{
ConfigureDevice();
Updater ();
}
else
{
ROM_SysTickIntDisable();
ROM_SysTickDisable();
HWREG (NVIC_DIS0)= 0xffffffff;
HWREG (NVIC_DIS1)= 0xffffffff;
(*(void (*)(void))(*(uint32_t *)(app_start_address+4))))();
}
while (1);
}
//*********
//
//关闭 Doxygen 组。
//! @}
//
//*********