DSP28335 自定义 Bootloader 设计:从原理到 Flash 跳转实践

dsp28335启动流程

Reset→0x3fffc0启动,经过固化在ram里面一次bootloader,根据选择的启动方式跳转。

用的是flash启动
从.cmd文件的begin 0x33FFF6的跳转指令 到codeStartBranch.asm里面的  c_int00再跳动bootloader的main函数,main函数再跳转到0x300000 (APP),app里面,app也要走一边begin→c_int00→main


我的测试流程

1.做写个简单的跳转测试,不用上位机,只通过ccs烧录功能。
先在ccs上烧录一个小灯的程序到flashB区域,(右键工程选择properties,步骤如下图,在烧录时只擦除flashB区域,烧录到哪配置在cmd中)

2.然后再烧录boot程序,主程序只写一个跳转到app的指针地址。

在烧录时配置只擦flash除扇区A。
3.重新上电,程序会运行到bootloader跳转到app,小灯闪烁。

说明一些问题

对于boot和app,在RAM上的分配,
我看网上有一些是直接在cmd里面把ram分配两块不重叠的区域,这样比较浪费空间,比较RAM的特点就是运行快但内存小。其实boot和app在cmd上可以完全重叠,在跳转到app的时候会进行覆盖,但需要注意Boot 跳转前清空中断、重置栈指针等:

·  RAM 里的代码段:通过 MemCopy 手动覆盖初始化。

·  RAM 里的变量段:通过 _c_int00 自动(编译器生成)覆盖初始化。

·  中断向量表:通过 InitPieVectTable() 手动覆盖初始化。



最后粘贴一下代码:
 

#include "DSP2833x_Device.h"

// 声明外部函数
void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr);
void InitSysCtrl(void);

// 引用全局的ramfuncs搬运变量
extern Uint16 RamfuncsLoadStart;
extern Uint16 RamfuncsLoadEnd;
extern Uint16 RamfuncsRunStart;

// APP起始地址(跳转到APP的codestart入口)
#define APP_CODESTART_ADDR 0x300000
#define VECT_ADDR_REG 0x000D08

void main(void) {
    Uint16 idx;

    // 1. 系统初始化:关闭看门狗、配置时钟
    InitSysCtrl();
    EALLOW;
    SysCtrlRegs.WDCR = 0x0068; // 彻底关闭看门狗
    EDIS;

    // 2. RAMfuncs搬运(Boot自己的ramfuncs)
    MemCopy((Uint16*)&RamfuncsLoadStart,
            (Uint16*)&RamfuncsLoadEnd,
            (Uint16*)&RamfuncsRunStart);

    // 3. 重置系统状态
    DINT;                   // 关全局中断
    IER = 0x0000;           // 清CPU中断使能
    IFR = 0x0000;           // 清CPU中断标志
    PieCtrlRegs.PIECTRL.bit.ENPIE = 0; // 禁用PIE
    PieCtrlRegs.PIEACK.all = 0xFFFF;    // 清所有PIE中断响应

    // 清空PIE向量表
    EALLOW;
    // 直接操作PIE向量表的物理地址0x00D00
    Uint32 *pie_vect_ptr = (Uint32 *)0x00D00;
    for(idx = 0; idx < 128; idx++) {
        *pie_vect_ptr++ = 0;
    }
    // 重置向量表到Boot ROM默认位置
    *((Uint32 *)VECT_ADDR_REG) = 0x3FFFC2;
    EDIS;

    // 4. 重置栈指针到RAMM1末尾
    asm(" MOV SP, #0x0007FF");

    // 5. 跳转到APP的codestart入口(0x300000)
    if(*(Uint32*)APP_CODESTART_ADDR != 0xFFFFFFFF) {
        ((void (*)(void))APP_CODESTART_ADDR)();
    }

    // 6. 跳转失败保底
    while(1);
}
//=================bootloader    main.c=================================



/* F28335 Bootloader.cmd(仅放扇区A,适配跳转功能) */
MEMORY
{
PAGE 0:    /* Program Memory */
   RAML0       : origin = 0x008000, length = 0x002000     /* RAML0(用于ramfuncs搬运) */
   BOOT_ENTRY  : origin = 0x338000, length = 0x007F80     /* 扇区A主区域(0x338000-0x33FF7F) */
   CSM_RSVD    : origin = 0x33FF80, length = 0x000076     /* 扇区A保留区 */
   BEGIN       : origin = 0x33FFF6, length = 0x000002     /* 启动向量 */
   CSM_PWL     : origin = 0x33FFF8, length = 0x000008     /* CSM密码区 */
   ADC_CAL     : origin = 0x380080, length = 0x000009     /* ADC校准 */
   ROM         : origin = 0x3FF27C, length = 0x000D44     /* Boot ROM */        
   RESET       : origin = 0x3FFFC0, length = 0x000002     /* 复位向量 */

PAGE 1 :   /* Data Memory */
   RAMM1       : origin = 0x000500, length = 0x000300     /* 栈空间:0x000500-0x0007FF,共768字节 */
   RAML4       : origin = 0x00C000, length = 0x001000     /* 数据段:4KB */
}

