ARMマイコン(nRF52832)でのSPI通信プログラム

今回はARMマイコンでSPI通信をしました。

 

エディタはEmbedded studio for ARM v4.16。

SDK15.0.0を使用。

SPI通信に必要な事項について書いておきます。

今回私はSDカードとのSPI通信をしたので単純にSPI通信をするにあたって必要のないものも含まれているかもしれません。

 -------------------------------------------------------------------------------------------------------------

1)includeファイル

・(ffとかgpioとか必要ないかも?)

・これらはインクルードパスを通さないといけない

 インクルードパスとは、これらのヘッダファイルがパソコン内のどこにあるかをエディタに定義しておくこと

 

#include "nrf_block_dev_sdc.h"
#include "ff.h"
#include "diskio_blkdev.h"
#include "nrf_gpio.h"
#include "nrf_drv_spi.h"
#include "nrf_assert.h"
#include "pt.h"
#include "nrf_pt.h"

 --------------------------------------------------------------------------------------------------------------

2)ピン定義

・使用するものによって変数名、数値(SPIが対応しているピン番号)を変更する

 

#define SCK_PIN  1   //sensor serial clock (SCK) pin.
#define MOSI_PIN   2   //sensor serial clock (MOSI) pin.
#define MISO_PIN   3  //sensor serial clock (MISO) pin.
#define CS_PIN    4   //sensor serial clock (CS) pin.

--------------------------------------------------------------------------------------------------------------

3)SPIスタート条件定義

・SPIのスタート条件として、CSをHIGHからLOWにする

#include "nrf_gpio.h"が必要

 

void SPI_start()
{
  nrf_gpio_cfg_output(sensor_CS_PIN);  //CSpinのgpio設定
  nrf_gpio_pin_set(sensor_CS_PIN);    //CSをHIGH
  nrf_gpio_pin_clear(sensor_CS_PIN);   //CSをLOW
}

--------------------------------------------------------------------------------------------------------------

4)SPIインスタンス生成

・SPIを使用するにあたってインスタンスが必要となる。

・複数のSPI通信をするにもインスタンスの設定をすることで差別化を図ることができる。

・これをするまえに"sdk_config.h"でもインスタンスを有効にする必要がある。

・これを記述することで"spi"をインスタンス1として設定する。 

 

#define SPI_INSTANCE 1;
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);//SPI_INSTANCE (spi1)
const nrf_drv_spi_t *p_spi = &spi;
static volatile bool spi_xfer_done; 

--------------------------------------------------------------------------------------------------------------

5)イベントハンドラ

・spi通信の状況(イベント)によって異なる処理をするためのもの

・今回のはSPIイベントが終わったらFlagをtrueにするといった処理

・これにより「SPI通信→(終わったら)ほかの処理」のようなものができる

 

volatile static bool spi_tx_done = false;
void nrf_drv_mpu_spi_event_handler(const nrf_drv_spi_evt_t *evt, void * p_context)
{
  if(evt->type == NRF_DRV_SPI_EVENT_DONE)
{
  spi_tx_done = true;
}else
 {
  // Something is wrong
 }
}

--------------------------------------------------------------------------------------------------------------

6)SPI初期化

・ピンなどの設定として初期化する必要がある

・SPIの周波数、MODE、ビットオーダー等の設定ができる

https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk51.v10.0.0/structnrf__drv__spi__config__t.html

 

void SPI_INIT()
{
  uint32_t err_code;

  nrf_drv_spi_config_t config = {
    .sck_pin = SCK_PIN,
    .mosi_pin = MOSI_PIN,
    .miso_pin = MISO_PIN,
    .ss_pin = CS_PIN,
    .frequency = NRF_DRV_SPI_FREQ_1M,
    .mode = NRF_DRV_SPI_MODE_0,
    .bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
  };
  err_code = nrf_drv_spi_init(&spi,&config,nrf_drv_mpu_spi_event_handler,NULL);

}

--------------------------------------------------------------------------------------------------------------

7)あるアドレス(0x6Bなど)に値(0x80など)を送信する方法

・まずdefineでアドレス定義

・アドレスと値を定義

・nrf_drv_spi_transferで送信

 

#define PWR_MGMT_1 0x6B

uint8_t reg_chipreset[2] = {PWR_MGMT_1,0x80};
nrf_drv_spi_transfer(&spi,reg_chipreset,sizeof(reg_chipreset),NULL,0);//chip reset

--------------------------------------------------------------------------------------------------------------

8)センサとのSPI通信などで、データを受け取るために送受信する方法

・まずセンサの読むためのアドレス(スレーブアドレス?)?を定義

・値を受け取る配列も定義

nrf_drv_spi_xfer_descのように設定することでアドレスに1バイト送信することで21バイトのデータが配列に入る

 

#define read_six_axis 0xBB//read data

uint8_t reg_six = read_six_axis;
uint8_t mpu_buf[25] = {0};

 

nrf_drv_spi_xfer_desc_t xfer_spi = NRF_DRV_SPI_XFER_TRX(&reg_six,1,mpu_buf,21);

 

・続いてフラグ設定(それぞれの意味は要検索)

uint32_t flags = NRF_DRV_SPI_FLAG_HOLD_XFER |
       NRF_DRV_SPI_FLAG_RX_POSTINC |
       NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER |
       NRF_DRV_SPI_FLAG_REPEATED_XFER;

--------------------------------------------------------------------------------------------------------------

9)main関数での呼び出し

・これらの定義をしたらmain関数内で呼び出す

int main(){

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  SPI_start();//スタート条件

  SPI_INIT();//SPI初期化

 

  //設定したフラグ通りに送信

  ret_code_t ret = nrf_drv_spi_xfer(&spi,&xfer_spi,flags);

  

  //SUCCESSだったらspiの通信をする

  //多分ここでセンサのデータを受け取っている?
  if(ret == NRF_SUCCESS)
  {
    uint32_t start_tsk_addr = nrf_drv_spi_start_task_get(&spi);
  }

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//センサのデータ処理など

}