在SPI(串行外设接口)通信中,D0、D1、D2、D3通常指的是数据线,也叫做数据引脚或通道。这些引脚的使用可能会根据具体设备或配置的不同而有所变化。

标准的SPI通信接口通常包含以下四个主要引脚:

  1. MOSI(Master Out Slave In) - 主设备输出从设备输入,也称D0或数据线0(Data Line 0)。
  2. MISO(Master In Slave Out) - 主设备输入从设备输出,也称D1或数据线1(Data Line 1)。
  3. SCLK(Serial Clock) - 串行时钟信号,用于同步主设备和从设备之间的数据传输。
  4. SS/CS(Slave Select/Chip Select) - 从设备选择信号,主设备使用该信号选择与哪个从设备进行通信。

除了上述标准的引脚,有些SPI设备支持双向或四向SPI通信模式,分别称为双SPI(Dual SPI)和四SPI(Quad SPI),这些模式可以利用更多的数据线来提高数据传输速率。以下是这些模式下的引脚描述:

双SPI(Dual SPI)

在双SPI模式下,数据通过两条线进行双向传输:

  • D0: 双SPI模式下的第一条数据线,相当于MOSI。
  • D1: 双SPI模式下的第二条数据线,相当于MISO。

四SPI(Quad SPI)

在四SPI模式下,数据通过四条线进行传输,以进一步提高传输速率:

  • D0: 四SPI模式下的第一条数据线(也称IO0或DQ0)。
  • D1: 四SPI模式下的第二条数据线(也称IO1或DQ1)。
  • D2: 四SPI模式下的第三条数据线(也称IO2或DQ2)。
  • D3: 四SPI模式下的第四条数据线(也称IO3或DQ3)。

四SPI模式允许在一次时钟周期内传输更多的数据,显著提高了数据传输效率。这种模式常用于需要高速数据传输的存储器件,如闪存。

同样在不使用QSPI时需要反初始化使设备进入低功耗状态 

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "nrf.h"
#include "bsp.h"
#include "app_util_platform.h"
#include "nrfx_qspi.h"
#include "nrf_delay.h"

#define QSPI_SCK_PIN   NRF_GPIO_PIN_MAP(0, 19)
#define QSPI_CSN_PIN   NRF_GPIO_PIN_MAP(0, 17)
#define QSPI_IO0_PIN   NRF_GPIO_PIN_MAP(0, 20)
#define QSPI_IO1_PIN   NRF_GPIO_PIN_MAP(0, 21)
#define QSPI_IO2_PIN   NRF_GPIO_PIN_MAP(0, 22)
#define QSPI_IO3_PIN   NRF_GPIO_PIN_MAP(0, 23)

#define DATA_SIZE      256
#define ERASE_ADDR     0x00000000

static uint8_t m_buffer_tx[DATA_SIZE];
static uint8_t m_buffer_rx[DATA_SIZE];
static volatile bool qspi_done = false;

static void qspi_handler(nrfx_qspi_evt_t event, void *p_context) {
    if (event == NRFX_QSPI_EVENT_DONE) {
        qspi_done = true;
    }
}

static void qspi_init(void) {
    nrfx_qspi_config_t qspi_config = NRFX_QSPI_DEFAULT_CONFIG;
    qspi_config.pins.sck_pin = QSPI_SCK_PIN;
    qspi_config.pins.csn_pin = QSPI_CSN_PIN;
    qspi_config.pins.io0_pin = QSPI_IO0_PIN;
    qspi_config.pins.io1_pin = QSPI_IO1_PIN;
    qspi_config.pins.io2_pin = QSPI_IO2_PIN;
    qspi_config.pins.io3_pin = QSPI_IO3_PIN;

    ret_code_t ret = nrfx_qspi_init(&qspi_config, qspi_handler, NULL);
    APP_ERROR_CHECK(ret);
}

// Function to uninitialize QSPI to save power
void qspi_uninit(void) {
    // Uninitialize QSPI
    nrfx_qspi_uninit();

    // Set QSPI pins to a low power state
    nrf_gpio_cfg_default(QSPI_SCK_PIN);
    nrf_gpio_cfg_default(QSPI_CSN_PIN);
    nrf_gpio_cfg_default(QSPI_IO0_PIN);
    nrf_gpio_cfg_default(QSPI_IO1_PIN);
    nrf_gpio_cfg_default(QSPI_IO2_PIN);
    nrf_gpio_cfg_default(QSPI_IO3_PIN);
}

static void wait_for_qspi(void) {
    while (!qspi_done) {
        __WFE();
    }
    qspi_done = false;
}

static void qspi_erase_sector(uint32_t addr) {
    ret_code_t ret = nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, addr);
    APP_ERROR_CHECK(ret);
    wait_for_qspi();
}

static void qspi_write_data(uint32_t addr, const uint8_t *data, size_t size) {
    ret_code_t ret = nrfx_qspi_write(data, size, addr);
    APP_ERROR_CHECK(ret);
    wait_for_qspi();
}

static void qspi_read_data(uint32_t addr, uint8_t *data, size_t size) {
    ret_code_t ret = nrfx_qspi_read(data, size, addr);
    APP_ERROR_CHECK(ret);
    wait_for_qspi();
}

int main(void) {
    bsp_board_init(BSP_INIT_LEDS);

    qspi_init();

    // 填充数据缓冲区
    for (uint32_t i = 0; i < DATA_SIZE; i++) {
        m_buffer_tx[i] = i;
    }

    // 擦除扇区
    qspi_erase_sector(ERASE_ADDR);

    // 写入数据到闪存
    qspi_write_data(ERASE_ADDR, m_buffer_tx, DATA_SIZE);

    // 读取数据从闪存
    qspi_read_data(ERASE_ADDR, m_buffer_rx, DATA_SIZE);
    
    qspi_uninit();
    // 验证数据
    for (uint32_t i = 0; i < DATA_SIZE; i++) {
        if (m_buffer_rx[i] != i) {
            bsp_board_led_on(BSP_BOARD_LED_1);  // 如果数据不匹配,点亮LED 1
            while (true) {
                // 数据不匹配,停留在此处
            }
        }
    }

    bsp_board_led_on(BSP_BOARD_LED_0);  // 数据匹配,点亮LED 0

    while (true) {
        // 主循环
    }
}