SECTIONS
{
   codestart           : > BEGIN       PAGE = 0          /* 启动向量,必须放在扇区A末尾 */
   .cinit              : > BOOT_ENTRY  PAGE = 0          /* 初始化段,放扇区A */
   .text               : > BOOT_ENTRY  PAGE = 0          /* 代码段,放扇区A */
   ramfuncs            : LOAD = BOOT_ENTRY,              /* 加载到Flash扇区A */
                         RUN = RAML0,                    /* 运行在RAML0 */
                         LOAD_START(_RamfuncsLoadStart), /* 生成搬运起始符号 */
                         LOAD_END(_RamfuncsLoadEnd),     /* 生成搬运结束符号 */
                         RUN_START(_RamfuncsRunStart),   /* 生成运行起始符号 */
                         PAGE = 0
   .stack              : > RAMM1       PAGE = 1          /* 栈空间,必须独立 */
   .ebss               : > RAML4       PAGE = 1          /* 全局变量段 */
   .econst             : > BOOT_ENTRY  PAGE = 0          /* 常量段 */
   .reset              : > RESET,      PAGE = 0, TYPE = DSECT /* 禁用Boot的复位段,避免覆盖 */
   .adc_cal            : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD /* ADC校准段,只读不加载 */
}
//=================bootloader    cmd.c=================================

#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"

// 声明ramfuncs搬运相关变量(由.cmd文件定义,必须声明才能正常搬运)
extern Uint16 RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart;

// 150MHz系统时钟下,延时约1秒
void delay_1s(void) {
    volatile Uint32 i;
    for(i = 0; i < 1500000; i++) {
        // 空循环,增加编译器优化屏障,避免被优化掉
        asm(" NOP");
    }
}

void main(void) {
    // 1. 系统初始化(关闭看门狗、配置PLL时钟=150MHz)
    InitSysCtrl();
    
    // 2. 搬运ramfuncs段(从Flash的APPLICATION区域搬运到RAML0区域运行)
    // 必须在初始化其他外设/中断前执行,避免Flash运行函数出错
    MemCopy(&RamfuncsLoadStart, &RamfuncsLoadEnd, &RamfuncsRunStart);
    
    // 3. 中断系统初始化(小灯APP无中断需求,仅做基础初始化,禁止所有中断)
    DINT;  // 禁止全局中断(防止初始化过程中触发中断)
    InitPieCtrl();  // 初始化PIE中断控制器:复位PIE寄存器到默认状态
    IER = 0x0000;   // 清空CPU中断使能寄存器(禁用所有CPU级中断)
    IFR = 0x0000;   // 清空CPU中断标志寄存器(清除所有未处理中断)
    InitPieVectTable();  // 初始化PIE向量表:将ROM默认向量表拷贝到RAM

    // 4. GPIO初始化(配置GPIO60、GPIO61为推挽输出,控制小灯)
    EALLOW;  // 解锁受保护的寄存器(GPIO控制寄存器属于受保护寄存器)
    // 配置GPIO60
    GpioCtrlRegs.GPBMUX2.bit.GPIO60 = 0;  // 0=通用GPIO模式(禁用外设功能)
    GpioCtrlRegs.GPBDIR.bit.GPIO60 = 1;   // 1=输出模式(0=输入模式)
    GpioCtrlRegs.GPBPUD.bit.GPIO60 = 0;   // 0=使能上拉电阻(避免IO口悬空)

    // 配置GPIO61
    GpioCtrlRegs.GPBMUX2.bit.GPIO61 = 0;  // 0=通用GPIO模式
    GpioCtrlRegs.GPBDIR.bit.GPIO61 = 1;   // 1=输出模式
    GpioCtrlRegs.GPBPUD.bit.GPIO61 = 0;   // 0=使能上拉电阻
    EDIS;  // 锁定受保护的寄存器(配置完成后锁定,防止误修改)

    // 5. 主循环:翻转GPIO60、GPIO61,实现小灯闪烁
    while(1) {
        GpioDataRegs.GPBTOGGLE.bit.GPIO60 = 1;  // 翻转GPIO60电平
        GpioDataRegs.GPBTOGGLE.bit.GPIO61 = 1;  // 翻转GPIO61电平
        delay_1s();  // 延时1秒
    }
}
//============================app     main.c=========================


