Rockchip · AI & Linux Hub

Speicher und Netzwerk

Rockchip RT-Thread SPI Flash: Entwicklerleitfaden

Rockchip RT-Thread SPI Flash: Entwicklerleitfaden — V1.4.0

· ArmSoM Editorial · Rockchip source documentation · 22 Min. Lesezeit

Rockchip-Plattformreferenz für das RK RT-Thread SDK mit den in der Quelle aufgeführten Chips einschließlich RK2108/RK2118. Unterstützung konkreter ArmSoM-Platinen ist unbestätigt; keine Hardwarevalidierung. Vor Anpassung SoC, SDK/BSP, RT-Thread-Version, Controller, IOMUX, Verdrahtung und Spannungsdomänen prüfen. Befehle und Testergebnisse stammen aus der Quelle, nicht aus ArmSoM-Messungen; keine Hardware- oder Flash-Operationen wurden ausgeführt. Nur das chinesische Original liegt vor; alle vier Sprachen verwenden dessen Abbildungen.

RK-KF-YF-080 · V1.4.0

ArmSoM Docs · RT-Thread

1. Einführung

1.1 Unterstützte Bausteine

SPI NOR bietet kleine Gehäuse, schnellere Lesezugriffe als andere kleine nichtflüchtige Speicher, wenige Pins und einfache Protokolle. Übliche Bausteine unterstützen 1/2/4 Leitungen, sind wenig anfällig für Bitfehler, byteadressierbar und lesen ohne Wartezeit nach Befehl/Adresse; dies ermöglicht XIP (Quelle: “Excute In Place”). RK RTOS bietet generische NOR-Schnittstellen und automatisches XIP. SPI NAND verwendet dieselben Controller und wird im RT-Thread SDK unterstützt. Es benötigt aber FTL oder ein FTL-fähiges Dateisystem, mit beträchtlichem RAM-/Codebedarf und begrenzter Stabilität. Stabile Versorgung beim Abschalten ist wichtig; batterielose MCU-Produkte sind gefährdet. Daher rät die Quelle von NAND ab, außer begrenzten Erweiterungen für schreibgeschützte Firmware.

1.2 Host-Controller

RK SPI flash kann FSPI, SFC oder SPI verwenden.

  • FSPI (Flexible Serial Peripheral Interface): SPI NOR/NAND und SPI-PSRAM/SRAM; Standard (eine Leitung), Dual, Quad, teils Octal; SDR, teils DTR; XIP; integriertes DMA.
  • SFC (Serial Flash Controller): SPI NOR/NAND und SPI-PSRAM/SRAM; Standard/Dual/Quad; SDR; integriertes DMA.
  • Allgemeines SPI: SPI NOR/NAND und SPI-PSRAM; Standard mit einer Leitung; SDR; externes DMA.

1.3 NOR-Flash-XIP

XIP (eXecute In Place) lässt die CPU Befehle direkt aus abgebildetem Flash holen, ohne Code ins RAM zu kopieren; Ausführungsadressen sind die Abbildungsadressen. NOR-XIP ist nur lesbar, daher nur Code und schreibgeschützte Daten dort ablegen. FSPI erlaubt auch DSP und anderen Mastern Zugriff wie auf schreibgeschütztes SRAM; siehe TRM FSPI. Die NOR-Lese-API kann XIP (Abbildungszugriff, keine redundante Registerkonfiguration, Prefetch, hohe Effizienz) oder CPU (Controller konfigurieren, FIFO per CPU bewegen) nutzen. Standard ist XIP. RT_SNOR_XIP_DATA_BEGIN setzt den Beginn; bei 327680 liest [0:327680) per CPU und [327680,Ende] per XIP.

1.4 SPI-Flash-Treiberarchitektur

Für FSPI/SFC/SPI wird die Controllerschicht abstrahiert. Vier NOR-Schichten: MTD; RTOS-Treiber (Geräteregistrierung, Controller/Operationen bei HAL_SNOR registrieren, Lesen/Schreiben/Löschen kapseln); HAL_SNOR-Protokoll; Controller. Die Quelle nennt trotz drei Einträgen „zwei“ Controllertypen.

Abbildung des chinesischen Originals (p.6)

Abbildung des chinesischen Originals (p.6)

