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 次 (擦除前需确认)
编程时可以开启中断,但中断服务函数不能在目标区域
擦除/编程后需重新配置等待状态