# parallel-nand Переносимый C99-драйвер асинхронной parallel NAND x8 и окно управления через общее адресное пространство GAS. Есть профили Micron `MT29F1G08ABADA` и Hynix `HY27UF084G2M` (512 MiB, 2048+64 байта, 64 страницы в блоке, 4096 блоков, ID `AD DC 80 95`). Подготовлены аппаратные порты: - `TMS320F2812` — XINTF Zone 6; - `STM32F407VET6` — аппаратный FSMC NAND Bank 2; - `STM32F103RCT6` — GPIO bit-bang, так как в LQFP64 FSMC недоступен; - `STM32F103ZET6` — аппаратный FSMC NAND Bank 3; - `STM32G474CEU6` — GPIO bit-bang для корпуса UFQFPN-48. Ядро не зависит от HAL и транспорта GUI. STM32 HAL используется только в конкретных портах. `parallel_nand_gas` реализует переносимую 16-битную карту GAS и компилируется в том числе TI C28x, где `char` имеет 16 бит. ## Подключение В проект добавить: ```text c/parallel-nand/src/parallel_nand.c c/parallel-nand/src/parallel_nand_gas.c ``` Пути заголовков: ```text c/parallel-nand/include c/parallel-nand/ports/<нужный-порт> ``` И один аппаратный порт, например: ```text c/parallel-nand/ports/stm32g474ce/parallel_nand_port_stm32g474ce.c ``` Минимальная инициализация: ```c static parallel_nand_t nand; static parallel_nand_gas_t nand_gas; void memory_init(void) { int rc = parallel_nand_init(&nand, parallel_nand_port_stm32g474ce(), ¶llel_nand_mt29f1g08_geometry); if (rc != PNAND_OK) { /* Оставить диагностику доступной GUI и сообщить ошибку платы. */ } parallel_nand_gas_init(&nand_gas, &nand, PNAND_GAS_DEFAULT_BASE); } ``` Для Hynix на STM32F103ZET6 используйте `parallel_nand_port_stm32f103ze()` и `parallel_nand_hy27uf084g2m_geometry`; распиновка и ограничения приведены в [`ports/stm32f103ze/README.md`](ports/stm32f103ze/README.md). Порт RCT6 с GPIO bit-bang сохранён как отдельный вариант для корпуса LQFP64. Диспетчер общего адресного пространства вызывает `parallel_nand_gas_read()`/`parallel_nand_gas_write()` для адресов `0xE000..0xE51F`. Для STM32 с `c/set-protocol/pcan_gas` дополнительно включить `src/parallel_nand_pcan_gas.c`, создать `pcan_gas_region_t` и вызвать `parallel_nand_pcan_gas_region_init()`. Этот адаптер намеренно не нужен TMS. Для полного дампа предпочтительны пакетные `READ_REGISTERS/WRITE_REGISTERS`, а classic CAN GAS оставлен для совместимости и коротких диагностических чтений. Доступ GUI и алгоритм полного дампа описаны в [docs/MEMORY_GAS.md](docs/MEMORY_GAS.md). Электрические соединения — в README соответствующего порта и [docs/EMPTY_BOARD_PINOUT.md](docs/EMPTY_BOARD_PINOUT.md). ## PROGRAM и ERASE - `parallel_nand_program_page()` записывает полную main-область и, при необходимости, полную OOB-область страницы. - `parallel_nand_erase_block()` стирает один физический блок. - Перед изменением ядро проверяет заводской bad-block marker, на время операции снимает `WP#`, ждёт `R/B#`, проверяет fail-бит статуса и снова включает защиту при любом результате. - Порт обязан объявить `write_supported = 1`; иначе возвращается `PNAND_ERROR_WRITE_PROTECTED`. Это защищает платы, где `WP#` постоянно соединён с GND. - Через GAS разрушительные команды требуют записи `0xA55A` в `CONFIRM` непосредственно перед `PROGRAM_PAGE` или `ERASE_BLOCK`. NAND можно программировать только из `1` в `0`; для повторной записи сначала стирается весь блок. Не стирайте заводские bad-блоки и не используйте raw-запись как файловую систему без ECC, wear leveling и защиты загрузочных блоков. ## Текущие границы - Реализованы чтение, программирование страницы, стирание блока, RESET, READ ID, STATUS и проверка bad-block marker. - ECC пока не исправляет данные. GUI получает физические main/OOB и должен помечать дамп как raw. - В полном дампе bad-блоки не пропускаются: сохраняется физический порядок. - Для другой NAND нужно передать другую `parallel_nand_geometry_t` и проверить команды/маркер по её datasheet. ## Проверка первого запуска 1. Запустить `parallel_nand_init()`. 2. Через GAS проверить `0xE000 = 0x4E44`. 3. Записать `2` в `0xE004` (`READ_ID`). 4. Проверить `0xE00B = 0x002C`, `0xE00C = 0x00F1`. 5. Записать номер страницы в `0xE005/0xE006`, затем `3` в `0xE004`. 6. Дождаться `READY | PAGE_VALID` в `0xE002`. 7. Прочитать main из `0xE100..0xE4FF`, OOB из `0xE500..0xE51F`. 8. PROGRAM/ERASE проверять только на заведомо расходном блоке после сохранения полного raw-дампа.