FSPI: drv_snor.c kapselt HAL-Lesen/-Schreiben als SPI_Xfer, registriert FSPI-Host und SPI_Xfer bei HAL_SNOR, kapselt Lesen/Schreiben/Löschen und registriert das OS-Gerät bei MTD. hal_snor.c implementiert NOR, hal_fspi.c den Controller. SPI: drv_snor.c kapselt OS-Treiber-Lesen/-Schreiben als SPI_Xfer, registriert Host und SPI_Xfer bei HAL_SNOR, kapselt Protokolloperationen und registriert MTD. hal_snor.c implementiert das Protokoll, hal_spi.c den Low-Level-Controller und SpiDevice.c Registrierung und Kapselung des RTOS-SPI-Treibers. Hinweise:

  1. Die Implementierungen entsprechen dem Diagramm.
  1. RK SPI DMA liegt im OS-Treiber. SPI bedient weitere Geräte und benötigt Ressourcenschutz. Daher muss Flash die OS-SPI-Schnittstelle verwenden, nicht direkt hal_spi.c.

1.5 FSPI-Chipeigenschaften

Nur SoCs mit Open-Source-Speicherlösung sind aufgeführt.

SOC FSPI/SFC IO max rate FSPI/SFC data io lines Support XIP
RK2108/Pisces 150MHz x1\x2\x4 SDR Y
RK2206 150MHz x1\x2\x4 SDR Y
RK2118 SDR:133MHz
DTR:80MHz
x1\x2\x4 SDR
x4 DDR with/without DQS
x8 DDR with/without DQS
Y

AP-Unterstützung: Rockchip_Developer_Guide_Linux_Flash_Open_Source_Solution_CN.md. x1 heißt Standard, x2 Dual, x4 Quad, x8 Octal. Quad standardmäßig SDR, Octal DDR with DQS.

2. SPI NOR

2.1 Konfiguration

2.1.1 Architektur

Type Memory Controller driver Flash framework
SPI NOR SPI NOR hal: lib/hal/src/hal_fspi.c
RT-Thread: bsp/rockchip/commob/drv_snor.c
hal: lib/hal/src/hal_snor.c

HAL-Wurzel: bsp/rockchip/common/hal. NOR-Unterstützung in lib/hal/src/hal_snor.c, weitere Dateien im gleichen Verzeichnis. Flash-ID oder Gehäuseaufdruck zuordnen. Die Software erkennt IDs und wählt die größte Controller-Breite; per Treibermakro reduzieren.

2.1.2 Treiberkonfiguration

Zuerst den tatsächlichen SPI-Flash-Controller bestimmen und passende Lösung wählen. Grundlegender menuconfig-Eintrag:

RT-Thread rockchip common drivers  --->
    [*] Enable ROCKCHIP SPI NOR Flash
    (80000000) Reset the speed of SPI Nor flash in Hz
    [ ]   Set SPI Host DUAL IO Lines /* 如果 FSPI 主控仅预留 IO0~1,应使用 Dual mode */
            Choose SPI Nor Flash Adapter (Attach FSPI controller to SNOR) --->

Konfigurationsdefinitionen:

RT_USING_MTD_NOR=y
RT_USING_SNOR=y
RT_SNOR_SPEED=80000000 /* IO 接口速率 */
# RT_SNOR_DUAL_IO=n /* 默认不配置,Quad SPI 限制为 Duad SPI 使用 */
# RT_SNOR_XIP_DATA_BEGIN=0 /* 默认不配置,XIP 读接口实现起始地址,详细参考 “Nor Flash XIP 技术”说明 */
RT_USING_SNOR_FSPI_HOST=y /* FSPI 控制器方案 */
# RT_USING_SNOR_SFC_HOST=y /* SFC 控制器方案 */
# RT_USING_SNOR_SPI_HOST=y /* SPI 控制器方案 */
# RT_SNOR_SPI_DEVICE_NAME="spi2_0" /* SPI 控制器方案,指定目标控制器 */
RT_USING_DFS_MNTTABLE=y                # 启动 DFS mnt table 自动挂载支持
RT_USING_DFS_ELMFAT=y                  # 启用 elm FatFs
RT_DFS_ELM_MAX_SECTOR_SIZE=4096        # 设置 elm FatFs sector size,设定固定为 4KB

2.1.3 Partitionstabelle

Siehe Partitionstabellenkonfiguration in rockchip/Rockchip_Developer_Guide_RT-Thread_CN.md. NOR registriert nur Partitionen mit FLAG [8,9] property 1, 2 oder 3 als RT-Thread-Geräte. root hat meist Flag=0x305 und wird als root-Blockgerät registriert.

2.1.4 Partitionen erzeugen, lesen und registrieren

Gepackte RK-RT-Thread-Firmware legt RK_PARTITION in die ersten 2KB Flash. Angaben in setting.ini ändern. Nach NOR-Initialisierung liest und registriert snor_partition_init in drv_snor.c die Tabelle. Registrierung prüfen:

