SPI(Serial Peripheral Interface) 协议是由摩托罗拉公司提出的通讯协议,即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间,要求通讯速率较高的场合。
芯片的管脚上只占用四根线。
MISO: 主器件数据输出,从器件数据输入。
MOSI:主器件数据输入,从器件数据输出。
SCK: 时钟信号,由主设备控制发出。
NSS(CS): 从设备选择信号,由主设备控制。当NSS为低电平则选中从器件。
以下 SPI 从机接口须包含头文件 nrf_drv_spis.h。
#include "nrf_drv_spis.h"
功能 | 实例化一个SPI从机 |
---|---|
函数定义 | NRFX_SPIS_INSTANCE(id) |
参数 | id:SPI从机实例编号 |
返回 | 携带有EasyDMA的SPI从机实例 |
功能 | 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-成功,或其他错误码 |
功能 | 配置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_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
#include "nrf_drv_spis.h"
#define SPIS_INSTANCE 1 /**< SPIS instance index. */
static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
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);
}
}
#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));
#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));
由于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灯置反
}
}
• 由 Leung 写于 2021 年 5 月 18 日
• 参考:nRF52832 寄存器操作 SPI Slave