lift_indicator_suite/bsp/qspi_flash
2026-07-17 16:49:02 +03:00
..
include/bsp # bootloader: SEMC Init, Led dictionary 2026-07-17 16:49:02 +03:00
src # bootloader: SEMC Init, Led dictionary 2026-07-17 16:49:02 +03:00
CMakeLists.txt # bsp_qspi_flash: in progress 2026-04-22 11:19:52 +03:00
README.md # bootloader: SEMC Init, Led dictionary 2026-07-17 16:49:02 +03:00

bsp_qspi_flash — QSPI Flash W25Q64/128/256/512

Драйвер QSPI Flash на FlexSPI1 с поддержкой четырёх чипов Winbond. XIP-безопасен: все функции, трогающие FlexSPI IP-регистры, размещены в ITCM и выполняются под IRQ lock.


Аппаратура

Параметр Значение
Интерфейс MCU FlexSPI1, порт A1

Поддерживаемые чипы:

Чип JEDEC mfr JEDEC cap Размер Адресация
W25Q64 0xEF 0x17 8 MB 3-byte
W25Q128 0xEF 0x18 16 MB 3-byte
W25Q256 0xEF 0x19 32 MB 4-byte
W25Q512 0xEF 0x20 64 MB 4-byte

Архитектура

XIP-безопасность

Прошивка исполняется XIP из Flash по AHB. Любая IP-команда FlexSPI блокирует AHB-путь — если в этот момент CPU фетчит инструкцию из Flash, происходит HardFault.

Решение — два уровня защиты:

flowchart LR
    A["публичная функция\nbsp_qspi_*(...)"] --> B["IRQ lock\n__get_PRIMASK + DSB + ISB"]
    B --> C["AHBCR.PREFETCHEN = 0"]
    C --> D["IP-команда FlexSPI\nиз ITCM\n(AT_QUICKACCESS_SECTION_CODE)"]
    D --> E["AHBCR.PREFETCHEN = 1"]
    E --> F["IRQ unlock\nвосстановить PRIMASK"]

ITCM (0x00000000) подключён к CPU по выделенной шине — фетч инструкций не конкурирует с AHB. IRQ lock гарантирует, что прерывание не застанет FlexSPI в середине IP-транзакции; PRIMASK восстанавливается, не сбрасывается безусловно — вызов из уже заблокированного контекста корректен.

Обязательный дефайн в CMakeLists потребителя:

target_compile_definitions(firmware_test PRIVATE
    __STARTUP_INITIALIZE_RAMFUNCTION   # ← без этого ITCM содержит нули → HardFault
    __STARTUP_CLEAR_BSS
)

Адресация W25Q256/512

Вместо Enter 4-Byte Mode (0xB7) используются dedicated 4-byte opcodes — XIP-слот 0 (24-bit адресация) не изменяется:

Операция W25Q64/128 W25Q256/512
Sector Erase 4KB 0x20 0x21
Block Erase 32KB 0x52 0x5C
Block Erase 64KB 0xD8 0xDC
Quad Page Prog 0x32 0x34
IP Quad Out Read 0x6B 0x6C

API

/* Инициализация — вызвать до bsp_tick_init() */
bsp_status_t bsp_qspi_init(void);

/* Идентификация — bsp_qspi_read_jedec_id() работает и без успешного init() */
bsp_status_t bsp_qspi_read_jedec_id(bsp_qspi_jedec_t *p_jedec);
const char  *bsp_qspi_decode_chip(uint8_t cap_byte, uint32_t *p_size_mb); /* device_id & 0xFF → "W25Q128" + МБ */
uint32_t     bsp_qspi_flash_size(void);   /* доступно после init() */

/* Стирание */
bsp_status_t bsp_qspi_erase_sector(uint32_t addr);      /* 4 KB,  ~45 мс  */
bsp_status_t bsp_qspi_erase_block_32k(uint32_t addr);   /* 32 KB, ~120 мс */
bsp_status_t bsp_qspi_erase_block_64k(uint32_t addr);   /* 64 KB, ~150 мс */

/* Запись одной страницы (256 байт, адрес выровнен на BSP_QSPI_PAGE_SIZE) */
bsp_status_t bsp_qspi_write_page(uint32_t addr, const uint8_t *p_data);  /* ~3 мс */

/* Чтение через IP-команду (не AHB/XIP) */
bsp_status_t bsp_qspi_read(uint32_t addr, uint8_t *p_buf, size_t size);

Все функции возвращают BSP_OK или BSP_ERR_HW.

Выбор операции стирания:

Объём Рекомендация Время
< 32 KB erase_sector 4KB ~45 мс × N
32 KB 1 MB erase_block_32k ~120 мс / 32KB
> 1 MB erase_block_64k ~150 мс / 64KB

Пример: 4 MB через 64KB = 64 × 150 мс ≈ 9.6 с против 46 с через 4KB.


Быстрый старт

#include "bsp/qspi_flash.h"

/* main.c — порядок инициализации: */
board_hw_init();
bsp_qspi_init();    /* ← до bsp_tick_init() */
bsp_tick_init();

/* Идентификация чипа — работает даже если bsp_qspi_init() выше вернула
   ошибку (LUT для JEDEC грузится безусловным первым шагом внутри неё) */
bsp_qspi_jedec_t jedec;
bsp_qspi_read_jedec_id(&jedec);
uint32_t size_mb;
const char *chip_name = bsp_qspi_decode_chip((uint8_t) (jedec.device_id & 0xFF), &size_mb);
/* chip_name = "W25Q128", size_mb = 16 — либо "UNKNOWN"/0, если чип не опознан */

/* Стереть сектор и записать страницу */
bsp_qspi_erase_sector(0x00010000);
uint8_t page[256] = { /* ... */ };
bsp_qspi_write_page(0x00010000, page);

/* Прочитать обратно */
uint8_t buf[256];
bsp_qspi_read(0x00010000, buf, sizeof(buf));

CMake

target_link_libraries(firmware_test PRIVATE bsp_qspi_flash)

target_compile_definitions(firmware_test PRIVATE
    __STARTUP_INITIALIZE_RAMFUNCTION
    __STARTUP_CLEAR_BSS
)

Зависимости модуля:

Зависимость Тип Описание
bsp_status PUBLIC bsp_status_t в публичном API
bsp_board PRIVATE Транзитивно: clock, SDK headers
sdk_flexspi PRIVATE fsl_flexspi.h — FlexSPI IP-команды