msh />list_device
device          type         ref count
------- -------------------- ----------
root     Block Device         1            /* 分区名 root,分区类型 block 设备,Nor flash 支持 setting.ini 修改设定为 MTD 设备 */
snor     MTD Device           0            /* SPI Nor 根存储设备,分区读写最终接入到该 节点完成读写擦除 */

2.1.5 elm-fat und Einhängen

RT-Thread-elm-fat-Unterstützung:

RT-Thread Components --->
    Device virtual file system  --->
    [*] Using device virtual file system
    [*]   Using mount table for file system /* 实现相应注册分区表,可实现分区上电自动挂 载 */
    [*]   Enable elm-chan fatfs /* fat 文件系统 */
        elm-chan's FatFs, Generic FAT Filesystem Module  --->
        (4096) Maximum sector size to be handled. /*对于 SPI Nor 产品必须修改为 4096 */

Mit CONFIG_RT_USING_DFS_MNTTABLE die Registrierung in mnt.c ergänzen, etwa root unter /:

const struct dfs_mount_tbl mount_table[] =
{
    {"root", "/", "elm", 0, 0},
    {0}
};

Für einen eigenen Einhängeablauf:

dfs_mount("root", "/", "elm", 0, 0)

Einhängebefehl:

mount root / elm

elm-fat-Abbilder: ./bsp/rockchip/tools/mkroot.sh verwenden; zentraler Befehl mkfs.fat.

2.2 XIP-Hinweise

NOR unterstützt XIP; FSPI-NOR aktiviert es automatisch. Folgende Hinweise betreffen die Produktnutzung.

2.2.1 XIP aktivieren

Nach Treiberkonfiguration eingerichtetes FSPI-Flash aktiviert XIP standardmäßig. Zum Abschalten “Enable FSPI XIP” deaktivieren.

2.2.2 XIP im Betrieb umschalten

Das Framework schaltet XIP automatisch; Nutzer müssen die Schalter nicht aufrufen. XIP aus:

NOR-Löschen/-Schreiben dauert lange und ist während XIP nicht unterstützt. Bei solchen Anfragen, auch Dateisystemschreiben, suspendiert die Software XIP und schaltet FSPI auf normal mode. XIP ist dann nicht verfügbar. Ablauf:

  1. Alle betroffenen Master zum Aussetzen des XIP-Zugriffs auffordern.
  1. Globale Interrupts sperren, damit kein Interrupt NOR-XIP-Code ausführt.
  1. XIP abschalten.

XIP ein: Nach Löschen/Schreiben und FSPI idle stellt der Treiber XIP wieder her. Ohne solche Operationen bleibt es aktiv. Wiederaufnahme:

  1. XIP aktivieren.
  1. Globale Interrupts freigeben (Quelle schreibt wörtlich „globales Terminal“; als Quellfehler dokumentiert).
  1. Alle ausgesetzten Geräte zur Wiederaufnahme auffordern. Einstiegspunkte:
static rt_base_t snor_xip_suspend(void)
static void snor_xip_resume(rt_base_t level)

Zusammenfassung: FSPI-NOR aktiviert XIP standardmäßig. Im Idle können Geräte NOR über die XIP-Abbildung lesen. Löschen/Schreiben deaktiviert XIP. Geräte müssen zum Stoppen/Fortsetzen benachrichtigt werden. XIP-Abschalten sperrt auch globale Interrupts.

2.3 API-Beispiele

2.3.1 SNOR-MTD-Bytegerät

Siehe _at_snor_test in snor_test.c:

snor_device = (struct rt_mtd_nor_device *)rt_device_find("snor");
rt_mtd_nor_erase_block(snor_device, test_lba * block_size, block_size);
rt_mtd_nor_write(snor_device, test_lba * block_size, (const rt_uint8_t
*)pwrite32, block_size);
rt_mtd_nor_read(snor_device, test_lba * block_size, (rt_uint8_t *)pread32,
block_size);

snor ist ein Bytegerät. rt_mtd_nor_erase_block: Bytes, mindestens 4096Bytes ausrichten (Flash-Sektor). rt_mtd_nor_write/read: Bytes, mindestens 1 Byte. RK-Partitionstabellen verwenden 512B-Sektoren; Einheiten umrechnen.

2.3.2 MTD-Bytegerät einer Partition

Der NOR-Treiber liest die Tabelle und registriert Partitionen. Eine MTD partition in setting.ini wird als Bytegerät mit denselben SNOR-MTD-APIs registriert:

snor_device = (struct rt_mtd_nor_device *)rt_device_find("xxxx");
rt_mtd_nor_erase_block(snor_device, test_lba * block_size, block_size);
rt_mtd_nor_write(snor_device, test_lba * block_size, (const rt_uint8_t
*)pwrite32, block_size);
rt_mtd_nor_read(snor_device, test_lba * block_size, (rt_uint8_t *)pread32,
block_size);

