# bsp_sd: on process
This commit is contained in:
parent
a1c6b1a30f
commit
3ec4aad771
24 changed files with 3327 additions and 633 deletions
|
|
@ -18,6 +18,7 @@ add_subdirectory(button)
|
|||
add_subdirectory(usb_cdc)
|
||||
add_subdirectory(sdram)
|
||||
add_subdirectory(qspi_flash)
|
||||
add_subdirectory(sd)
|
||||
|
||||
# Подавляем предупреждения при компиляции собственных .c файлов библиотеки
|
||||
target_compile_options(bsp_board PRIVATE -w)
|
||||
|
|
@ -31,6 +32,27 @@ target_compile_definitions(bsp_board PUBLIC CPU_MIMXRT1052CVJ5B)
|
|||
# sdk_device PUBLIC — транзитивно подтянется во все firmware таргеты
|
||||
target_link_libraries(bsp_board PUBLIC sdk_device sdk_clock sdk_common
|
||||
sdk_lpuart)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# bsp_sdmmc_config — board-level конфигурация SDMMC (BOARD_SD_Config и пр.)
|
||||
# Отдельный таргет, чтобы sdk_sdmmc_sd не тянулся во все бинарники через
|
||||
# bsp_board. Линкуется только теми, кто реально работает с SD: bsp_usd →
|
||||
# bsp_sdmmc_config
|
||||
# -----------------------------------------------------------------------------
|
||||
add_library(bsp_sdmmc_config STATIC generated/sdmmc_config.c)
|
||||
|
||||
target_include_directories(bsp_sdmmc_config PUBLIC generated)
|
||||
|
||||
target_compile_definitions(bsp_sdmmc_config PUBLIC SD_ENABLED)
|
||||
|
||||
target_link_libraries(
|
||||
bsp_sdmmc_config
|
||||
PUBLIC bsp_board # board.h, pin_mux.h, clock_config.h, fsl_gpio.h
|
||||
PUBLIC sdk_sdmmc_sd # fsl_sd.h, fsl_sdmmc_host.h, sdmmchost_t
|
||||
)
|
||||
|
||||
target_compile_options(bsp_sdmmc_config PRIVATE -w)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Boot-стратегии — INTERFACE
|
||||
# ------------------------------------------------------------------
|
||||
|
|
|
|||
150
bsp/generated/sdmmc_config.c
Normal file
150
bsp/generated/sdmmc_config.c
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* sdmmc_config.c — board-level реализация SDMMC для MIMXRT1052CVJ5B.
|
||||
*/
|
||||
|
||||
#define SD_ENABLED /* нужен для fsl_sd.h, до включений */
|
||||
|
||||
#include "sdmmc_config.h"
|
||||
|
||||
#include "fsl_iomuxc.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Статические объекты хоста (не экспортируются)
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/* DMA-дескрипторы: некэшируемая секция, выравнивание по требованию USDHC. */
|
||||
AT_NONCACHEABLE_SECTION_ALIGN(
|
||||
static uint32_t s_dma_buf[BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE],
|
||||
SDMMCHOST_DMA_DESCRIPTOR_BUFFER_ALIGN_SIZE);
|
||||
|
||||
static sdmmchost_t s_host;
|
||||
static sd_detect_card_t s_cd;
|
||||
static sd_io_voltage_t s_io_voltage = {
|
||||
.type = BOARD_SDMMC_SD_IO_VOLTAGE_TYPE,
|
||||
.func = NULL, /* управление через регистры USDHC, не через внешний LDO */
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Внутренние функции
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Возвращает частоту источника USDHC1.
|
||||
*
|
||||
* BOARD_BootClockRUN() уже настроил SysPll и PFD0 → не трогаем PLL.
|
||||
* Просто возвращаем известное значение из clock_config.h.
|
||||
*/
|
||||
static uint32_t get_usdhc1_src_clock_hz(void)
|
||||
{
|
||||
return BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT; /* 198 000 000 Hz */
|
||||
}
|
||||
|
||||
/*
|
||||
* Управление питанием карты: GPIO1[19] (SdPwr), active-high.
|
||||
*/
|
||||
static void sd_power_control(bool enable)
|
||||
{
|
||||
GPIO_PinWrite(BOARD_SDMMC_SD_PWR_GPIO_BASE, BOARD_SDMMC_SD_PWR_GPIO_PIN, enable ? 1U : 0U);
|
||||
}
|
||||
|
||||
/*
|
||||
* Инициализация GPIO питания карты как выход, начальное состояние — выкл.
|
||||
* Вызывается однократно из BOARD_SD_Config().
|
||||
*/
|
||||
static void sd_power_init(void)
|
||||
{
|
||||
const gpio_pin_config_t cfg = {
|
||||
.direction = kGPIO_DigitalOutput,
|
||||
.outputLogic = 0U, /* питание выключено при старте */
|
||||
.interruptMode = kGPIO_NoIntmode,
|
||||
};
|
||||
GPIO_PinInit(BOARD_SDMMC_SD_PWR_GPIO_BASE, BOARD_SDMMC_SD_PWR_GPIO_PIN, &cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Динамическая настройка пад-конфигурации линий SD в зависимости от частоты.
|
||||
* Вызывается SDMMC стеком при смене скорости (HS, SDR50, SDR104).
|
||||
*
|
||||
* speed/strength подобраны по таблице EVK — для данной платы проверить
|
||||
* при трассировке > 50 MHz.
|
||||
*/
|
||||
static void sd_pin_config(uint32_t freq)
|
||||
{
|
||||
uint32_t speed;
|
||||
uint32_t strength;
|
||||
|
||||
if (freq <= 50000000U)
|
||||
{
|
||||
speed = 0U;
|
||||
strength = 7U;
|
||||
}
|
||||
else if (freq <= 100000000U)
|
||||
{
|
||||
speed = 2U;
|
||||
strength = 7U;
|
||||
}
|
||||
else
|
||||
{
|
||||
speed = 3U;
|
||||
strength = 7U;
|
||||
}
|
||||
|
||||
const uint32_t pad = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
|
||||
IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |
|
||||
IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
|
||||
IOMUXC_SW_PAD_CTL_PAD_PUS(1) /* 47k pull-up */
|
||||
| IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
|
||||
|
||||
const uint32_t clk_pad = IOMUXC_SW_PAD_CTL_PAD_SPEED(speed) | IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |
|
||||
IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |
|
||||
IOMUXC_SW_PAD_CTL_PAD_PUS(0) /* no pull on CLK */
|
||||
| IOMUXC_SW_PAD_CTL_PAD_DSE(strength);
|
||||
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, pad);
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, clk_pad);
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, pad);
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, pad);
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, pad);
|
||||
IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, pad);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Публичный API
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef SD_ENABLED
|
||||
void BOARD_SD_Config(void *card, sd_cd_t cd, uint32_t host_irq_priority, void *user_data)
|
||||
{
|
||||
assert(card != NULL);
|
||||
|
||||
/* --- host --- */
|
||||
s_host.dmaDesBuffer = s_dma_buf;
|
||||
s_host.dmaDesBufferWordsNum = BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE;
|
||||
s_host.enableCacheControl = BOARD_SDMMC_HOST_CACHE_CONTROL;
|
||||
|
||||
sd_card_t *sd = (sd_card_t *) card;
|
||||
|
||||
sd->host = &s_host;
|
||||
sd->host->hostController.base = BOARD_SDMMC_SD_HOST_BASEADDR;
|
||||
sd->host->hostController.sourceClock_Hz = get_usdhc1_src_clock_hz();
|
||||
|
||||
/* --- card detect: HostCD, GPIO-прерывание не нужно --- */
|
||||
s_cd.cdDebounce_ms = BOARD_SDMMC_SD_CD_DEBOUNCE_MS;
|
||||
s_cd.type = BOARD_SDMMC_SD_CD_TYPE; /* kSD_DetectCardByHostCD */
|
||||
s_cd.cardDetected = NULL; /* SDK читает PRSSTAT самостоятельно */
|
||||
s_cd.callback = cd; /* обычно NULL из bsp_sd */
|
||||
s_cd.userData = user_data;
|
||||
|
||||
sd->usrParam.cd = &s_cd;
|
||||
sd->usrParam.pwr = sd_power_control;
|
||||
sd->usrParam.ioStrength = sd_pin_config;
|
||||
sd->usrParam.ioVoltage = &s_io_voltage;
|
||||
sd->usrParam.maxFreq = BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ;
|
||||
|
||||
/* --- GPIO питания --- */
|
||||
sd_power_init();
|
||||
|
||||
/* --- приоритет прерывания хоста --- */
|
||||
NVIC_SetPriority(BOARD_SDMMC_SD_HOST_IRQ, host_irq_priority);
|
||||
}
|
||||
#endif /* SD_ENABLED */
|
||||
80
bsp/generated/sdmmc_config.h
Normal file
80
bsp/generated/sdmmc_config.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* sdmmc_config.h — board-level конфигурация SDMMC для MIMXRT1052CVJ5B.
|
||||
*
|
||||
* SD_CD : GPIO_B1_12 → USDHC1.usdhc_cd_b (периферийный сигнал, не GPIO).
|
||||
* Детект через USDHC_GetPresentStatusFlags → kSD_DetectCardByHostCD.
|
||||
* GPIO-прерывание на CD не нужно.
|
||||
*
|
||||
* SD_PWR: GPIO_AD_B1_03 → GPIO1[19] (SdPwr).
|
||||
* Active-high: 1 = питание включено.
|
||||
*/
|
||||
|
||||
#ifndef BSP_SDMMC_CONFIG_H
|
||||
#define BSP_SDMMC_CONFIG_H
|
||||
|
||||
#include "clock_config.h"
|
||||
#include "fsl_common.h"
|
||||
#include "fsl_gpio.h"
|
||||
#include "fsl_sdmmc_common.h"
|
||||
#include "fsl_sdmmc_host.h"
|
||||
|
||||
#ifdef SD_ENABLED
|
||||
#include "fsl_sd.h"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Host controller
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_SD_HOST_BASEADDR USDHC1
|
||||
#define BOARD_SDMMC_SD_HOST_IRQ USDHC1_IRQn
|
||||
#define BOARD_SDMMC_SD_HOST_IRQ_PRIORITY 5U
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Card detect
|
||||
* CD_B подключён как периферийный сигнал USDHC1 — детект через регистр
|
||||
* PRSSTAT, а не через GPIO. Прерывание и callback на CD не используются.
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_SD_CD_TYPE kSD_DetectCardByHostCD
|
||||
#define BOARD_SDMMC_SD_CD_DEBOUNCE_MS 100U
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Card power — GPIO1[19] (GPIO_AD_B1_03, SdPwr), active-high
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_SD_PWR_GPIO_BASE GPIO1
|
||||
#define BOARD_SDMMC_SD_PWR_GPIO_PIN 19U
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* IO voltage — управляется хостом (LDO внутри USDHC)
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_SD_IO_VOLTAGE_TYPE kSD_IOVoltageCtrlByHost
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* DMA и кэш
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_HOST_DMA_DESCRIPTOR_BUFFER_SIZE 32U
|
||||
#define BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE 32U
|
||||
#define BOARD_SDMMC_HOST_CACHE_CONTROL kSDMMCHOST_CacheControlRWBuffer
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Максимальная частота (SDR104)
|
||||
* ------------------------------------------------------------------------- */
|
||||
#define BOARD_SDMMC_SD_HOST_SUPPORT_SDR104_FREQ 200000000U
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifdef SD_ENABLED
|
||||
/*
|
||||
* Конфигурирует sd_card_t: host, CD, power, IO voltage, частота.
|
||||
* cd и userData передаются NULL из bsp_sd — CD управляется хостом.
|
||||
*/
|
||||
void BOARD_SD_Config(void *card, sd_cd_t cd, uint32_t host_irq_priority, void *user_data);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_SDMMC_CONFIG_H */
|
||||
|
|
@ -23,23 +23,38 @@
|
|||
|
||||
### Проблема
|
||||
|
||||
Прошивка исполняется XIP из того же Flash через FlexSPI AHB-интерфейс.
|
||||
CPU непрерывно читает инструкции через AHB, который маршрутизируется по
|
||||
LUT-слоту 0. Любая IP-команда FlexSPI прерывает AHB-путь на время
|
||||
выполнения команды. Если в момент IP-команды CPU попытается фетчить
|
||||
инструкцию из Flash — HardFault.
|
||||
Прошивка исполняется XIP из Flash через FlexSPI AHB-интерфейс.
|
||||
CPU непрерывно фетчит инструкции из Flash по AHB — через LUT-слот 0.
|
||||
Любая IP-команда FlexSPI блокирует AHB-путь на время выполнения.
|
||||
Если в этот момент CPU попытается фетчить инструкцию из Flash — **HardFault**.
|
||||
|
||||
### Решение
|
||||
### Решение: ITCM + IRQ lock
|
||||
|
||||
Все функции, обращающиеся к регистрам FlexSPI (IPCMD, IPCR0/1, RFDR, TFDR,
|
||||
LUT, INTR, …), размещены в **ITCM** через `AT_QUICKACCESS_SECTION_CODE`.
|
||||
Инструкции этих функций загружаются в ITCM при старте и CPU не обращается
|
||||
к Flash во время их выполнения.
|
||||
Все функции, обращающиеся к регистрам FlexSPI, размещены в **ITCM**
|
||||
(`0x00000000`) через `AT_QUICKACCESS_SECTION_CODE`. ITCM подключён к CPU
|
||||
по выделенной шине (не AHB), поэтому фетч инструкций из ITCM не конкурирует
|
||||
с IP-командами FlexSPI.
|
||||
|
||||
AHB prefetch отключается (`AHBCR.PREFETCHEN = 0`) перед каждой серией
|
||||
IP-транзакций и восстанавливается после (`qspi_ahb_disable` / `qspi_ahb_enable`).
|
||||
Это дополнительно предотвращает спекулятивные AHB-чтения Flash во время
|
||||
IP-команд.
|
||||
Дополнительно, каждая публичная операция выполняется под **IRQ lock**
|
||||
(`qspi_irq_lock` / `qspi_irq_unlock` с `__get_PRIMASK()` + `DSB` + `ISB`):
|
||||
это гарантирует, что прерывание не застанет FlexSPI в середине IP-транзакции.
|
||||
IRQ unlock восстанавливает предыдущий `PRIMASK`, не включает IRQ безусловно —
|
||||
вызов из уже заблокированного контекста корректен.
|
||||
|
||||
AHB prefetch отключается (`AHBCR.PREFETCHEN = 0`) перед серией IP-транзакций
|
||||
и восстанавливается после.
|
||||
|
||||
### Обязательный дефайн в CMakeLists потребителя
|
||||
|
||||
```cmake
|
||||
target_compile_definitions(firmware_test PRIVATE
|
||||
__STARTUP_INITIALIZE_RAMFUNCTION # ← обязательно
|
||||
__STARTUP_CLEAR_BSS)
|
||||
```
|
||||
|
||||
Без `__STARTUP_INITIALIZE_RAMFUNCTION` startup-файл NXP SDK не копирует
|
||||
`CodeQuickAccess` секцию из Flash в ITCM. В ITCM остаются нули. Первый же
|
||||
вызов любой ITCM-функции вызывает **HardFault**.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -47,33 +62,31 @@ IP-команд.
|
|||
|
||||
### Почему не Enter 4-Byte Mode (0xB7)
|
||||
|
||||
FDCB задаёт XIP слот 0 с 24-bit адресацией для **всех** чипов. Если
|
||||
переключить чип в 4-byte mode командой 0xB7, следующий AHB-фетч
|
||||
инструкции из Flash пойдёт через слот 0 с 24-bit адресом, а чип теперь
|
||||
ждёт 32-bit — **HardFault**.
|
||||
FDCB фиксирует XIP-слот 0 в режиме 24-bit адресации на всех чипах.
|
||||
Переключение чипа командой 0xB7 сломало бы XIP — AHB продолжал бы
|
||||
посылать 24-bit адреса, чип ждал бы 32-bit → **HardFault**.
|
||||
|
||||
### Dedicated 4-byte address opcodes
|
||||
|
||||
W25Q256/512 имеют отдельный набор opcodes, принимающих 32-bit адрес
|
||||
**независимо от текущего режима адресации чипа**:
|
||||
W25Q256/512 принимают 32-bit адрес через отдельный набор opcodes — без
|
||||
изменения режима адресации чипа:
|
||||
|
||||
| Операция | 3-byte opcode (W25Q64/128) | 4-byte opcode (W25Q256/512) |
|
||||
|-------------------|----------------------------|-----------------------------|
|
||||
| Операция | W25Q64/128 (3-byte) | W25Q256/512 (4-byte) |
|
||||
|-------------------|---------------------|----------------------|
|
||||
| Sector Erase 4KB | `0x20` | `0x21` |
|
||||
| Block Erase 32KB | `0x52` | `0x5C` |
|
||||
| Block Erase 64KB | `0xD8` | `0xDC` |
|
||||
| Quad Page Program | `0x32` | `0x34` |
|
||||
| Quad Output Read | `0x6B` | `0x6C` |
|
||||
| IP Quad Out Read | `0x6B` | `0x6C` |
|
||||
|
||||
Слот 0 (XIP) **не изменяется**. Чип остаётся в 24-bit режиме. XIP работает
|
||||
непрерывно на всех чипах.
|
||||
Слот 0 (XIP) **не изменяется**. XIP работает непрерывно на всех чипах.
|
||||
|
||||
---
|
||||
|
||||
## LUT-слоты
|
||||
|
||||
| Слот | Константа | Команда | Зависит от чипа |
|
||||
|------|----------------|----------------------------|-----------------|
|
||||
|------|----------------|-----------------------------|-----------------|
|
||||
| 0 | (XIP, FDCB) | Quad Read | Нет (не трогаем)|
|
||||
| 1 | LSEQ_READ_SR1 | Read SR1 (0x05) | Нет |
|
||||
| 2 | LSEQ_WR_EN | Write Enable (0x06) | Нет |
|
||||
|
|
@ -87,15 +100,30 @@ W25Q256/512 имеют отдельный набор opcodes, принимающ
|
|||
| 10 | LSEQ_ERASE_64K | Block Erase 64KB (0xD8/0xDC)| Да |
|
||||
| 11 | LSEQ_IP_READ | Quad Out Read (0x6B/0x6C) | Да |
|
||||
|
||||
Слоты 1–11 обновляются в `bsp_qspi_init()` под конкретный чип.
|
||||
Слот 0 никогда не изменяется BSP-кодом.
|
||||
|
||||
---
|
||||
|
||||
## Watermark FIFO
|
||||
|
||||
Размер watermark-юнита читается из регистров `IPRXFCR.RXWMRK` и
|
||||
`IPTXFCR.TXWMRK` в рантайме — не зашит константой. Это гарантирует
|
||||
корректную работу если FDCB или SDK изменили настройки watermark по
|
||||
умолчанию.
|
||||
|
||||
---
|
||||
|
||||
## Публичный API
|
||||
|
||||
Все публичные функции размещены в ITCM (`AT_QUICKACCESS_SECTION_CODE`) и
|
||||
выполняются под IRQ lock.
|
||||
|
||||
```c
|
||||
/* Инициализация — первый вызов */
|
||||
/* Инициализация — вызвать до bsp_tick_init() и любой другой функции модуля */
|
||||
bsp_status_t bsp_qspi_init(void);
|
||||
|
||||
/* Чтение JEDEC ID */
|
||||
/* Чтение JEDEC ID (0x9F) */
|
||||
bsp_status_t bsp_qspi_read_jedec_id(bsp_qspi_jedec_t *p_jedec);
|
||||
|
||||
/* Стирание */
|
||||
|
|
@ -103,72 +131,85 @@ bsp_status_t bsp_qspi_erase_sector(uint32_t addr); /* 4KB, ~45 мс */
|
|||
bsp_status_t bsp_qspi_erase_block_32k(uint32_t addr); /* 32KB, ~120 мс */
|
||||
bsp_status_t bsp_qspi_erase_block_64k(uint32_t addr); /* 64KB, ~150 мс */
|
||||
|
||||
/* Запись одной страницы */
|
||||
/* Запись одной страницы (256 байт) */
|
||||
bsp_status_t bsp_qspi_write_page(uint32_t addr, const uint8_t *p_data); /* ~3 мс */
|
||||
|
||||
/* Чтение произвольного числа байт (через IP-команду, не AHB) */
|
||||
/* Чтение через IP-команду (не AHB/XIP) */
|
||||
bsp_status_t bsp_qspi_read(uint32_t addr, uint8_t *p_buf, size_t size);
|
||||
|
||||
/* Размер Flash — доступен после init */
|
||||
/* Размер Flash — доступен после bsp_qspi_init() */
|
||||
uint32_t bsp_qspi_flash_size(void);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Выбор операции стирания для массовой очистки
|
||||
|
||||
| Объём очистки | Рекомендуемая операция | Примерное время |
|
||||
|------------------|------------------------|-----------------|
|
||||
| < 32 KB | `erase_sector` (4KB) | пропорционально |
|
||||
| 32 KB — 1 MB | `erase_block_32k` | 120 мс / 32KB |
|
||||
| > 1 MB | `erase_block_64k` | 150 мс / 64KB |
|
||||
|
||||
Пример: очистка 4 MB через 64KB блоки = 64 операции × 150 мс ≈ **9.6 с**
|
||||
против 1024 × 45 мс ≈ **46 с** через 4KB секторы.
|
||||
Все функции возвращают `BSP_OK` при успехе или `BSP_ERR_HW` при ошибке
|
||||
FlexSPI / неверном аргументе. `BSP_ERR_HW` должен присутствовать в
|
||||
`bsp/common/include/bsp/status.h`.
|
||||
|
||||
---
|
||||
|
||||
## Порядок вызова
|
||||
## Порядок инициализации
|
||||
|
||||
`bsp_qspi_init()` должна вызываться **до** `bsp_tick_init()`:
|
||||
|
||||
```c
|
||||
/* 1. Инициализация (один раз) */
|
||||
if (bsp_qspi_init() != BSP_OK) { /* обработка ошибки */ }
|
||||
|
||||
/* 2. Операции */
|
||||
bsp_qspi_erase_sector(addr); /* блокирует ~45 мс */
|
||||
|
||||
|
||||
bsp_qspi_write_page(addr, buf); /* блокирует ~3 мс */
|
||||
|
||||
bsp_qspi_read(addr, buf, 256); /* быстро */
|
||||
/* main.c */
|
||||
board_hw_init();
|
||||
bsp_qspi_init(); /* ← сначала QSPI, до SysTick */
|
||||
bsp_tick_init(); /* ← потом SysTick */
|
||||
bsp_usb_cdc_init();
|
||||
```
|
||||
|
||||
Причина: `bsp_qspi_init()` и все ITCM-функции выполняются под полным
|
||||
IRQ lock. Если SysTick уже запущен и прерывание сработает в момент
|
||||
IP-команды — возможен AHB stall. Порядок инициализации устраняет эту
|
||||
гонку при первом запуске.
|
||||
|
||||
---
|
||||
|
||||
## Выбор операции стирания
|
||||
|
||||
| Объём очистки | Рекомендация | Время |
|
||||
|---------------|------------------------|-----------------|
|
||||
| < 32 KB | `erase_sector` (4KB) | пропорционально |
|
||||
| 32 KB — 1 MB | `erase_block_32k` | ~120 мс / 32KB |
|
||||
| > 1 MB | `erase_block_64k` | ~150 мс / 64KB |
|
||||
|
||||
Пример: 4 MB через 64KB = 64 × 150 мс ≈ **9.6 с**
|
||||
против 1024 × 45 мс ≈ **46 с** через 4KB.
|
||||
|
||||
---
|
||||
|
||||
## CMake
|
||||
|
||||
```cmake
|
||||
# bsp/qspi/CMakeLists.txt
|
||||
target_link_libraries(bsp_qspi
|
||||
# bsp/qspi_flash/CMakeLists.txt
|
||||
target_link_libraries(bsp_qspi_flash
|
||||
PUBLIC bsp_status
|
||||
PRIVATE bsp_board sdk_flexspi
|
||||
)
|
||||
```
|
||||
|
||||
Потребители (например, `firmware_test`) линкуют `bsp_qspi`:
|
||||
Потребитель (`firmware_test`):
|
||||
|
||||
```cmake
|
||||
target_link_libraries(firmware_test PRIVATE ... bsp_qspi)
|
||||
target_link_libraries(firmware_test PRIVATE
|
||||
bsp_qspi_flash
|
||||
...
|
||||
)
|
||||
|
||||
target_compile_definitions(firmware_test PRIVATE
|
||||
__STARTUP_INITIALIZE_RAMFUNCTION # обязательно для ITCM-функций
|
||||
__STARTUP_CLEAR_BSS
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
- `bsp_qspi_write_page()` записывает строго одну страницу (256 байт).
|
||||
Запись через границу страницы не поддерживается — вызывающий код
|
||||
обязан выровнять адрес.
|
||||
- `bsp_qspi_write_page()` — строго одна страница (256 байт). Адрес обязан
|
||||
быть выровнен на `BSP_QSPI_PAGE_SIZE`. Запись через границу страницы не
|
||||
поддерживается.
|
||||
- Нет timeout в `qspi_wait_not_busy()`. Зависание из-за дефектного чипа
|
||||
потребует watchdog reset. Для диагностической прошивки это приемлемо.
|
||||
- Chip Erase (0xC7) не реализован — слишком деструктивно для XIP-прошивки.
|
||||
Используй `erase_block_64k` в цикле по всему адресному пространству.
|
||||
- Chip Erase (0xC7) не реализован — слишком деструктивно при XIP-исполнении.
|
||||
|
|
|
|||
10
bsp/sd/CMakeLists.txt
Normal file
10
bsp/sd/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
add_library(bsp_sd STATIC src/sd.c)
|
||||
|
||||
target_include_directories(bsp_sd PUBLIC include)
|
||||
|
||||
target_link_libraries(
|
||||
bsp_sd
|
||||
PUBLIC bsp_status # bsp_status_t
|
||||
PRIVATE bsp_sdmmc_config # BOARD_SD_Config, sdmmc_config.h тащит sdk_sdmmc_sd
|
||||
# транзитивно
|
||||
)
|
||||
130
bsp/sd/README.md
Normal file
130
bsp/sd/README.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# bsp_sd — SD host-контроллер (USDHC1)
|
||||
|
||||
Модуль инициализирует SD host-контроллер и проверяет наличие карты.
|
||||
Файловой системой не занимается — это ответственность `bsp_usd` (поверх) или
|
||||
приложения напрямую.
|
||||
|
||||
## Место в архитектуре
|
||||
|
||||
Каждый слой знает только о слое ниже — зависимости не пересекают границы.
|
||||
|
||||
```bash
|
||||
firmware_test / tft_app
|
||||
│
|
||||
▼
|
||||
bsp_usd ← монтирование FatFS, тест R/W
|
||||
│
|
||||
├──► firmware_test_fatfs ← ff.c + fsl_sd_disk + diskio (bare-metal ffconf)
|
||||
│ tft_app_fatfs ← ff.c + fsl_sd_disk + diskio (FreeRTOS ffconf)
|
||||
│ │
|
||||
│ ▼
|
||||
│ port/fatfs/sd ← diskio_sd.c: microsd_disk_* → fsl_sd_disk
|
||||
│ │
|
||||
▼ ▼
|
||||
bsp_sd ← этот модуль: host init / deinit / card detect
|
||||
│
|
||||
▼
|
||||
bsp/generated/sdmmc_config ← board-level: BOARD_SD_Config, GPIO питания, pad config
|
||||
│
|
||||
▼
|
||||
sdk_sdmmc_sd ← NXP: fsl_sd, fsl_sdmmc_common, fsl_sdmmc_host (non-blocking)
|
||||
│
|
||||
▼
|
||||
sdk_usdhc ← NXP HAL: fsl_usdhc
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Аппаратный контекст
|
||||
|
||||
| Сигнал | Пин MCU | Конфигурация |
|
||||
|----------|-----------------|---------------------------------------------------|
|
||||
| CLK | GPIO_SD_B0_01 | USDHC1_CLK, периферийный режим |
|
||||
| CMD | GPIO_SD_B0_00 | USDHC1_CMD, периферийный режим |
|
||||
| D0–D3 | GPIO_SD_B0_02–05| USDHC1_DATA0–3, периферийный режим |
|
||||
| CD_B | GPIO_B1_12 | USDHC1_CD_B — детект через USDHC PRSSTAT |
|
||||
| SdPwr | GPIO_AD_B1_03 | GPIO1[19], active-high, управляется SDK через BSP |
|
||||
|
||||
**CD_B** подключён как периферийный сигнал USDHC1, а не как GPIO. Детект карты
|
||||
читается через `USDHC_GetPresentStatusFlags` → `kUSDHC_CardInsertedFlag`.
|
||||
GPIO-прерывание на CD не используется (`kSD_DetectCardByHostCD`).
|
||||
|
||||
**SdPwr** инициализируется в `BOARD_SD_Config()` как GPIO-выход, выключен при старте.
|
||||
SDK включает питание автоматически в процессе `SD_HostInit()` через callback.
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
### `bsp_sd_init(void)`
|
||||
|
||||
Конфигурирует SDMMC host однократно (`BOARD_SD_Config`) и запускает
|
||||
host-контроллер (`SD_HostInit`).
|
||||
|
||||
Повторный вызов без `bsp_sd_deinit` — no-op, возвращает `BSP_OK`.
|
||||
|
||||
Возвращает:
|
||||
|
||||
- `BSP_OK` — host готов к работе;
|
||||
- `BSP_ERR_INIT` — `SD_HostInit` вернул ошибку.
|
||||
|
||||
### `bsp_sd_deinit(void)`
|
||||
|
||||
Останавливает host-контроллер и отключает питание карты.
|
||||
Безопасен при вызове до `init` или повторно после `deinit`.
|
||||
|
||||
Возвращает:
|
||||
|
||||
- `BSP_OK` — всегда.
|
||||
|
||||
### `bsp_sd_is_inserted(void)`
|
||||
|
||||
Читает регистр `USDHC1 PRSSTAT`. Не требует предварительного `bsp_sd_init()` —
|
||||
включает тактирование USDHC1 самостоятельно через `CLOCK_EnableClock`.
|
||||
|
||||
Возвращает:
|
||||
|
||||
- `true` — карта вставлена;
|
||||
- `false` — карта отсутствует.
|
||||
|
||||
---
|
||||
|
||||
## Разделение ответственности: bsp_sd vs sdmmc_config vs port_fatfs_sd
|
||||
|
||||
| Слой | Что делает | Где живёт |
|
||||
|-----------------------|---------------------------------------------------------|------------------------|
|
||||
| `sdmmc_config` | Константы платы, `BOARD_SD_Config`, GPIO питания, pads | `bsp/generated/` |
|
||||
| `bsp_sd` | `SD_HostInit/Deinit`, идемпотентность, card detect | `bsp/sd/` |
|
||||
| `port_fatfs_sd` | `microsd_disk_*` → `fsl_sd_disk` (FatFS diskio glue) | `port/fatfs/sd/` |
|
||||
| `firmware_test_fatfs` | `ff.c` + `fsl_sd_disk` + `diskio.c` (bare-metal ffconf)| `firmware/test/fatfs/` |
|
||||
| `tft_app_fatfs` | `ff.c` + `fsl_sd_disk` + `diskio.c` (FreeRTOS ffconf) | `firmware/tft_app/fatfs/` (будущее) |
|
||||
|
||||
**Почему `ff.c` и `fsl_sd_disk.c` не компилируются один раз как общая библиотека:**
|
||||
оба включают `ff.h` → `ffconf.h`, который разный для `firmware_test` (bare-metal,
|
||||
`FF_FS_REENTRANT=0`) и `tft_app` (FreeRTOS, `FF_FS_REENTRANT=1`, `FF_VOLUMES=3`).
|
||||
Общий только `port_fatfs_sd` — он не включает `ff.h` напрямую.
|
||||
|
||||
---
|
||||
|
||||
## Зависимости
|
||||
|
||||
```cmake
|
||||
target_link_libraries(bsp_sd
|
||||
PUBLIC bsp_status # bsp_status_t
|
||||
PRIVATE bsp_sdmmc_config # BOARD_SD_Config, sdmmc_config.h, sdk_sdmmc_sd
|
||||
)
|
||||
```
|
||||
|
||||
`sdk_sdmmc_sd` — транзитивно через `bsp_sdmmc_config`.
|
||||
`sdk_usdhc` — транзитивно через `sdk_sdmmc_sd`.
|
||||
|
||||
---
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Модуль рассчитан на одну карту (USDHC1, `g_sd` — единственный дескриптор).
|
||||
- `bsp_sd_is_inserted()` читает аппаратный регистр без дебаунса. При
|
||||
механическом детекте возможны ложные срабатывания в момент вставки/извлечения —
|
||||
добавляй дебаунс в вызывающем коде если нужно.
|
||||
- Hot-swap не поддерживается: `bsp_sd_deinit()` + `bsp_sd_init()` между сессиями.
|
||||
35
bsp/sd/include/bsp/sd.h
Normal file
35
bsp/sd/include/bsp/sd.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* bsp_sd — инициализация SD host-контроллера и детект карты.
|
||||
*
|
||||
* Модуль управляет только железом (USDHC host, питание карты).
|
||||
* Монтирование файловой системы — в bsp_usd поверх этого модуля.
|
||||
*/
|
||||
|
||||
#ifndef BSP_SD_H
|
||||
#define BSP_SD_H
|
||||
|
||||
#include "bsp/status.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Инициализировать SD host-контроллер.
|
||||
* Вызывать до любых операций с картой.
|
||||
* Повторный вызов без deinit возвращает BSP_OK (идемпотентен).
|
||||
*/
|
||||
bsp_status_t bsp_sd_init(void);
|
||||
|
||||
/*
|
||||
* Деинициализировать SD host-контроллер и отключить питание карты.
|
||||
* Безопасен при вызове до init или после deinit.
|
||||
*/
|
||||
bsp_status_t bsp_sd_deinit(void);
|
||||
|
||||
/*
|
||||
* Проверить физическое наличие карты через регистр USDHC PRSSTAT.
|
||||
* Не требует предварительного вызова bsp_sd_init().
|
||||
* Включает тактирование USDHC1 на время чтения регистра.
|
||||
*/
|
||||
bool bsp_sd_is_inserted(void);
|
||||
|
||||
#endif /* BSP_SD_H */
|
||||
93
bsp/sd/src/sd.c
Normal file
93
bsp/sd/src/sd.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* bsp_sd — реализация.
|
||||
*/
|
||||
|
||||
#include "bsp/sd.h"
|
||||
|
||||
#include "fsl_clock.h"
|
||||
#include "fsl_sd.h"
|
||||
#include "sdmmc_config.h" /* BOARD_SD_Config, BOARD_SDMMC_SD_HOST_BASEADDR */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Глобальный дескриптор карты — нужен SDK-стеку (передаётся по указателю
|
||||
* в BOARD_SD_Config и sd_disk_initialize через g_sd).
|
||||
* Объявлен без static — fsl_sd_disk.c ссылается на него как extern sd_card_t g_sd.
|
||||
* ------------------------------------------------------------------------- */
|
||||
extern sd_card_t g_sd;
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Состояние модуля
|
||||
* ------------------------------------------------------------------------- */
|
||||
static bool g_s_host_configured = false;
|
||||
static bool g_s_initialized = false;
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Внутренние функции
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Конфигурирует SDMMC host однократно.
|
||||
* Повторный вызов — no-op: BOARD_SD_Config не идемпотентен сам по себе
|
||||
* (переинициализирует GPIO питания), поэтому защищаем флагом.
|
||||
*/
|
||||
static void ensure_host_configured(void)
|
||||
{
|
||||
if (g_s_host_configured)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* cd=NULL, userData=NULL: CD управляется хостом через PRSSTAT */
|
||||
BOARD_SD_Config(&g_sd, NULL, BOARD_SDMMC_SD_HOST_IRQ_PRIORITY, NULL);
|
||||
g_s_host_configured = true;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Публичный API
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
bsp_status_t bsp_sd_init(void)
|
||||
{
|
||||
if (g_s_initialized)
|
||||
{
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
ensure_host_configured(); /* только BOARD_SD_Config — заполняет g_sd */
|
||||
|
||||
/*
|
||||
* Полный init (host + card) происходит в sd_disk_initialize → SD_Init,
|
||||
* который вызывается из f_mount → disk_initialize.
|
||||
*/
|
||||
|
||||
g_s_initialized = true;
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
bsp_status_t bsp_sd_deinit(void)
|
||||
{
|
||||
if (!g_s_initialized)
|
||||
{
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
SD_HostDeinit(&g_sd);
|
||||
SD_SetCardPower(&g_sd, false);
|
||||
|
||||
g_s_initialized = false;
|
||||
return BSP_OK;
|
||||
}
|
||||
|
||||
bool bsp_sd_is_inserted(void)
|
||||
{
|
||||
/*
|
||||
* CD_B подключён как периферийный сигнал USDHC1, поэтому детект —
|
||||
* через регистр PRSSTAT, а не GPIO.
|
||||
*
|
||||
* USDHC1 может быть ещё не тактирован в момент вызова (до init),
|
||||
* поэтому явно включаем clock. После init clock уже включён SDK-стеком,
|
||||
* повторный вызов CLOCK_EnableClock безвреден.
|
||||
*/
|
||||
CLOCK_EnableClock(kCLOCK_Usdhc1);
|
||||
uint32_t prsstat = USDHC_GetPresentStatusFlags(BOARD_SDMMC_SD_HOST_BASEADDR);
|
||||
return (prsstat & (uint32_t) kUSDHC_CardInsertedFlag) != 0U;
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
set(TARGET_NAME firmware_test)
|
||||
|
||||
add_subdirectory(fatfs)
|
||||
|
||||
add_executable(
|
||||
${TARGET_NAME}
|
||||
src/main.c
|
||||
|
|
@ -38,7 +40,9 @@ target_link_libraries(
|
|||
bsp_boot_xip
|
||||
bsp_usb_cdc
|
||||
bsp_sdram
|
||||
bsp_qspi_flash)
|
||||
bsp_qspi_flash
|
||||
bsp_sd
|
||||
firmware_test_fatfs)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Linker script
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
# firmware_test — Plan of Development
|
||||
|
||||
> Документ для нового треда. Содержит все принятые решения, текущий статус и
|
||||
> пошаговый план дальнейшей разработки.
|
||||
> Версия: 0.2 | Обновлён после реализации скелета + bsp_usb_cdc.
|
||||
> Версия: 0.4 | Обновлён после завершения Этапов 1–3 (bsp_sdram + bsp_qspi_flash).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -12,548 +10,282 @@
|
|||
Запускается через BootROM (USB SDP), без предварительной прошивки загрузчика.
|
||||
|
||||
**Стенд:**
|
||||
- Хост подключается через USB CDC ACM (J2) — единственный канал
|
||||
- Тесты с внешними сигналами управляются через M5StampPLC (реле, оптовходы)
|
||||
- Отдельный компьютер-сервер запускает pytest
|
||||
- Хост подключается через USB CDC ACM — единственный канал firmware_test
|
||||
- Тесты с внешними сигналами управляются через M5StampPLC
|
||||
- Сервер запускает `tools/hil/` (разработка) или `tools/production/` (производство)
|
||||
|
||||
---
|
||||
|
||||
## Статус на момент создания документа
|
||||
## Текущий статус
|
||||
|
||||
| Компонент | Статус | Примечание |
|
||||
|---|---|---|
|
||||
| `bsp_usb_cdc` | ✅ Готов | HIL тест пройден (`05_test_usb_cdc.py`) |
|
||||
| `firmware_test` скелет | ✅ Готов | `main.c` + `cli.c` + PING работает |
|
||||
| Host-тест CLI | ✅ Готов | `test_cli.c`, 8 тестов, зелёные |
|
||||
| `bsp_sdram` | ⬜ Не начат | |
|
||||
| `bsp_qspi` | ⬜ Не начат | |
|
||||
| `bsp_usd` | ⬜ Не начат | |
|
||||
| Протокол v2 | ⬜ Не начат | Эволюция от cmd/ok к event-driven |
|
||||
| Test runner | ⬜ Не начат | |
|
||||
| Provisioning | ⬜ Не начат | |
|
||||
|----------------------------|--------|------------|
|
||||
| `bsp_usb_cdc` | ✅ | HIL тест пройден |
|
||||
| firmware_test скелет | ✅ | `main.c` + `cli.c` |
|
||||
| Протокол v2 + test_runner | ✅ | JSON-lines event-driven |
|
||||
| `bsp_sdram` + `test_sdram` | ✅ | 4 фазы: addr/data/seq/retention |
|
||||
| `bsp_qspi_flash` | ✅ | W25Q64/128/256/512, ITCM, IRQ lock |
|
||||
| `test_qspi` | ✅ | JEDEC + erase + rw + addr range |
|
||||
| `bsp_usd` | ⬜ | Этап 4 |
|
||||
| `test_usd` | ⬜ | Этап 4 |
|
||||
| Display test | ⬜ | Этап 5 |
|
||||
| Button test | ⬜ | Этап 5 |
|
||||
| CAN test | ⬜ | Этап 6 (bsp_can ✅) |
|
||||
| UART TTL test | ⬜ | Этап 6 (bsp_uart_host ✅) |
|
||||
| UART ISO test | ⬜ | Этап 6 |
|
||||
| Opto test | ⬜ | Этап 6 (bsp_opto ✅) |
|
||||
| Provisioning | ⬜ | Этап 7 |
|
||||
|
||||
### Закрытые архитектурные решения
|
||||
---
|
||||
|
||||
## Закрытые архитектурные решения
|
||||
|
||||
> Не пересматривать без явного запроса.
|
||||
|
||||
- **[DECISION] Транспорт:** USB CDC ACM — единственный канал. UART не используется в firmware_test.
|
||||
- **[DECISION] Парсинг JSON:** без cJSON, строковый `strstr`. Входящее поле всегда `"cmd"` / `"type"`.
|
||||
- **[DECISION] SDRAM и DCD:** SEMC инициализируется DCD до `main()`. `bsp_sdram_init()` только верифицирует.
|
||||
- **[DECISION] SDRAM тест — не HIL ELF:** тест прогоняется командами через firmware_test, не отдельным ELF.
|
||||
- **[DECISION] IR и RTC:** не реализуются.
|
||||
- **Транспорт:** USB CDC ACM — единственный канал. UART не используется в firmware_test.
|
||||
- **Парсинг JSON:** без cJSON, строковый `strstr`. Входящее поле всегда `"type"` / `"cmd"`.
|
||||
- **SDRAM и DCD:** SEMC инициализируется DCD до `main()`. `bsp_sdram_init()` только верифицирует.
|
||||
- **SDRAM тест:** прогоняется командами через firmware_test, не отдельным HIL ELF.
|
||||
- **QSPI-функции в ITCM:** `AT_QUICKACCESS_SECTION_CODE` + `__STARTUP_INITIALIZE_RAMFUNCTION` в CMakeLists.
|
||||
- **QSPI IRQ lock:** `__get_PRIMASK()` + DSB/ISB. Публичные API под полным lock.
|
||||
- **W25Q256/512:** dedicated 4-byte opcodes, без Enter 4-Byte Mode (0xB7).
|
||||
- **Порядок init в main.c:** `bsp_qspi_init()` до `bsp_tick_init()`.
|
||||
- **IR и RTC:** не реализуются.
|
||||
- **Производственный runner:** Вариант D — отдельный `tools/production/` без pytest.
|
||||
|
||||
---
|
||||
|
||||
## Протокол v2 — решение, требующее принятия в новом треде
|
||||
## Этап 4 — `bsp_usd` + `test_usd`
|
||||
|
||||
Текущий скелет использует упрощённый протокол:
|
||||
```json
|
||||
{"cmd":"PING"} → {"ok":true,"result":"PONG"}
|
||||
### Аппаратный контекст
|
||||
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Интерфейс | USDHC (SDIO) |
|
||||
| Карта | microSD, вставляется оператором перед тестом |
|
||||
| Файловая система | FatFS (SDK middleware) |
|
||||
| Детект карты | GPIO (CD pin) или опрос через USDHC status |
|
||||
|
||||
### BSP API (предварительно)
|
||||
|
||||
```c
|
||||
/* bsp/usd/include/bsp/usd.h */
|
||||
|
||||
typedef enum {
|
||||
BSP_USD_OK = 0,
|
||||
BSP_USD_ERR_NO_CARD, /* карта не вставлена */
|
||||
BSP_USD_ERR_INIT, /* USDHC или FatFS init failed */
|
||||
BSP_USD_ERR_MOUNT, /* f_mount() failed */
|
||||
BSP_USD_ERR_RW, /* read/write/compare failed */
|
||||
} bsp_usd_status_t;
|
||||
|
||||
bsp_usd_status_t bsp_usd_init(void);
|
||||
bsp_usd_status_t bsp_usd_is_card_present(void);
|
||||
bsp_usd_status_t bsp_usd_test_rw(void); /* write + read + compare тестового файла */
|
||||
void bsp_usd_deinit(void);
|
||||
```
|
||||
|
||||
TODO.md описывает расширенный протокол с типами событий:
|
||||
```json
|
||||
{"type":"session_start","fw":"0.1.0","target":"IMXRT1052","uptime_ms":0}
|
||||
{"type":"test_begin","id":"sdram","name":"SDRAM 32MB","critical":true}
|
||||
{"type":"test_result","id":"sdram","status":"pass","ms":312}
|
||||
{"type":"summary","passed":7,"failed":0,"overall":"pass"}
|
||||
### test_usd — шаги
|
||||
|
||||
| Шаг | Действие | Время |
|
||||
|---|---|---|
|
||||
| 1: Card detect | `bsp_usd_is_card_present()` | < 1 мс |
|
||||
| 2: Mount | `f_mount()` — FAT/exFAT | < 200 мс |
|
||||
| 3: Write | Записать 4 KB тестовый файл | < 500 мс |
|
||||
| 4: Read + Compare | Прочитать и сравнить побайтово | < 200 мс |
|
||||
| 5: Unmount | `f_unmount()` | < 50 мс |
|
||||
|
||||
### Интерактивность
|
||||
|
||||
Тест помечен `requires_hil = false`, `pre_confirm_prompt = "Вставьте microSD и нажмите OK"`.
|
||||
test_runner ждёт `{"type":"confirm","id":"usd_insert","confirmed":true}` до вызова `run()`.
|
||||
Отказ или таймаут 30 с → `TEST_STATUS_SKIP`.
|
||||
|
||||
### Файлы
|
||||
|
||||
```
|
||||
|
||||
**Вопросы для обсуждения в треде:**
|
||||
|
||||
1. Переходить ли на v2 сразу или итерационно (сначала SDRAM с cmd/ok, потом рефакторинг)?
|
||||
2. Как обрабатывать `confirm_request` (display test) в cli.c — отдельный тип входящего сообщения?
|
||||
3. `session_start` — посылать ли при каждом `READY` или только по команде `START_SESSION`?
|
||||
|
||||
**Рекомендация:** реализовать v2 до добавления первого теста, иначе рефакторинг CLI затронет уже написанные тест-модули.
|
||||
|
||||
---
|
||||
|
||||
## Структура файлов — целевое состояние
|
||||
```
|
||||
firmware/test/
|
||||
bsp/usd/
|
||||
├── CMakeLists.txt
|
||||
├── README.md
|
||||
└── src/
|
||||
├── main.c # ✅ готов
|
||||
├── cli.h / cli.c # ✅ готов (v1), требует эволюции до v2
|
||||
├── protocol.h / protocol.c # ⬜ новый: сериализация ответов
|
||||
├── test_runner.h / .c # ⬜ новый: реестр + sequencer
|
||||
├── provisioning.h / .c # ⬜ новый: chip UID + provision_ack
|
||||
└── tests/
|
||||
├── test_sdram.h / .c # ⬜
|
||||
├── test_qspi.h / .c # ⬜
|
||||
├── test_usd.h / .c # ⬜
|
||||
├── test_display.h / .c # ⬜ интерактивный (кнопки)
|
||||
├── test_can.h / .c # ⬜ HIL (M5StampPLC)
|
||||
├── test_uart.h / .c # ⬜ HIL TTL + ISO
|
||||
└── test_opto.h / .c # ⬜ HIL (M5StampPLC)
|
||||
├── include/bsp/usd.h
|
||||
└── src/usd.c
|
||||
|
||||
bsp/
|
||||
├── sdram/ # ⬜ CMakeLists.txt + sdram.c (структура есть)
|
||||
├── qspi/ # ⬜ новый модуль
|
||||
└── usd/ # ⬜ новый модуль
|
||||
firmware/test/src/tests/test_usd.c
|
||||
```
|
||||
|
||||
### CMake
|
||||
|
||||
```cmake
|
||||
# bsp/usd/CMakeLists.txt
|
||||
target_link_libraries(bsp_usd
|
||||
PUBLIC bsp_status
|
||||
PRIVATE bsp_board sdk_usdhc middleware_fatfs
|
||||
)
|
||||
```
|
||||
|
||||
### Открытые вопросы перед реализацией
|
||||
|
||||
- [ ] Есть ли `sdk_usdhc` таргет в `sdk/CMakeLists.txt`?
|
||||
- [ ] Карта вставлена постоянно или оператор вставляет каждый раз?
|
||||
- [ ] Нужен ли Card Detect GPIO или только USDHC status?
|
||||
- [ ] Файловая система: FAT32 или exFAT (размер карт)?
|
||||
|
||||
---
|
||||
|
||||
## Матрица тестов
|
||||
## Этап 5 — Display + Button (интерактивные)
|
||||
|
||||
| ID | Название | Тип | Critical | HIL (M5) | HIL ELF | BSP | Статус |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| — | PING | cmd | — | — | — | — | ✅ |
|
||||
| `sdram` | SDRAM 32MB | self | ✅ | ❌ | ❌ | `bsp_sdram` | ⬜ |
|
||||
| `qspi` | QSPI Flash | self | ✅ | ❌ | ❌ | `bsp_qspi` | ⬜ |
|
||||
| `usd` | uSD (SDIO) | self | ✅ | ❌ | ❌ | `bsp_usd` | ⬜ |
|
||||
| `display` | Display RGB888 | interactive | ❌ | ❌ | ❌ | существующий BSP | ⬜ |
|
||||
| `can` | CAN | HIL | ❌ | ✅ | ❌ | `bsp_can` ✅ | ⬜ |
|
||||
| `uart_ttl` | UART TTL | HIL | ❌ | ✅ | ❌ | `bsp_uart_host` ✅ | ⬜ |
|
||||
| `uart_iso` | UART ISO +24V | HIL | ❌ | ✅ | ❌ | уточнить | ⬜ |
|
||||
| `opto` | Opto-in +24V | HIL | ❌ | ✅ | ❌ | `bsp_opto` ✅ | ⬜ |
|
||||
### test_display
|
||||
|
||||
**Колонка "HIL ELF":** отдельная RAM-прошивка через pyOCD. Для firmware_test тестов — не нужна, тесты идут через USB CDC.
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Critical | ❌ |
|
||||
| HIL | ❌ |
|
||||
| Confirm | Внутри `run()` — 4 отдельных confirm |
|
||||
|
||||
**Колонка "HIL (M5)":** нужна ли M5StampPLC для управления внешними сигналами.
|
||||
Шаги: заливка Red → confirm → Green → confirm → Blue → confirm → White → confirm.
|
||||
Каждый шаг посылает `confirm_request`, ждёт `confirm` с таймаутом 15 с.
|
||||
Итог = AND всех четырёх подтверждений.
|
||||
|
||||
---
|
||||
`detail` при FAIL содержит ID первого непрошедшего шага: `"display_blue not confirmed"`.
|
||||
|
||||
## Пошаговый план
|
||||
### test_buttons
|
||||
|
||||
### Этап 0 — Вопросы, требующие ответа до кода
|
||||
| Параметр | Значение |
|
||||
|---|---|
|
||||
| Critical | ❌ |
|
||||
| HIL | ❌ |
|
||||
| Confirm | prompt only (детект через bsp_button) |
|
||||
|
||||
Обсудить в начале треда:
|
||||
Шаги: Test_But_1 → Test_But_2. Таргет посылает `confirm_request` как инструкцию
|
||||
оператору, детектирует нажатие через `bsp_button` — JSON confirm не нужен.
|
||||
Таймаут 10 с на каждую кнопку.
|
||||
|
||||
- Протокол v2: переходить сейчас или после SDRAM?
|
||||
- `uart_iso`: есть отдельный BSP модуль или это тот же `bsp_uart_host` с другими параметрами?
|
||||
- `usd`: карта вставлена постоянно на плате или оператор вставляет перед тестом?
|
||||
- QSPI: какой конкретно чип (W25Q128?), есть ли уже sdk_flexspi таргет в CMake?
|
||||
### Аппаратный контекст кнопок
|
||||
|
||||
---
|
||||
|
||||
### Этап 1 — Протокол v2 + Test runner скелет
|
||||
|
||||
**Цель:** эволюция cli.c → protocol.c + test_runner.c. После этого этапа добавление каждого теста — одна строка в реестре.
|
||||
|
||||
**Файлы:**
|
||||
```
|
||||
firmware/test/src/
|
||||
├── cli.c ← упрощается: только IO (read/write/buffer)
|
||||
├── protocol.h/.c ← новый: сериализация всех типов сообщений
|
||||
├── test_module.h ← новый: интерфейс тест-модуля
|
||||
└── test_runner.h/.c ← новый: реестр + sequencer
|
||||
```
|
||||
|
||||
**Интерфейс тест-модуля (`test_module.h`):**
|
||||
```c
|
||||
typedef enum { TEST_STATUS_PASS = 0, TEST_STATUS_FAIL, TEST_STATUS_SKIP } test_status_t;
|
||||
|
||||
typedef struct {
|
||||
test_status_t status;
|
||||
uint32_t duration_ms;
|
||||
char detail[96];
|
||||
} test_result_t;
|
||||
|
||||
typedef struct {
|
||||
const char *id;
|
||||
const char *name;
|
||||
bool critical;
|
||||
bool requires_hil;
|
||||
void (*init)(void);
|
||||
test_result_t (*run)(void);
|
||||
void (*deinit)(void);
|
||||
} test_module_t;
|
||||
```
|
||||
|
||||
**Сериализация (protocol.h):** функции `protocol_send_session_start()`,
|
||||
`protocol_send_test_begin()`, `protocol_send_test_result()`,
|
||||
`protocol_send_summary()`, `protocol_send_confirm_request()` — все через `cli_send()`.
|
||||
|
||||
**Команды хоста v2:**
|
||||
|
||||
| Входящий тип | Поле | Действие |
|
||||
| Кнопка | Пин MCU | GPIO |
|
||||
|---|---|---|
|
||||
| `cmd` | `"run_all"` | Запустить все тесты по реестру |
|
||||
| `cmd` | `"run"` + `"id"` | Запустить один тест |
|
||||
| `cmd` | `"ping"` | `{"type":"pong"}` |
|
||||
| `confirm` | `"id"` + `"confirmed"` | Ответ оператора на display тест |
|
||||
|
||||
**Host-тесты:** расширить `test_cli.c` + добавить `test_protocol.c` (Категория A).
|
||||
| Test_But_1 | GPIO_B1_14 | GPIO2[30] |
|
||||
| Test_But_2 | GPIO_B1_15 | GPIO2[31] |
|
||||
|
||||
---
|
||||
|
||||
### Этап 2 — `bsp_sdram`
|
||||
## Этап 6 — CAN + UART + Opto (HIL, M5StampPLC)
|
||||
|
||||
Все три теста `requires_hil = true`. Запускаются только при наличии стенда.
|
||||
BSP для всех трёх уже готов.
|
||||
|
||||
### test_can
|
||||
|
||||
M5StampPLC отправляет CAN-фрейм → плата принимает → сравниваем ID и payload.
|
||||
|
||||
**Шаги:**
|
||||
1. M5 → `{"cmd":"can_send","id":0x100,"data":[0xDE,0xAD,0xBE,0xEF]}` (через `confirm_request`)
|
||||
2. Таргет: `uart_cmd("CAN_RECV 500")` → `"100 DEADBEEF"` или `"TIMEOUT"`
|
||||
3. Ответный: таргет посылает → M5 `can_recv` → верификация
|
||||
|
||||
### test_uart_ttl
|
||||
|
||||
M5 loopback через UART TTL → echo-верификация.
|
||||
|
||||
### test_uart_iso
|
||||
|
||||
M5 RLY2 → RS_RX оптовход (BSP_OPTO_CH_RS) → детект ACTIVE/INACTIVE.
|
||||
Использует `bsp_opto` с `rs_as_gpio=true`.
|
||||
|
||||
### test_opto
|
||||
|
||||
M5 RLY3/RLY4 → EXT_IN1/IN2 → детект ACTIVE/INACTIVE через `bsp_opto`.
|
||||
|
||||
**Параметры стенда (из HIL_BENCH.md):**
|
||||
```
|
||||
RLY2 → RS_RX (BSP_OPTO_CH_RS) GPIO1[23]
|
||||
RLY3 → EXT_IN1 (BSP_OPTO_CH_IN1) GPIO1[22]
|
||||
RLY4 → EXT_IN2 (BSP_OPTO_CH_IN2) GPIO1[21]
|
||||
```
|
||||
|
||||
### HIL pytest для Этапа 6
|
||||
|
||||
Тесты firmware_test через USB CDC — отдельные от существующих HIL ELF тестов:
|
||||
|
||||
```
|
||||
tools/hil/
|
||||
├── conftest.py ← добавить фикстуру firmware_cdc (USB CDC клиент)
|
||||
├── 06_test_firmware_can.py ← M5 + USB CDC
|
||||
├── 06_test_firmware_uart.py
|
||||
└── 06_test_firmware_opto.py
|
||||
```
|
||||
|
||||
Фикстура `firmware_cdc` открывает CDC порт firmware_test (прошит в Flash),
|
||||
посылает JSON команды, читает события. Аналог `uart_cmd` для USB CDC.
|
||||
|
||||
---
|
||||
|
||||
## Этап 7 — Provisioning
|
||||
|
||||
### Что нужно
|
||||
|
||||
1. Читать `OCOTP_UNIQUE_ID` (или `OCOTP_MAC0/1`) через SDK fsl_ocotp.
|
||||
2. Посылать `{"type":"provision_ready","chip_uid":"AABB..."}` после `summary`.
|
||||
3. Ждать `{"type":"cmd","cmd":"provision_ack"}` от хоста.
|
||||
4. Записывать статус в Flash (первый сектор после прошивки, вне XIP).
|
||||
|
||||
### BSP (предварительно)
|
||||
|
||||
API уже описан в `firmware_test_plan.md` (закрытое решение):
|
||||
```c
|
||||
bsp_sdram_status_t bsp_sdram_init(void);
|
||||
bsp_sdram_status_t bsp_sdram_test_fast(bsp_sdram_result_t *result);
|
||||
bsp_sdram_status_t bsp_sdram_test_full(bsp_sdram_result_t *result);
|
||||
/* bsp/provisioning/include/bsp/provisioning.h */
|
||||
bsp_status_t bsp_prov_read_uid(uint8_t *p_uid, size_t len); /* 8 байт из OCOTP */
|
||||
```
|
||||
|
||||
**Файлы:**
|
||||
```
|
||||
bsp/sdram/
|
||||
├── CMakeLists.txt ← создать
|
||||
├── include/bsp/sdram.h ← по spec из firmware_test_plan.md
|
||||
└── src/sdram.c
|
||||
```
|
||||
### Открытые вопросы
|
||||
|
||||
**Тест модуль firmware_test:**
|
||||
```
|
||||
firmware/test/src/tests/test_sdram.c
|
||||
```
|
||||
|
||||
Команды через реестр: `run` + `id: "sdram"`. Отдельной HIL ELF нет.
|
||||
|
||||
**HIL pytest (`tools/hil/test_sdram.py`):** подключается к firmware_test через USB CDC.
|
||||
Фикстура `cdc_firmware_test` — firmware_test прошит в Flash, pytest открывает CDC порт.
|
||||
|
||||
**Just рецепты:** `hil-sdram` (без `--slow`), `hil-sdram-full` (с `@pytest.mark.slow`).
|
||||
- [ ] Что именно записывать как "пройдено": флаг в Flash или только отправить UID?
|
||||
- [ ] Нужна ли защита от повторного provisioning (write-once)?
|
||||
|
||||
---
|
||||
|
||||
### Этап 3 — `bsp_qspi` + QSPI тест
|
||||
## Матрица тестов — итоговая
|
||||
|
||||
**Аппаратный контекст:** W25Q64FVSSIG (из схемы, 8MB SPI NOR Flash), интерфейс FlexSPI.
|
||||
|
||||
**API:**
|
||||
```c
|
||||
bsp_qspi_status_t bsp_qspi_init(void);
|
||||
bsp_qspi_status_t bsp_qspi_read_jedec_id(uint8_t *manufacturer, uint16_t *device_id);
|
||||
bsp_qspi_status_t bsp_qspi_test(bsp_qspi_result_t *result); /* erase sector + write + verify */
|
||||
```
|
||||
|
||||
**Что проверяет тест:**
|
||||
|
||||
1. JEDEC ID совпадает с ожидаемым для W25Q64 (`0xEF`, `0x4017`)
|
||||
2. Erase тестового сектора (последний сектор, чтобы не трогать прошивку)
|
||||
3. Write + Read + Compare 256 байт
|
||||
|
||||
**Нет HIL ELF, нет M5.** Тест полностью самостоятельный.
|
||||
|
||||
**Вопрос перед началом:** проверить есть ли `sdk_flexspi` таргет в `sdk/CMakeLists.txt`.
|
||||
|
||||
---
|
||||
|
||||
### Этап 4 — `bsp_usd` + uSD тест
|
||||
|
||||
**Аппаратный контекст:** SDMMC (uSD слот), интерфейс USDHC. SDK таргет `sdk_usdhc` есть в матрице.
|
||||
|
||||
**Стратегия:** использовать FatFS из SDK middleware (уже vendored в `middleware/fatfs/`).
|
||||
|
||||
**API:**
|
||||
```c
|
||||
bsp_usd_status_t bsp_usd_init(void); /* USDHC init + mount FAT */
|
||||
bsp_usd_status_t bsp_usd_test(bsp_usd_result_t *result); /* write + read + verify */
|
||||
bsp_usd_status_t bsp_usd_deinit(void); /* unmount */
|
||||
```
|
||||
|
||||
**Поведение при отсутствии карты:** `TEST_STATUS_SKIP` (критически важно для
|
||||
производственного прогона — карта может быть не вставлена).
|
||||
|
||||
**Вопрос:** карта вставлена постоянно или оператор вставляет? Если оператор — нужен `confirm_request` перед тестом.
|
||||
|
||||
---
|
||||
|
||||
### Этап 5 — Display тест (интерактивный)
|
||||
|
||||
**Что проверяем:** RGB888 интерфейс + подсветка + реакция оператора через кнопки.
|
||||
|
||||
**Последовательность:**
|
||||
```
|
||||
firmware → LCD: залить R (красный)
|
||||
firmware → хост: {"type":"confirm_request","id":"display_red","timeout_ms":15000}
|
||||
оператор: нажать кнопку PASS (Test_But_1) или FAIL (Test_But_2)
|
||||
firmware → хост: {"type":"confirm_ack","id":"display_red","confirmed":true/false}
|
||||
повторить для G, B, W
|
||||
итоговый результат = AND всех подтверждений
|
||||
```
|
||||
|
||||
**Особенности:**
|
||||
|
||||
- Одновременно тестируются кнопки (`bsp_button` уже есть с HIL тестами)
|
||||
- Таймаут 15 с → `TEST_STATUS_SKIP`
|
||||
- Маркер `@pytest.mark.interactive` в pytest — не входит в `hil-run`
|
||||
|
||||
**HIL pytest:** `tools/hil/test_display.py` с `_operator_prompt()` через `/dev/tty`.
|
||||
|
||||
---
|
||||
|
||||
### Этап 6 — HIL тесты: CAN, UART, Opto в firmware_test
|
||||
|
||||
Эти BSP модули уже реализованы и имеют отдельные HIL ELF тесты.
|
||||
Задача этапа — **интегрировать их в firmware_test** как тест-модули,
|
||||
запускаемые через протокол v2.
|
||||
|
||||
#### 6.1 CAN (`bsp_can` ✅)
|
||||
|
||||
- Стенд: M5StampPLC подключён к CAN шине платы через интерфейсную плату
|
||||
- Тест: M5 посылает CAN фрейм → плата принимает → сравниваем
|
||||
|
||||
#### 6.2 UART TTL (`bsp_uart_host` ✅)
|
||||
|
||||
- Стенд: M5 UART ↔ UART TTL платы (loopback или echo)
|
||||
- Уточнить: какой UART порт на плате (LPUART1 занят MCU-Link, какой свободен?)
|
||||
|
||||
#### 6.3 UART ISO
|
||||
|
||||
- Уточнить наличие отдельного BSP модуля или это конфигурация `bsp_uart_host`
|
||||
- +24V уровни через интерфейсную плату
|
||||
|
||||
#### 6.4 Opto (`bsp_opto` ✅)
|
||||
|
||||
- Стенд: M5 реле → оптовходы EXT_IN1, EXT_IN2, RS_RX
|
||||
- Логика уже отработана в `02_test_opto.py` (HIL ELF)
|
||||
- Переиспользовать: тот же M5 агент, другой транспорт (USB CDC вместо UART)
|
||||
|
||||
**Важно для всех HIL тестов этапа 6:** pytest для firmware_test использует
|
||||
`cdc_firmware_test` фикстуру (USB CDC), а не `uart_<n>` (UART + pyOCD).
|
||||
M5StampPLC управляет сигналами так же, как в существующих HIL ELF тестах.
|
||||
|
||||
---
|
||||
|
||||
### Этап 7 — Provisioning
|
||||
|
||||
**Источник UID:** OCOTP регистры через `OCOTP_GetFuseData()` (NXP HAL).
|
||||
```c
|
||||
void provisioning_run(provision_info_t *out);
|
||||
```
|
||||
|
||||
**Поток:**
|
||||
```
|
||||
firmware → хост: {"type":"provision_ready","chip_uid":"A3F2...","fw":"0.1.0"}
|
||||
хост → БД: uid ↔ fw_version (логика на хосте)
|
||||
хост → firmware: {"type":"cmd","cmd":"provision_ack","fw":"1.0.0","bootloader":"1.0.0"}
|
||||
firmware → хост: {"type":"provision_done","recorded":true}
|
||||
```
|
||||
|
||||
**Запускается только при `overall == pass`.** В pytest отдельная фикстура
|
||||
`provision_firmware_test`.
|
||||
| ID | Название | Тип | Critical | HIL (M5) | BSP | Статус |
|
||||
|-------------|----------------|-------------|----------|----------|------------------|--------|
|
||||
| — | PING | cmd | — | ❌ | — | ✅ |
|
||||
| `sdram` | SDRAM 32MB | self | ✅ | ❌ | `bsp_sdram` ✅ | ✅ |
|
||||
| `qspi` | QSPI Flash | self | ✅ | ❌ | `bsp_qspi_flash` ✅ | ✅ |
|
||||
| `usd` | uSD (SDIO) | interactive | ✅ | ❌ | `bsp_usd` ⬜ | ⬜ |
|
||||
| `display` | Display RGB888 | interactive | ❌ | ❌ | существующий BSP | ⬜ |
|
||||
| `buttons` | Test_But_1/2 | interactive | ❌ | ❌ | `bsp_button` ✅ | ⬜ |
|
||||
| `can` | CAN loopback | HIL | ❌ | ✅ | `bsp_can` ✅ | ⬜ |
|
||||
| `uart_ttl` | UART TTL | HIL | ❌ | ✅ | `bsp_uart_host`✅| ⬜ |
|
||||
| `uart_iso` | UART ISO +24V | HIL | ❌ | ✅ | `bsp_opto` ✅ | ⬜ |
|
||||
| `opto` | Opto-in EXT | HIL | ❌ | ✅ | `bsp_opto` ✅ | ⬜ |
|
||||
|
||||
---
|
||||
|
||||
## Зависимости между этапами
|
||||
```
|
||||
Этап 1 (протокол v2 + runner)
|
||||
├── Этап 2 (bsp_sdram)
|
||||
│ └── HIL: test_sdram.py
|
||||
├── Этап 3 (bsp_qspi)
|
||||
│ └── HIL: test_qspi.py
|
||||
├── Этап 4 (bsp_usd)
|
||||
│ └── HIL: test_usd.py
|
||||
├── Этап 5 (display, interactive)
|
||||
│ └── HIL: test_display.py (@pytest.mark.interactive)
|
||||
└── Этап 6 (CAN + UART + Opto)
|
||||
└── HIL: test_can.py, test_uart.py, test_opto.py
|
||||
|
||||
Этап 7 (provisioning) → зависит от всех предыдущих
|
||||
```
|
||||
✅ Этап 1 (протокол v2 + runner)
|
||||
✅ Этап 2 (bsp_sdram + test_sdram)
|
||||
✅ Этап 3 (bsp_qspi_flash + test_qspi)
|
||||
⬜ Этап 4 (bsp_usd + test_usd) ← ТЕКУЩИЙ
|
||||
⬜ Этап 5 (display + buttons)
|
||||
⬜ Этап 6 (CAN + UART + Opto, HIL)
|
||||
⬜ Этап 7 (provisioning)
|
||||
⬜ Этап 8 (tools/production/ TUI runner) ← параллельно с 6-7
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BSP модули — итог
|
||||
## Хостовое ПО производственного прогона (Этап 8)
|
||||
|
||||
| BSP | Статус | Нужен HIL ELF | Нужен в firmware_test |
|
||||
|---|---|---|---|
|
||||
| `bsp_usb_cdc` | ✅ | ✅ (есть) | ✅ (есть) |
|
||||
| `bsp_led` | ✅ | ❌ | ✅ |
|
||||
| `bsp_tick` | ✅ | ❌ | ✅ |
|
||||
| `bsp_button` | ✅ | ✅ (есть) | ✅ (display тест) |
|
||||
| `bsp_opto` | ✅ | ✅ (есть) | ✅ этап 6 |
|
||||
| `bsp_can` | ✅ | ✅ (есть) | ✅ этап 6 |
|
||||
| `bsp_uart_host` | ✅ | ✅ (есть) | ✅ этап 6 |
|
||||
| `bsp_sdram` | ⬜ | ❌ | ✅ этап 2 |
|
||||
| `bsp_qspi` | ⬜ | ❌ | ✅ этап 3 |
|
||||
| `bsp_usd` | ⬜ | ❌ | ✅ этап 4 |
|
||||
**Решение принято (Вариант D):** отдельное приложение `tools/production/`,
|
||||
без pytest, с TUI (Textual).
|
||||
|
||||
---
|
||||
Подробная архитектура описана в предыдущей версии плана (v0.2, раздел
|
||||
"Открытый вопрос: ПО на стороне хоста").
|
||||
|
||||
## Контекст для нового треда — что передать
|
||||
```
|
||||
Системный промпт: тот же (роль + правила).
|
||||
### Открытые вопросы (перед Этапом 8)
|
||||
|
||||
Приложить файлы:
|
||||
- firmware_test_plan.md (обновлённый)
|
||||
- usb_cdc.md
|
||||
- firmware/test/src/main.c (текущий)
|
||||
- firmware/test/src/cli.h/.c (текущий)
|
||||
- firmware/test/CMakeLists.txt (текущий)
|
||||
- tests/host/CMakeLists.txt
|
||||
- tests/host/cli/test_cli.c
|
||||
- этот план (PLAN.md)
|
||||
|
||||
Первый вопрос нового треда:
|
||||
"Начинаем Этап 1 — протокол v2 и test_runner.
|
||||
Ответы на открытые вопросы: [...]"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Открытый вопрос: ПО на стороне хоста для производственного прогона
|
||||
|
||||
### Контекст и разделение ответственности
|
||||
|
||||
Принципиально важно разделить два окружения:
|
||||
|
||||
| Окружение | Кто запускает | Инструмент | Что тестирует |
|
||||
|---|---|---|---|
|
||||
| **Разработка** | Разработчик, локальный ПК | pytest (`just host::hil-*`) | Отдельные BSP модули через HIL ELF + UART |
|
||||
| **Производство / Сервис** | Оператор, сервер | ??? | Плата целиком через firmware_test + USB CDC |
|
||||
|
||||
Это два **принципиально разных** use case с разными требованиями к UX,
|
||||
надёжности и изоляции. Смешивать их в одном pytest-прогоне нельзя.
|
||||
|
||||
---
|
||||
|
||||
### Почему "просто pytest" недостаточно для производства
|
||||
|
||||
Производственный прогон отличается от HIL тестов разработчика по нескольким осям:
|
||||
|
||||
**Оператор — не разработчик.** Он не читает pytest output в терминале.
|
||||
Ему нужно видеть: какой тест сейчас идёт, прошёл или нет, что делать дальше
|
||||
(вставить карту, посмотреть на дисплей, нажать кнопку).
|
||||
|
||||
**Последовательность фиксирована.** Прогон всегда идёт по реестру:
|
||||
flash → READY → run_all → summary → provisioning. Никакого выбора тестов.
|
||||
|
||||
**Результат — не лог, а запись в БД.** `chip_uid` + результат + версия прошивки
|
||||
должны сохраняться. pytest ничего не знает о БД.
|
||||
|
||||
**Интерактивные тесты** (display) требуют управляемого диалога с оператором,
|
||||
а не `input()` в терминале с флагом `-s`.
|
||||
|
||||
---
|
||||
|
||||
### Варианты хостового ПО — анализ
|
||||
|
||||
#### Вариант A: pytest + плагины + HTML отчёт
|
||||
|
||||
Обернуть весь прогон в pytest, добавить `pytest-html` для отчётов,
|
||||
интерактивные тесты через `@pytest.mark.interactive` с `-s`.
|
||||
|
||||
**Плюсы:** минимум нового кода, знакомый инструмент.
|
||||
|
||||
**Минусы:** оператор смотрит в терминал; интерактивность через `/dev/tty` хрупкая;
|
||||
provisioning (запись в БД) — костыль в фикстуре; нет живого статуса
|
||||
"тест N из M идёт X секунд". Для производства неприемлемо.
|
||||
|
||||
#### Вариант B: TUI — Python + Textual / Rich
|
||||
|
||||
Самостоятельное Python-приложение с текстовым интерфейсом.
|
||||
Управляет всем: flash через spsdk, M5StampPLC, USB CDC, provisioning, БД.
|
||||
pytest не используется как runner — только как библиотека для assert-логики
|
||||
(или вообще не используется).
|
||||
|
||||
**Плюсы:** полный контроль над UX; живой прогресс; чёткие диалоги оператора;
|
||||
нативная запись в БД; изолировано от HIL тестов разработчика полностью.
|
||||
|
||||
**Минусы:** значительный объём разработки хостового ПО;
|
||||
нужен отдельный репозиторий или директория `tools/production/`.
|
||||
|
||||
#### Вариант C: pytest как backend, TUI/GUI как frontend
|
||||
|
||||
pytest запускается программно через `pytest.main()` или subprocess,
|
||||
результаты передаются через JSON reporter (`pytest-json-report`) в
|
||||
отдельное GUI/TUI приложение которое их отображает.
|
||||
|
||||
**Плюсы:** переиспользуем pytest инфраструктуру (фикстуры, параллелизм).
|
||||
|
||||
**Минусы:** архитектурно сложно; интерактивные тесты всё равно требуют
|
||||
кастомного канала; два процесса вместо одного.
|
||||
|
||||
#### Вариант D: pytest только для разработки, отдельный runner для производства
|
||||
|
||||
**Разработка:** pytest (`just host::hil-*`) — тесты отдельных BSP модулей
|
||||
через HIL ELF. Остаётся как есть.
|
||||
|
||||
**Производство:** отдельное Python-приложение (`tools/production/run.py`)
|
||||
без pytest. Использует те же низкоуровневые библиотеки
|
||||
(`pyserial`, `spsdk`, M5 агент) но со своим runner-ом и TUI.
|
||||
|
||||
Тест-логика на стороне прошивки (в `test_runner.c`) — единственная
|
||||
точка истины. Хостовое ПО только отправляет команды и интерпретирует события.
|
||||
|
||||
**Это рекомендуемый вариант** — наиболее чистое разделение.
|
||||
|
||||
---
|
||||
|
||||
### Рекомендуемая архитектура (Вариант D, детально)
|
||||
```
|
||||
tools/
|
||||
├── hil/ # СУЩЕСТВУЮЩИЙ — разработчик, локальный ПК
|
||||
│ ├── conftest.py # pytest фикстуры
|
||||
│ ├── 01_test_uart.py # HIL тесты отдельных BSP модулей
|
||||
│ ├── 02_test_opto.py
|
||||
│ └── ...
|
||||
│
|
||||
└── production/ # НОВЫЙ — производство / сервис
|
||||
├── pyproject.toml # отдельное окружение uv
|
||||
├── run.py # точка входа: python run.py
|
||||
├── runner/
|
||||
│ ├── flasher.py # spsdk: flash firmware_test.elf
|
||||
│ ├── cdc_client.py # USB CDC: send cmd, recv events
|
||||
│ ├── m5_client.py # переиспользовать tools/hil/m5/
|
||||
│ ├── test_sequence.py # порядок: flash→READY→run_all→provision
|
||||
│ └── db.py # запись chip_uid + результатов
|
||||
└── ui/
|
||||
├── tui.py # Textual TUI: живой прогресс + диалоги
|
||||
└── report.py # HTML / JSON отчёт после прогона
|
||||
```
|
||||
|
||||
**Поток производственного прогона:**
|
||||
```
|
||||
Оператор запускает: python tools/production/run.py
|
||||
│
|
||||
├── flasher.py: spsdk → flash firmware_test.elf → Reset
|
||||
├── cdc_client: ждёт {"type":"session_start",...}
|
||||
├── TUI: показывает "Подключение... ОК"
|
||||
│
|
||||
├── cdc_client: → {"type":"cmd","cmd":"run_all"}
|
||||
│
|
||||
├── [цикл событий]
|
||||
│ ├── {"type":"test_begin","id":"sdram"} → TUI: "SDRAM... ⏳"
|
||||
│ ├── {"type":"test_result","id":"sdram","status":"pass"} → TUI: "SDRAM ✅ 47ms"
|
||||
│ ├── {"type":"confirm_request","id":"display_red"} →
|
||||
│ │ TUI: диалог оператора "Экран красный? [PASS/FAIL]"
|
||||
│ │ cdc_client: → {"type":"confirm","id":"display_red","confirmed":true}
|
||||
│ └── ...
|
||||
│
|
||||
├── {"type":"summary","overall":"pass"} → TUI: финальный результат
|
||||
├── {"type":"provision_ready","chip_uid":"..."} →
|
||||
│ db.py: записать в БД
|
||||
│ cdc_client: → {"type":"cmd","cmd":"provision_ack",...}
|
||||
└── TUI: "Плата принята ✅ | UID: A3F2..." | печать этикетки?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Изоляция от HIL тестов разработчика
|
||||
|
||||
| Аспект | HIL тесты (разработка) | Production runner |
|
||||
|---|---|---|
|
||||
| Инструмент | pytest | Самостоятельный Python runner |
|
||||
| Директория | `tools/hil/` | `tools/production/` |
|
||||
| Окружение uv | `tools/hil/pyproject.toml` | `tools/production/pyproject.toml` |
|
||||
| Just рецепты | `just host::hil-*` | `just host::production-run` |
|
||||
| Прошивка | HIL ELF в RAM (pyOCD) | firmware_test в Flash (spsdk) |
|
||||
| Транспорт | UART CLI (pyserial) | USB CDC JSON-lines |
|
||||
| UX | Терминал / pytest output | TUI (Textual) |
|
||||
| БД | Нет | Да |
|
||||
| M5StampPLC | Да (реле для сигналов) | Да (те же реле) |
|
||||
| CI | Да (автоматический) | Нет |
|
||||
|
||||
Общий код (M5 агент, низкоуровневый spsdk wrapper) можно вынести в
|
||||
`tools/shared/` и подключать как локальный пакет в обоих `pyproject.toml`.
|
||||
|
||||
---
|
||||
|
||||
### Открытые вопросы для обсуждения
|
||||
|
||||
- [ ] **TUI библиотека:** Textual (современный, богатый) или Rich (проще, достаточно)?
|
||||
Или вообще минималистичный вывод без TUI фреймворка на первой итерации?
|
||||
- [ ] **БД:** SQLite локально на сервере или REST API на внешний сервис?
|
||||
- [ ] **Этикетка:** нужна ли автоматическая печать после provisioning?
|
||||
- [ ] **Несколько стендов:** один сервер управляет несколькими платами параллельно
|
||||
или всегда одна плата?
|
||||
- [ ] **Первая итерация:** допустимо ли начать с простого `run.py` без TUI
|
||||
(plain print + input) и добавить TUI позже?
|
||||
- [ ] TUI: Textual или Rich или plain print на первой итерации?
|
||||
- [ ] БД: SQLite локально или REST API?
|
||||
- [ ] Несколько стендов параллельно или всегда один?
|
||||
- [ ] Этикетка: нужна ли автоматическая печать после provisioning?
|
||||
29
firmware/test/fatfs/CMakeLists.txt
Normal file
29
firmware/test/fatfs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# firmware_test_fatfs — FatFS, скомпилированный с bare-metal ffconf.h.
|
||||
#
|
||||
# ff.c, fsl_sd_disk.c, diskio_sd.c включают ff.h → ffconf.h. Все три
|
||||
# компилируются здесь, чтобы видели один и тот же ffconf.h из
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/include.
|
||||
#
|
||||
# tft_app заведёт свой аналогичный таргет с FreeRTOS ffconf.h — эти два таргета
|
||||
# никак не пересекаются.
|
||||
|
||||
add_library(
|
||||
firmware_test_fatfs STATIC
|
||||
${SDK_FATFS_FF_SRC} # sdk/middleware/fatfs/source/ff.c
|
||||
${SDK_FATFS_SD_DISK_SRC} # sdk/middleware/fatfs/source/fsl_sd_disk/fsl_sd_disk.c
|
||||
${PORT_FATFS_SD_SRC} # port/fatfs/sd/src/diskio_sd.c
|
||||
src/diskio.c)
|
||||
|
||||
# include/ первым — ffconf.h отсюда должен перекрыть любой шаблонный
|
||||
target_include_directories(
|
||||
firmware_test_fatfs
|
||||
PUBLIC include # ffconf.h, виден потребителям (bsp_usd, test_usd)
|
||||
PRIVATE src)
|
||||
|
||||
target_link_libraries(
|
||||
firmware_test_fatfs
|
||||
PUBLIC port_fatfs_sd # diskio_sd.h, ff.h, fsl_sd_disk.h, bsp_sd
|
||||
PRIVATE bsp_sdmmc_config) # SD_ENABLED транзитивно из bsp_sd, но явно для
|
||||
# ясности
|
||||
|
||||
target_compile_options(firmware_test_fatfs PRIVATE -w)
|
||||
78
firmware/test/fatfs/include/ffconf.h
Normal file
78
firmware/test/fatfs/include/ffconf.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* ffconf.h — конфигурация FatFS для firmware_test (bare-metal, только SD).
|
||||
*
|
||||
* Ключевые отличия от tft_app:
|
||||
* FF_FS_REENTRANT = 0 — нет RTOS, нет мьютексов
|
||||
* FF_VOLUMES = 3 — 0: зарезервирован, 1: зарезервирован, 2: SD
|
||||
* FF_MAX_SS = 512 — SD всегда 512 байт/сектор, ioctl не нужен
|
||||
*/
|
||||
|
||||
#ifndef _FFCONF_H_
|
||||
#define _FFCONF_H_
|
||||
|
||||
#define FFCONF_DEF 80286
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ MSDK adaptation
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define SD_DISK_ENABLE 1
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define FF_FS_READONLY 0
|
||||
#define FF_FS_MINIMIZE 0
|
||||
#define FF_USE_FIND 0
|
||||
#define FF_USE_MKFS 0 /* f_mkfs не нужна — карта уже отформатирована */
|
||||
#define FF_USE_FASTSEEK 0
|
||||
#define FF_USE_EXPAND 0
|
||||
#define FF_USE_CHMOD 0
|
||||
#define FF_USE_LABEL 0
|
||||
#define FF_USE_FORWARD 0
|
||||
#define FF_USE_STRFUNC 0
|
||||
#define FF_PRINT_LLI 0
|
||||
#define FF_PRINT_FLOAT 0
|
||||
#define FF_STRF_ENCODE 3
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define FF_CODE_PAGE 437 /* U.S. — минимальный, имена файлов ASCII */
|
||||
|
||||
#define FF_USE_LFN 0 /* только 8.3 — достаточно для FWTEST.TMP */
|
||||
#define FF_MAX_LFN 255
|
||||
#define FF_LFN_UNICODE 0
|
||||
#define FF_LFN_BUF 255
|
||||
#define FF_SFN_BUF 12
|
||||
#define FF_FS_RPATH 0 /* относительные пути не нужны */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define FF_VOLUMES 3 /* 0: зарезервирован, 1: зарезервирован, 2: SD */
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_MULTI_PARTITION 0
|
||||
|
||||
#define FF_MIN_SS 512
|
||||
#define FF_MAX_SS 512 /* SD: всегда 512, GET_SECTOR_SIZE не нужен */
|
||||
|
||||
#define FF_LBA64 0
|
||||
#define FF_MIN_GPT 0x10000000
|
||||
#define FF_USE_TRIM 0
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
#define FF_FS_TINY 0
|
||||
#define FF_FS_EXFAT 0 /* exFAT требует LFN — оба отключены */
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2024
|
||||
#define FF_FS_NOFSINFO 0
|
||||
#define FF_FS_LOCK 0
|
||||
|
||||
#define FF_FS_REENTRANT 0 /* bare-metal: нет RTOS, нет мьютексов */
|
||||
/* FF_FS_TIMEOUT и FF_SYNC_t не нужны */
|
||||
|
||||
#endif /* _FFCONF_H_ */
|
||||
62
firmware/test/fatfs/src/diskio.c
Normal file
62
firmware/test/fatfs/src/diskio.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* diskio.c — FatFS diskio диспетчер для firmware_test.
|
||||
*
|
||||
* FF_VOLUMES=1: единственный диск "0:/" = SDDISK.
|
||||
* W25Q и RAM-диск отсутствуют — нет зависимости на bsp_qspi_flash.
|
||||
*/
|
||||
|
||||
#include "diskio.h"
|
||||
|
||||
#include "port/fatfs/diskio_sd.h"
|
||||
|
||||
#define SDDISK 2U
|
||||
|
||||
DSTATUS disk_initialize(BYTE pdrv)
|
||||
{
|
||||
if (pdrv == SDDISK)
|
||||
{
|
||||
return microsd_disk_initialize(pdrv);
|
||||
}
|
||||
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
DSTATUS disk_status(BYTE pdrv)
|
||||
{
|
||||
if (pdrv == SDDISK)
|
||||
{
|
||||
return microsd_disk_status(pdrv);
|
||||
}
|
||||
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
if (pdrv == SDDISK)
|
||||
{
|
||||
return microsd_disk_read(pdrv, buff, sector, count);
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
if (pdrv == SDDISK)
|
||||
{
|
||||
return microsd_disk_write(pdrv, buff, sector, count);
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
|
||||
{
|
||||
if (pdrv == SDDISK)
|
||||
{
|
||||
return microsd_disk_ioctl(pdrv, cmd, buff);
|
||||
}
|
||||
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
|
@ -19,9 +19,11 @@
|
|||
*/
|
||||
#include "board.h"
|
||||
#include "bsp/led.h"
|
||||
#include "bsp/sd.h"
|
||||
#include "bsp/tick.h"
|
||||
#include "bsp/usb_cdc.h"
|
||||
#include "cli.h"
|
||||
#include "ff.h"
|
||||
#include "protocol.h"
|
||||
#include "test_runner.h"
|
||||
|
||||
|
|
@ -51,6 +53,7 @@ int main(void)
|
|||
bsp_delay(CONNECT_BLINK_MS);
|
||||
}
|
||||
|
||||
#if 0
|
||||
bsp_led_on(LED_APP);
|
||||
|
||||
cli_init();
|
||||
|
|
@ -62,4 +65,55 @@ int main(void)
|
|||
cli_process();
|
||||
test_runner_process();
|
||||
}
|
||||
#endif
|
||||
static FATFS s_fs;
|
||||
const char *step = "card_detect";
|
||||
bool passed = false;
|
||||
|
||||
if (!bsp_sd_is_inserted())
|
||||
{
|
||||
/* нет карты — пропускаем, это не ошибка стека */
|
||||
bsp_usb_cdc_write((const uint8_t *) "The card is not inserted.\r\n", 27);
|
||||
goto sd_smoke_done;
|
||||
}
|
||||
|
||||
step = "sd_init";
|
||||
if (bsp_sd_init() != BSP_OK)
|
||||
{
|
||||
goto sd_smoke_fail;
|
||||
}
|
||||
|
||||
step = "f_mount";
|
||||
FRESULT res = f_mount(&s_fs, "2:/", 1);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
bsp_sd_deinit();
|
||||
goto sd_smoke_fail;
|
||||
}
|
||||
|
||||
/* всё ок */
|
||||
res = f_unmount("2:/");
|
||||
if (res != FR_OK)
|
||||
{
|
||||
bsp_sd_deinit();
|
||||
goto sd_smoke_fail;
|
||||
}
|
||||
bsp_sd_deinit();
|
||||
passed = true;
|
||||
|
||||
bsp_usb_cdc_write((const uint8_t *) "The test passed.\r\n", 18);
|
||||
goto sd_smoke_done;
|
||||
|
||||
sd_smoke_fail:
|
||||
{
|
||||
/* маленький буфер: step не длиннее 16 символов */
|
||||
bsp_usb_cdc_write((const uint8_t *) "The test failed.\r\n", 18);
|
||||
}
|
||||
(void) passed;
|
||||
|
||||
sd_smoke_done:
|
||||
while (1)
|
||||
{
|
||||
bsp_usb_cdc_poll();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,3 +2,4 @@ if(BUILD_TESTS_HOST)
|
|||
return()
|
||||
endif()
|
||||
add_subdirectory(log)
|
||||
add_subdirectory(fatfs)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ port/
|
|||
├── CMakeLists.txt
|
||||
├── README.md ← этот файл
|
||||
└── log/ ← UART-адаптер для utils/log
|
||||
├── fatfs/ ← diskio поверх bsp_sd / bsp_qspi
|
||||
# Планируется:
|
||||
├── fatfs/ ← diskio поверх bsp_sdio / bsp_qspi
|
||||
└── freertos/ ← heap_4.c, configASSERT, vApplicationHooks
|
||||
```
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ port/
|
|||
## Соглашения
|
||||
|
||||
**Именование таргетов:** `port_<что>_<транспорт>` — например `port_log_uart`,
|
||||
`port_fatfs_sdio`. Позволяет иметь несколько адаптеров для одной библиотеки.
|
||||
`port_fatfs_sd`. Позволяет иметь несколько адаптеров для одной библиотеки.
|
||||
|
||||
**Include-путь:** `#include "port/<модуль>.h"` — публичные заголовки
|
||||
всегда в `port/<модуль>/include/port/`.
|
||||
|
|
|
|||
1
port/fatfs/CMakeLists.txt
Normal file
1
port/fatfs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(sd)
|
||||
19
port/fatfs/sd/CMakeLists.txt
Normal file
19
port/fatfs/sd/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# port_fatfs_sd — INTERFACE: не компилирует diskio_sd.c сам.
|
||||
#
|
||||
# Причина: diskio_sd.c включает diskio.h → ff.h → ffconf.h, который разный у
|
||||
# firmware_test (bare-metal) и tft_app (FreeRTOS). Каждый бинарник компилирует
|
||||
# diskio_sd.c в свой FatFS-таргет сам, используя PORT_FATFS_SD_SRC.
|
||||
|
||||
add_library(port_fatfs_sd INTERFACE)
|
||||
|
||||
target_include_directories(port_fatfs_sd INTERFACE include)
|
||||
|
||||
target_link_libraries(
|
||||
port_fatfs_sd
|
||||
INTERFACE sdk_fatfs_headers # ff.h, fsl_sd_disk.h + SDK_FATFS_*_SRC
|
||||
bsp_sd) # g_sd, bsp_sd_is_inserted()
|
||||
|
||||
set(PORT_FATFS_SD_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/diskio_sd.c
|
||||
CACHE INTERNAL
|
||||
"port_fatfs_sd: путь к diskio_sd.c (компилировать per-binary)")
|
||||
20
port/fatfs/sd/include/port/fatfs/diskio_sd.h
Normal file
20
port/fatfs/sd/include/port/fatfs/diskio_sd.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* diskio_sd — реализация FatFS diskio-интерфейса для microSD через fsl_sd_disk.
|
||||
*
|
||||
* Функции microsd_disk_* вызываются диспетчером diskio.c каждого бинарника.
|
||||
* Никогда не вызывать напрямую из прикладного кода.
|
||||
*/
|
||||
|
||||
#ifndef PORT_FATFS_DISKIO_SD_H
|
||||
#define PORT_FATFS_DISKIO_SD_H
|
||||
|
||||
#include "diskio.h" /* DSTATUS, DRESULT, BYTE, LBA_t, UINT */
|
||||
#include "ff.h"
|
||||
|
||||
DSTATUS microsd_disk_initialize(BYTE pdrv);
|
||||
DSTATUS microsd_disk_status(BYTE pdrv);
|
||||
DRESULT microsd_disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count);
|
||||
DRESULT microsd_disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count);
|
||||
DRESULT microsd_disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);
|
||||
|
||||
#endif /* PORT_FATFS_DISKIO_SD_H */
|
||||
37
port/fatfs/sd/src/diskio_sd.c
Normal file
37
port/fatfs/sd/src/diskio_sd.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* diskio_sd — тонкая обёртка fsl_sd_disk → FatFS diskio для microSD.
|
||||
*
|
||||
* fsl_sd_disk.c из SDK уже реализует sd_disk_* поверх fsl_sd / USDHC.
|
||||
* Наша задача — только пробросить вызовы и изолировать номер диска:
|
||||
* sd_disk_* всегда работают с диском 0 внутри себя, pdrv мы передаём
|
||||
* для соблюдения сигнатуры, но fsl_sd_disk игнорирует его значение.
|
||||
*/
|
||||
|
||||
#include "port/fatfs/diskio_sd.h"
|
||||
|
||||
#include "fsl_sd_disk.h"
|
||||
|
||||
DSTATUS microsd_disk_initialize(BYTE pdrv)
|
||||
{
|
||||
return sd_disk_initialize(pdrv);
|
||||
}
|
||||
|
||||
DSTATUS microsd_disk_status(BYTE pdrv)
|
||||
{
|
||||
return sd_disk_status(pdrv);
|
||||
}
|
||||
|
||||
DRESULT microsd_disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
return sd_disk_read(pdrv, buff, sector, count);
|
||||
}
|
||||
|
||||
DRESULT microsd_disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
|
||||
{
|
||||
return sd_disk_write(pdrv, buff, sector, count);
|
||||
}
|
||||
|
||||
DRESULT microsd_disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
|
||||
{
|
||||
return sd_disk_ioctl(pdrv, cmd, buff);
|
||||
}
|
||||
300
project_tree.txt
Normal file
300
project_tree.txt
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
.
|
||||
├── bootstrap.sh
|
||||
├── bsp
|
||||
│ ├── button
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── can
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── mocks
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── common
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ └── include
|
||||
│ ├── display
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── generated
|
||||
│ │ ├── board
|
||||
│ │ ├── board.c
|
||||
│ │ ├── board.h
|
||||
│ │ ├── clock_config.c
|
||||
│ │ ├── clock_config.h
|
||||
│ │ ├── pin_mux.c
|
||||
│ │ ├── pin_mux.h
|
||||
│ │ ├── README.md
|
||||
│ │ ├── startup
|
||||
│ │ ├── syscalls.c
|
||||
│ │ └── TFT_Board.mex
|
||||
│ ├── led
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── opto
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── qspi_flash
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ ├── REFACTORING.md
|
||||
│ │ └── src
|
||||
│ ├── README.md
|
||||
│ ├── sdram
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── tick
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ ├── uart_host
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── mocks
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ └── usb_cdc
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── include
|
||||
│ ├── README.md
|
||||
│ └── src
|
||||
├── cmake
|
||||
│ ├── linker
|
||||
│ │ ├── MIMXRT1052xxxxx_flexspi_nor_sdram.ld
|
||||
│ │ ├── MIMXRT1052xxxxx_flexspi_nor.ld
|
||||
│ │ ├── MIMXRT1052xxxxx_ram.ld
|
||||
│ │ ├── MIMXRT1052xxxxx_sdram_txt.ld
|
||||
│ │ └── MIMXRT1052xxxxx_sdram.ld
|
||||
│ ├── toolchain_arm.cmake
|
||||
│ └── toolchain_host.cmake
|
||||
├── CMakeLists.txt
|
||||
├── CMakePresets.json
|
||||
├── docs
|
||||
│ ├── DEV_ARCH.md
|
||||
│ ├── hardware
|
||||
│ │ ├── board
|
||||
│ │ ├── m5stamPLC
|
||||
│ │ ├── MCULINKINSERT.pdf
|
||||
│ │ └── tft_displays
|
||||
│ ├── HOW_TO_DEBUG.md
|
||||
│ ├── HOW_TO_FLASH.md
|
||||
│ ├── mimxrt1052
|
||||
│ │ ├── BOOT_FLAGS.md
|
||||
│ │ ├── HAB_GUIDE.md
|
||||
│ │ ├── manufacturing_user's_guide.pdf
|
||||
│ │ └── mcu_rm.pdf
|
||||
│ └── testing
|
||||
│ ├── hil
|
||||
│ ├── host
|
||||
│ └── PROTOCOL.md
|
||||
├── firmware
|
||||
│ ├── bootloader
|
||||
│ ├── test
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── PLAN.md
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ └── tft_app
|
||||
├── just
|
||||
│ ├── build.just
|
||||
│ ├── ci_workflow.md
|
||||
│ ├── ci.just
|
||||
│ └── host.just
|
||||
├── Justfile
|
||||
├── lib
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── fff
|
||||
│ │ ├── buildandtest
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── examples
|
||||
│ │ ├── fakegen.rb
|
||||
│ │ ├── fff.h
|
||||
│ │ ├── LICENSE
|
||||
│ │ ├── README.md
|
||||
│ │ └── test
|
||||
│ ├── SEGGER
|
||||
│ │ ├── RTT
|
||||
│ │ └── wrapper
|
||||
│ └── Unity
|
||||
│ ├── auto
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── docs
|
||||
│ ├── examples
|
||||
│ ├── extras
|
||||
│ ├── library.json
|
||||
│ ├── LICENSE.txt
|
||||
│ ├── meson_options.txt
|
||||
│ ├── meson.build
|
||||
│ ├── platformio-build.py
|
||||
│ ├── README.md
|
||||
│ ├── src
|
||||
│ ├── test
|
||||
│ └── unityConfig.cmake
|
||||
├── port
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── log
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── include
|
||||
│ │ ├── README.md
|
||||
│ │ └── src
|
||||
│ └── README.md
|
||||
├── project_tree.txt
|
||||
├── pyocd_debug.yaml
|
||||
├── pyocd.yaml
|
||||
├── README.md
|
||||
├── sdk
|
||||
│ ├── boards
|
||||
│ │ └── evkbimxrt1050
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── CMSIS
|
||||
│ │ ├── Core
|
||||
│ │ ├── Driver
|
||||
│ │ ├── DSP
|
||||
│ │ ├── LICENSE.txt
|
||||
│ │ ├── NN
|
||||
│ │ └── RTOS2
|
||||
│ ├── components
|
||||
│ │ ├── audio
|
||||
│ │ ├── button
|
||||
│ │ ├── codec
|
||||
│ │ ├── common_task
|
||||
│ │ ├── crc
|
||||
│ │ ├── display
|
||||
│ │ ├── exception_handling
|
||||
│ │ ├── flash
|
||||
│ │ ├── gpio
|
||||
│ │ ├── i2c
|
||||
│ │ ├── internal_flash
|
||||
│ │ ├── led
|
||||
│ │ ├── lists
|
||||
│ │ ├── log
|
||||
│ │ ├── mem_manager
|
||||
│ │ ├── messaging
|
||||
│ │ ├── mx25r_flash
|
||||
│ │ ├── osa
|
||||
│ │ ├── panic
|
||||
│ │ ├── phy
|
||||
│ │ ├── pmic
|
||||
│ │ ├── reset
|
||||
│ │ ├── rng
|
||||
│ │ ├── rtt
|
||||
│ │ ├── sensor
|
||||
│ │ ├── serial_manager
|
||||
│ │ ├── silicon_id
|
||||
│ │ ├── spi
|
||||
│ │ ├── timer
|
||||
│ │ ├── timer_manager
|
||||
│ │ ├── touch
|
||||
│ │ ├── uart
|
||||
│ │ ├── video
|
||||
│ │ └── wifi_bt_module
|
||||
│ ├── COPYING-BSD-3
|
||||
│ ├── devices
|
||||
│ │ └── MIMXRT1052
|
||||
│ ├── docs
|
||||
│ │ └── readme.md
|
||||
│ ├── LA_OPT_NXP_Software_License.txt
|
||||
│ ├── middleware
|
||||
│ │ ├── audio_voice
|
||||
│ │ ├── cjson
|
||||
│ │ ├── dhara
|
||||
│ │ ├── fatfs
|
||||
│ │ ├── freemaster
|
||||
│ │ ├── libjpeg
|
||||
│ │ ├── littlefs
|
||||
│ │ ├── mcuboot_opensource
|
||||
│ │ ├── pkcs11
|
||||
│ │ ├── pngdec
|
||||
│ │ ├── sdmmc
|
||||
│ │ ├── tfm
|
||||
│ │ ├── tinycbor
|
||||
│ │ └── usb
|
||||
│ ├── MIMXRT1052xxxxB_manifest_v3_15.xml
|
||||
│ ├── README.md
|
||||
│ ├── rtos
|
||||
│ │ └── freertos
|
||||
│ ├── sdk_tree.txt
|
||||
│ ├── SW-Content-Register.txt
|
||||
│ └── tools
|
||||
│ └── cmake_toolchain_files
|
||||
├── tests
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── host
|
||||
│ │ ├── button
|
||||
│ │ ├── can
|
||||
│ │ ├── cli
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ │ ├── led
|
||||
│ │ ├── log
|
||||
│ │ ├── mocks
|
||||
│ │ ├── opto
|
||||
│ │ ├── prio_queue
|
||||
│ │ ├── protocol
|
||||
│ │ ├── README.md
|
||||
│ │ ├── ring_buffer
|
||||
│ │ ├── runner
|
||||
│ │ ├── timeout
|
||||
│ │ └── uart_host
|
||||
│ └── target
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── hil_button
|
||||
│ ├── hil_can
|
||||
│ ├── hil_opto
|
||||
│ ├── hil_usb_cdc
|
||||
│ └── host_uart
|
||||
├── tools
|
||||
│ ├── hil
|
||||
│ │ ├── __pycache__
|
||||
│ │ ├── 01_test_uart.py
|
||||
│ │ ├── 02_test_opto.py
|
||||
│ │ ├── 03_test_can.py
|
||||
│ │ ├── 04_test_button.py
|
||||
│ │ ├── 05_test_usb_cdc.py
|
||||
│ │ ├── conftest.py
|
||||
│ │ ├── env_config.py
|
||||
│ │ ├── load_and_run.py
|
||||
│ │ ├── m5
|
||||
│ │ ├── pyocd_utils.py
|
||||
│ │ ├── pyproject.toml
|
||||
│ │ ├── README.md
|
||||
│ │ └── uv.lock
|
||||
│ ├── host
|
||||
│ │ ├── dcd
|
||||
│ │ ├── flash_swd.py
|
||||
│ │ ├── flash_usb.py
|
||||
│ │ ├── hab
|
||||
│ │ ├── pyproject.toml
|
||||
│ │ ├── README.md
|
||||
│ │ └── uv.lock
|
||||
│ ├── production
|
||||
│ └── shared
|
||||
└── utils
|
||||
├── CMakeLists.txt
|
||||
├── log
|
||||
│ ├── log.c
|
||||
│ ├── log.h
|
||||
│ └── README.md
|
||||
├── prio_queue
|
||||
│ ├── prio_queue.c
|
||||
│ ├── prio_queue.h
|
||||
│ └── README.md
|
||||
├── README.md
|
||||
└── ring_buffer
|
||||
├── README.md
|
||||
├── ring_buffer.c
|
||||
└── ring_buffer.h
|
||||
|
||||
174 directories, 124 files
|
||||
|
|
@ -33,7 +33,12 @@ target_compile_definitions(sdk_device PUBLIC CPU_MIMXRT1052CVJ5B)
|
|||
# -----------------------------------------------------------------------------
|
||||
# Утилиты — базовые вещи, нужны большинству драйверов
|
||||
# -----------------------------------------------------------------------------
|
||||
add_sdk_driver(common fsl_common.c)
|
||||
add_library(sdk_common STATIC devices/MIMXRT1052/drivers/fsl_common.c
|
||||
devices/MIMXRT1052/drivers/fsl_common_arm.c)
|
||||
target_include_directories(sdk_common PUBLIC devices/MIMXRT1052/drivers)
|
||||
target_compile_definitions(
|
||||
sdk_common PUBLIC SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY=600000000U)
|
||||
target_link_libraries(sdk_common PUBLIC sdk_device)
|
||||
add_sdk_driver(clock fsl_clock.c)
|
||||
|
||||
# clock зависит от common
|
||||
|
|
@ -50,6 +55,7 @@ add_sdk_driver(lpi2c fsl_lpi2c.c)
|
|||
add_sdk_driver(pwm fsl_pwm.c)
|
||||
add_sdk_driver(adc fsl_adc.c)
|
||||
add_sdk_driver(elcdif fsl_elcdif.c)
|
||||
add_sdk_driver(cache fsl_cache.c)
|
||||
|
||||
# Драйверы которые зависят от clock
|
||||
target_link_libraries(sdk_lpuart PUBLIC sdk_clock)
|
||||
|
|
@ -101,15 +107,67 @@ target_link_libraries(
|
|||
sdk_usb_config sdk_osa_bm)
|
||||
target_compile_options(sdk_usb_device_ehci PRIVATE -w)
|
||||
|
||||
# --- sdk_usb_device_ch9: Chapter 9 standard requests ---
|
||||
# add_library(sdk_usb_device_ch9 STATIC middleware/usb/device/usb_device_ch9.c)
|
||||
# target_include_directories( sdk_usb_device_ch9 PUBLIC middleware/usb/device
|
||||
# middleware/usb/device/class) target_link_libraries(sdk_usb_device_ch9 PUBLIC
|
||||
# sdk_usb_device_ehci) target_compile_options(sdk_usb_device_ch9 PRIVATE -w)
|
||||
|
||||
# --- sdk_usb_phy: USB PHY ---
|
||||
add_library(sdk_usb_phy STATIC middleware/usb/phy/usb_phy.c)
|
||||
target_include_directories(sdk_usb_phy PUBLIC middleware/usb/phy)
|
||||
target_link_libraries(sdk_usb_phy PUBLIC sdk_device sdk_common sdk_usb_common
|
||||
sdk_usb_config sdk_osa_bm)
|
||||
target_compile_options(sdk_usb_phy PRIVATE -w)
|
||||
|
||||
# =============================================================================
|
||||
# SDMMC middleware — SD-карта через USDHC, non-blocking (interrupt-driven).
|
||||
#
|
||||
# НЕ зависит от ffconf.h → безопасно компилировать один раз как общую
|
||||
# статическую библиотеку. Оба бинарника (firmware_test, tft_app) линкуются к
|
||||
# одному и тому же sdk_sdmmc_sd.
|
||||
#
|
||||
# =============================================================================
|
||||
add_library(
|
||||
sdk_sdmmc_sd STATIC
|
||||
middleware/sdmmc/sd/fsl_sd.c middleware/sdmmc/common/fsl_sdmmc_common.c
|
||||
middleware/sdmmc/osa/fsl_sdmmc_osa.c
|
||||
middleware/sdmmc/host/usdhc/non_blocking/fsl_sdmmc_host.c)
|
||||
|
||||
target_include_directories(
|
||||
sdk_sdmmc_sd
|
||||
PUBLIC middleware/sdmmc/sd middleware/sdmmc/common middleware/sdmmc/osa
|
||||
middleware/sdmmc/host/usdhc/non_blocking middleware/sdmmc/host/usdhc)
|
||||
|
||||
target_link_libraries(sdk_sdmmc_sd PUBLIC sdk_usdhc sdk_osa_bm sdk_cache
|
||||
sdk_common)
|
||||
|
||||
# Подавляем предупреждения SDK — они нам не принадлежат.
|
||||
target_compile_options(sdk_sdmmc_sd PRIVATE -w)
|
||||
|
||||
# =============================================================================
|
||||
# FatFS — только заголовки и переменные с путями к исходникам.
|
||||
#
|
||||
# ff.c и fsl_sd_disk.c НЕ компилируются здесь, потому что оба включают ff.h →
|
||||
# ffconf.h, который разный у firmware_test (bare-metal) и tft_app (FreeRTOS).
|
||||
# Каждый бинарник сам добавляет их в свои sources.
|
||||
#
|
||||
# Использование в CMakeLists.txt бинарника:
|
||||
# target_link_libraries(my_fatfs_target PRIVATE sdk_fatfs_headers)
|
||||
# target_sources(my_fatfs_target PRIVATE ${SDK_FATFS_FF_SRC}
|
||||
# ${SDK_FATFS_SD_DISK_SRC})
|
||||
# =============================================================================
|
||||
add_library(sdk_fatfs_headers INTERFACE)
|
||||
target_include_directories(
|
||||
sdk_fatfs_headers INTERFACE middleware/fatfs/source
|
||||
middleware/fatfs/source/fsl_sd_disk)
|
||||
# Транзитивно тащим SDMMC: fsl_sd_disk.c вызывает SD_*() из sdk_sdmmc_sd.
|
||||
target_link_libraries(sdk_fatfs_headers INTERFACE sdk_sdmmc_sd)
|
||||
|
||||
# Пути к исходникам, которые должны компилироваться per-binary. CACHE INTERNAL —
|
||||
# видны во всём дереве, не переопределяются.
|
||||
set(SDK_FATFS_FF_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/middleware/fatfs/source/ff.c
|
||||
CACHE INTERNAL
|
||||
"FatFS: путь к ff.c (компилировать per-binary с нужным ffconf.h)")
|
||||
|
||||
set(SDK_FATFS_SD_DISK_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/middleware/fatfs/source/fsl_sd_disk/fsl_sd_disk.c
|
||||
CACHE
|
||||
INTERNAL
|
||||
"FatFS: путь к fsl_sd_disk.c (компилировать per-binary с нужным ffconf.h)"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@
|
|||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#include "ff.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Definitions of physical drive number for each drive */
|
||||
|
|
@ -21,7 +23,8 @@ extern "C" {
|
|||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
|
|
@ -29,25 +32,21 @@ typedef enum {
|
|||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize(BYTE pdrv);
|
||||
DSTATUS disk_status(BYTE pdrv);
|
||||
DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
|
|
@ -55,7 +54,8 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
|||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
#define CTRL_TRIM \
|
||||
4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
|
|
|
|||
1738
sdk/sdk_tree.txt
Normal file
1738
sdk/sdk_tree.txt
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue