#ifndef __W25Q64_H #define __W25Q64_H #include #include "main.h" #ifdef __cplusplus extern "C" { #endif /* ------------------------------------------------- * W25Q64 外部 SPI Flash 驱动接口 * 硬件连接(软件 SPI,任意 GPIO): * CS -> PB4 * CLK -> PB3 * DO -> PB5 (Flash 数据输出 / MCU 输入) * DI -> PA15 (Flash 数据输入 / MCU 输出) * ------------------------------------------------- */ #define W25Q64_FLASH_SIZE (8ul * 1024 * 1024) /* 8MB */ #define W25Q64_SECTOR_SIZE 4096u #define W25Q64_BLOCK_SIZE 65536u #define W25Q64_PAGE_SIZE 256u #define W25Q64_JEDEC_ID 0xEF4017u /* W25Q64JV */ /* 命令字 */ #define W25Q64_CMD_WRITE_ENABLE 0x06u #define W25Q64_CMD_WRITE_DISABLE 0x04u #define W25Q64_CMD_READ_STATUS1 0x05u #define W25Q64_CMD_READ_DATA 0x03u #define W25Q64_CMD_PAGE_PROGRAM 0x02u #define W25Q64_CMD_SECTOR_ERASE 0x20u #define W25Q64_CMD_BLOCK_ERASE 0xD8u #define W25Q64_CMD_CHIP_ERASE 0xC7u #define W25Q64_CMD_READ_ID 0x9Fu /* 外部 Flash 分区布局(每个区 256KB,足够放下 224KB 的 APP) */ #define W25Q64_SLOT_SIZE 0x40000u /* 256KB */ #define W25Q64_SLOT_BACKUP_ADDR 0x000000u /* 槽 A:旧版本 / 回退镜像 */ #define W25Q64_SLOT_NEW_ADDR 0x040000u /* 槽 B:新下载的固件 */ /* 信息区:两个独立的 4KB 扇区,双副本冗余,必须避开固件槽 B 的 0x040000~0x07FFFF */ #define W25Q64_INFO_SECTOR_A 0x080000u #define W25Q64_INFO_SECTOR_B 0x081000u #define W25Q64_INFO_MAGIC 0x5741544Fu /* 'WATO' */ /* OTA 状态 */ #define W25Q64_STATE_IDLE 0u #define W25Q64_STATE_DOWNLOADED 1u #define W25Q64_STATE_COPYING 2u #define W25Q64_STATE_INSTALLED 3u #define W25Q64_STATE_ROLLBACK 4u #define W25Q64_MAX_TRIALS 3u #pragma pack(push, 1) typedef struct { uint32_t magic; /* 0x5741544F */ uint32_t sequence; /* 写入序号,越大越新 */ uint16_t new_version; /* 新版本号 */ uint32_t new_size; /* 新固件大小 */ uint16_t new_crc16; /* 新固件 MODBUS CRC16 */ uint8_t new_valid; /* 槽 B 固件是否有效 */ uint8_t update_state; /* 当前 OTA 状态 */ uint16_t boot_trial_count; /* 已尝试启动次数 */ uint8_t app_confirmed; /* APP 运行稳定后置 1 */ uint8_t reserved1; uint16_t backup_version; /* 备份固件版本号 */ uint32_t backup_size; /* 备份固件大小 */ uint16_t backup_crc16; /* 备份固件 CRC16 */ uint8_t backup_valid; /* 槽 A 备份是否有效 */ uint8_t reserved2; uint16_t checksum; /* 前面所有字节累加和 */ } W25Q64_OtaInfo; #pragma pack(pop) /* 基础 SPI Flash 操作 */ uint8_t W25Q64_Init(void); void W25Q64_ReadID(uint8_t *id3); uint8_t W25Q64_ReadStatus(void); void W25Q64_WaitBusy(void); void W25Q64_WriteEnable(void); void W25Q64_SectorErase(uint32_t addr); void W25Q64_BlockErase(uint32_t addr); void W25Q64_ChipErase(void); void W25Q64_PageProgram(uint32_t addr, const uint8_t *data, uint16_t len); void W25Q64_Read(uint32_t addr, uint8_t *buf, uint32_t len); void W25Q64_EraseRegion(uint32_t addr, uint32_t size); int W25Q64_WriteBuffer(uint32_t addr, const uint8_t *data, uint32_t len); int W25Q64_Verify(uint32_t addr, const uint8_t *data, uint32_t len); /* OTA 专用信息区操作 */ int W25Q64_OTA_ReadInfo(W25Q64_OtaInfo *info); int W25Q64_OTA_WriteInfo(const W25Q64_OtaInfo *info); int W25Q64_OTA_SetNewInfo(uint16_t version, uint32_t size, uint16_t crc16); int W25Q64_OTA_SetBackupInfo(uint32_t size, uint16_t crc16); int W25Q64_OTA_ClearNew(void); int W25Q64_OTA_SetState(uint8_t state); int W25Q64_OTA_IncTrial(void); int W25Q64_OTA_SetConfirmed(void); int W25Q64_OTA_ClearConfirmed(void); uint16_t W25Q64_CRC16(const uint8_t *data, uint32_t len); #ifdef __cplusplus } #endif #endif /* __W25Q64_H */