feat: add STM32F103ZE FSMC NAND port
This commit is contained in:
@@ -10,6 +10,7 @@ Hynix `HY27UF084G2M` (512 MiB, 2048+64 байта, 64 страницы в бло
|
|||||||
- `TMS320F2812` — XINTF Zone 6;
|
- `TMS320F2812` — XINTF Zone 6;
|
||||||
- `STM32F407VET6` — аппаратный FSMC NAND Bank 2;
|
- `STM32F407VET6` — аппаратный FSMC NAND Bank 2;
|
||||||
- `STM32F103RCT6` — GPIO bit-bang, так как в LQFP64 FSMC недоступен;
|
- `STM32F103RCT6` — GPIO bit-bang, так как в LQFP64 FSMC недоступен;
|
||||||
|
- `STM32F103ZET6` — аппаратный FSMC NAND Bank 3;
|
||||||
- `STM32G474CEU6` — GPIO bit-bang для корпуса UFQFPN-48.
|
- `STM32G474CEU6` — GPIO bit-bang для корпуса UFQFPN-48.
|
||||||
|
|
||||||
Ядро не зависит от HAL и транспорта GUI. STM32 HAL используется только в
|
Ядро не зависит от HAL и транспорта GUI. STM32 HAL используется только в
|
||||||
@@ -57,10 +58,11 @@ void memory_init(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Для Hynix на STM32F103RCT6 используйте
|
Для Hynix на STM32F103ZET6 используйте
|
||||||
`parallel_nand_port_stm32f103rc()` и
|
`parallel_nand_port_stm32f103ze()` и
|
||||||
`parallel_nand_hy27uf084g2m_geometry`; распиновка и ограничения приведены в
|
`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()` для адресов
|
`parallel_nand_gas_read()`/`parallel_nand_gas_write()` для адресов
|
||||||
|
|||||||
59
ports/stm32f103ze/README.md
Normal file
59
ports/stm32f103ze/README.md
Normal file
@@ -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`.
|
||||||
183
ports/stm32f103ze/parallel_nand_port_stm32f103ze.c
Normal file
183
ports/stm32f103ze/parallel_nand_port_stm32f103ze.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
16
ports/stm32f103ze/parallel_nand_port_stm32f103ze.h
Normal file
16
ports/stm32f103ze/parallel_nand_port_stm32f103ze.h
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user