1.8. Flash 编程与启动引导

F28335 内置 512 KB Flash,用于存储程序代码。调试时通常在 RAM 中运行, 最终产品需烧写到 Flash。

1.8.1. Flash 与 RAM 的区别

特性

RAM 调试

Flash 运行

加载速度

快(< 1s)

慢(~5~10s)

掉电保持

丢失

保持

运行速度

150 MHz

150 MHz(需配置等待状态)

代码修改

可直接修改

需擦除再写

适用场景

开发调试

最终产品

1.8.2. Flash 配置

void InitFlash(void)
{
    EALLOW;

    // 使能 Flash 流水线
    FlashRegs.FOPT.bit.ENPIPE = 1;

    // 配置等待状态
    // 150 MHz 运行时:
    FlashRegs.FBANKWAIT.bit.RANDWAIT = 5;   // 随机访问等待
    FlashRegs.FBANKWAIT.bit.PAGEWAIT = 5;   // 页访问等待
    FlashRegs.FSTATUS.bit.V3VSTAT = 1;     // 3.3V 操作

    // 配置 OTP 等待
    FlashRegs.FOTPWAIT.bit.OTPWAIT = 5;

    EDIS;

    // 等待 Flash 就绪
    while (FlashRegs.FPWR.bit.PWRSTAT == 0) { }
}

警告

Flash 等待状态设置不足会导致程序**跑飞**。 150 MHz 运行时至少需要 5 个等待周期(RANDWAIT = 5)。

1.8.3. 链接文件(CMD)

F28335.cmd(存储器分配)
MEMORY
{
    PAGE 0:                 /* 程序空间 */
    PRAMH0      : origin = 0x008000, length = 0x008000   /* 32K RAM */

    FLASH_A     : origin = 0x300000, length = 0x00FFFF   /* 64K */
    FLASH_B     : origin = 0x310000, length = 0x00FFFF   /* 64K */
    FLASH_C     : origin = 0x320000, length = 0x00FFFF   /* 64K */
    FLASH_D     : origin = 0x330000, length = 0x00FFFF   /* 64K */
    FLASH_E     : origin = 0x380000, length = 0x00FFFF   /* 64K */
    FLASH_F     : origin = 0x390000, length = 0x00FFFF   /* 64K */
    FLASH_G     : origin = 0x3A0000, length = 0x00FFFF   /* 64K */
    FLASH_H     : origin = 0x3B0000, length = 0x00FFFF   /* 64K */

    PAGE 1:                 /* 数据空间 */
    DRAMH0      : origin = 0x00C000, length = 0x008000   /* 32K RAM */
}

SECTIONS
{
    /* Flash 中的代码段 */
    .text        : > FLASH_A,     PAGE = 0   /* 代码 */
    .cinit       : > FLASH_A,     PAGE = 0   /* 全局变量初始化 */
    .pinit       : > FLASH_A,     PAGE = 0   /* 构造函数 */

    /* RAM 中的数据段 */
    .ebss        : > DRAMH0,      PAGE = 1   /* 全局变量 */
    .esysmem     : > DRAMH0,      PAGE = 1   /* 堆 */
    .stack       : > DRAMH0,      PAGE = 1   /* 栈 */

    /* 将关键函数复制到 RAM 运行(提高速度) */
    ramfuncs     : LOAD = FLASH_A,           /* 存储在 Flash */
                   RUN = PRAMH0,             /* 在 RAM 中运行 */
                   LOAD_START(_RamfuncsLoadStart),
                   LOAD_END(_RamfuncsLoadEnd),
                   RUN_START(_RamfuncsRunStart),
                   PAGE = 0
}

1.8.4. RAM 中运行关键函数

// 将关键函数指定到 ramfuncs 段(在链接文件中配置)

#pragma CODE_SECTION(interrupt_loop, "ramfuncs");
void interrupt_loop(void)   // 电流环——在 RAM 中执行
{
    // 高速控制代码
    // 比 Flash 运行快 2~3 倍
}