2.3.3 Partitionsblockgerät

Eine Block partition aus setting.ini wird als Blockgerät registriert. Standard-RT-Thread-read/write verwenden; Sektoreinheit 4KB.

2.4 Testtreiber

Bei SPI-Flash-Entwicklung folgende einfache Lese-/Schreibtests einplanen.

2.4.1 Treiberkonfiguration

RT-Thread bsp test case  --->
    RT-Thread Common Test case  --->
        [*] Enable BSP Common TEST
        [*]   Enable BSP Common SNOR TEST (NEW)

Nach erfolgreicher Konfiguration ist snor_test in msh verfügbar.

2.4.2 Testbefehle

snor_test zeigt Hilfe. Alle folgenden Befehlseinheiten sind Bytes.

1. snor_test write offset size
2. snor_test read offset size loop
3. snor_test erase offset
4. snor_test stress offset size loop
5. snor_test io_stress offset size loop width rw
6. snor_test pm_test
like:
        snor_test write 2097152 4096
        snor_test read 2097152 4096 2000
        snor_test erase 2097152
        snor_test stress 2097152 2097152 5000
        snor_test io_stress 2097152 2097152 5000 4
        snor_test pm_test

offset: Byteversatz im Flash, keine XIP-Adresse; nur dezimal. stress: aufsteigende Daten. io_stress width: Folge zum Prüfen der IO-Zustände; 4 für Quad, 8 für Octal. rw: 1 nur Schreiben inklusive Löschen, 2 nur Lesen, 3 Lesen/Schreiben.

2.4.3 Befehlsbeispiele

2.4.3.1 Leserate
msh >snor_test read 2097152 4096 2000
[SNOR TEST] read:  30219d00 + 0x0:0x00000200,0x0000000f,0x000000ff,0x00000000,
[SNOR TEST] read:  30219d00 + 0x10:0x000000ff,0x000000cc,0x000000c3,0x000000cc,
[SNOR TEST] read:  30219d00 + 0x20:0x000000c3,0x0000003c,0x000000cc,0x000000ff,
[SNOR TEST] read:  30219d00 + 0x30:0x000000fe,0x000000ff,0x000000fe,0x000000ef,
snor read speed: 143719 KB/s
2.4.3.2 Quad-Flash-Signaltest

Schreibsignaltest:

snor_test io_stress 2097152 2097152 5000 4 1

Lesesignaltest:

snor_test io_stress 2097152 2097152 5000 4 2
2.4.3.3 Octal-Flash-Signaltest

Schreibsignaltest:

snor_test io_stress 2097152 2097152 5000 8 1

Lesesignaltest:

snor_test io_stress 2097152 2097152 5000 8 2

2.5 Fehlerbehebung

Registrierung prüfen: list_device muss snor zeigen.

“Init adapte error ret= -19” meldet snor_adapt: -1 bedeutet NOR-ID 0xff, eventuell schlechte Lötstelle; Schaltung/Signale prüfen. -19 bedeutet nicht unterstützten Baustein; RK um Ergänzung bitten. -22 bedeutet fehlenden SPI-Controller.

Mehrverbrauch durch dauerhaftes XIP? FSPI gibt nach Idle-Timeout CS frei; NOR geht in stromsparendes Idle. Der Unterschied ist nicht groß.

Mehrere XIP-Master: Der Bus arbitriert und serialisiert; wartende Anfragen bleiben am Bus.

Häufige Dateisystemschreibzugriffe: Code in SRAM/PSRAM legen und XIP deaktivieren, sonst leidet RTOS-Echtzeitverhalten. Bei XIP-Code NOR-Löschen/-Schreiben minimieren.

Dateisystemlesen schaltet XIP nicht ab; der Treiber liest darüber.

Ohne gespeicherte Partitionstabelle ist Einhängen nicht möglich. Die Tabelle muss am Flash-Anfang liegen; der aktuelle RK-NOR-Treiber liest nur diese Tabelle.

3. SPI NAND

3.1 Hinweise

3.1.1 RK-SPI-NAND-Speicher

Filesystem Update
FATFS USB / programmer / OTA

3.2 Konfiguration

3.2.1 Architektur

Abbildung des chinesischen Originals (p.15)

Abbildung des chinesischen Originals (p.15)

Type Memory Driver
SPI Nand SPI Nand DHARA FTL: bsp/rockchip/common/dhara/
RTT Mini FTL: bsp/rockchip/common/mini_ftl.c
RTT SPI Nand: bsp/rockchip/common/drv_spinand.c
HAL SPI Nand: lib/hal/src/hal_spinand.c
HAL Controller: lib/hal/src/hal_fspi.c

