Nordic52810入门篇-硬件SPIM外设

一、前言

Nordic的SPI串行外设主要分成两类,SPIM(基于EasyDMA的主机) SPIS(基于EasyDMA的从机)
ps:如有错误,请留言指正,谢谢

二、工作原理

功能特点

  • 四种模式(模式0 - 模式3关联到不同的极性与相位)
  • EasyDMA进行RAM数据与寄存器的传输
  • 可映射到任意的GPIO引脚

原理框图
Nordic52810入门篇-硬件SPIM外设_第1张图片
四种工作模式
Nordic52810入门篇-硬件SPIM外设_第2张图片
Nordic52810入门篇-硬件SPIM外设_第3张图片
数据通信

如下图

  • SPI通信通过START任务进行触发,最终通过STOP结束任务,通信过程中会产生相关事件
  • 当指定TXD.MAXCNT寄存器中TXD缓存发送完成后会生成ENDTX事件
  • 当指定RXD.MAXCNT寄存器中RXD缓存接收完成后生成ENDRX事件
  • STOP停止任务将会触发STOPPED事件
  • 当SPI被停止时,数据未发完货未接收完成,也会触发对应的事件ENDTX ENDRX
    Nordic52810入门篇-硬件SPIM外设_第4张图片

三、寄存器

  • SHORTSEND_START位写1使能循环模式,写0禁用循环模式;(发送接收结束事件后自动触发START任务)
  • INTENSET:中断使能寄存器,可配置 STOPPED ENDRX END ENDTX STARTED事件中断,写1有效
  • INTENCLR:中断禁用寄存器,可配置 STOPPED ENDRX END ENDTX STARTED事件中断,写1有效
  • SPIM:SPI外设使能寄存器
  • PLSEL.SCK:关联SCK引脚,低4位有效
  • PLSEL.MOSI:关联MOSI引脚,低4位有效
  • PLSE.MISO:关联MISO引脚,低4位有效
  • FREQUENCY:SPI通信速率选择 125k 250k 500k 1M 2M 4M 8M
  • RXD.PTR:接收数据寄存器,指向RXD接收缓存
  • RXD.MAXCNT:接收数据缓存区最大长度
  • RXD.AMOUNT:最近一次数据通信的接收传输字节长度
  • RXD.LIST:EasyDMA列表类型,写1使用arraylist接收缓存,触发START任务时无需更新PTR数据指针寄存器,类似DMA串口中双缓存循环读取
  • TXD.PTR:发送数据寄存器,指向TXD发送缓存
  • TXD.MAXCNT:需要发送数据缓存的最大长度
  • TXD.AMOUNT:最近一次数据通信的发送传输字节长度
  • TXD.LIST:EasyDMA列表类型,写1使用arraylist发送缓存,触发START任务时无需更新PTR数据指针寄存器,类似DMA串口中双缓存循环发送
  • CONFIG:配置寄存器,主要进行配置发送高位在前还是低位在前,通信的极性与相位

四、相关接口

SPIM的驱动目录在modules\nrfx\drivers\src\nrfx_spim.c

  • nrfx_spim_init:初始化spim,形参nrfx_spim_config_t p_config传入引脚的映射关系与SPI的参数(频率、工作模式、高低位传输);函数指针nrfx_spim_evt_handler_t handler用于定义事件回调(数据的发送与接收)
nrfx_err_t nrfx_spim_init(nrfx_spim_t  const * const p_instance, 
                            nrfx_spim_config_t const * p_config,
                            nrfx_spim_evt_handler_t    handler, 
                            void * p_context)
  • nrfx_spim_uninit:禁用spim外设,系统进入低功耗的时候可以调用
void nrfx_spim_uninit(nrfx_spim_t const * const p_instance)
  • nrfx_spim_xfer:数据传输接口,形参nrfx_spim_xfer_desc_t const * p_xfer_desc定义了发送TX与接收RX的缓存与长度
nrfx_err_t nrfx_spim_xfer(nrfx_spim_t     const * const p_instance,
                          nrfx_spim_xfer_desc_t const * p_xfer_desc,
                          uint32_t                      flags)

五、代码实例

打开工程目录 examples\peripheral\spi,选择pca10040

贴上例程代码,更改宏定义NRF_DRV_SPI_DEFAULT_CONFIG更新SPIM的配置,填充m_tx_buf来更新发送的数据,m_rx_buf为接收到的数据

/*
* 默认的SPIM的参数
*/
#define NRF_DRV_SPI_DEFAULT_CONFIG                           \
{                                                            \
    .sck_pin      = NRF_DRV_SPI_PIN_NOT_USED,                \
    .mosi_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \
    .miso_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \
    .ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,                \
    .irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY,         \
    .orc          = 0xFF,                                    \
    .frequency    = NRF_DRV_SPI_FREQ_4M,                     \
    .mode         = NRF_DRV_SPI_MODE_0,                      \
    .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,         \
}

int main(void)
{
    bsp_board_init(BSP_INIT_LEDS); //初始化LED

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

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; //缺省参数
    spi_config.ss_pin   = SPI_SS_PIN; //关联SPI引脚
    spi_config.miso_pin = SPI_MISO_PIN;
    spi_config.mosi_pin = SPI_MOSI_PIN;
    spi_config.sck_pin  = SPI_SCK_PIN;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));  //执行初始化

    NRF_LOG_INFO("SPI example started.");

    while (1)
    {
        // Reset rx buffer and transfer done flag
        memset(m_rx_buf, 0, m_length);  //清缓存
        spi_xfer_done = false; //清状态

        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length)); //开始传输

        while (!spi_xfer_done) //等待传输完成
        {
            __WFE();
        }

        NRF_LOG_FLUSH();

        bsp_board_led_invert(BSP_BOARD_LED_0); //指示灯
        nrf_delay_ms(200);
    }
}

你可能感兴趣的:(蓝牙BLE)