NRF52832學(xué)習(xí)筆記(5)——SPI(主機(jī))接口使用

一、硬件連接

功能口 引腳
MISO 17
MOSI 18
CLK 20
CSN 19

二、移植文件

注意:以下出現(xiàn)缺失common.h文件錯(cuò)誤,去除即可。uint8改為uint8_t或unsigned char或自己宏定義
鏈接:https://pan.baidu.com/s/1AP3VuZz2v5gN47zDDTqCVA 提取碼:d84r
board_spi.cboard_spi.h 兩個(gè)文件加入工程的Application文件夾下


2.1 board_spi.c

NRF的SPI片選引腳CSN只支持低電平活動(dòng)。如果該信號(hào)應(yīng)該是高的,應(yīng)由外部控制,即單獨(dú)寫個(gè)GPIO控制。

/*********************************************************************
 * INCLUDES
 */
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"
#include "app_error.h"

#include "board_spi.h"
#include "common.h"     

static void spiCallbackFunc(nrf_drv_spi_evt_t const *pEvent, void *arg);

/*********************************************************************
 * LOCAL VARIABLES
 */
static volatile bool s_transferOk = true;                                       // SPI數(shù)據(jù)傳輸完成標(biāo)志
static const nrf_drv_spi_t s_spiHandle = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);    // SPI instance

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief SPI的初始化函數(shù)
 @param 無
 @return 無
*/
void SPI_Init(void)
{
    ret_code_t errCode;
    
    nrf_drv_spi_config_t spiConfig = NRF_DRV_SPI_DEFAULT_CONFIG;                // 使用SPI默認(rèn)配置
    // 配置SPI端口,注意CSN不要在這設(shè)置,另外用GPIO口控制
    spiConfig.miso_pin = BOARD_SPI0_MISO_IO;
    spiConfig.mosi_pin = BOARD_SPI0_MOSI_IO;
    spiConfig.sck_pin = BOARD_SPI0_CLK_IO;
    spiConfig.mode = NRF_DRV_SPI_MODE_0;
    spiConfig.frequency = SPI_FREQUENCY_FREQUENCY_K250; 
    spiConfig.irq_priority = 4;                                                 // 在定時(shí)器中使用優(yōu)先級(jí)需小于6
    
    errCode = nrf_drv_spi_init(&s_spiHandle, &spiConfig, spiCallbackFunc, NULL);
    APP_ERROR_CHECK(errCode);
    
    nrf_gpio_cfg_output(BOARD_SPI0_CSN_IO);
}

/**
 @brief SPI片選信號(hào)設(shè)置
 @param pinState -[in] 引腳狀態(tài)
 @return 無
*/
void SPI_CsnSet(bool pinState)
{
    if(pinState == BOARD_SPI_CS_OFF)
    {
        nrf_gpio_pin_write(BOARD_SPI0_CSN_IO, 1);
    }
    else if(pinState == BOARD_SPI_CS_ON)
    {
        nrf_gpio_pin_write(BOARD_SPI0_CSN_IO, 0);
    }
}

/**
 @brief SPI讀出寫入數(shù)據(jù)
 @param pWriteData -[in] 寫入數(shù)據(jù)
 @param pReadData -[out] 讀出數(shù)據(jù)
 @param writeDataLen -[in] 寫入數(shù)據(jù)長(zhǎng)度
 @return 無
*/
void SPI_ReadWriteData(uint8 *pWriteData, uint8 *pReadData, uint8 writeDataLen)
{
    s_transferOk = false;

    APP_ERROR_CHECK(nrf_drv_spi_transfer(&s_spiHandle, pWriteData, writeDataLen, pReadData, writeDataLen));

    while(!s_transferOk)
    {
        __WFE();
    }                                                                           // Error in SPI or transfer already in progress.
}

/**
 @brief 開啟SPI,與初始化區(qū)別:沒有初始化CS引腳
 @param 無
 @return 無
*/
void SPI_Enable(void)
{
    ret_code_t errCode;
    
    nrf_drv_spi_config_t spiConfig = NRF_DRV_SPI_DEFAULT_CONFIG;                // 使用SPI默認(rèn)配置
    // 配置SPI端口,注意CSN不要在這設(shè)置,另外用GPIO口控制
    spiConfig.miso_pin = BOARD_SPI0_MISO_IO;
    spiConfig.mosi_pin = BOARD_SPI0_MOSI_IO;
    spiConfig.sck_pin = BOARD_SPI0_CLK_IO;
    spiConfig.mode = NRF_DRV_SPI_MODE_0;
    spiConfig.frequency = SPI_FREQUENCY_FREQUENCY_K250; 
    spiConfig.irq_priority = 4;                                                 // 在定時(shí)器中使用優(yōu)先級(jí)需小于6
    
    errCode = nrf_drv_spi_init(&s_spiHandle, &spiConfig, spiCallbackFunc, NULL);
    APP_ERROR_CHECK(errCode);
}