HAL-Wurzel: bsp/rockchip/common/hal. NAND-Unterstützung in lib/hal/src/hal_spinand.c und Nachbardateien. ID/Aufdruck zuordnen. Der Treiber erkennt IDs und wählt maximale IO-Breite; per Makro reduzieren.

3.2.2 Treiberkonfiguration

Vor Auswahl den tatsächlichen SPI-Flash-Controller bestimmen. menuconfig-Eintrag:

RT-Thread rockchip common drivers  --->
    [*] Enable ROCKCHIP SPI Nand Flash
    (80000000) Reset the speed of SPI Nand flash in Hz
    (y)   Support mini ftl
          Choose SPI Nor Flash Adapter (Attach FSPI controller to SNOR) --->
            Attach FSPI controller to SPINAND
    [ ]     extend fspi cs1 as SPINAND device (NEW)

Konfigurationsdefinitionen:

RT_USING_SNOR=n                        # 关闭 SPI Nor 驱动,通常外设仅有一种 SPI Flash
RT_USING_MTD_NAND=y
RT_USING_SPINAND=y
RT_SPINAND_SPEED=80000000              # IO 接口速率
RT_USING_SPINAND_FSPI_HOST=y           # FSPI 控制器方案
RT_USING_FTL=y                         # 启用 SPI Nand FTL 存储管理算法
RT_USING_DHARA=y                       # 启用 SPI Nand DHARA FTL 存储管理算法(与 Mini FTL 兼容)
RT_USING_DFS_MNTTABLE=y                # 启动 DFS mnt table 自动挂载支持
RT_USING_DFS_ELMFAT=y                  # 启用 elm FatFs
RT_DFS_ELM_MAX_SECTOR_SIZE=2048        # 设置 elm FatFs sector size,设定为 flash pagesize,通常为 2KB/4KB,参考颗粒手册

Auch XIP deaktivieren: XIP = ‘N’ in rtconfig.py.

3.2.3 FTL-Algorithmen

3.2.3.1 DHARA FTL

Dhara (Dæ:ra) ist Open-Source-FTL für ressourcenarme NAND-Systeme mit veränderlicher Block-Lese-/Schreibschnittstelle.

  • Wear Leveling: Löschzähler zweier Blöcke unterscheiden sich höchstens um 1.
  • GC-Geschwindigkeit lässt sich über das GC-Verhältnis zulasten freien Platzes anpassen.
  • Logisches Sektorschreiben/Trim ist atomar. Stromausfall rollt zum letzten Synchronisationspunkt zurück; Synchronisation periodisch oder explizit.
  • Bei gleichmäßig verteilten schlechten Blöcken benötigen alle Operationen einschließlich Start im schlechtesten Fall O(log n) für Chipgröße n. Mit DHARA nutzen Partitionsblock-APIs DHARA, Sektorgröße gleich Seitengröße, meist 2KB/4KB. Einschränkung: Standardmäßig nur der gesamte NAND als FTL-Bereich. Anwendungen: ein FSPI mit NAND für Firmware/Daten; ein FSPI mit CS0-NOR-Firmware ohne XIP und CSN1-NAND-Daten; mehrere FSPI mit FSPI0-NOR-Firmware und FSPI1-NAND-Daten.
3.2.3.2 Mini-FTL-Treiber

Mini FTL ist keine normale FTL-Schicht: nur grundlegende Bad-Block-Verwaltung, hauptsächlich für Firmwareupdates. Die Partition root wird als gleichnamiges Blockgerät für ein schreibgeschütztes Dateisystem registriert.

3.2.4 Partitionstabelle konfigurieren

3.2.4.1 Partitionsplanung

Beginn und Größe an 256KB ausrichten für 128KB/256KB-Blöcke. Ersatzplatz: außer Tabellenpartition brauchen kleine Partitionen 1–2 Flash-Blöcke, über 8MB 1%. Am Ende 2MB für vier Bad-Block-Tabellenblöcke und einen guten Backup-Tabellenblock reservieren, passend für 128KB/256KB. Für OTA A/B empfohlen.

3.2.4.2 RK-Partition-Erweiterung

RKs Tabelle ähnelt GPT, braucht weniger Ressourcen und startet schneller, vor allem RV1107/8 und MCU. NAND registriert standardmäßig die letzte Partition für DHARA FTL, meist root für das Dateisystem.

3.2.4.3 GPT-Erweiterung

Das RK SDK unterstützt auch GPT; die letzte Partition wird standardmäßig DHARA FTL zugeordnet, meist root für ein Dateisystem.

