nRF52 シリーズでのADXL345(加速度センサー) をSPIで動かす

***はじめに***
Nordic nRF5x シリーズで、ADXL345(加速度センサー) を SPI モードで動作させた時の覚書

---

***ADXL345(加速度センサー)について***
ANALOG DEVICES ADXL345(加速度センサー) に関する資料は、以下のページに置かれている
[https://www.analog.com/jp/products/adxl345.html](https://www.analog.com/jp/products/adxl345.html)

SPIを使用する時の注意点は、以下の通り
・SPI の mode設定は、mode3
・SPI の frequency を 8MHz以下のに設定
・CS(Chip Select) ピンを High にした後、nRF52を SPI設定を行う。


***nRF52 のプログラム***
nRF52480 で確認をした。ベースにしたプログラムは、[SDK](https://www.nordicsemi.com/Products/Development-software/nRF5-SDK/Download)に収められている
***SDK\examples\peripheral\spi*** をベースにした。

元にした main.c を下記の様に修正した。(一部を記載)

尚、ADXL345 と nRF52840 の接続は、以下の通り
***[ADXL345] - - - - - - - - - - - - ---- [nRF52840]***
***CS(Chip Select) - - - - - - ------ SPI_SS_PIN  (P0.31)***
***SDO(Serial Data Output) ----- SPI_MISO_PIN(P0.30)***
***SDA(Serial Data Input) - - - -- SPI_MOSI_PIN(P0.29)***
***SCL(Serial Comunication)----- SPI_SCK_PIN (P0.26)***


~~~main.c
#define SPI_INSTANCE  0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */

#define TEST_STRING "012456789012345678901234567890"
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. */

/*************************** REGISTER MAP ********************************/
#define ADXL345_DEVID			0x00U		// Device ID
#define ADXL345_RESERVED1		0x01U		// Reserved. Do Not Access. 
#define ADXL345_THRESH_TAP		0x1DU		// Tap Threshold. 
#define ADXL345_OFSX			0x1EU		// X-Axis Offset. 
#define ADXL345_OFSY			0x1FU		// Y-Axis Offset.
#define ADXL345_OFSZ			0x20U		// Z- Axis Offset.
#define ADXL345_DUR 			0x21U		// Tap Duration.
#define ADXL345_LATENT			0x22U		// Tap Latency.
#define ADXL345_WINDOW			0x23U		// Tap Window.
#define ADXL345_THRESH_ACT		0x24U		// Activity Threshold
#define ADXL345_THRESH_INACT            0x25U		// Inactivity Threshold
#define ADXL345_TIME_INACT		0x26U		// Inactivity Time
#define ADXL345_ACT_INACT_CTL           0x27U		// Axis Enable Control for Activity and Inactivity Detection
#define ADXL345_THRESH_FF		0x28U		// Free-Fall Threshold.
#define ADXL345_TIME_FF			0x29U		// Free-Fall Time.
#define ADXL345_TAP_AXES		0x2AU		// Axis Control for Tap/Double Tap.
#define ADXL345_ACT_TAP_STATUS          0x2BU		// Source of Tap/Double Tap
#define ADXL345_BW_RATE			0x2CU		// Data Rate and Power mode Control
#define ADXL345_POWER_CTL		0x2DU		// Power-Saving Features Control
#define ADXL345_INT_ENABLE		0x2EU		// Interrupt Enable Control
#define ADXL345_INT_MAP			0x2FU		// Interrupt Mapping Control
#define ADXL345_INT_SOURCE		0x30U		// Source of Interrupts
#define ADXL345_DATA_FORMAT		0x31U		// Data Format Control
#define ADXL345_DATAX0			0x32U		// X-Axis Data 0
#define ADXL345_DATAX1			0x33U		// X-Axis Data 1
#define ADXL345_DATAY0			0x34U		// Y-Axis Data 0
#define ADXL345_DATAY1			0x35U		// Y-Axis Data 1
#define ADXL345_DATAZ0			0x36U		// Z-Axis Data 0
#define ADXL345_DATAZ1			0x37U		// Z-Axis Data 1
#define ADXL345_FIFO_CTL		0x38U		// FIFO Control
#define ADXL345_FIFO_STATUS		0x39U		// FIFO Status
-- 省略 --

/*
 * Read & Write data from ADXL345 Register.
 */
static void adxl345_spi_transfer(uint8_t rw_mode, uint8_t length)
{
    ret_code_t err_code;
 
    spi_xfer_done = false;

    switch(rw_mode)
    {
      //Single Read
      case 1:
        m_tx_buf[0] = 0x80|m_tx_buf[0];
        break;

      //Multi Read
      case 2:
        m_tx_buf[0] = 0x80|0x40|m_tx_buf[0];
        break;

      //Single Write
      case 3:
        //m_tx_buf[0] = m_tx_buf[0];
        break;
       
      //Multi Write
      case 4:
        m_tx_buf[0] = 0x40|m_tx_buf[0];
        break;

      default:
        break;
    }

    err_code = nrf_drv_spi_transfer(&spi, m_tx_buf, length, m_rx_buf, length);
    APP_ERROR_CHECK(err_code);
    while (spi_xfer_done == false);
}

static void adxl345_read_acceler()
{
    // Read Write Mode
    // Single  Read:1
    // Multi   Read:2
    // Single Write:3
    // Multi  Write:4
    uint8_t   rw_mode;
    uint8_t   rw_length;

    memset(m_rx_buf, 0, m_length);
    memset(m_tx_buf, 0, m_length);

    m_tx_buf[0] = ADXL345_DATAX0;
    rw_length = 7;
    rw_mode   = 2; //Multi Read
    adxl345_spi_transfer(rw_mode, rw_length);
    nrf_delay_ms(10);
    NRF_LOG_INFO("Read Accelerometer:%02X%02X-%02X%02X-%02X%02X", m_rx_buf[0],m_rx_buf[1], m_rx_buf[2],m_rx_buf[3], m_rx_buf[4],m_rx_buf[5]);
}

int main(void)
{  
-- 省略 --
   /*
    * for ADXL345 First ALL Pin Clear
    */
    nrf_gpio_pin_clear(SPI_SS_PIN);
    nrf_gpio_pin_clear(SPI_MISO_PIN);
    nrf_gpio_pin_clear(SPI_MOSI_PIN);
    nrf_gpio_pin_clear(SPI_SCK_PIN);

    NRF_LOG_INFO("\n\rADXL345 Ready.......");
    NRF_LOG_FLUSH();
    nrf_delay_ms(2000);

   /*
    * for ADXL345
    * If power is applied to the ADXL345
    * before set MODE2 to nRF52 (the clock polarity and phase of the host processor are configured),
    * the CS pin should be brought high before set MODE2 to nRF52(changing the clock polarity and phase). 
    */
    nrf_gpio_pin_set(SPI_SS_PIN);
    nrf_delay_ms(1);

    /*
     *       [ADXL345]  ---------------- [nRF52840]
     *   CS(Chip Select) ------------ SPI_SS_PIN  (P0.31)
     *  SDO(Serial Data Output) ----- SPI_MISO_PIN(P0.30)
     *  SDA(Serial Data Input)  ----- SPI_MOSI_PIN(P0.29)
     *  SCL(Serial Comunication)----- SPI_SCK_PIN (P0.26)
     */
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin    = SPI_SS_PIN;
    spi_config.miso_pin  = SPI_MISO_PIN;
    spi_config.mosi_pin  = SPI_MOSI_PIN;
    spi_config.sck_pin   = SPI_SCK_PIN;

    // for ADXL345
    spi_config.frequency = NRF_DRV_SPI_FREQ_8M;
    spi_config.mode      = NRF_DRV_SPI_MODE_3;

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));

   /*
    * Check ADXL345 Device ID=0xE5
    */
    while(m_rx_buf[1]!=0xE5)
    {
      memset(m_rx_buf, 0, m_length);
      memset(m_tx_buf, 0, m_length);

      m_tx_buf[0] = ADXL345_DEVID;
      rw_mode   = 1; //Single Read
      rw_length = 2;
      adxl345_spi_transfer(rw_mode, rw_length);
      NRF_LOG_INFO("ADXL345_DEVID:%02X-%02X", m_rx_buf[0], m_rx_buf[1]);
      nrf_delay_ms(10);
    }

   /*
    * Check All Register ADXL345
    */
    memset(m_rx_buf, 0, m_length);
    memset(m_tx_buf, 0, m_length);

    m_tx_buf[0] = ADXL345_THRESH_TAP;
    rw_mode   =  2; //Multi Read
    rw_length = 30;
    adxl345_spi_transfer(rw_mode, rw_length);
    NRF_LOG_INFO("ADXL345_BW_RATE   :%02X", m_rx_buf[16]);
    NRF_LOG_INFO("ADXL345_INT_SOURCE:%02X", m_rx_buf[20]);
    nrf_delay_ms(10);

    ///////////////////////////////////////
    // Write data to DATA FORMAT(0x31)
    // D1  D0  gRange
    //  0  0   ±2g
    //  0  1   ±4g
    //  1  0   ±8g
    //  1  1  ±16g
    ///////////////////////////////////////
    memset(m_rx_buf, 0, m_length);
    memset(m_tx_buf, 0, m_length);

    m_tx_buf[0] = ADXL345_DATA_FORMAT;
    m_tx_buf[1] = 0x0B;
    rw_length = 2;
    rw_mode   = 3; // Single Write
    adxl345_spi_transfer(rw_mode, rw_length);
    nrf_delay_ms(10);

#if 0
    ///////////////////////////////////////
    // Cheack data to DATA FORMAT(0x31)
    ///////////////////////////////////////
    memset(m_rx_buf, 0, m_length);
    memset(m_tx_buf, 0, m_length);

    m_tx_buf[0] = ADXL345_DATA_FORMAT;
    rw_length = 2;
    rw_mode   = 1; // Single Read
    adxl345_spi_transfer(rw_mode, rw_length);
    nrf_delay_ms(10);
#endif

    ///////////////////////////////////////
    // Write data to POWER CTL(0x2D)
    // D3:1 - measurement mode
    // D3:0 - standby mode 
    memset(m_rx_buf, 0, m_length);
    memset(m_tx_buf, 0, m_length);

    m_tx_buf[0] = ADXL345_POWER_CTL;
    m_tx_buf[1] = 0x08;
    rw_length = 2;
    rw_mode   = 3; //Single Write
    adxl345_spi_transfer(rw_mode, rw_length);
    nrf_delay_ms(10);

    while (1)
    {

      adxl345_read_acceler();

      while (!spi_xfer_done)
      {
        __WFE(); 
      }

      NRF_LOG_FLUSH();

      bsp_board_led_invert(BSP_BOARD_LED_0);
      nrf_delay_ms(200);
    }
}
-- 省略 --



~~~
---
☆2022年 4月19日(火) 午前8時55分 初版(Ver1.00) 作成