| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #include "board.h"
- #include "hpm_romapi.h"
- #include "hpm_l1c_drv.h"
- #include "hpm_soc.h"
- #include "bsp_V8M_flash.h"
- // 这里要重新安排,程序什么的所有都要写在外部flash里 且有一些字段是芯片定义的不可写入地区,比如
- // __attribute__ ((section(".nor_cfg_option"))) const uint32_t option[4] = {0xfcf90002, 0x00000007, 0xE, 0x0};
- // define region NOR_CFG_OPTION = [ from 0x80000400 size 0x0C00 ];
- // define region BOOT_HEADER = [ from 0x80001000 size 0x2000 ];
- // 这个字段就是narflash 的描述符,不能覆盖 所以程序得后移
- // 从链接字段里可以发现 define region XPI0 = [from 0x80003000 size (_flash_size - 0x3000) ]; /* XPI0 */
- // app是从0x80003000开始的 也就是boot只能从这开始
- #if 0
- // 起始地址 0x80000000
- // IAP标志地址 - 选择Flash中一个合适的扇区
- // HPM6750 Flash通常映射在0x80000000开始
- #define IAP_FLAG_ADDR ((uint32_t)0x8000C000)
- #define IAP_FLAG_NEED_UPDATE ((uint16_t)0xABCD)
- // Flash大小配置 - 根据实际Flash芯片修改
- #define FLASH_BASE_ADDR 0x80000000
- #define FLASH_SECTOR_SIZE 0x1000 // 4KB,常见QSPI Flash扇区大小
- #define FLASH_PAGE_SIZE 256 // 编程页大小
- // XPI Nor Flash 配置结构体
- static xpi_nor_config_t s_flash_config;
- /**
- * @brief 初始化Flash控制器并获取配置
- */
- static void flash_init(void)
- {
- static bool s_flash_inited = false;
-
- if (!s_flash_inited) {
- // 获取Flash配置(从ROM API读取)
- rom_xpi_nor_get_config(HPM_XPI0, &s_flash_config, NULL);
- s_flash_inited = true;
- }
- }
- /**
- * @brief 根据地址计算所在扇区(HPM6750版)
- *
- * HPM6750的外部Flash扇区划分与具体Flash芯片有关
- * 这里以常见的4KB扇区为例
- */
- static uint32_t get_sector_index(uint32_t address)
- {
- // 计算相对于Flash基址的偏移
- uint32_t offset = address - FLASH_BASE_ADDR;
-
- // 扇区索引 = 偏移 / 扇区大小
- return offset / FLASH_SECTOR_SIZE;
- }
- /**
- * @brief 擦除包含指定地址的扇区
- */
- static void flash_erase_sector(uint32_t address)
- {
- flash_init();
-
- // HPM6750需要先禁用缓存,因为我们在擦除Flash
- l1c_dc_invalidate_all();
-
- // 确保地址对齐到扇区边界
- uint32_t sector_start = address & ~(FLASH_SECTOR_SIZE - 1);
-
- // 调用ROM API擦除扇区
- rom_xpi_nor_erase_sector(HPM_XPI0, &s_flash_config, sector_start);
-
- // 擦除后清理缓存
- l1c_dc_invalidate_all();
- }
- /**
- * @brief 编程半字(2字节)到Flash
- */
- static void flash_program_halfword(uint32_t address, uint16_t data)
- {
- flash_init();
-
- // 准备要写入的数据(需要是32位对齐)
- uint32_t prog_data[2];
- prog_data[0] = (uint32_t)data; // 低16位有效
-
- // HPM6750要求编程地址对齐到编程单元
- // 这里我们读取整个页,修改后再写回
- uint8_t page_buffer[FLASH_PAGE_SIZE] __attribute__((aligned(4)));
-
- // 计算页起始地址
- uint32_t page_start = address & ~(FLASH_PAGE_SIZE - 1);
- uint32_t offset_in_page = address - page_start;
-
- // 先读取整个页
- rom_xpi_nor_read(HPM_XPI0, &s_flash_config, page_start, page_buffer, FLASH_PAGE_SIZE);
-
- // 修改目标位置
- *(uint16_t*)(page_buffer + offset_in_page) = data;
-
- // 擦除整个页所在的扇区
- flash_erase_sector(address);
-
- // 重新编程整个页
- rom_xpi_nor_program(HPM_XPI0, &s_flash_config, page_start, page_buffer, FLASH_PAGE_SIZE);
-
- // 清理缓存
- l1c_dc_invalidate_all();
- }
- /**
- * @brief 从Flash读取N个字节
- */
- int hpm_flash_read_nbytes(uint32_t read_addr, uint8_t *read_buf, int32_t read_num)
- {
- flash_init();
-
- // HPM6750可以直接通过内存映射读取
- // 但需要确保缓存一致性
- l1c_dc_invalidate((uint32_t)read_addr, read_num);
-
- memcpy(read_buf, (void*)read_addr, read_num);
-
- return read_num;
- }
- /**
- * @brief 清除升级标志
- */
- void hpm_clear_iap_flag(void)
- {
- uint32_t mask;
-
- // 保存当前中断状态并关闭所有中断
- mask = disable_global_irq(CSR_MSTATUS_MIE_MASK);
-
- // 写入0xFFFF表示无升级标志
- flash_program_halfword(IAP_FLAG_ADDR, 0xFFFF);
-
- // 恢复中断状态
- restore_global_irq(mask);
- }
- /**
- * @brief 记录升级标志
- */
- void hpm_record_iap_flag(void)
- {
- uint32_t mask;
-
- // 保存当前中断状态并关闭所有中断
- mask = disable_global_irq(CSR_MSTATUS_MIE_MASK);
-
- flash_program_halfword(IAP_FLAG_ADDR, IAP_FLAG_NEED_UPDATE);
-
- // 恢复中断状态
- restore_global_irq(mask);
- }
- /**
- * @brief 检查升级标志位
- */
- void hpm_check_iap_flag(void)
- {
- uint16_t iap_flag;
-
- // 读取标志
- hpm_flash_read_nbytes(IAP_FLAG_ADDR, (uint8_t*)&iap_flag, sizeof(iap_flag));
-
- // 如果需要升级,清除标志
- if (iap_flag == IAP_FLAG_NEED_UPDATE) {
- hpm_clear_iap_flag();
- // 这里可以触发跳转到Bootloader的逻辑
- // printf("IAP flag detected, jumping to bootloader...\n");
- }
- }
- #endif
|