3.2.4.4 Eigene ROOT-Partition

Ohne Partitionstabellenerweiterung diese einzelne ROOT-Definition in drv_spinand.c verwenden:

RT_ROOT_PART_OFFSET
RT_ROOT_PART_SIZE

Einheiten: Sektoren mit 512B. RK3308 RT-Thread build.sh zeigt die Anbindung dieser Definitionen an das Buildskript.

3.2.5 Partitionen lesen und registrieren

Nach NAND-Initialisierung die Tabelle auswerten und letzte Partition registrieren. Prüfung:

msh />list_device
device          type         ref count
------- -------------------- ----------
userdata Block Device         0            /* DHARA FTL 实现,分区类型 block 设备, 通常为可读写 FAT 文件系统 */
root     Block Device         1            /* Mini FTL 实现,分区类型 block 设备,通 常为只读 FAT 文件系统 */
spinand  MTD Device           0            /* SPI Nand MTD 设备,分区读写最终接入到该 节点完成读写擦除 */

3.3 PC-Flashwerkzeuge

SocToolKit für Windows/Linux verwenden; passende Serienwerkzeuge existieren. Für OTA A/B empfohlen.

Separate wie gepackte NAND-Abbilder werden letztlich partitionsweise geschrieben. RK Partition unterstützt Einzelabbilder, nicht Firmware.img. GPT unterstützt Einzelabbilder und update.img. Andere Erweiterungen nur Einzelabbilder.

3.4 API-Beispiele

Abbildung des chinesischen Originals (p.19)

Abbildung des chinesischen Originals (p.19)

3.4.1 MTD-Bytegerät: Basis-API

Siehe spinand_test in spinand_test.c:

mtd_dev = (struct rt_mtd_nor_device *)rt_device_find("spinand0");
rt_mtd_nand_check_block(mtd_dev, block);
rt_mtd_nand_erase_block(mtd_dev, block);
rt_mtd_nand_write(mtd_dev, page_addr + i, (const rt_uint8_t *)buffer, mtd_dev->page_size, RT_NULL, 0);
rt_mtd_nand_read(mtd_dev, page_addr + i, (rt_uint8_t *)buffer, mtd_dev->page_size, RT_NULL, 0);

spinand0 ist ein Bytegerät. rt_mtd_nand_check_block: true für schlechte, false für gute Blöcke. Die Quelle nennt hier rt_mtd_nor_erase_block (Blöcke) und rt_mtd_nor_write/read (Bytes, Seitenausrichtung, meist 2KB/4KB; Flash-Handbuch beachten); NOR-Namen bleiben erhalten. RK-Tabellen verwenden 512B-Sektoren; Einheiten umrechnen.

3.4.2 Mini FTL: OTA-/Dateisystem-API

Für OTA siehe mini_ftl_test_one_flash_block in spinand_test.c:

rt_uint32_t block_size = mtd_dev->pages_per_block * mtd_dev->page_size;
mtd_dev = (struct rt_mtd_nor_device *)rt_device_find("spinand0");
mini_ftl_erase(mtd_dev, addr, block_size);
mini_ftl_write(mtd_dev, buffer, addr, block_size);
mini_ftl_read(mtd_dev, buffer, addr, block_size);

mini_ftl_erase: Bytes, blocksize-Ausrichtung. mini_ftl_write: Bytes, pagesize-Ausrichtung, vorher löschen. mini_ftl_read: Bytes, pagesize-Ausrichtung. Bei OTA buffer an block_size ausrichten und erase/write/read-Prüfung in einem Aufruf abschließen; vor elm-FatFs-Update gesamte Partition löschen. RK Partition: rk_partition_list; GPT: dfs_part_list, noch ohne name info. Nach Partitionskonfiguration wird root als root-Blockgerät über Mini FTL für ein schreibgeschütztes Dateisystem registriert. Nur Abbild-Flashen, kein Online-Formatieren.

3.4.3 DHARA-FTL-Dateisystem-API

Die letzte Partition wird gleichnamiges DHARA-FTL-Blockgerät für ein les-/schreibbares Dateisystem. Abbild-Flashen und Online-Formatieren werden unterstützt.

3.5 Dateisysteme

3.5.1 elm-FatFs-Unterstützung

Mini-FTL-Blockgeräte sind schreibgeschützt, hängen FAT ein, verwenden FAT-Firmwareabbilder und erlauben kein Online-Formatieren. DHARA-FTL-Geräte lesen/schreiben FAT, benötigen ein als DHARA verpacktes FAT-Abbild und unterstützen Online-Formatieren.

3.5.1.1 Partitionen einhängen

Mit CONFIG_RT_USING_DFS_MNTTABLE Registrierung in mnt.c ergänzen, etwa root unter /:

