High-Speed SPI NOR Flash Black-Box Flight Data Logger
Log 100Hz aerospace telemetry frames to an external Winbond W25Q128 16MB SPI Flash chip using DMA double-buffering and wear-leveling.
2. Prerequisites & Background Theory:
SPI bus modes (CPOL/CPHA), flash page programming vs sector erasing, and DMA double-buffering.
Goal & Engineering Objectives
Stream high-density flight telemetry frames at 100 Hz to non-volatile SPI flash memory without blocking the primary flight stabilization loop.
Governing Mathematical Formulation & Physics
System Architecture & Block Flow Diagram
[IMU / Barometer / GPS] --(Sensors 100Hz)--> [Ring Buffer in RAM (2x 256B)]
|
(DMA Stream Peripheral Transfer)
v
[SPI Controller @ 20 MHz]
|
v
[Winbond W25Q128 Flash (16 MB)]
Required Hardware Bill of Materials (BOM)
| Hardware Component | Qty | Engineering Specification |
|---|---|---|
| Winbond W25Q128JV 128Mbit (16MB) SPI NOR Flash | 1 | 133 MHz SPI, 2.7V - 3.6V, SOIC-8 |
| STM32F4 or ESP32-S3 Microcontroller | 1 | Hardware SPI with DMA controller |
| 100 nF Ceramic Bypass Capacitor | 1 | Place directly adjacent to Flash VCC pin |
| 10 kΩ Resistor | 2 | Hold /WP (Write Protect) and /HOLD pins HIGH |
Wiring, Pinout & Schematics Mapping
Firmware Implementation & Algorithms
// C: SPI Flash 256-Byte Page Program with Write-Enable (ANSI C)
#include <stdint.h>
#include <stdbool.h>
#define W25Q_WRITE_ENABLE 0x06
#define W25Q_PAGE_PROGRAM 0x02
#define W25Q_READ_STATUS_REG_1 0x05
extern void spi_select_cs(void);
extern void spi_deselect_cs(void);
extern void spi_transfer_bytes(const uint8_t *tx, uint8_t *rx, uint16_t len);
void w25q_wait_busy(void) {
uint8_t cmd = W25Q_READ_STATUS_REG_1;
uint8_t status = 0;
do {
spi_select_cs();
spi_transfer_bytes(&cmd, NULL, 1);
spi_transfer_bytes(NULL, &status, 1);
spi_deselect_cs();
} while (status & 0x01); // Poll BUSY bit 0
}
void w25q_write_page(uint32_t pageAddress, const uint8_t *data256) {
w25q_wait_busy();
// Send Write Enable Latch (WEL)
uint8_t cmd_we = W25Q_WRITE_ENABLE;
spi_select_cs();
spi_transfer_bytes(&cmd_we, NULL, 1);
spi_deselect_cs();
// Send Page Program Command + 24-bit Address
uint8_t header[4];
header[0] = W25Q_PAGE_PROGRAM;
header[1] = (uint8_t)(pageAddress >> 16);
header[2] = (uint8_t)(pageAddress >> 8);
header[3] = (uint8_t)(pageAddress);
spi_select_cs();
spi_transfer_bytes(header, NULL, 4);
spi_transfer_bytes(data256, NULL, 256); // 256-byte payload
spi_deselect_cs();
}