NRF52832学习笔记(37)——SPI(从机)接口使用

一、SPI简介

SPI(Serial Peripheral Interface) 协议是由摩托罗拉公司提出的通讯协议,即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。

芯片的管脚上只占用四根线。
MISO: 主器件数据输出,从器件数据输入。
MOSI:主器件数据输入,从器件数据输出。
SCK: 时钟信号,由主设备控制发出。
NSS(CS): 从设备选择信号,由主设备控制。当NSS为低电平则选中从器件。

二、API说明

以下 SPI 从机接口须包含头文件 nrf_drv_spis.h

#include "nrf_drv_spis.h"

2.1 NRF_DRV_SPIS_INSTANCE

功能 实例化一个SPI从机
函数定义 NRFX_SPIS_INSTANCE(id)
参数 id:SPI从机实例编号
返回 携带有EasyDMA的SPI从机实例

2.2 nrf_drv_spis_init

功能 SPI从机驱动初始化
函数定义 ret_code_t nrf_drv_spis_init(nrf_drv_spis_t const * const p_instance,
nrf_drv_spis_config_t const * p_config,
nrf_drv_spis_event_handler_t event_handler)
参数 p_instance:SPI从机实例
p_config:配置参数
event_handler:回调处理函数
返回 0-成功,或其他错误码

2.3 nrf_drv_spis_buffers_set

功能 配置SPI从机发送和接收缓存区
函数定义 nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * const p_instance,
uint8_t const * p_tx_buffer,
size_t tx_buffer_length,
uint8_t * p_rx_buffer,
size_t rx_buffer_length)
参数 p_instance:SPI从机实例
p_tx_buffer:发送数据缓存区
tx_buffer_length:发送数据长度
p_rx_buffer:接收数据缓存区
rx_buffer_length:接收数据长度
返回 0-成功,或其他错误码

三、SDK配置

点击 sdk_config.h 文件


选择 Configuration Wizard

nRF_Drivers 中勾选SPIS相关选项


nRF_Drivers 中添加文件

nrfx_spis.c 新版本 SPIS 兼容库 modules\nrfx\drivers\src
nrf_drv_spis.c 老版本 SPIS 基础库 integration\nrfx\legacy

四、硬件连接

功能口 引脚
MISO 30
MOSI 29
CLK 26
CSN 31

五、使用例子

打开SDK示例工程 examples\peripheral\spis

5.1 包含头文件

#include "nrf_drv_spis.h"

5.2 实例化SPI从机

#define SPIS_INSTANCE 1 /**< SPIS instance index. */
static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */

5.3 定义SPI从机事件处理函数

spis_event_handler 接收事件处理函数,当SPI从机接收到数据时进入该函数。
spis_xfer_done 接收数据标志,当SPI从机接收到数据时置1,处理完接收数据后要清0。

static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */

/**
 * @brief SPIS user event handler.
 *
 * @param event
 */
void spis_event_handler(nrf_drv_spis_event_t event)
{
    if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
    {
        spis_xfer_done = true;
        SEGGER_RTT_printf(0," Transfer completed. Received: %s\n",(uint32_t)m_rx_buf);
    }
}

5.4 初始化SPI从机

#define APP_SPIS_CS_PIN 31
#define APP_SPIS_MISO_PIN 30
#define APP_SPIS_MOSI_PIN 29
#define APP_SPIS_SCK_PIN 26

nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
spis_config.csn_pin               = APP_SPIS_CS_PIN;
spis_config.miso_pin              = APP_SPIS_MISO_PIN;
spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
spis_config.sck_pin               = APP_SPIS_SCK_PIN;

APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));

5.5 配置发送和接收缓存区

#define TEST_STRING "Nordic"
static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */

APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));

5.6 完整代码

由于SDK原工程NRF_LOG打印不出来,这里我改成了使用SEGGER_RTT打印。须包含头文件 SEGGER_RTT.h

#include "sdk_config.h"
#include "nrf_drv_spis.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "boards.h"
#include "app_error.h"
#include 

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "SEGGER_RTT.h"

#define SPIS_INSTANCE 1 /**< SPIS instance index. */
static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */

#define TEST_STRING "Nordic"
static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */

static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */

/**
 * @brief SPIS user event handler.
 *
 * @param event
 */
void spis_event_handler(nrf_drv_spis_event_t event)
{
    if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
    {
        spis_xfer_done = true;
        SEGGER_RTT_printf(0," Transfer completed. Received: %s\n",(uint32_t)m_rx_buf);
    }
}

int main(void)
{
    // Enable the constant latency sub power mode to minimize the time it takes
    // for the SPIS peripheral to become active after the CSN line is asserted
    // (when the CPU is in sleep mode).
    NRF_POWER->TASKS_CONSTLAT = 1;

    bsp_board_init(BSP_INIT_LEDS);  // 板载LED灯初始化

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    SEGGER_RTT_printf(0,"SPIS example\n");

    nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
    spis_config.csn_pin               = APP_SPIS_CS_PIN;
    spis_config.miso_pin              = APP_SPIS_MISO_PIN;
    spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
    spis_config.sck_pin               = APP_SPIS_SCK_PIN;

    APP_ERROR_CHECK(nrf_drv_spis_init(&spis, &spis_config, spis_event_handler));

    while (1)
    {
        memset(m_rx_buf, 0, m_length);
        spis_xfer_done = false;

        APP_ERROR_CHECK(nrf_drv_spis_buffers_set(&spis, m_tx_buf, m_length, m_rx_buf, m_length));

        while (!spis_xfer_done)
        {
            __WFE();
        }

        NRF_LOG_FLUSH();

        bsp_board_led_invert(BSP_BOARD_LED_0);  // LED灯置反
    }
}

查看打印:
使用SDK中SPI主机工程进行接收。


• 由 Leung 写于 2021 年 5 月 18 日

• 参考:nRF52832 寄存器操作 SPI Slave

你可能感兴趣的:(NRF52832学习笔记(37)——SPI(从机)接口使用)