const struct dfs_mount_tbl mount_table[] =
{
    {"root", "/", "elm", 0, 0},
    {0}
};

Für einen eigenen Einhängeablauf:

dfs_mount("root", "/", "elm", 0, 0)

Einhängebefehl:

mount root / elm
3.5.1.2 Online-Partitionsformatierung
mkfs -t elm userdata

root ist schreibgeschützt: nur Einhängen, kein Online-Formatieren.

3.5.1.3 elm-fat-Abbilder offline erstellen

./bsp/rockchip/tools/mkroot.sh mit mkfs.fat verwenden; -S entsprechend page_size, meist 2048/4096 laut NAND-Handbuch.

3.5.1.4 DHARA-Abbilder offline erstellen

DHARA-Werkzeug:

Usage: ./dhara_utils <file_path> <flash_page_size> <num_blocks>

Beispiel: FAT16-DHARA offline, Partition 504 Blöcke, NAND-Seite 2KB:

mkfs.vfat -F 16 -s 1 -S 2048 fat.img
./rkbin/dhara_utils fat.img 2 504

Ausgabe: fat.img.dhara.

Partitionsgröße siehe Partitionsplanung.

3.6 Testtreiber

3.6.1 Grundlegende Testkonfiguration

RT-Thread bsp test case  --->
    RT-Thread Common Test case  --->
        [*] Enable BSP Common TEST
        [*]   Enable BSP Common SPINAND TEST (NEW)

Nach Konfiguration ist spinand_test in msh verfügbar:

msh />spinand_test
1. spinand_test write <page_addr> <page_num>
2. spinand_test read <page_addr> <page_nun>
3. spinand_test erase <blk_addr>
4. spinand_test erase_all <blk_addr>
5. spinand_test stress <loop>
6. spinand_test bbt
7. spinand_test markbad <blk_addr>
8. spinand_test mini_ftl_test <byte_offset>
9. spinand_test part_list
like:
        spinand_test write 1024 1
        spinand_test read 1024 1
        spinand_test erase 16
        spinand_test erase_all 512
        spinand_test stress 5000
        spinand_test bbt
        spinand_test mini_ftl_test 67108864
        spinand_test part_list

3.6.2 flash_stress_test-Lese-/Schreiblast

Ziel: NAND-Stabilität unter Lese-/Schreiblast. 10 Zielgeräte vorbereiten. Testbereich: Offset 512 Blöcke, Länge 256 Flash-Blöcke.

  1. Nach Start spinand_test stress 5000 512 256 ausführen und Versorgung ununterbrochen halten.
  1. Testprotokolle aufzeichnen.
  1. Bestanden bei normalem Betrieb nach 24 Stunden, sonst fehlgeschlagen.

3.6.3 power_lost_test bei Stromausfall

Ziel: Robustheit bei Stromausfällen, besonders häufig bei batterielosen NAND-Produkten. 10 Geräte vorbereiten. Verfahren:

  1. Dateikopierlast erzeugen.
  1. 2 Sekunden einschalten, 3 Sekunden ausschalten: 5-Sekunden-Zyklus über 8 Stunden, etwa 5760 Unterbrechungen. Nach jeder Unterbrechung innerhalb 5 Sekunden hochfahren und Kopieren ausführen.
  1. Testprotokolle aufzeichnen.
  1. Die Quelle verlangt normalen Betrieb nach 24 Stunden (Widerspruch zu 8 Stunden oben; beide Werte bleiben), sonst fehlgeschlagen. Siehe Referenzquellcode für Stromausfälle.

3.7 Fehlerbehebung

3.7.1 RK2118 hängt mit aktiviertem NAND

Symptom:

FW data_offset:2048
FW data_size:  195584
FW load_addr:  0x1060800
copy 1090000 20a200 400
hash_256 fail! ret:-1
MemBoot fali!

SoftReset...

XIP versuchsweise deaktivieren:

diff --git a/bsp/rockchip/rk2118/rtconfig.py b/bsp/rockchip/rk2118/rtconfig.py
index 2b6e696e2b..32b5117513 100644
--- a/bsp/rockchip/rk2118/rtconfig.py
+++ b/bsp/rockchip/rk2118/rtconfig.py
@@ -29,8 +29,8 @@ if os.getenv('RTT_EXEC_PATH'):
 #BUILD = 'debug'
 BUILD = 'release'

-XIP = 'Y'
-#XIP = 'N'
+#XIP = 'Y'
+XIP = 'N'
 if os.getenv('RTT_BUILD_XIP'):
     XIP = os.getenv('RTT_BUILD_XIP').upper()

