# Работа с parallel NAND через GAS ## Архитектура Внешняя NAND значительно больше общего адресного пространства GAS. Например, `MT29F1G08ABADA` содержит 128 МиБ main area, а GAS имеет только 65536 16-битных регистров. Поэтому NAND представлена не линейным диапазоном, а банковым окном одной физической страницы. ```text SETGUI │ GUI protocol v1: READ_REGISTERS / WRITE_REGISTERS ▼ карта GAS 0x0000..0xFFFF │ 0xE000: управление, 0xE100: main, 0xE500: OOB ▼ parallel_nand_gas ▼ общее ядро parallel_nand ├─ TMS320F2812: XINTF ├─ STM32F407VE: FSMC └─ STM32G474CE: GPIO ``` GUI работает одинаково со всеми МК. Тип процессора влияет только на выбранный файл из `ports/`. Встроенный проект должен направлять весь диапазон `0xE000..0xE51F` в `parallel_nand_gas_read()` и `parallel_nand_gas_write()`. Их аргументы имеют тип `unsigned int`: на C28x это нативное 16-битное слово, а на ARM функции явно оставляют только младшие 16 бит. Так карта и wire-формат совпадают без предположения, что C `char` всегда восьмибитный. Для STM32, использующего карту `pcan_gas`, готов адаптер: ```c #include "parallel_nand_pcan_gas.h" static pcan_gas_region_t nand_region; parallel_nand_pcan_gas_region_init(&nand_region, &nand_gas); ``` Для TMS320F2812 переносимый обработчик вызывается прямо из существующего GAS диспетчера: ```c if (address >= nand_gas.base && address < nand_gas.base + PNAND_GAS_REGION_REGS) { return parallel_nand_gas_read(&nand_gas, address, value); } ``` Если тип результата диспетчера отличается, статусы `PNAND_GAS_OK`, `PNAND_GAS_NO_REG`, `PNAND_GAS_READ_ONLY` и `PNAND_GAS_REJECTED` преобразуются в его локальные статусы так же, как это сделано в `parallel_nand_pcan_gas.c`. ## Транспорт до GUI Карта GAS не привязана к физическому каналу. Рекомендуемый путь для полного дампа — используемые SETGUI сообщения `WRITE_REGISTERS (0x0A)` и `READ_REGISTERS (0x09)`: они позволяют передавать крупные блоки поверх USB, UART, RS-485 или Ethernet. Адаптер `pcan_gas` нужен, когда теми же регистрами обмениваются по classic CAN; там один кадр несёт только четыре регистра, и полный 128-MiB дамп будет значительно медленнее. Устройство не должно собирать весь дамп в RAM. Буферизуется только одна страница. Из-за переносимости на C28x каждый octet хранится в `unsigned short`, поэтому статические буферы GAS занимают примерно 4,2 KiB RAM и на TMS, и на ARM. ## Карта GAS Базовый адрес по умолчанию — `0xE000`. Его можно изменить при вызове `parallel_nand_gas_init()`; все смещения ниже останутся прежними. | Адрес | Доступ | Название | Значение | |---:|:---:|---|---| | `E000` | R | `SIGNATURE` | `0x4E44` (`ND`) | | `E001` | R | `VERSION` | версия окна, сейчас 1 | | `E002` | R | `STATUS` | состояние операции | | `E003` | R | `ERROR` | код `PNAND_*`, 0 = нет ошибки | | `E004` | W | `COMMAND` | команда окна | | `E005` | R/W | `PAGE_LO` | младшие 16 бит физической страницы | | `E006` | R/W | `PAGE_HI` | старшие 16 бит физической страницы | | `E007` | R | `PAGE_MAIN` | main bytes, для MT29 = 2048 | | `E008` | R | `PAGE_OOB` | OOB bytes, для MT29 = 64 | | `E009` | R | `PAGES_PER_BLOCK` | для MT29 = 64 | | `E00A` | R | `BLOCKS` | для MT29 = 1024 | | `E00B` | R | `MANUFACTURER_ID` | ожидается `0x2C` | | `E00C` | R | `DEVICE_ID` | ожидается `0xF1` | | `E00D` | R | `BAD_BLOCK` | 1 для физически плохого блока | | `E00E` | R | `GENERATION_LO` | счётчик загруженных страниц, low | | `E00F` | R | `GENERATION_HI` | счётчик загруженных страниц, high | | `E100..E4FF` | R | `PAGE_DATA` | 1024 регистра main, два байта LE | | `E500..E51F` | R | `PAGE_OOB` | 32 регистра OOB, два байта LE | Между управляющими регистрами и окнами данных есть зарезервированные адреса. Чтение блока через них не выполняется: каждый запрос должен начинаться внутри существующего участка. ## STATUS | Бит | Маска | Смысл | |---:|---:|---| | 0 | `0x0001` | `READY` | | 1 | `0x0002` | `BUSY` | | 2 | `0x0004` | `PAGE_VALID` | | 3 | `0x0008` | `BAD_BLOCK` | | 15 | `0x8000` | `ERROR`, подробность в `E003` | GUI читает окно данных только при `READY=1`, `PAGE_VALID=1`, `ERROR=0`. ## COMMAND | Значение | Команда | Результат | |---:|---|---| | 1 | `RESET` | сброс NAND и ожидание Ready | | 2 | `READ_ID` | обновляет `E00B/E00C` | | 3 | `READ_PAGE` | загружает main/OOB выбранной страницы | Запись номера страницы и запуск — две отдельные операции. Сначала GUI пишет `PAGE_LO/PAGE_HI`, затем записывает `READ_PAGE` в `COMMAND`. Нельзя отправлять один блок, начинающийся с `COMMAND`: команда выполнилась бы до обновления номера страницы. ## Последовательность полного дампа 1. Прочитать `E000..E00F`, проверить подпись, версию и геометрию. 2. Выполнить `READ_ID`; для микросхемы с фотографии проверить `2C F1`. 3. Рассчитать `page_count = PAGES_PER_BLOCK * BLOCKS`. 4. Для каждой физической страницы от 0 до `page_count - 1`: - записать номер страницы в `E005/E006`; - записать `3` в `E004`; - опрашивать `E002`, пока не установлен `READY`; - проверить `ERROR`, `BAD_BLOCK` и изменение `GENERATION`; - прочитать `E100..E4FF`; - прочитать `E500..E51F`; - сразу дописать данные и метаданные в файлы. 5. Не пропускать bad-блоки: иначе файл потеряет соответствие физическим страницам микросхемы. GUI protocol v1 допускает payload до 512 байт. Ответ `READ_REGISTERS` содержит четырёхбайтовый заголовок диапазона, поэтому за один запрос следует читать не более 254 GAS-регистров. Страница main читается пятью запросами: четыре раза по 254 регистра и последний раз 8 регистров. OOB читается одним запросом на 32 регистра. ## Возобновление GUI хранит номер последней полностью записанной страницы. После разрыва связи он повторно проверяет подпись/ID/геометрию и продолжает со следующей страницы. Страница считается готовой только после записи main, OOB и записи её статуса в метаданные. Рекомендуемые выходные файлы: - `dump.bin` — 2048 байт main каждой физической страницы; - `dump.oob` — 64 байта OOB каждой физической страницы; - `dump.json` — ID, геометрия, bad-блоки, ошибки и последняя готовая страница. Для `MT29F1G08ABADA` размеры завершённого дампа: `dump.bin` = 134217728 байт, `dump.oob` = 4194304 байта. ## ECC Текущая версия шаблона отдаёт raw main/OOB и не заявляет исправление ошибок. Статус bad-блока определяется по первому байту OOB первых двух страниц блока. Перед использованием дампа как рабочего образа нужно добавить ECC-политику для точного чипа и формата OOB. Само окно GAS при этом менять не требуется: можно добавить новые флаги состояния в свободные биты `STATUS`. ## PROGRAM/ERASE Запись и стирание не включены намеренно. Они требуют отдельного разрешения, проверки ECC, защиты загрузочных блоков и двухфазного подтверждения через GAS. До добавления этих функций `WP#` удерживается активным аппаратным портом.