MCU串口实现串行flash编程器功能
- ✨MCU串口实现串行flash编程器功能,是基于STC公司
AiCube-ISP上位机上的扩展小工具实现的,参考其相关协议,移植到其他单片机上,实现相同的功能。
- 📌项目开源地址:
https://github.com/yourusername/spiflash_Serial_Read_Write - 📍参考STC官方的"外部串行Flash编程器":
https://www.stcaimcu.com/thread-10774-1-1.html
通过串口与上位机通讯,对串行 Flash 芯片进行读取、写入、擦除等操作。适用于嵌入式开发、固件更新、数据存储等场景。摆脱专用的flash编程器依赖。

目前仅移植到了STM32F1单片机上,以及基于Arduino平台的ESP32和ESP8266上实现此功能。其他单片机,只要带串口和软、硬件spi、QSPI接口都可以实现此功能的移植。
📝可扩展性说明
上位机与MCU串口之间的通讯协议是固定的,MCU与串行flash驱动方式可以根据所使用的MCU硬件条件实现,可以是软件模拟SPI方式或者硬件SPI方式,也可以是QSPI方式。
- 📙串行flash编程器界面:

📑例程说明
- 对于stm32单片机提供的2种串口接收数据处理方式:
- 单字节串口接收中断处理方式。
- 空闲中断 + DMA接收方式。
对于大多数单片机,不管是8位还是32位,方式一,基本都可以做到。
- Arduino 平台例程,串口接收数据处理方式:
- esp8266采用的是
serialEvent+超时查询接收方式。 - esp32采用
onReceive中断接收方式.
🍁flash编程验证工具
- 可以使用十六进制根据:HxD、WinHex、Compare工具。
通过写入和读取扇区数据,进行数据对比验证。
📘移植注意事项
- 串行flash与MCU之间的通讯时钟频率,一定要稳定,超出硬件通讯频率,会导致读写数据有问题。
个人在ESP8266上做验证时,通讯频率设置2MHz,读取的数据部分字节数据错误。调整到1MHz时钟频率,读取的全部数据验证完整。
- 数据的读写完整性影响因数:
- 串口波特率。
- MCU与串行flash的通讯时钟频率。
这两个因数,都会影响数据的读写准确性。
📗串行FLASH编程接口协议
- 通信概述
- 通信数据通过串口发送。
- 使用普通串口收发数据时,必须设置正确的波特率。
数据传输协议
功能 F0:读取目标FLASH的JEDEC ID
命令格式
41H 49H 43H F0H
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F0H |
功能命令 |
返回数据
41H 49H 53H EFH 40H 18H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
| 4 | EFH |
厂商代码ID |
| 5 | 40H |
FLASH类型ID |
| 6 | 18H |
FLASH容量ID |
功能 F1:读取目标FLASH的状态寄存器
命令格式
41H 49H 43H F1H
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F1H |
功能命令 |
返回数据
41H 49H 53H 00H 02H 60H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
| 4 | 00H |
状态寄存器1 |
| 5 | 02H |
状态寄存器2 |
| 6 | 60H |
状态寄存器3 |
功能 F2:读取目标FLASH的数据
命令格式
41H 49H 43H F2H A[3] A[2] A[1] A[0] L[3] L[2] L[1] L[0]
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F2H |
功能命令 |
| 5~8 | A[3] A[2] A[1] A[0] |
目标地址(高字节在前) |
| 9~12 | L[3] L[2] L[1] L[0] |
读取的长度(高字节在前) |
返回数据
41H 49H 53H D[0] D[1] D[2] ...
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
| 4 | D[0] |
读取的数据1 |
| 5 | D[1] |
读取的数据2 |
| 6 | D[2] |
读取的数据3 |
| ... | ... | 后续数据 |
功能 F3:编程数据到目标FLASH
命令格式
41H 49H 43H F3H A[3] A[2] A[1] A[0] L[3] L[2] L[1] L[0] D[0] ...
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F3H |
功能命令 |
| 5~8 | A[3] A[2] A[1] A[0] |
目标地址(高字节在前) |
| 9~12 | L[3] L[2] L[1] L[0] |
编程的长度(高字节在前) |
| 13 | D[0] |
编程的数据1 |
| 14 | D[1] |
编程的数据2 |
| ... | ... | 后续数据 |
返回数据
41H 49H 53H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
功能 F4:擦除目标FLASH的全部扇区
命令格式
41H 49H 43H F4H
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F4H |
功能命令 |
返回数据
41H 49H 53H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
功能 F5:擦除目标FLASH扇区(4K字节)
命令格式
41H 49H 43H F5H A[3] A[2] A[1] A[0]
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F5H |
功能命令 |
| 5~8 | A[3] A[2] A[1] A[0] |
目标扇区起始地址(高字节在前) |
返回数据
41H 49H 53H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
功能 F6:擦除目标FLASH块扇区(32K字节)
命令格式
41H 49H 43H F6H A[3] A[2] A[1] A[0]
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F6H |
功能命令 |
| 5~8 | A[3] A[2] A[1] A[0] |
目标扇区起始地址(高字节在前) |
返回数据
41H 49H 53H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
功能 F7:擦除目标FLASH块扇区(64K字节)
命令格式
41H 49H 43H F7H A[3] A[2] A[1] A[0]
命令说明
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 43H |
命令头(固定为 "AIC") |
| 4 | F7H |
功能命令 |
| 5~8 | A[3] A[2] A[1] A[0] |
目标扇区起始地址(高字节在前) |
返回数据
41H 49H 53H
| 字节序号 | 内容 | 说明 |
|---|---|---|
| 1~3 | 41H 49H 53H |
数据头(固定为 "AIS") |
说明 :所有多字节数值均采用大端模式(高字节在前)。示例中的返回数据为典型值,实际使用时请根据FLASH芯片返回的真实数据解析。