/* F28335 APP.cmd(小灯程序专用) */
MEMORY
{
PAGE 0:    /* Program Memory */
   ZONE0       : origin = 0x004000, length = 0x001000     /* XINTF zone 0 */
   RAML0       : origin = 0x008000, length = 0x002000     /* on-chip RAM block L0 */
   RAML2       : origin = 0x00A000, length = 0x001000     /* on-chip RAM block L2 */
   RAML3       : origin = 0x00B000, length = 0x001000     /* on-chip RAM block L3 */
   ZONE6A      : origin = 0x100000, length = 0x00FC00    /* XINTF zone 6 - program space*/
   ZONE7       : origin = 0x200000, length = 0x100000    /* XINTF zone 7  */
   BEGIN       : origin = 0x300000, length = 0x000002
   APP_ENTRY   : origin = 0x300002, length = 0x007FFE
   OTP         : origin = 0x380400, length = 0x000400     /* on-chip OTP */
   ADC_CAL     : origin = 0x380080, length = 0x000009     /* ADC_cal function */

   IQTABLES    : origin = 0x3FE000, length = 0x000b50     /* IQ Math Tables in Boot ROM */
   IQTABLES2   : origin = 0x3FEB50, length = 0x00008c     /* IQ Math Tables in Boot ROM - 放回PAGE 0 */
   FPUTABLES   : origin = 0x3FEBDC, length = 0x0006A0     /* FPU Tables in Boot ROM */
   ROM         : origin = 0x3FF27C, length = 0x000D44     /* Boot ROM */
   RESET       : origin = 0x3FFFC0, length = 0x000002     /* part of boot ROM  */
   VECTORS     : origin = 0x3FFFC2, length = 0x00003E     /* part of boot ROM  */

PAGE 1 :   /* Data Memory */
   BOOT_RSVD   : origin = 0x000000, length = 0x000050     /* Part of M0 */
   RAMM0       : origin = 0x000050, length = 0x0004B0     /* on-chip RAM block M0 */
   RAMM1       : origin = 0x000500, length = 0x000300     /* on-chip RAM block M1 */
   RAML4       : origin = 0x00C000, length = 0x001000     /* on-chip RAM block L4 */
   RAML5       : origin = 0x00D000, length = 0x001000     /* on-chip RAM block L5 */
   RAML6       : origin = 0x00E000, length = 0x001000     /* on-chip RAM block L6 */
   RAML7       : origin = 0x00F000, length = 0x001000     /* on-chip RAM block L7 */
   ZONE6B      : origin = 0x10FC00, length = 0x000400     /* XINTF zone 6 - data space */
}

SECTIONS
{
    codestart           : > BEGIN       PAGE = 0
   /* 程序段映射到APP Flash分区 */
   .cinit              : > APP_ENTRY      PAGE = 0
   .pinit              : > APP_ENTRY,     PAGE = 0
   .text               : >> APP_ENTRY     PAGE = 0

   /* ramfuncs段:从Flash搬运到RAML0运行 */
   ramfuncs            : LOAD = APP_ENTRY,
                         RUN = RAML0,
                         LOAD_START(_RamfuncsLoadStart),
                         LOAD_END(_RamfuncsLoadEnd),
                         RUN_START(_RamfuncsRunStart),
                         PAGE = 0

   /* 未初始化数据段 */
   .stack              : > RAMM1       PAGE = 1
   .ebss               : > RAML4       PAGE = 1
   .esysmem            : > RAMM1       PAGE = 1

   /* 初始化数据段 */
   .econst             : > APP_ENTRY    PAGE = 0
   .switch             : > APP_ENTRY    PAGE = 0

   /* IQ数学库相关  */
   IQmath              : > APP_ENTRY    PAGE = 0
   IQmathTables        : > IQTABLES,    PAGE = 0, TYPE = NOLOAD
   IQmathTables2       : > IQTABLES2,   PAGE = 0, TYPE = NOLOAD
   FPUmathTables       : > FPUTABLES,   PAGE = 0, TYPE = NOLOAD

   /* DMA相关RAM */
   DMARAML4            : > RAML4,       PAGE = 1
   DMARAML5            : > RAML5,       PAGE = 1
   DMARAML6            : > RAML6,       PAGE = 1
   DMARAML7            : > RAML7,       PAGE = 1

   /* XINTF Zone6数据区 */
   ZONE6DATA           : > ZONE6B,      PAGE = 1

   /* 复位和向量表(禁用) */
   .reset              : > RESET,       PAGE = 0, TYPE = DSECT
   vectors             : > VECTORS      PAGE = 0, TYPE = DSECT
   
   /* ADC校准函数 */
   .adc_cal            : load = ADC_CAL, PAGE = 0, TYPE = NOLOAD
}



//============================app     cmd.c=========================


#10063-D entry-point symbol other than "_c_int00" specified:  "code_start"    test_upgrade             C/C++ Problem
这个app编译时会有一个警告,这个是正常的,意思是手动指定了一个非标准的程序入口点,先烧录app也是在测试app代码是否正确,ccs在调试时会智能帮助找到代码运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值