Programming External SPI Flash on MM32F5330 through USART Host Interface

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.

Tags: mm32f5330 SPI Flash USART Embedded C python

Posted on Thu, 13 Aug 2026 16:48:12 +0000 by thepriest