diff --git a/README.md b/README.md index b2b585e..915931e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Hynix `HY27UF084G2M` (512 MiB, 2048+64 байта, 64 страницы в бло - `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 используется только в @@ -57,10 +58,11 @@ void memory_init(void) } ``` -Для Hynix на STM32F103RCT6 используйте -`parallel_nand_port_stm32f103rc()` и +Для Hynix на STM32F103ZET6 используйте +`parallel_nand_port_stm32f103ze()` и `parallel_nand_hy27uf084g2m_geometry`; распиновка и ограничения приведены в -[`ports/stm32f103rc/README.md`](ports/stm32f103rc/README.md). +[`ports/stm32f103ze/README.md`](ports/stm32f103ze/README.md). Порт RCT6 +с GPIO bit-bang сохранён как отдельный вариант для корпуса LQFP64. Диспетчер общего адресного пространства вызывает `parallel_nand_gas_read()`/`parallel_nand_gas_write()` для адресов diff --git a/ports/stm32f103ze/README.md b/ports/stm32f103ze/README.md new file mode 100644 index 0000000..0be0c35 --- /dev/null +++ b/ports/stm32f103ze/README.md @@ -0,0 +1,59 @@ +# Порт STM32F103ZET6 для HY27UF084G2M + +Порт использует аппаратный контроллер `FSMC NAND Bank 3`, 8-битную шину и +окно памяти `0x70000000`. Сигналы `CE#`, `WE#`, `RE#`, `CLE` и `ALE` +формируются FSMC. Защита записи `WP#` управляется отдельным GPIO `PG8`. + +## Соединения + +| HY27UF084G2M | STM32F103ZET6 | LQFP144 | Функция FSMC | +|---|---|---:|---| +| `I/O0` | `PD14` | 85 | `D0` | +| `I/O1` | `PD15` | 86 | `D1` | +| `I/O2` | `PD0` | 114 | `D2` | +| `I/O3` | `PD1` | 115 | `D3` | +| `I/O4` | `PE7` | 58 | `D4` | +| `I/O5` | `PE8` | 59 | `D5` | +| `I/O6` | `PE9` | 60 | `D6` | +| `I/O7` | `PE10` | 63 | `D7` | +| `CLE` | `PD11` | 80 | `A16/CLE` | +| `ALE` | `PD12` | 81 | `A17/ALE` | +| `WE#` | `PD5` | 119 | `NWE` | +| `RE#` | `PD4` | 118 | `NOE` | +| `CE#` | `PD7` | 123 | `NCE2` | +| `R/B#` | `PD6` | 122 | вход GPIO (`NWAIT`) | +| `WP#` | `PG8` | 93 | выход GPIO | + +`R/B#` имеет открытый сток и требует внешней подтяжки 4,7–10 кОм к 3,3 В. +Питание NAND — 3,3 В; возле каждой пары питания нужен 100 нФ, рядом с +микросхемой — 1–4,7 мкФ. Все номера выводов MCU указаны для вида сверху. + +## Подключение к STM32Cube HAL + +В `stm32f1xx_hal_conf.h` должны быть включены `HAL_NAND_MODULE_ENABLED` и +`HAL_GPIO_MODULE_ENABLED`. В проект добавляются: + +- `parallel_nand_port_stm32f103ze.c`; +- `stm32f1xx_hal_nand.c`; +- `stm32f1xx_ll_fsmc.c`. + +Инициализация переносимой библиотеки: + +```c +#include "parallel_nand.h" +#include "parallel_nand_port_stm32f103ze.h" + +static parallel_nand_t nand; + +int nand_init(void) +{ + return parallel_nand_init( + &nand, + parallel_nand_port_stm32f103ze(), + ¶llel_nand_hy27uf084g2m_geometry); +} +``` + +Начальные тайминги намеренно консервативны. После запуска проверьте +осциллографом длительности `WE#`/`RE#` и время установки данных. Ожидаемый ID +HY27UF084G2M: `AD DC 80 95`. diff --git a/ports/stm32f103ze/parallel_nand_port_stm32f103ze.c b/ports/stm32f103ze/parallel_nand_port_stm32f103ze.c new file mode 100644 index 0000000..e1e6a3e --- /dev/null +++ b/ports/stm32f103ze/parallel_nand_port_stm32f103ze.c @@ -0,0 +1,183 @@ +#include "parallel_nand_port_stm32f103ze.h" + +#include "stm32f1xx_hal.h" +#include "stm32f1xx_hal_nand.h" + +/* STM32F103 names this block FSMC NAND Bank 3. Its HAL memory window is + * NAND_DEVICE1; each access makes FSMC assert PD7/FSMC_NCE2 automatically. */ +#define PNAND_F103ZE_DATA_ADDRESS 0x70000000UL +#define PNAND_F103ZE_COMMAND_AREA (1UL << 16U) +#define PNAND_F103ZE_ADDRESS_AREA (1UL << 17U) + +/* WP# is not generated by FSMC, so it is controlled as an ordinary GPIO. */ +#define PNAND_F103ZE_WP_PORT GPIOG +#define PNAND_F103ZE_WP_PIN GPIO_PIN_8 + +/* HAL owns the FSMC registers through this handle during initialization. */ +static NAND_HandleTypeDef nand_handle; + +/** Configure all FSMC signals that belong to GPIO port D. */ +static void configure_fsmc_gpio_d(void) +{ + GPIO_InitTypeDef pin = {0}; + + /* D0..D3, NOE, NWE, NCE2, CLE and ALE are driven by FSMC. On STM32F1 + * alternate-function output mode is selected without an AF number. */ + pin.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | + GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_12 | + GPIO_PIN_14 | GPIO_PIN_15; + pin.Mode = GPIO_MODE_AF_PP; + pin.Pull = GPIO_NOPULL; + pin.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOD, &pin); + + /* R/B# is read directly. Its open-drain output needs an external + * 4.7..10 kOhm pull-up to 3.3 V. */ + pin.Pin = GPIO_PIN_6; + pin.Mode = GPIO_MODE_INPUT; + pin.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOD, &pin); +} + +/** Configure FSMC data bits D4..D7 on GPIO port E. */ +static void configure_fsmc_gpio_e(void) +{ + GPIO_InitTypeDef pin = {0}; + + pin.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; + pin.Mode = GPIO_MODE_AF_PP; + pin.Pull = GPIO_NOPULL; + pin.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOE, &pin); +} + +/** Configure the explicit write-protect output and assert protection. */ +static void configure_write_protect(void) +{ + GPIO_InitTypeDef pin = {0}; + + /* Set the safe active-low level before changing the pad to an output. */ + HAL_GPIO_WritePin(PNAND_F103ZE_WP_PORT, PNAND_F103ZE_WP_PIN, + GPIO_PIN_RESET); + + pin.Pin = PNAND_F103ZE_WP_PIN; + pin.Mode = GPIO_MODE_OUTPUT_PP; + pin.Pull = GPIO_NOPULL; + pin.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(PNAND_F103ZE_WP_PORT, &pin); +} + +/** Initialize the STM32F1 HAL NAND layer with conservative 72 MHz timings. */ +static int f103ze_init(void) +{ + FSMC_NAND_PCC_TimingTypeDef common_timing = {0}; + FSMC_NAND_PCC_TimingTypeDef attribute_timing = {0}; + + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_FSMC_CLK_ENABLE(); + + configure_fsmc_gpio_d(); + configure_fsmc_gpio_e(); + configure_write_protect(); + + nand_handle.Instance = FSMC_NAND_DEVICE; + nand_handle.Init.NandBank = FSMC_NAND_BANK3; + nand_handle.Init.Waitfeature = FSMC_NAND_PCC_WAIT_FEATURE_DISABLE; + nand_handle.Init.MemoryDataWidth = FSMC_NAND_PCC_MEM_BUS_WIDTH_8; + nand_handle.Init.EccComputation = FSMC_NAND_ECC_DISABLE; + nand_handle.Init.ECCPageSize = FSMC_NAND_ECC_PAGE_SIZE_2048BYTE; + nand_handle.Init.TCLRSetupTime = 2U; + nand_handle.Init.TARSetupTime = 2U; + + /* One FSMC tick is about 13.9 ns at HCLK=72 MHz. These deliberately + * relaxed values are suitable for first bring-up and signal probing. */ + common_timing.SetupTime = 2U; + common_timing.WaitSetupTime = 5U; + common_timing.HoldSetupTime = 3U; + common_timing.HiZSetupTime = 2U; + attribute_timing = common_timing; + + return HAL_NAND_Init(&nand_handle, &common_timing, &attribute_timing) == + HAL_OK + ? 0 + : -1; +} + +static void f103ze_select(void) +{ + /* A memory-window access asserts NCE2; no separate software GPIO exists. */ +} + +static void f103ze_deselect(void) +{ + /* NCE2 is released automatically when the FSMC access finishes. */ +} + +static void f103ze_write_command(pnand_octet_t value) +{ + *(__IO uint8_t *)(PNAND_F103ZE_DATA_ADDRESS | + PNAND_F103ZE_COMMAND_AREA) = (uint8_t)value; + __DSB(); /* Complete the external bus write before the next NAND cycle. */ +} + +static void f103ze_write_address(pnand_octet_t value) +{ + *(__IO uint8_t *)(PNAND_F103ZE_DATA_ADDRESS | + PNAND_F103ZE_ADDRESS_AREA) = (uint8_t)value; + __DSB(); +} + +static void f103ze_write_data(pnand_octet_t value) +{ + *(__IO uint8_t *)PNAND_F103ZE_DATA_ADDRESS = (uint8_t)value; + __DSB(); +} + +static pnand_octet_t f103ze_read_data(void) +{ + uint8_t value = *(__IO uint8_t *)PNAND_F103ZE_DATA_ADDRESS; + __DSB(); + return (pnand_octet_t)value; +} + +static int f103ze_is_ready(void) +{ + return HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_6) == GPIO_PIN_SET; +} + +static void f103ze_set_write_protect(int enabled) +{ + /* NAND WP# is active low: RESET protects, SET permits program/erase. */ + HAL_GPIO_WritePin(PNAND_F103ZE_WP_PORT, PNAND_F103ZE_WP_PIN, + enabled ? GPIO_PIN_RESET : GPIO_PIN_SET); +} + +static void f103ze_delay_us(unsigned long us) +{ + /* Approximate delay used only around reset/status polling. The factor + * accounts for loop instructions in addition to the NOP. */ + uint32_t cycles = (SystemCoreClock / 3000000UL) * (uint32_t)us; + while (cycles-- != 0U) { + __NOP(); + } +} + +static const parallel_nand_port_t f103ze_port = { + f103ze_init, + f103ze_select, + f103ze_deselect, + f103ze_write_command, + f103ze_write_address, + f103ze_write_data, + f103ze_read_data, + f103ze_is_ready, + f103ze_set_write_protect, + f103ze_delay_us +}; + +const parallel_nand_port_t *parallel_nand_port_stm32f103ze(void) +{ + return &f103ze_port; +} diff --git a/ports/stm32f103ze/parallel_nand_port_stm32f103ze.h b/ports/stm32f103ze/parallel_nand_port_stm32f103ze.h new file mode 100644 index 0000000..d5483a4 --- /dev/null +++ b/ports/stm32f103ze/parallel_nand_port_stm32f103ze.h @@ -0,0 +1,16 @@ +#ifndef PARALLEL_NAND_PORT_STM32F103ZE_H +#define PARALLEL_NAND_PORT_STM32F103ZE_H + +#include "parallel_nand_port.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const parallel_nand_port_t *parallel_nand_port_stm32f103ze(void); + +#ifdef __cplusplus +} +#endif + +#endif