// 复制代码到 RAM
void MemCopy(uint16_t *dest, uint16_t *src, uint16_t size)
{
    while (size--) *dest++ = *src++;
}

void main(void)
{
    // 将 ramfuncs 从 Flash 复制到 RAM
    MemCopy(&RamfuncsRunStart, &RamfuncsLoadStart,
            &RamfuncsLoadEnd - &RamfuncsLoadStart);

    // ... 其他初始化
}

1.8.5. Boot ROM 与启动模式

F28335 上电启动流程:

1. CPU 从 Boot ROM (0x3F FFC0) 开始执行
2. Boot ROM 检测 GPIO 引脚状态
3. 根据引脚电平选择启动模式

启动模式选择(GPIO87, GPIO86, GPIO85):

+--------+--------+--------+------------------+
| GPIO87 | GPIO86 | GPIO85 | 启动模式         |
+========+========+========+==================+
| 1      | 1      | 1      | Flash 启动       |
+--------+--------+--------+------------------+
| 0      | 1      | 1      | SCI 启动         |
+--------+--------+--------+------------------+
| 1      | 0      | 1      | SPI 启动         |
+--------+--------+--------+------------------+
| 1      | 1      | 0      | I2C 启动         |
+--------+--------+--------+------------------+
| 0      | 1      | 0      | eCAN 启动        |
+--------+--------+--------+------------------+
| 0      | 0      | 1      | 并行 I/O 启动     |
+--------+--------+--------+------------------+
| 0      | 0      | 0      | 分支到 SARAM     |
+--------+--------+--------+------------------+

Flash 启动是最常用的模式(GPIO87/86/85 全部上拉 = 3.3V)。

1.8.6. SCI 串口 Bootloader

SCI Bootloader (GPIO85=1, GPIO86=1, GPIO87=0):

主机通过 SCI-A (GPIO28/29) 发送固件:

1. Boot ROM 等待接收 8 字节的"魔术字"
   0x08 0xAA 0x02 0x00 0x00 0x00 0xAA 0x02

2. 接收到后发送确认,开始接收 S19 格式的固件

3. 烧写完成后跳转到 Flash 执行

用途:产品现场升级(不需仿真器)

1.8.7. Flash API

// 擦除 Flash 扇区
void Flash_Erase(uint16_t sector)
{
    EALLOW;
    FlashRegs.FERASECR = FERASE_SECTOR_BITS(sector);
    FlashRegs.FSTDBYWAIT = 0x01FF;      // 进入待机
    FlashRegs.FERASECR.bit.FRES = 0xA;  // 擦除命令
    while (FlashRegs.FSTATUS.bit.BUSY) { }
    EDIS;
}

// 编程 Flash(写入 64 位数据)
void Flash_Program(uint32_t addr, uint64_t *data)
{
    EALLOW;
    FlashRegs.FPROGCR = FPROG_SECTOR_BITS;
    FlashRegs.FSTDBYWAIT = 0x01FF;
    FlashRegs.FPROGCR.bit.FRES = 0x4;   // 编程命令

    // 写入数据到编程缓冲区
    FlashRegs.FDATA[0] = *((uint16_t *)data + 0);
    FlashRegs.FDATA[1] = *((uint16_t *)data + 1);
    FlashRegs.FDATA[2] = *((uint16_t *)data + 2);
    FlashRegs.FDATA[3] = *((uint16_t *)data + 3);

    FlashRegs.FPROGCR.bit.FRES = 0x8;   // 启动编程
    while (FlashRegs.FSTATUS.bit.BUSY) { }
    EDIS;
}

警告

Flash 操作注意事项:

  • 擦除/编程时必须工作在 Flash 中或 RAM 中 (不能在待擦除扇区执行代码)

  • Flash 擦除寿命约 1000 次 (擦除前需确认)

  • 编程时可以开启中断,但中断服务函数不能在目标区域

  • 擦除/编程后需重新配置等待状态