3.7.2 NAND unterstützt RK Firmware.img nicht

RK Firmware.img füllt ungenutzten Partitionsplatz mit Nullen, außer die letzte Partition darf leer sein. Bei gleichen Nutzabbildern wächst das Padding mit größeren Partitionen stark; alles wird als ein Update übertragen. NAND erlaubt werkseitige Bad Blocks und braucht Ersatzraum. Ein aufgefülltes “one firmware” widerspricht dem; selbst ein einzelnes Paket muss entpackt und nur Nutzabbilder partitionsweise geschrieben werden. Auch Programmiergeräte können kein monolithisches Abbild verwenden.

3.7.3 NAND-Stromausfallprobleme

Abnormales Abschalten umgeht die normale Deinitialisierung und kann NAND bei instabiler Spannung betreiben. Vor allem Löschen (mehrere Millisekunden) und Programmieren (Hunderte Mikrosekunden) sind betroffen. 3V3-Bausteine benötigen meist mindestens 2.7V; Datenblatt beachten. Zwei Fehlerarten: unvollständige Schreibdaten; zufällige Befehlsfehler bei instabiler Spannung. Dateisystem-Recovery schützt vor unvollständigen Daten, Datenverlust bleibt möglich. Schutz gegen instabile Spannung:

  • PMIC überwacht VCC IO und setzt CPU meist unter 2.91V zurück, sodass keine neuen Lösch-/Schreibbefehle kommen. Die Entladung muss etwa 1ms Betriebsspannung für den letzten Zugriff halten.
  • Reset IC ähnlich, typischer Schwellwert 2.93V.
  • RK NPOR überwacht VCCIO und setzt bei seinem Schwellwert zurück. NAND-Produkte möglichst mit Batterie oder Dauerstrom auslegen. Sonst Hardware verbessern: PMIC/Reset IC/RK NPOR erkennt fallendes VCC IO und setzt CPU vor Niederspannungsbefehlen zurück.

Kapazität nach RK-Demoplatinen ergänzen, damit VCCIO flash gültig bleibt, normalerweise für tBERS (Blocklöschzeit). Stromausfälle bei Flash-Zugriffen vermeiden. Backups/Recovery: doppelte Firmware, kritische Daten im schreibgeschützten Dateisystem, Wiederherstellung beschädigter Schreibpartitionen für Betrieb oder OTA. Zeitablauf am realen Produkt unter realer Last mit power_lost_test prüfen und VCC3V3/RESETn erfassen:

Abbildung des chinesischen Originals (p.25)

Abbildung des chinesischen Originals (p.25)

Das Oszilloskop muss RESETn-/Reset-IC-Auslösung (Y1), VCC3V3-Abfall auf 2V7 (Y2) und ΔY1Y2-Zeit zeigen. Wiederholen und kleinstes Intervall analysieren. Bei RV1106 und ähnlichem RKNPOR ist RESETn intern: GPIO high mit externem Pull-down als Näherung verwenden. CPU-Reset deaktiviert GPIO, Pull-down zieht es low; diese Flanke entspricht näherungsweise dem Reset.

3.7.4 NAND-Stromausfall-Referenzcode

#include <dfs_file.h>

static void readwrite_test(void *param)
{
    int fd, size, len = 2048, loops = 0;
    char *pwrite, *pread;

    pwrite = rt_malloc(len);
    if (!pwrite) {
        rt_kprintf("malloc pwrite failed\n");
        return;
    }
    pread = rt_malloc(len);
    if (!pread) {
        rt_kprintf("malloc pread failed\n");
        rt_free(pwrite);
        return;
    }

    fd = open("/file_stress.txt", O_RDWR | O_CREAT);
    if (fd < 0)
    {
        rt_kprintf("%s open file failed\n", __func__);
        goto err_open;
    }

    while (1) {
        rt_kprintf("file_stress, loops=%d\n", loops);
        rt_memset(pwrite, loops & 0xff, len);

        lseek(fd, 0, SEEK_SET);
        write(fd, pwrite, len);
        lseek(fd, 0, SEEK_SET);
        size = read(fd, pread, len);
        if (size < 0) {
            break;
        }

        if (rt_memcmp(pwrite, pread, len)) {
            rt_kprintf("%s compare failed, %x\n", __func__, pread[0]);
            break;
        }
        loops++;
    }

    close(fd);
err_open:
    rt_free(pread);
    rt_free(pwrite);
}

void file_stress(void)
{
    rt_thread_t thread;

    thread = rt_thread_create("file_stresss",
                              readwrite_test, NULL,
                              2048,
                              21, 20);
    rt_thread_startup(thread);
}

Dieses Thema entdecken → · Lernpfade →