The MM32F5330 evaluation board is equipped with a 1 MB 25Q80 SPI NOR Flash and several USART/UART instances. By dedicating UART1 (PB6) to printf debug output and USART1 RX (PA10) to the host link, the MCU can receive a binary stream from a PC and persist it to external Flash.
Host Frame Format
The Python host transmits the file in fixed-size segments. Each frame consists of:
| Field | Size | Description |
|---|---|---|
| Sync | 4 B | 0xAA 0x55 0xAA 0x55 |
| Sequence | 2 B | Big-endian packet index |
| Length | 2 B | Big-endian payload length (≤ 128) |
| Payload | ≤ 128 B | Raw data from binary file |
| Terminator | 2 B | 0x0D 0x0A |
Host Transmsision Script
import serial
import struct
import time
DEV = 'COM14'
BAUD = 115200
link = serial.Serial(DEV, BAUD, timeout=1)
hdr = bytes([0xAA, 0x55, 0xAA, 0x55])
ftr = bytes([0x0D, 0x0A])
seq = 0
with open('gb2312_80.bin', 'rb') as f:
while True:
chunk = f.read(128)
if not chunk:
break
plen = len(chunk)
packet = struct.pack('!4sHH', hdr, seq, plen) + chunk + ftr
print(chunk)
link.write(packet)
seq += 1
time.sleep(0.1)
link.close()
MCU Rceeption Structure
typedef struct
{
uint8_t Data[140];
uint16_t FillLevel;
uint16_t RxIndex;
uint8_t Done;
} CommBuffer_t;
Blocking USART Dispatcher
void HostCommandListener(void)
{
uint8_t ch;
uint16_t i;
uint8_t idx;
uint8_t page[128];
memset(page, 0, sizeof(page));
UartInit(115200);
while (1)
{
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
{
ch = USART_ReceiveData(USART1);
CommPkt.Data[CommPkt.RxIndex++] = ch;
if (CommPkt.RxIndex >= 2 &&
CommPkt.Data[CommPkt.RxIndex - 2] == 0x0D &&
CommPkt.Data[CommPkt.RxIndex - 1] == 0x0A)
{
if (strncmp((char *)CommPkt.Data, "test", 4) == 0)
{
printf("test ack\r\n");
RunSpiFlashDemo();
}
else if (strncmp((char *)CommPkt.Data, "help", 4) == 0)
{
printf("available commands\r\n 1.abc\r\n");
}
else if (memcmp(CommPkt.Data, "\xAA\x55\xAA\x55", 4) == 0)
{
HandleFlashWrite((uint8_t *)&CommPkt.Data[4]);
}
else if (strncmp((char *)CommPkt.Data, "read", 4) == 0)
{
idx = CommPkt.Data[4] - '0';
memset(page, 0, sizeof(page));
SPI_FLASH_FastRead(idx * 128, page, 128);
for (i = 0; i < 128; i++)
{
if ((i % 8) == 0)
printf("\r\n");
printf("0x%02x ", page[i]);
}
}
else
{
printf("invalid command\r\n");
}
CommPkt.RxIndex = 0;
ClearRxBuffer();
}
}
}
}
Flash Programming Handler
void HandleFlashWrite(uint8_t *raw)
{
uint16_t blk, len;
uint8_t *src = raw;
blk = ((uint16_t)src[0] << 8) | src[1];
len = ((uint16_t)src[2] << 8) | src[3];
if ((blk % 32) == 0)
{
SPI_FLASH_SectorErase(blk / 32);
}
SPI_FLASH_PageProgram(blk * 128, src + 4, len);
printf("flash write block=%u size=%u\r\n", blk, len);
}
Because the 25Q80 is organized into 4 KB sectors and the host delivers 128 bytes per frame, a sector erase is triggered every 32 frames when the block index crosses a 4 KB boundary. After programming, the readN command can retrieve any 128-byte page. For example, sending read0 returns the first page; comparing this dump against the original file confirms successful programming. Once verified, the stored image can serve as a pre-loaded font library for subsequent LCD character rendering.