This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C1294NCPDT:SD 卡的引导加载程序不会跳转到应用程序文件。

Guru**** 2611705 points
Other Parts Discussed in Thread: EK-TM4C1294XL

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1110956/tm4c1294ncpdt-bootloader-for-sd-card-not-jumping-to-application-file

器件型号:TM4C1294NCPDT
Thread 中讨论的其他器件:EK-TM4C1294XL

您好!

我为 SD 卡引导加载程序自定义了引导加载程序代码。一切正常、但此代码无法跳转并执行应用程序文件。请检查是否缺少任何内容。

连接引导加载程序 codee2e.ti.com/.../X24015_5F00_boot_5F00_loader_5F00_sd.rar

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是我用于 BL_main.c 的引导加载程序代码

    //
    //
    // bl_main.c -文件保存引导加载程序的主控制循环。
    //
    //版权所有(c) 2006-2020 Texas Instruments Incorporated。 保留所有权利。
    //软件许可协议
    //
    //德州仪器(TI)仅提供和使用此软件
    //专门用于 TI 的微控制器产品。 该软件归其所有
    // TI 和/或其供应商、受适用版权保护
    //法律。 您不能将此软件与"病毒"开源软件结合使用
    //软件,以便形成一个更大的程序。
    //
    //此软件按“原样”提供,且存在所有故障。
    //不作任何明示、暗示或法定的保证,包括但
    //不限于对适销性和适用性的暗示保证
    //此软件的特定用途。 TI 不得在任何情况下使用
    //情况,对特殊、偶然或从属事件负责
    //任何原因造成的损害。
    //
    //这是 Tiva 固件开发包2.2.0.295修订版的一部分。
    //
    //

    #include
    #include
    #include
    #include "inc/hw_gpio.h"
    #include "inc/hw_flash.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_NVIC.h"
    #include "inc/hw_ssI.h"
    #include "inc/hw_sysctl.h"
    #include "inc/hw_types.h"
    #include "bl_config.h"
    #include "bootloader/bl_flash.h"
    #include "bootloader/bl_hooks.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/ssi.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "Petit/pff.h"
    #include "Petit/pffconf.h"
    #include "custom.h"

    //
    //指定一次从文件读取多少个字节来写入闪存
    //如果增大 RAM 大小,则会缩短程序加载时间
    //否则减小 RAM 大小会增加程序加载时间
    //

    #define WRITE_DATA_PACKET_SIZE 128//128 -默认值

    静态字节 bWriteBuffer[WRITE_DATA_PACKE_SIZE];
    静态 FATFS 死亡;

    //函数原型

    void ConfigureSSIPort (uint32_t ui32协议、uint32_t ui32模式、
    uint32_t ui32BitRate、uint32_t ui32DataWidth);

    //
    //
    //确保应用程序起始地址位于闪存页边界上
    //
    //
    #if (APP_START_ADDRESS &(FLASH_PAGE_SIZE - 1))
    错误错误:APP_START_ADDRESS 必须是 FLASH_PAGE_SIZE 字节的倍数!
    #endif

    //
    //
    //确保闪存保留空间是闪存页的倍数。
    //
    //
    #if (FLASH_RSVD_SPACE 和(FLASH_PAGE_SIZE - 1))
    错误错误:FLASH_RSVD_SPACE 必须是 FLASH_PAGE_SIZE 字节的倍数!
    #endif

    //
    //
    //! \addtogroup bl_main_API
    //! @{
    //
    //

    //
    //
    //用于调用的函数的原型(在启动代码中)
    //应用。
    //
    //
    extern void CallApplication (uint32_t ui32Base);

    //
    //
    //可预测长度的函数原型(在启动代码中)
    //延迟。
    //
    //
    extern void delay (uint32_t ui32Count);

    //
    //
    //将一个字从大端字节序转换为小端字节序。 这个宏使用编译器-
    //执行"rev"指令内联插入的特定结构,
    //它直接执行字节交换。
    //
    //
    #IF 定义(ewarm)
    #include
    #define SwapWord (x)_REV (x)
    #endif
    #if defined (CodeRed)|| Defined (gcc)|| Defined (sourceygxx)
    #define SwapWord (x)__extension__\
    ({\
    寄存器 uint32_t __ret、__INP = x;\
    __asm__("rev %0,%1":"=r"(__ret):"r"(__INP));\
    __转台;\
    })
    #endif
    #if defined (rvmdk)|| defined (__ARMCC_VERSION)
    #define SwapWord (x)_rev (x)
    #endif
    #if defined (CCS)(如果已定义)
    uint32_t
    SwapWord (uint32_t x)

    _asm (" rev r0、r0\n"
    " BX lr\n");//需要此操作以确保返回 r0
    return (x + 1);// return 使编译器满意-忽略

    #endif

    //
    //
    //! 配置微控制器。
    //!
    //! 此函数用于配置微控制器的外设和 GPIO、
    //! 准备供引导加载程序使用。 接口
    //! 因为更新端口将被配置、并且将自动波特
    //! 必要时执行。
    //!
    //! \无返回。
    //
    //

    空配置设备(空)

    #ifdef crystal_FREQ
    //
    //由于指定了晶振频率,因此启用主振荡器
    //并从它为处理器计时。
    //
    #if defined (target_IS_TM4C129_RA0)||\
    已定义(TARGET_IS_TM4C129_RA1)||\
    已定义(TARGET_IS_TM4C129_RA2)
    //
    //由于指定了晶振频率,因此启用主振荡器
    //并从它为处理器计时。 检查振荡器范围
    //必须设置,等待状态需要更新
    //
    if (crystal_FREQ >= 10000000)

    HWREG (SYSCTL_MOSCCTL)|=(SYSCTL_MOSCCTL_OSCRNG);
    HWREG (SYSCTL_MOSCCTL)&=~(SYSCTL_MOSCCTL_PWRDN |
    SYSCTL_MOSCCTL_NOXTAL);

    其他

    HWREG (SYSCTL_MOSCCTL)&=~(SYSCTL_MOSCCTL_PWRDN |
    SYSCTL_MOSCCTL_NOXTAL);

    //
    //等待振荡器稳定
    //
    延迟(524288);

    if (crystal_FREQ > 16000000)

    HWREG (SYSCTL_MEMTIME0)=(SYSCTL_MEMTIME0_FBCHT_1_5 |
    (1 << SYSCTL_MEMTIME0_FWS_S)|
    SYSCTL_MEMTIME0_EBCHT_1_5 |
    (1 << SYSCTL_MEMTIME0_EWS_S)|
    SYSCTL_MEMTIME0_MB1);
    HWREG (SYSCTL_RSCLKCFG)=(SYSCTL_RSCLKCFG_MEMTIMEU |
    SYSCTL_RSCLKCFG_OSCSRC_MOSC);

    其他

    HWREG (SYSCTL_RSCLKCFG)=(SYSCTL_RSCLKCFG_OSCSRC_MOSC);

    其他
    HWREG (SYSCTL_RCC)&=~(SYSCTL_RCC_MOSCDIS);
    延迟(524288);
    HWREG (SYSCTL_RCC)=((HWREG (SYSCTL_RCC)&~(SYSCTL_RCC_OSCSRC_M)))|
    SYSCTL_RCC_OSCSRC_MAIN);
    #endif
    #endif

    //
    //
    //! 在 SPI 模式中为 SD 接口配置 SSI 端口 SPI。
    //
    //

    空配置 SSI (空)

    /*启用 SD SSI 外设*/

    ROM_SysCtlPeripheralEnable (SD_SYSCTL_Periph_SSI);
    ROM_SysCtlPeripheralEnable (SD_SYSCTL_Periph_GPIO_SCLK);
    ROM_SysCtlPeripheralEnable (SD_SYSCTL_Periph_GPIO_MOSI);
    ROM_SysCtlPeripheralEnable (SD_SYSCTL_Periph_GPIO_MISO);
    ROM_SysCtlPeripheralEnable (SD_SYSCTL_Periph_GPIO_FSS);

    /* SSI-1配置引脚*/

    SSI SSI1CLK 的//使能引脚
    ROM_GPIOPinConfigure (SD_GPIO_SCLK_PINCFG);
    ROM_GPIOPinTypeSSI (SD_GPIO_SCLK_base、SD_GPIO_SCLK_PIN);

    SSI SSI1XDAT0 (MOSI)的//使能引脚
    ROM_GPIOPinConfigure (SD_GPIO_MOSI_PINCFG);
    ROM_GPIOPinTypeSSI (SD_GPIO_MOSI_BASE、SD_GPIO_MOSI_PIN);

    SSI SSI1XDAT1的//使能引脚(MISO)
    ROM_GPIOPinConfigure (SD_GPIO_MISO/PINCFG);
    ROM_GPIOPinTypeSSI (SD_GPIO_MISO、SD_GPIO_MISO);

    //为 SSI1 SSI1FSS 启用引脚 PB4
    //GPIOPinConfigure (SD_GPIO_FFS_PINCFG);
    //GPIOPinTypeSSI (SD_GPIO_FSS_BASE、SD_GPIO_FSS_PIN);
    // GPIOOutput 的使能引脚 PK7 (SSI1FSS_SD)
    ROM_GPIOPinTypeGPIOOutput (SD_GPIO_FFS_BASE、SD_GPIO_FFS_PIN);

    /*配置焊盘设置*/

    /* SCLK (PD3)*/
    MAP_GPIOPadConfigSet (SD_GPIO_SCLK_base、
    SD_GPIO_SCLK_PIN、
    GPIO_Strength _4mA、GPIO_PIN_TYPE_STD);
    /* MOSI (PD1)*/
    MAP_GPIOPadConfigSet (SD_GPIO_MOSI_BASE、
    SD_GPIO_MOSI_PIN、
    GPIO_Strength _4mA、GPIO_PIN_TYPE_STD);
    /* MISO (PD0)*/
    MAP_GPIOPadConfigSet (SD_GPIO_MISO/base、
    SD_GPIO_MISO、
    GPIO_Strength _4mA、GPIO_PIN_TYPE_STD_WPU);
    /* CS (PD2)*/
    MAP_GPIOPadConfigSet (SD_GPIO_FFS_BASE、
    SD_GPIO_FFS_PIN、
    GPIO_Strength _4mA、GPIO_PIN_TYPE_STD);

    //
    //为 SPI 主控模式配置和启用 SSI 端口。 使用 SSI1、
    //系统时钟电源,空闲时钟低电平和低电平有效时钟输入
    //飞思卡尔 SPI 模式、主控模式、1MHz SSI 频率和8位数据。
    //对于 SPI 模式,可以设置 SSI 时钟的极性
    //单元空闲。 您还可以配置所需的时钟边沿
    //在上捕获数据。 有关的更多信息、请参阅数据表
    //不同的 SPI 模式。
    //

    uint32_t sysclock = 120000000;

    ROM_SSIConfigSetExpClk (SD_SSI_base、sysclock、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、400000、 8);

    //
    //启用 SSI1模块。
    //
    ROM_SSIEnable (SD_SSI_base);

    //
    //
    //! 此函数对所选端口执行更新。
    //!
    //! 此函数由引导加载程序直接调用或作为调用
    //! 应用程序更新请求的结果。
    //!
    //! 返回但不返回。
    //
    //

    空更新程序(空)

    /*
    uint32_t EraseSize=0;
    uint32_t AppAddress=0;
    uint32_t i、j、k、l;
    uint32_t WriteDataPacketCount;
    uint32_t WriteDataPacketRemainder;
    FRESULT RC;
    通用 br
    *


    uint32_t EraseSize=0;
    uint32_t AppAddress=0;
    uint32_t i、j;
    uint32_t WriteDataPacketCount、WriteDataPacketRemainder;

    FRESULT RC;
    FATFS 死亡;
    通用 br

    //初始化控制台消息的 UART
    ConfigureUART();

    //初始化 SSI 控制器
    ConfigureSSI();

    // LED GPIO 引脚设置
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPION);
    ROM_GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_1);

    // LED 闪烁
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、GPIO_PIN_1);
    for (i=0;i<100000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、!GPIO_PIN_1);
    for (i=0;i<100000;i++);

    //尝试安装 SD 卡10次。 每次尝试时闪烁 LED。
    J=0;
    执行{
    RC = pf_mount (&fatfs);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、GPIO_PIN_1);
    for (i=0;i<100000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、!GPIO_PIN_1);
    for (i=0;i<100000;i++);
    J++;

    while (rc && j<10);

    //如果 SD 卡安装失败,则退出,否则继续
    if (!rc){

    //尝试打开 SD 卡中的 app.bin 文件(如果存在) 10次。 每次尝试时闪烁 LED。
    J=0;
    执行{
    RC = pf_open ("X24015.bin");
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、GPIO_PIN_1);
    for (i=0;i<100000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、!GPIO_PIN_1);
    for (i=0;i<100000;i++);
    J++;

    while (rc && j<10);

    //如果 app.bin 文件失败,则打开 exit,否则继续
    if (!rc)

    UARTprintf ("fatfs.fsize %d \n"、fatfs.fsize);
    //如果文件大小不是4个 exit 的倍数,则继续
    if ((fatfs.fsize & 0x03)==0)

    //计算将根据 app.bin 文件大小擦除的页数
    EraseSize = fatfs.fsize/flash_page_size;
    if (fatfs.fsize%flash_page_size)
    EraseSize++;

    //擦除必要的页
    AppAddress=APP_START_ADDRESS;
    for (i=0;i< EraseSize;i++)

    ROM_FlashErase (AppAddress);
    AppAddress += FLASH_PAGE_SIZE;

    AppAddress=APP_START_ADDRESS;//设置要写入的应用地址
    //根据用户定义的写入数据包大小计算数据包计数
    WriteDataPacketCount=fatfs.fsize/write_data_packet_size;
    UARTprintf ("WriteDataPacketCount %d \n"、WriteDataPacketCount);
    //计算除法的余数
    WriteDataPacketRemainder=fatfs.fsize=write_data_packet_size;
    UARTprintf ("WriteDataPacketRemainder %d \n"、WriteDataPacketRemainder);
    //从 app.bin 文件和中读取 write_data_packet_size 个字节的数量
    //将其写入闪存存储器的 WriteDataPacketCount 次。
    for (i=0;i<WriteDataPacketCount;i++){
    PF_Read (bWriteBuffer、WRITE_DATA_PACKE_SIZE、&);
    ROM_FlashProgram (((uint32_t*) bWriteBuffer、AppAddress、write_data_packet_size);
    AppAddress += write_data_packet_size;
    UARTPutch ('.');

    //从 app.bin 文件和中读取4个字节
    //将其写入快闪存储器的 WriteDataPacketRemainder 次数。
    for (i=0;i<WriteDataPacketRemaineder/4;i++)

    PF_Read (bWriteBuffer、4、& br);
    ROM_FlashProgram (((uint32_t*) bWriteBuffer、AppAddress、4);
    AppAddress += 4;

    //如果完成,则以较长的延迟使 LED 闪烁2次。
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、GPIO_PIN_1);
    for (i=0;i<1000000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、!GPIO_PIN_1);
    for (i=0;i<1000000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、GPIO_PIN_1);
    for (i=0;i<1000000;i++);
    ROM_GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、!GPIO_PIN_1);
    for (i=0;i<1000000;i++);
    UARTprintf ("Done1\n");
    //复位和禁用引导加载程序使用的 SSI 外设。
    ROM_SysCtlPeripheralDisable (SD_SYSCTL_Periph_SSI);
    ROM_SysCtlPeripheralReset (SD_SYSCTL_Periph_SSI);

    ROM_SysCtlPeripheralDisable (SD_SYSCTL_Periph_GPIO_SCLK);
    ROM_SysCtlPeripheralReset (SD_SYSCTL_Periph_GPIO_SCLK);

    ROM_SysCtlPeripheralDisable (SD_SYSCTL_Periph_GPIO_MOSI);
    ROM_SysCtlPeripheralReset (SD_SYSCTL_Periph_GPIO_MOSI);

    ROM_SysCtlPeripheralDisable (SD_SYSCTL_Periph_GPIO_MISO);
    ROM_SysCtlPeripheralReset (SD_SYSCTL_Periph_GPIO_MISO);

    ROM_SysCtlPeripheralDisable (SD_SYSCTL_Periph_GPIO_FSS);
    ROM_SysCtlPeripheralReset (SD_SYSCTL_Periph_GPIO_FSS);
    for (i=0;i<1000000;i++);

    UARTprintf ("Done2\n");
    for (i=0;i<1000000;i++);
    ((int (*)(void)) app_start_address)();
    HWREG (NVIC_APINT)=(NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ);
    while (1);




    // for (i=0;i<1000000;i++);
    // UARTprintf ("Done11\n");
    // for (i=0;i<1000000;i++);
    //重置
    ((int (*)(void)) app_start_address)();
    HWREG (NVIC_APINT)=(NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ);

    //
    //
    //关闭 Doxygen 组。
    //! @}
    //
    //

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是 bl_config.h 文件

    其中起始地址为  #define APP_START_ADDRESS 0x00004000

    //
    //
    // bl_config.h -引导加载程序的可配置参数。
    //
    //版权所有(c) 2010-2017 Texas Instruments Incorporated。 保留所有权利。
    //软件许可协议
    //
    //德州仪器(TI)仅提供和使用此软件
    //专门用于 TI 的微控制器产品。 该软件归其所有
    // TI 和/或其供应商、受适用版权保护
    //法律。 您不能将此软件与"病毒"开源软件结合使用
    //软件,以便形成一个更大的程序。
    //
    //此软件按“原样”提供,且存在所有故障。
    //不作任何明示、暗示或法定的保证,包括但
    //不限于对适销性和适用性的暗示保证
    //此软件的特定用途。 TI 不得在任何情况下使用
    //情况,对特殊、偶然或从属事件负责
    //任何原因造成的损害。
    //
    //这是 Tiva 固件开发包的修订版2.1.4.178的一部分。
    //
    //

    #ifndef __BL_CONFIG_H__
    #define __BL_CONFIG_H__

    #include "custom.h"

    //
    //
    //以下定义用于配置引导操作
    //加载程序。 对于每个定义、都描述了它与其他定义的交互。
    //第一个是依赖项(即如果它也必须定义的定义)
    //已定义),接下来是排除(即无法定义的定义)
    //如果定义了它),最后是要求(即
    //定义如果定义了它,则必须定义)。
    //
    //引导加载程序必须定义以下定义
    //操作:
    //
    //其中一个 CAN_ENABLE_UPDATE、ENET_ENABLE_UPDATE、I2C_ENABLE_UPDATE、
    // SSI_ENABLE_UPDATE、UART_ENABLE_UPDATE 或 USB_ENABLE_UPDATE
    // app_start_address
    // stack_size
    // buffer_size
    //
    //

    //
    //
    //用于为微控制器计时的晶体的频率。
    //
    //这定义了运行的微控制器所使用的晶振频率
    //引导加载程序。 如果在生产时这是未知的、则使用
    // UART_autobaud 功能以正确配置 UART。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define CRYSTICL_FREQ 25000000

    //
    //
    //这可以将 LDO 电压升压到2.75V。 引导加载程序
    //启用 PLL 的配置(例如、使用以太网端口)
    //对于具有 PLL 勘误表的器件,应启用此功能。 这适用于
    // Fury 级器件的修订版 A2。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    //#define BOOST_LDO_VOLTAGE

    //
    //
    //应用程序的起始地址。 这必须是1024的倍数
    //字节(使其与页边界对齐)。 矢量表的预期值为
    //此位置,以及向量表(位于的栈)的感知有效性
    //在 SRAM 中、位于闪存中的复位矢量)用作的指示
    //应用程序映像的有效性。
    //
    //引导加载程序的闪存映像不得大于此值。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define APP_START_ADDRESS 0x00004000

    //
    //
    //应用程序查找其异常矢量表的地址。
    //这必须是1KB 的倍数(使其与页边界对齐)。
    //通常,应用程序将从其矢量表和该值开始
    //将默认为 APP_START_ADDRESS。 提供此选项以满足需求
    //从无法访问的外部存储器运行的应用程序
    // NVIC (矢量表偏移寄存器的长度只有30位)。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define VTABLE vstart_address 0x00004000

    //
    //
    //闪存中单个可擦除页的大小。 这必须是电源
    //共2个。 默认值1KB 表示内部的页面大小
    //所有 Tiva MCU 上的闪存和该值只应在以下情况下被覆盖
    //配置引导加载程序以访问页大小的外部闪存设备
    //与此不同。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define FLASH_PAGE_SIZE 0x00004000

    //
    //
    //闪存末尾要保留的空间量。 这必须是 A
    // 1024字节的倍数(使其与页边界对齐)。 这种情况
    //更新应用程序时不会擦除保留空间,提供
    //可用于参数的非易失性存储。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    //#define FLASH_RSVD_SPACE 0x00000800

    //
    //
    //为引导加载程序保留的堆栈空间字数。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define STACK_SIZE 1024

    //
    //
    //数据缓冲区中用于接收数据包的字数。 这种情况
    //值必须至少为3。 如果在 UART 上使用自动辅助、则必须位于
    //至少20个。 最大可用值为65 (较大的值将导致
    //缓冲区中未使用的空间)。
    //
    //取决于:无
    //不包括:无
    //要求:无
    //
    //
    #define buffer_size 20

    //
    //
    //启用基于引脚的强制更新检查。 启用后、引导加载程序
    //将进入更新模式,而不是在读取引脚时调用应用程序
    //在特定极性强制执行更新操作。 在这两种情况下、都是
    //应用程序仍然能够将控制权返回给引导加载程序以
    //开始更新。
    //
    //取决于:无
    //不包括:无
    //需要:forced_update_Periph、forced_update_port、forced_update_pin、
    //强制_更新_极性
    //
    //
    #define ENABLE_UPDATE_CHECK

    //
    //
    //启用 GPIO 模块以检查强制更新。 这将会
    //是 SYSCTL_RCGCGPIO_Rx 值之一、其中 Rx 代表所需值
    // GPIO 端口。 这适用于 Blizzard 类以及用于 forced_update_port 的更高版本器件。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    #define Forced_update_Periph sysctl_RCGCGPIO_R5 /*端口 F */

    //
    //
    // GPIO 端口以检查强制更新。 这将是其中之一
    // GPIO_Portx_BASE 值、其中"x"替换为端口名称(例如
    // B)。 "x"的值应与"x"的值匹配
    // Forced_update_Periph。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    #define FORUD_UPDATE_PORT GPIO_PORTF_BASE

    //
    //
    //检查强制更新的引脚。 这是一个介于0和7之间的值。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    #define Forced_update_PIN 4 //连接到引导开关的 PF4

    //
    //
    //导致强制更新的 GPIO 引脚的极性。 该值
    如果引脚应为低电平、//应为0;如果引脚应为高电平、则应为1。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    #define Forced_update_polarity 0 // PF0 = 0触发引导加载程序更新

    //
    //
    //这为强制更新中使用的 GPIO 引脚启用弱上拉。 这种情况
    如果引脚应该具有内部弱下拉电阻、//值应该为0
    // 1如果引脚应该具有内部弱上拉电阻。
    //只应定义 Forced_update_WPU 或 Forced_update_wpd,或两者都不应定义。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    //#define Forced_update_WPU
    //#define forced_update_wpd

    //
    //
    //这可以使用 GPIO_LOCK 机制进行配置
    //受保护的 GPIO 引脚(例如 JTAG 引脚)。 如果未定义此值、
    //不使用锁定机制。 唯一的合法值
    //功能包括 Fury 器件的 GPIO_LOCK_KEY 和全部的 GPIO_LOCK_KEY_DD
    //除 Sandstorm 设备以外的其它设备,它们不支持此功能。
    //
    //取决于:enable_update_check
    //不包括:无
    //库:无
    //
    //
    //#define Forced_update_key GPIO_lock_key
    //#define Forced_update_key GPIO_lock_key_DD

    //
    //
    //引导加载程序挂钩函数。
    //
    //以下定义允许您添加特定于应用程序的函数
    //在引导加载程序执行期间的不同点调用。
    //
    //

    //
    //
    //在系统上执行应用特定的低级硬件初始化
    //复位。
    //
    //如果挂钩,则在引导加载程序之后立即调用此函数
    //代码重定位完成。 应用程序可以执行任何所需的低电平
    //在该函数期间进行硬件初始化。 请注意系统时钟
    调用此函数时、//尚未设置。 进行初始化
    //可以在 BL_INIT_FN_Hook 函数中执行系统时钟设置
    //而是。
    //
    // void MyHwInitFunc (void);
    //
    //
    //#define BL_HW_INIT_FN_Hook MyHwInitFunc

    //
    //
    //在系统复位时执行应用特定的初始化。
    //
    //如果挂钩,则在引导加载程序之后立即调用此函数
    //设置系统时钟。 应用程序可以执行任何附加操作
    //在此函数期间进行初始化。
    //
    // void MyInitFunc (void);
    //
    //
    #define BL_INIT_FN_Hook MyInitFunc

    //
    //
    //通过 SVC 在引导加载程序进入时执行应用特定的重新初始化。
    //
    //如果挂钩,则在引导加载程序之后立即调用此函数
    //从应用程序输入时,重新初始化系统时钟
    //通过 SVC 机制而不是系统复位的结果。 一个
    //应用程序可以在此函数中执行任何其他重新初始化。
    //
    // void MyReinitFunc (void);
    //
    //
    //#define BL_reinit_fn_hook MyReinitFunc

    //
    //
    //通知应用程序正在开始下载。
    //
    //如果已连接,则在下载新固件时将调用此函数
    //即将开始。 应用程序可以使用该信号来初始化任何信号
    //进度显示。
    //
    //空 MyStartFunc (空);
    //
    //
    #define BL_START_FN_Hook MyStartFunc

    //
    //
    //通知应用程序 SD 驱动器安装状态
    //
    //如果已连接,则在加载程序安装 SD 驱动器时调用此函数。
    //
    //空 MyMountFunc (uint32_t 错误);
    //
    //
    #define BL_MOUN_FN_Hook MyMountFunc

    //
    //
    //通知应用程序 SD 驱动器映像文件打开状态。
    //
    //如果挂钩,则在加载程序打开 SD 驱动器时调用此函数。
    //
    // void MyOpenFunc (uint32_t 错误);
    //
    //
    #define BL_open_fn_hook MyOpenFunc

    //
    //
    //通知应用程序闪存进程已开始。
    //
    //如果已连接,则在加载程序启动固件时调用此函数
    //闪存过程。
    //
    // void MyBeginFunc (uint32_t 错误);
    //
    //
    #define BL_BEGIN_FN_Hook MyBeginFunc

    //
    //
    //通知应用程序闪存进程已完成。
    //
    //如果挂钩,则在加载程序完成固件时调用此函数
    //闪存过程。
    //
    // void MyEndFunc (uint32_t 错误);
    //
    //
    #define BL_END_Hook MyEndFunc

    //
    //
    //通知应用下载进度。
    //
    //如果已连接,则在固件期间将定期调用此函数
    //下载。 应用程序可以使用此更新其用户界面。
    //使用的协议不会将的最终大小通知客户端
    //预先下载(例如 TFTP)、ulTotal 参数将为0、
    //否则,它指示完整下载的预期大小。
    //
    //空 MyProgresFunc (unsigned long ulCompleded、unsigned long ulTotal);
    //
    //其中:
    //
    //-已完成表示已下载的字节数。
    //- ulTotal 表示预期的字节数,如果不知道,则为0。
    //
    //
    #define BL_Progress_fn_hook MyProgressFunc

    //
    //
    //通知应用程序闪存进程正在退出引导加载程序。
    //
    //如果挂钩,则在加载程序完成固件时调用此函数
    //闪存过程。
    //
    // void MyExitFunc (uint32_t 错误);
    //
    //
    #define BL_EXIT_FN_Hook MyExitFunc

    //
    //
    //定义要在 SD 驱动器上查找的应用程序 bin 映像文件名。
    //引导加载程序将尝试装入并打开此文件十次。 如果
    //成功,它会将文件的内容刷写到程序中
    //内存空间。
    //
    //
    #define BL_IMAGE_FILENAME "X24015.bin"

    //
    //
    // X24015 SD 卡插槽 SPI 引脚分配
    //
    //.baseAddr = SSI1_base、// SPI 基址*/
    //.portSCK = GPIO_PORTB_BASE、// SPI SCK 端口*/
    //.pinSCK = GPIO_PIN_5、// SCK 引脚(PB5)*/
    //.portMISO = GPIO_Porte _BASE、// SPI MISO 端口*/
    //.pinMISO = GPIO_PIN_5、// MISO 引脚(PE5)*/
    //.portMOSI = GPIO_Porte _BASE、// SPI MOSI 端口*/
    //.pinMOSI = GPIO_PIN_4、// MOSI 引脚(PE4)*/
    //.portCS = GPIO_PORTK_base、// GPIO CS 端口*/
    //.pinCS = GPIO_PIN_7 // CS PIN (PK7)*/
    //
    //

    // SD 驱动器使用的外设
    #define SD_SYSCTL_PERIPH_SSI SYSCTL_PERIPH_SSI2
    #define SD_SYSCTL_Periph_GPIO_SCLK SYSCTL_Periph_GPIOD // PD3 -- CLK
    #define SD_SYSCTL_PERIPH_GPIO_MOSI SYSCTL_PERIPH_GPIOD // PD1 -- DAT0
    #define SD_SYSCTL_PERIPH_GPIO_MISO SYSCTL_PERIPH_GPIOD // PD0 -- DAT1
    #define sd_sysctl_Periph_GPIO_FSS SYSCTL_Periph_GPIOD // PD2 -- FSS

    针对 SD SSI 的/*基本端口*/
    #define SD_SSI_base SSI2_base

    /* SD 驱动器 SCLK 端口/引脚定义*/
    #define SD_GPIO_SCLK_base GPIO_PORTD_base
    #define SD_GPIO_SCLK_PINCFG GPIO_PD3_SSI2CLK
    #define SD_GPIO_SCLK_PIN GPIO_PIN_3

    /* SD 驱动器 MOSI 端口/引脚定义*/
    #define SD_GPIO_MOSI_BASE GPIO_PORTD_BASE
    #define SD_GPIO_MOSI_PINCFG GPIO_PD1_SSI2XDAT0
    #define SD_GPIO_MOSI_PIN GPIO_PIN_1

    /* SD Drive MISO 端口/引脚定义*/
    #define SD_GPIO_Miso_base GPIO_PORTD_base
    #define SD_GPIO_MISO/PINCFG GPIO_PD0_SSI2XDAT1
    #define SD_GPIO_MISO GPIO_PIN_0

    /* SD 驱动器 FSS 端口/引脚定义*/
    #define SD_GPIO_FFS_BASE GPIO_PORTD_BASE
    #define SD_GPIO_FFS_PIN GPIO_PIN_2

    //
    // UART 可用于调试输出消息支持
    //

    //
    //
    //选择 UART 使用的波特率。
    //
    //取决于:UART_ENABLE_UPDATE、CRYSTRAL_FREQ
    //不包括:UART_autobaud
    //要求:无
    //
    //
    #define UART_FIXED_BAUDRATE 115200

    //
    //
    //选择 UART 外设模块的时钟启用
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UARTx_BASE
    //
    //
    #define UART_CLOCK_ENABLE SYSCTL_RCGCUART_R0

    //
    //
    //选择 UART 外设模块的基地址
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_CLOCK_ENABLE
    //
    //
    #define UARTx_BASE UART0_BASE

    //
    //
    //为对应于 UART RX 引脚的 GPIO 选择时钟启用
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_RXPIN_BASE、UART_RXPIN_PCTL 和 UART_RXPIN_POS
    //
    //
    #define UART_RXPIN_CLOCK_ENABLE SYSCTL_RCGCGPIO_R0

    //
    //
    //为对应于 UART RX 引脚的 GPIO 选择基地址
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_RXPIN_CLOCK_ENABLE、UART_RXPIN_PCTL 和 UART_RXPIN_POS
    //
    //
    #define UART_RXPIN_BASE GPIO_PORta_base

    //
    //
    //为对应于 UART RX 引脚的 GPIO 选择端口控制值
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_RXPIN_CLOCK_ENABLE、UART_RXPIN_BASE 和 UART_RXPIN_POS
    //
    //
    #define UART_RXPIN_PCTL 0x1

    //
    //
    //为对应于 UART RX 引脚的 GPIO 选择引脚编号
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_RXPIN_CLOCK_ENABLE、UART_RXPIN_BASE 和 UART_RXPIN_PCTL
    //
    //
    #define UART_RXPIN_POS 0

    //
    //
    //为对应于 UART TX 引脚的 GPIO 选择时钟启用
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_TXPIN_BASE、UART_TXPIN_PCTL 和 UART_TXPIN_POS
    //
    //
    #define UART_TXPIN_CLOCK_ENABLE SYSCTL_RCGCGPIO_R0

    //
    //
    //为对应于 UART TX 引脚的 GPIO 选择基地址
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_TXPIN_CLOCK_ENABLE、UART_TXPIN_PCTL 和 UART_TXPIN_POS
    //
    //
    #define UART_TXPIN_BASE GPIO_PORta_base

    //
    //
    //为对应于 UART TX 引脚的 GPIO 选择端口控制值
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_TXPIN_CLOCK_ENABLE、UART_TXPIN_BASE 和 UART_TXPIN_POS
    //
    //
    #define UART_TXPIN_PCTL 0x1

    //
    //
    //为与 UART TX 引脚相对应的 GPIO 选择引脚编号
    //
    //取决于:UART_ENABLE_UPDATE
    //不包括:无
    //需要:UART_TXPIN_CLOCK_ENABLE、UART_TXPIN_BASE 和 UART_TXPIN_PCTL
    //
    //
    #define UART_TXPIN_POS 1.

    #endif //__BL_CONFIG_H__

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这是 需要由引导加载程序运行的主应用程序的.cmd 文件。

    /*********
    *
    * enet_weather_ccs.cmd - enet_weather.的 CCS 链接器配置文件。
    *
    *版权所有(c) 2013-2017 Texas Instruments Incorporated。 保留所有权利。
    *软件许可协议
    *
    *德州仪器(TI)提供此软件仅用于和
    *专门用于 TI 的微控制器产品。 该软件归其所有
    * TI 和/或其供应商、受适用版权保护
    *法律。 您不能将此软件与"病毒"开源软件结合使用
    *软件、以便形成更大的程序。
    *
    *此软件按"原样"提供、且存在所有缺陷。
    *不作任何明示、默示或法定的保证、包括但
    *不限于对适销性和适用性的暗示保证
    *此软件有一个特殊用途。 TI 不得在任何情况下使用
    *情况下、应对特殊、偶然或必然的情况负责
    *任何原因造成的损失。
    *
    *这是 EK-TM4C1294XL 固件包版本2.1.4.178的一部分。
    *
    (小部分 /

    --retain=g_pfnVectors

    /*以下命令行选项作为 CCS 项目的一部分进行设置。 *
    /*如果您使用命令行构建,或者出于某种原因想要*/
    /*在此处定义它们,您可以根据需要取消注释并修改这些行。 *
    /*如果您使用 CCS 进行构建、最好进行任何这样的构建*/
    /*对 CCS 项目进行修改并将此文件保留为单独文件。 *
    /**//
    /*--heap_size=0 */
    /*--stack_size=256 */
    /*--library=rtsv7M3_T_le_eabi.lib */

    /*应用程序的起始地址。 通常是中断矢量*/
    /*必须位于应用程序的开头。 *
    #define APP_BASE 0x00004000 // 0x00004000 [用于引导加载程序]//0x00000000 [用于正常]
    #define RAM_base 0x20000000

    /*系统内存映射*/

    存储器

    /*存储在内部闪存中并从内部闪存执行的应用程序*/
    闪存(RX):origin = APP_BASE,length = 0x000FC000 // 0x000FC000[对于引导加载程序]// 0x00100000 [对于正常]
    /*应用程序使用内部 RAM 进行数据*/
    SRAM (rwx):origin = 0x20000000,length = 0x00040000

    /*内存中的段分配*/

    部分

    .intvecs:> app_base
    .text:> FLASH
    .const:> FLASH
    .cinit:>闪存
    .pinit:> FLASH
    init_array:> FLASH

    .vtable:> RAM_base
    .data :> SRAM
    .bss:> SRAM
    .sysmem:> SRAM
    .stack:> SRAM

    //__STACK_TOP =__STACK + 2048;原始
    __STACK_TOP =__STACK + 2048;

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    SD 卡读取和 SD 卡中的数据也正常。

    下面是我从串行端口获取的日志

    fatfs.fsize 185360
    WriteDataPacketCount 1448
    WriteDataPacketRemainder 16.
    ................................................................................................................................ Done1.
    Done2.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     如果您查看引导加载程序启动文件 BL_STARTUP_CCS.s、它将在跳转到应用程序之前检查是否存在强制更新。  CheckForceUpdate 位于文件 BL_CHECK.c 中 它将检查 APP_START_ADDRESS = 0x4000的前两个位置是否全部为0xFFFFFFFF。 它将检查程序映像的 CRC 是否正确。 它将检查引脚是否强制执行引导加载。 如果其中任何一个为 true,则不会跳转到应用程序,而是跳转到更新程序。 因此、您需要检查您的案例中是否存在任何这些条件。



    ;复位处理程序,在处理器启动时调用。


    .thumbfunc ResetISR
    ResetISR:.asmfunc

    ;启用浮点单元。 如果有任何情况、必须在此处执行此操作
    ;;后面的 C 函数使用浮点。 请注意、有些工具链会
    ;;即使没有显式浮点、也可将 FPU 寄存器用于通用工作区
    ;点数据类型正在使用中。

    movw r0、#0xED88
    movt r0、#0xE000
    LDR R1、[r0]
    ORR R1、R1、#0x00F00000
    STR R1、[r0]


    ;初始化处理器。

    BL 处理器初始化


    ;;调用用户提供的低级硬件初始化函数
    ;如果提供。

    .if $defined (BL_HW_INIT_FN_Hook)
    .ref BL_HW_INIT_FN_HOOK
    BL BL_HW_INIT_FN_HOOK
    .endif


    ;查看是否应执行更新。

    .ref CheckForceUpdate
    BL CheckForceUpdate
    CBZ r0、CallApplication


    ;;配置微控制器。

    thumbfunc EnterBootLoader
    EnterBootLoader:
    .if $$defined (ENET_ENABLE_UPDATE)
    .ref 配置环境
    BL 配置 Enet
    .elseif $$defined (CAN_ENABLE_UPDATE)
    .ref 配置 CAN
    BL 配置 CAN
    .elseif $$defined (USB_ENABLE_UPDATE)
    .ref 配置 USB
    BL 配置 USB
    其他
    .ref 配置设备
    BL 配置设备
    .endif


    ;;调用用户提供的初始化函数(如果提供)。

    .if $defined (bl_init_fn_hook)
    .ref bl_init_fn_hook
    BL BL_INIT_FN_HOOK
    .endif


    ;;分支到更新处理程序。

    .if $$defined (ENET_ENABLE_UPDATE)
    .ref UpdateBOOTP
    b 更新 BOOTP
    .elseif $$defined (CAN_ENABLE_UPDATE)
    .ref UpdateerCAN
    b 更新 CAN
    .elseif $$defined (USB_ENABLE_UPDATE)
    .ref UpdateerUSB
    B 更新程序 USB
    其他
    .ref 更新程序
    b 更新程序
    .endif
    endasmfunc

    uint32_t
    CheckForceUpdate(void)
    {
    #ifdef CHECK_CRC
        uint32_t ui32Retcode;
    #endif
    
    #ifdef BL_CHECK_UPDATE_FN_HOOK
        //
        // If the update check function is hooked, call the application to determine
        // how to proceed.
        //
        return(BL_CHECK_UPDATE_FN_HOOK());
    #else
        uint32_t *pui32App;
    
    #ifdef ENABLE_UPDATE_CHECK
        g_ui32Forced = 0;
    #endif
    
        //
        // See if the first location is 0xfffffffff or something that does not
        // look like a stack pointer, or if the second location is 0xffffffff or
        // something that does not look like a reset vector.
        //
        pui32App = (uint32_t *)APP_START_ADDRESS;
        if((pui32App[0] == 0xffffffff) ||
           ((pui32App[0] & 0xfff00000) != 0x20000000) ||
           (pui32App[1] == 0xffffffff) ||
           ((pui32App[1] & 0xfff00001) != 0x00000001))
        {
            return(1);
        }
    
        //
        // If required, scan the image for an embedded CRC and ensure that it
        // matches the current CRC of the image.
        //
    #ifdef CHECK_CRC
        InitCRC32Table();
        ui32Retcode = CheckImageCRC32(pui32App);
    
        //
        // If ENFORCE_CRC is defined, we only boot the image if the CRC is
        // present in the image information header and the value calculated
        // matches the value in the header.  If ENFORCE_CRC is not defined, we
        // the image if the CRC is good but also if the length field of the header
        // is zero (which typically indicates that the post-build step of running
        // binpack to add the length and CRC to the header was not run).
        //
    #ifdef ENFORCE_CRC
        if(ui32Retcode != CHECK_CRC_OK)
    #else
        if((ui32Retcode != CHECK_CRC_OK) && (ui32Retcode != CHECK_CRC_NO_LENGTH))
    #endif
        {
            //
            // The CRC32 image check failed indicating that the image is
            // corrupt (or doesn't have the CRC embedded correctly).  Either way,
            // fail the update check and force the boot loader to retain control.
            //
            return(2);
        }
    #endif
    
    #ifdef ENABLE_UPDATE_CHECK
        //
        // If simple GPIO checking is configured, determine whether or not to force
        // an update.
        //
        return(CheckGPIOForceUpdate());
    #else
        //
        // GPIO checking is not required so, if we get here, a valid image exists
        // and no update is needed.
        //
        return(0);
    #endif
    #endif
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢 Charles 的指点 out.it 解决了我的问题。感谢您的支持。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Charles,现在我无法从主应用程序跳转到引导加载程序。

    我将使用以下函数。

    空 JumpToBootLoader (空)

    //
    //禁用所有处理器中断。 而不是禁用它们
    //一次一个,直接写入 NVIC 即可禁用所有功能
    //外设中断。
    //
    HWREG (NVIC_DIS0)= 0xffffffff;
    HWREG (NVIC_DIS1)= 0xffffffff;


    //
    //将控制权返回给引导加载程序。 这是对 SVC 的调用
    //引导加载程序中的处理程序。
    //
    (*(void (*)(void))(*(uint32_t *) 0x2C))();

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我甚至尝试了以下操作、但引导加载程序无法从主应用程序进行 RUM、请建议您执行此操作。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_SSI2);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_SSI2);

    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOD);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPIOD);

    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOD);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPIOD);

    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOD);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPIOD);

    ROM_SysCtlPeripheralDisable (SYSCTL_Periph_GPIOD);
    ROM_SysCtlPeripheralReset (SYSCTL_Periph_GPIOD);


    HWREG (NVIC_DIS0)= 0xffffffff;
    HWREG (NVIC_DIS1)= 0xffffffff;
    HWREG (NVIC_DIS2)= 0xffffffff;
    HWREG (NVIC_DIS3)= 0xffffffff;
    HWREG (NVIC_DIS4)= 0xffffffff;

    //也禁用 SysTick 中断。
    ROM_SysTickIntDisable();
    ROM_SysTickDisable();

    (*(void (*)(void))(*(uint32_t *) 0x2C))();

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     不确定发生了什么。 您如何知道它在执行 (*(void (*)(void)(*(void))(*(uint32_t *) 0x2C)))之后没有跳转到引导加载程序?(

     如果您查看 BL_STARTUP_CCS.s、对于 SVC 调用、处理器应该跳转到0x2C。 如您所见,它将跳转到 UpdateHandler 处的向量。  

        .word   0                               ;; Offset 24: Reserved
        .word   0                               ;; Offset 28: Reserved
        .word   UpdateHandler - 0x20000000      ;; Offset 2C: SVCall handler
        .word   IntDefaultHandler               ;; Offset 30: Debug monitor handler

    查看 UpdateHandler,它最终应该再次调用 Updater。   为什么不在反汇编窗口中单步执行 UpdateHandler 并从此处进行调试?
    UpdateHandler: .asmfunc
        ;;
        ;; Initialize the processor.
        ;;
        bl      ProcessorInit
    
        ;;
        ;; Load the stack pointer from the vector table.
        ;;
        movs    r0, #0x0000
        ldr     sp, [r0]
    
        ;;
        ;; Call the user-supplied low level hardware initialization function
        ;; if provided.
        ;;
     .if $$defined(BL_HW_INIT_FN_HOOK)
        bl      BL_HW_INIT_FN_HOOK
     .endif
    
        ;;
        ;; Call the user-supplied re-initialization function if provided.
        ;;
     .if $$defined(BL_REINIT_FN_HOOK)
        .ref    BL_REINIT_FN_HOOK
        bl      BL_REINIT_FN_HOOK
     .endif
    
        ;;
        ;; Branch to the update handler.
        ;;
     .if $$defined(ENET_ENABLE_UPDATE)
        b       UpdateBOOTP
     .elseif $$defined(CAN_ENABLE_UPDATE)
        .ref    AppUpdaterCAN
        b       AppUpdaterCAN
     .elseif $$defined(USB_ENABLE_UPDATE)
        .ref    AppUpdaterUSB
        b       AppUpdaterUSB
     .else
        b       Updater
     .endif
        .endasmfunc