/**
 @brief 禁用SPI
 @param 無
 @return 無
*/
void SPI_Disable(void)
{
    nrf_drv_spi_uninit(&s_spiHandle);
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief SPI中斷處理回調(diào)函數(shù)
 @param 無
 @return 無
*/
static void spiCallbackFunc(nrf_drv_spi_evt_t const *pEvent, void *arg)
{
    s_transferOk = true;
}

/****************************************************END OF FILE****************************************************/

2.2 board_spi.h

#ifndef _BOARD_SPI_H_
#define _BOARD_SPI_H_

/*********************************************************************
 * INCLUDES
 */
#include <stdbool.h>

#include "common.h"

/*********************************************************************
 * DEFINITIONS
 */
#define BOARD_SPI_CS_ON             0
#define BOARD_SPI_CS_OFF            1

#define SPI_CS_HIGH                 SPI_CsnSet(BOARD_SPI_CS_OFF)
#define SPI_CS_LOW                  SPI_CsnSet(BOARD_SPI_CS_ON)

#define BOARD_SPI0_MISO_IO          17
#define BOARD_SPI0_MOSI_IO          18
#define BOARD_SPI0_CLK_IO           20
#define BOARD_SPI0_CSN_IO           19

#define SPI_INSTANCE                0           // SPI instance index 

/*********************************************************************
 * API FUNCTIONS
 */
void SPI_Init(void);
void SPI_CsnSet(bool pinState);
void SPI_ReadWriteData(uint8 *pWriteData, uint8 *pReadData, uint8 writeDataLen);
void SPI_Enable(void);
void SPI_Disable(void);

#endif /* _BOARD_SPI_H_ */

三、API調(diào)用

需包含頭文件 board_spi.h

SPI_Init

功能 初始化SPI驅(qū)動(dòng)
函數(shù)定義 void SPI_Init(void)
參數(shù)
返回

1.其中CS片選信號(hào)引腳不要直接在 spiConfig.ss_pin 設(shè)置,需要自己另外用GPIO驅(qū)動(dòng)
2.spiConfig.irq_priority 為中斷優(yōu)先級(jí),如果在定時(shí)器中使用則優(yōu)先級(jí)需小于6
3.spiConfig.frequency 為傳輸速率,最高可設(shè)為SPI_FREQUENCY_FREQUENCY_M8即 8 Mbps
4.spiConfig.mode 為SPI模式,有4種模式0-3,通常為模式0

SPI_CsnSet

功能 SPI片選信號(hào)設(shè)置
函數(shù)定義 void SPI_CsnSet(bool pinState)
參數(shù) pinState:引腳狀態(tài)
返回

SPI_ReadWriteData

功能 SPI讀出寫入數(shù)據(jù)
函數(shù)定義 void SPI_ReadWriteData(uint8_t *pWriteData, uint8_t *pReadData, uint8_t writeDataLen)
參數(shù) pWriteData:寫入數(shù)據(jù)
pReadData:讀出數(shù)據(jù)
writeDataLen:寫入數(shù)據(jù)長(zhǎng)度
返回

SPI_Enable

功能 開啟SPI,實(shí)現(xiàn)低功耗配合SPI_Disable使用
函數(shù)定義 void SPI_Enable(void)
參數(shù)
返回

SPI_Disable

功能 禁用SPI,實(shí)現(xiàn)低功耗配合SPI_Enable使用
函數(shù)定義 void SPI_Disable(void)
參數(shù)
返回

四、SDK配置

點(diǎn)擊 sdk_config.h 文件


選擇 Configuration Wizard

nRF_Drivers 中勾選SPI及SPIM相關(guān)選項(xiàng)


注意,使用EasyDMA(例如SPIM)的外圍設(shè)備要求將傳輸緩沖區(qū)放在數(shù)據(jù)RAM區(qū)域。如果不是,并且使用SPM實(shí)例,nrf_drv_spi_transfet()函數(shù)將失敗,錯(cuò)誤代碼為NRF_ERROR_INVALID_ADDR。

nRF_Drivers 中添加文件


五、使用例子

1)添加頭文件

#include "board_spi.h"

2)添加初始化代碼(SDK15.3 中 ble_peripheral 的 ble_app_template 工程 main() 函數(shù)中)
加入 SPI_Init() 并在初始化后調(diào)用 SPI_Disable 進(jìn)入低功耗,在需要用SPI時(shí)調(diào)用 SPI_Enable 開啟SPI

int main(void)
{
    bool erase_bonds;

    /*-------------------------- 外設(shè)驅(qū)動(dòng)初始化 ---------------------------*/
    // Initialize.
    log_init();                                                                 // 日志驅(qū)動(dòng)初始化                                                                  
    timers_init();                                                              // 定時(shí)器驅(qū)動(dòng)初始化(在此加入自定義定時(shí)器)
    SI522_Init();                                                               // SI522驅(qū)動(dòng)初始化(含SPI) 
    
    /*-------------------------- 藍(lán)牙協(xié)議棧初始化 ---------------------------*/
    power_management_init();
    ble_stack_init();                                                           // 協(xié)議棧初始化
    gap_params_init();
    gatt_init();
    advertising_init();                                                         // 廣播初始化
    services_init();                                                            // 服務(wù)初始化
    conn_params_init();                                                         // 連接參數(shù)初始化
    peer_manager_init();
    
    /*-------------------------- 開啟應(yīng)用 ---------------------------*/
    // Start execution.
    NRF_LOG_INFO("Template example started."); 
    advertising_start(erase_bonds);                                             // 開啟廣播 
    application_timers_start();                                                 // 定時(shí)器應(yīng)用開啟(在此開啟自定義定時(shí)器)  
    SPI_Disable();                                                              // 禁用SPI,進(jìn)入低功耗模式,等待讀卡時(shí)再開啟
    
    // Enter main loop.
    for(;;)
    {
        idle_state_handle();
    }
}

3)寫入數(shù)據(jù)

uint8_t temp[1] = {0x01};
SPI_ReadWriteData(temp, NULL, sizeof(uint8_t));

4)查看示波器
CLK

MOSI


? 由 Leung 寫于 2019 年 12 月 24 日

? 參考:青風(fēng)電子社區(qū)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容