Rockchip · AI & Linux Hub

Hardware-Schnittstellen

Rockchip RT-Thread SPI2APB: Entwicklerleitfaden

Rockchip RT-Thread SPI2APB: Entwicklerleitfaden — V1.2.0

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

Rockchip-Plattformreferenz für das RK RT-Thread SDK mit RK2108/RK2118 (SPI2APB hauptsächlich 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-498 · V1.2.0

ArmSoM Docs · RT-Thread

1. Einführung

1.1 Wichtige Hinweise

SPI2APB legt ein proprietäres RK-Protokoll über Standard-SPI, anders als das allgemeinere RK SPI ohne Zusatzprotokoll. Dies bei der Schaltplanprüfung beachten.

1.2 Controller-Eigenschaften

Unterstützt SPI-Modi 0/2 (0 empfohlen), 8-Bit-Übertragungen, Interrupts und Lesen/Schreiben interner Register. LSB/MSB und Little Endian/Big Endian sind einstellbar. Nur Simplex und Slave werden unterstützt. Der Master muss SPI2APB-konform senden. Grundformat: <CMD-32bits> [ADDR-32bits] [DUMMY-32bits] [READ_BEGING-32bits] [DATA]. Varianten siehe Tabelle.

Operation Protocol CMD-32bits Little Endian
Daten lesen read data <0x00000077> <ADDR> <DUMMY> <READ_BEGING> <DATA>
Daten schreiben write data <0x00000011> <ADDR> <DATA>
REG0 schreiben write msg reg0 <0x00010011> <DATA-32bits>
REG1 schreiben, Interrupt write msg reg1 <0x00020011> <DATA-32bits>
Status der letzten Übertragung query state <0x000000ff> <DATA-32bits>
REG2 lesen query msg reg2 <0x000001ff> <DATA-32bits>

[ADDR-32bits] ist eine unterstützte Speicheradresse, meist SRAM/DRAM. [DUMMY-32bits] ist beliebig und kann 0 sein. [READ_BEGING-32bits] ist 0x000000AA. Rückgaben von query state siehe “State Register Information” im SPI2APB-Kapitel des TRM.

1.3 Schnittstelleneigenschaften

SoC Max rate
RK2118 50MHz

Die Maximalrate ist theoretisch; Leitungsführung und PCB-Qualität beeinflussen das zu messende Ergebnis.

2. Software

2.1 Quellcodepfade

Framework-Code:

components/drivers/include/drivers/spi.h
components/drivers/spi/spi_core.c
components/drivers/spi/spi_dev.c

Treiberanpassung:

bsp/rockchip/common/drivers/drv_spi2apb.c
bsp/rockchip/common/hal/lib/hal/src/hal_spi2apb.c

Testbefehle; Anwendungen können diesem Treiber folgen:

bsp/rockchip-common/tests/spi2apb_test.c

2.2 Konfiguration

Option mit SPI2APB im Namen aktivieren.

RT-Thread bsp drivers  --->
    RT-Thread rockchip "project" drivers  --->
        [*] Enable SPI
        [*]   Enable SPI0 (SPI2APB)
        [ ]   Enable SPI1
        [ ]   Enable SPI2

Platinen-iomux konfigurieren.

2.3 Nutzungskonfiguration

Standard: LSB, Little Endian. Änderungsbeispiel in drv_spi2apb.c:

diff --git a/bsp/rockchip/common/drivers/drv_spi2apb.c b/bsp/rockchip/common/drivers/drv_spi2apb.c
index 15045270fe..ef055d8d03 100644
--- a/bsp/rockchip/common/drivers/drv_spi2apb.c
+++ b/bsp/rockchip/common/drivers/drv_spi2apb.c
@@ -45,7 +45,7 @@ struct rockchip_spi2apb

 static struct rockchip_spi2apb rk_spi2apb =
 {
-    .device.config.mode = (SPI2APB_LITTLE_ENDIAN | SPI2APB_LSB),
+    .device.config.mode = (SPI2APB_LITTLE_ENDIAN | SPI2APB_MSB),
     .device.config.clock_polarity = SPI2APB_TXCP_INVERT,
     .base = SPI2APB,
     .irq = SPISLV0_IRQn,

Nur LSB/MSB ändern; die übrigen Standardwerte beibehalten.

3. Tests

3.1 Konfiguration

RT-Thread bsp test case  --->
    [*] RT-Thread Common Test case  --->
        [*] Enable BSP Common TEST
        [*]  Enable BSP Common SPI2APB TEST

3.2 Testbefehle

spi2apb_test config spi2apb 1 2         # <mode> <polarity>
spi2apb_test cb spi2apb                 # 注册 SPI2APB->REG1 中断回调
spi2apb_test read spi2apb 0             # 读取 SPI2APB->REG0 信息,建议调试方式,先主 设备端参考 'write msg reg0' 协议写,后从设备端执行该命令读
spi2apb_test read spi2apb 1             # 读取 SPI2APB->REG1 信息,建议调试方式,先主 端参考 'write msg reg1' 协议写,后从端执行该命令读
spi2apb_test query spi2apb              # 读取 SPI2APB->SR 信息
spi2apb_test write spi2apb 0x12345678   # 写入 SPI2APB->REG2 信息,建议调试方式,先从 端执行该命令,后主端参考 'query msg reg2' 协议读

Master = SPI master; Slave = RK SPI2APB slave. mode: bit0 0-LSB/1-MSB; bit1 0-LittleEndian/1-BigEndian. polarity nur zum Debuggen ändern; im Betrieb TX invert/RX normal beibehalten, also polarity =

  1. bit0: 0-RX normal, 1-RX invert; bit1: 0-TX normal, 1-TX invert.

4. Anwendungsintegration

Beide Seiten müssen Datenfluss und Steuerinformationen auf SPI2APB aufbauen. Master-Anwendung und Treiber können vom RK-Referenzcode abgeleitet werden. Quellenort laut Original: SPI-Entwicklungsmaterialien — FAE-Projekt — Rockchip Redmine (rock-chips.com).

4.1 Grundarchitektur

Abbildung des chinesischen Originals (p.7)

Abbildung des chinesischen Originals (p.7)

API-/Ablauftext der Abbildung (Originalnamen/Nummerierung; kein ausführbarer Code)

spidev_rkspi2apb_app -> spidev_rkspi2apb.c -> SPI driver -> spi master
spi2apb_test.c <-> SPI2APB RTOS driver -> SPI2APB IP -> spi2apb slave
SPI2APB IP -> SRAM

Beispiel: RV1106 SPI master mit RK2118 SPI2APB. Quellcodekomponenten:

Schicht Master (Linux 5.10) Slave (HAL + RTOS)
Anwendung spidev_rkspi2apb_app: ioctl/read/write test_spi2apb.c: REG
Kerneltreiber spidev_rkspi2apb.c: SPI2APB ioctl/read/write  
Controllertreiber spi-rockchip.c drv_spi2apb.c
hal_spi2apb.c
Controller spi master spi2apb slave

ioctl-Schnittstelle von spidev_rkspi2apb.c:

#define SPIDEV_RKSPI2APB_GET_DEV_STATE      _IOR(SPIDEV_RKSPI2APB_BASE, 0, __u32)
/* 参考 'query msg reg2' 协议 */
#define SPIDEV_RKSPI2APB_SET_DST_ADDR       _IOW(SPIDEV_RKSPI2APB_BASE, 1, __u32)
/* 设置传输的目标内存地址,指向从设备端内存地址 */
#define SPIDEV_RKSPI2APB_SEND_MSG       _IOW(SPIDEV_RKSPI2APB_BASE, 2, __u32) /* 参考 'write msg reg0' 协议 */
#define SPIDEV_RKSPI2APB_INT_REQ        _IOW(SPIDEV_RKSPI2APB_BASE, 3, __u32) /* 参考 'write msg reg1' 协议 */

Lesen/Schreiben in spidev_rkspi2apbc.c (Quellenschreibweise):

write(spidev_fd, buffer_w, size); /* 参考 'write data' 协议,addr 由 ioctl SPIDEV_RKSPI2APB_SET_DST_ADDR 设定 */
read(spidev_fd, buffer_r, size); /* 参考 'read data' 协议,addr 由 ioctl SPIDEV_RKSPI2APB_SET_DST_ADDR 设定 */

Zieladresse vereinbaren: Vorbelegung wird empfohlen. Bekannte SRAM-Adresse im Slave reservieren und am Master per ioctl SPIDEV_RKSPI2APB_SET_DST_ADDR setzen. RT-Thread reserviert meist über spi2apb_buffer_start im Linkerskript. Alternativ SRAM im Slave allozieren und die Adresse durch einen eigenen Austausch an den Master senden, wie im folgenden Ablauf.

Abbildung des chinesischen Originals (p.9)

Abbildung des chinesischen Originals (p.9)

API-/Ablauftext der Abbildung (Originalnamen/Nummerierung; kein ausführbarer Code)

SPI Master APP -> ioctl SPIDEV_RKSPI2APB_INT_REQ -> SPI master
SPI master -> write reg1 -> SPI2APB slave -> interrupt call back -> SPI2APB APP
SPI2APB APP -> write address info to reg2 -> SPI2APB slave
SPI Master APP -> ioctl SPIDEV_RKSPI2APB_GET_DEV_STATE -> read reg2

4.2 Flash-Object-Dienst

Flash Object überträgt Anfragen über spi/spi2apb, damit der SPI-Master den SPI NOR am SPI2APB-Slave lesen/schreiben kann.

4.2.1 Grundprinzip

Abbildung des chinesischen Originals (p.9)

Abbildung des chinesischen Originals (p.9)

API-/Ablauftext der Abbildung (Originalnamen/Nummerierung; kein ausführbarer Code)

spi2apb_flash_obj_mst.c -> drv_spi.c -> spi master
spi2apb_test.c -> SRAM_SPI2APB_BASE
spi2apb slave <-> SRAM_SPI2APB_BASE <-> spinor

NOR-Flash-Leseablauf:

Abbildung des chinesischen Originals (p.10)

Abbildung des chinesischen Originals (p.10)

API-/Ablauftext der Abbildung (Originalnamen/Nummerierung; kein ausführbarer Code)

1. cmd (CMD_READ)
2. write reg1
3. set reg2 (SLAVE_BUSY)
4. rt_mtd_nor_read
5. set reg (SLAVE_SUCCESS)
6. wait status (SLAVE_SUCCESS)
7. read data
8. read data

NOR-Flash-Schreibablauf:

Abbildung des chinesischen Originals (p.10)

Abbildung des chinesischen Originals (p.10)

API-/Ablauftext der Abbildung (Originalnamen/Nummerierung; kein ausführbarer Code)

1. write data
2. write data
3. cmd (CMD_PROG)
4. write reg1
5. set reg2 (SLAVE_BUSY)
6. rt_mtd_nor_erase/write
6. set reg (SLAVE_SUCCESS)
7. wait status (SLAVE_SUCCESS)

4.2.2 Schnittstellen

flash_obj-Master-Schnittstelle:

rt_err_t spi2apb_flash_obj_mst_init(struct rt_spi_device *spi_device);
/**
  * @brief  Write sector from remote spinor device.
  * @param  sec: pointer to spinor 4KB sector offset.
  * @param  buffer: data buffer.
  * @return rt_err_t
  */
rt_err_t spi2apb_flash_obj_mst_write_sector(rt_uint32_t sec, void *buffer);
/**
  * @brief  Read sector from remote spinor device.
  * @param  sec: pointer to spinor 4KB sector offset.
  * @param  buffer: data buffer.
  * @return rt_err_t
  */
rt_err_t spi2apb_flash_obj_mst_read_sector(rt_uint32_t sec, void *buffer);

SPI2APB-Wrapper des flash_obj-Masters:

/**
  * @brief  Write data to remote sram by spi2apb interface.
  * @param  addr: pointer to remote sram address.
  * @param  buffer: data buffer.
  * @param  size: data size.
  * @param  trigger: if valid write spi2apb reg1 to trigger a interrupt.
  * @return rt_err_t
  */
static rt_err_t spi2apb_flash_obj_mst_spi2apb_progsram(uint32_t addr, uint8_t
*buffer, uint32_t size, uint32_t trigger);
/**
  * @brief  Read data from remote sram by spi2apb interface.
  * @param  addr: pointer to remote sram address.
  * @param  buffer: data buffer.
  * @param  size: data size.
  * @param  trigger: if valid write spi2apb reg1 to trigger a interrupt.
  * @return rt_err_t
  */
static rt_err_t spi2apb_flash_obj_mst_spi2apb_readsram(uint32_t addr, uint8_t
*buffer, uint32_t size, uint32_t trigger);
/**
  * @brief  Write msg reg in spi2apb.
  * @param  index: reg index.
  * @param  val: reg value.
  * @param  status: if valid check write success.
  * @return rt_err_t
  */
static rt_err_t spi2apb_flash_obj_mst_spi2apb_writemsg(uint8_t index, uint32_t
value, bool status);
/**
  * @brief  Query msg reg2 in spi2apb.
  * @return rt_err_t
  */
static uint32_t spi2apb_flash_obj_mst_spi2apb_querymsg(void);
/**
  * @brief  Query state abort last transmission.
  * @return uint32_t status.
  */
static uint32_t spi2apb_flash_obj_mst_spi2apb_querystatus(void);

flash_obj-Slave-Schnittstelle:

rt_err_t spi_test_spi2apb_flash_obj_init(void);
static void spi_test_spi2apb_flash_obj_work(struct rt_work *work, void
*work_data);
rt_err_t spi_test_spi2apb_flash_obj_write(rt_uint8_t index, rt_uint16_t addr,
void *buffer);
rt_err_t spi_test_spi2apb_flash_obj_read(rt_uint8_t index, rt_uint16_t addr, void
*buffer);
rt_err_t spi_test_spi2apb_flash_obj_set_status(rt_uint8_t index, rt_uint8_t
status);

Nach Initialisierung den SPI2APB-Interrupt-Callback registrieren. Die reg1-Bottom-Half-Workqueue analysiert Transaktionen, liest/schreibt spinor und setzt Statusbits der Zustandsmaschine.

4.2.3 Flash-obj-Konfiguration

CONFIG_RT_USING_COMMON_TEST_SPI2APB_FLASH_OBJ = y

4.2.4 Flash-obj-Testbefehle

flash_obj-Slave-Befehle:

spi2apb_test flash_obj spi2apb

flash_obj-Master-Befehle:

1. spi2apb_flash_obj_mst spi2apb_progsram <spi_dev> <size>
2. spi2apb_flash_obj_mst spi2apb_readsram <spi_dev> <size>
3. spi2apb_flash_obj_mst spi2apb_writemsg <spi_dev> <reg> <val>
4. spi2apb_flash_obj_mst spi2apb_querymsg <spi_dev>
5. spi2apb_flash_obj_mst write_sector <spi_dev> <sector> <val> <loops>
6. spi2apb_flash_obj_mst read_sector <spi_dev> <sector> <loops>
7. spi2apb_flash_obj_mst stress <spi_dev> <sector> <n_sec>
like:
        spi2apb_flash_obj_mst spi2apb_progsram spi1_0 32
        spi2apb_flash_obj_mst spi2apb_readsram spi1_0 32
        spi2apb_flash_obj_mst spi2apb_writemsg spi1_0 1 55
        spi2apb_flash_obj_mst spi2apb_querymsg spi1_0
        spi2apb_flash_obj_mst write_sector spi1_0 512 1 10
        spi2apb_flash_obj_mst read_sector spi1_0 512 10
        spi2apb_flash_obj_mst stress spi1_0 512 32

spi2apb_progsram verwendet write data; anschließend löst write msg reg1 den SPI2APB-Interrupt aus. spi2apb_readsram verwendet read data und wartet zuvor auf reg2-Status SPI2APB_FLASH_OBJ_CMD_READ_SRAM_READY. spi2apb_writemsg entspricht write msg reg0/1, spi2apb_querymsg read msg reg2. write_sector schreibt NOR flash, read_sector liest, stress schreibt und liest für einen Belastungstest zurück. Alle drei verwenden 4KB-Sektoren.

5. Fehlerbehebung

5.1 SPI2APB-Übertragungsfehler

Nach dem Testabschnitt SPI-Modus 0, lsb, Little Endian konfigurieren und Callback registrieren:

spi2apb_test config spi2apb 1 2
spi2apb_test cb spi2apb

Der Master muss dem Übertragungsprotokoll folgen. Zuerst write reg1 versuchen, um einen SPI2APB-Interrupt auszulösen. Gemeinsame Masse, Master-csn/clock per Oszilloskop, Slave-Verdrahtung und unbestückte 0Ω-Widerstände prüfen. Bei falschen Empfangsdaten Geschwindigkeit reduzieren. LSB/MSB und Byte-Reihenfolge prüfen. Sind nur Teile gültig und hängt das Muster mit der Cache-Zeilengröße zusammen, fehlen wahrscheinlich Slave-Kohärenzoperationen: normalerweise invalidate nach Lesen und flush vor Schreiben. Wurde der Lesepuffer zuvor gelöscht oder beschrieben, auch vor der Übertragung flush ausführen.

Dieses Thema entdecken → · Lernpfade →