SDK 2.xで一度書いた
SPIMについてはSDK 2.xになったときに一度記事を書いています。
が、この時に書いたものはまだNRFXのAPIを直接叩いています。つい最近、NRFXのAPIを使わない形のTWIMを記事にしましたが、SPIMも同様にNRFXのAPIを直接叩かない形(HAL)があるはずだよね・・・ということで調べてみました。
TWIMの場合はAPIを直接叩くプログラムが動かなかったので仕方がなく・・・。
SPIMも同様にサンプルがある
TWIMと同じようにSPIMにもサンプルがあります。しかも同じ富士通のFRAM(笑)です。
説明は省略
サンプルプロジェクトそのものの説明は省略します。読みたい人は読んでください。
ところで今頃気が付きましたが、このサンプルプロジェクトってCSを制御していないですね。気になったのでICの仕様を調べてみましたがちゃんとCSピンはあるみたいです。
当たり前か・・・
例によって
私のサンプルプロジェクトではInvensenseのICM-2064xを動かします。これは手元にあってお手軽に扱える評価ボードがこれしかないからという理由によるものです。ですので、ソースコード中にはIC固有の情報表記が多々出てきますが、そこらへんは無視するか自分で調べてください。
まずはペリフェラルの設定
何度も出てきていますが、評価ボード(正確には評価ボード用に用意されたDeviceTree)を使うとペリフェラルの設定が固定されてしまっているためOverlayを使って設定を変えてあげる必要があります。今回はSPIM0を使いたいのでTWIM0をdisableにした上でSPIM0を有効にしています。
// Copyright (c) 2022 Nordic Semiconductor ASA
// SPDX-License-Identifier: Apache-2.0
&i2c0 {
status = "disabled";
};
&i2c1 {
status = "disabled";
};
&spi0 {
compatible = "nordic,nrf-spim";
status = "okay";
cs-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
};
ちなみにSPIM0が使うピンはそれぞれ
SCLK = P0.27
MOSI = P0.26
MISO = P0.29
となっています。そこに加えてapp.overlayでCSをP0.28として定義しています。
ソースコード
TWIMでも似たようなコードを書いているのでいきなり載せてしまいます。ただ、TWIMと違うのはCSピンを使うように設定してやらないといけないという点です。CSピンを使うコンフィグをSPIM Read/Writeを呼び出すたびに渡しているので、CS以外のピンがパラレル接続になっている場合にコントロールするCSを変えながら動かすというのも簡単にできそうです。
僕はそもそもそんなハードウェア作りませんけどね・・・めんどくさいから(笑)
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include "defines_ICM2064x.h"
const uint8_t INIT_CMD[] = {
UB0_PWR_MGMT_1,
WAIT_MSEC,
UB0_USER_CTRL,
UB0_INT_PIN_CFG,
UB0_PWR_MGMT_1,
UB0_LP_CONFIG,
UB0_REG_BANK_SEL,
UB2_GYRO_SMPLRT_DIV,
UB2_GYRO_CONFIG_1,
UB2_GYRO_CONFIG_2,
UB2_ACCEL_SMPLRT_DIV_1,
UB2_ACCEL_SMPLRT_DIV_2,
UB2_ACCEL_CONFIG,
UB2_REG_BANK_SEL,
UB0_PWR_MGMT_1,
};
const uint8_t INIT_PARAM[] = {
PWR_MGMT_1_DEVICE_RESET,
0x64,
0x00,
INT_PIN_CFG_BYPASS_EN,
PWR_MGMT_1_CLKSEL_AUTO,
LP_CONFIG_ACCEL_CYCLE | LP_CONFIG_GYRO_CYCLE,
REG_BANK_SEL_USER_BANK_2,
0x04,
GYRO_CONFIG_1_GYRO_DLPFCFG_0 | GYRO_CONFIG_1_GYRO_FS_SEL_FULL | GYRO_CONFIG_1_GYRO_FS_SEL_GYRO_FCHOICE,
0x00,
0x00,
0x04,
ACCEL_CONFIG_ACCEL_FS_SEL_FULL,
REG_BANK_SEL_USER_BANK_0,
PWR_MGMT_1_LP_EN | PWR_MGMT_1_CLKSEL_AUTO,
};
/* write */
static int write_bytes(const struct device *spi, struct spi_config *spi_cfg, uint8_t *data, uint32_t num_bytes)
{
int err;
struct spi_buf bufs[] = {
{
.buf = data,
.len = num_bytes
}
};
struct spi_buf_set tx = {
.buffers = bufs,
.count = 1
};
err = spi_write(spi, spi_cfg, &tx);
if (err) {
printk("Error during SPI write\n");
return -EIO;
}
return 0;
}
/* read */
static int read_bytes(const struct device *spi, struct spi_config *spi_cfg, uint8_t *tx_data, uint32_t tx_num_bytes, uint8_t *rx_data, uint32_t rx_num_bytes)
{
int err;
struct spi_buf bufs_tx[] = {
{
.buf = tx_data,
.len = tx_num_bytes
}
};
struct spi_buf bufs_rx[] = {
{
.buf = rx_data,
.len = rx_num_bytes
}
};
struct spi_buf_set tx = {
.buffers = bufs_tx,
.count = 1
};
struct spi_buf_set rx = {
.buffers = bufs_rx,
.count = 1
};
err = spi_transceive(spi, spi_cfg, &tx, &rx);
if (err) {
printk("Error during SPI read\n");
return -EIO;
}
return 0;
}
void main(void)
{
const struct device *spi;
static const struct spi_cs_control spi_dev_cs_ctrl = {
.gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(spi0), cs_gpios),
};
struct spi_config spi_cfg = {
.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8),
.frequency = 4000000U,
.cs = &spi_dev_cs_ctrl,
.slave = 0,
};
int err;
uint8_t tx_buf[16] = {0};
uint8_t rx_buf[16] = {0};
spi = DEVICE_DT_GET(DT_NODELABEL(spi0));
if (!device_is_ready(spi)) {
printk("SPI device %s is not ready\n", spi->name);
return;
}
for (int i = 0; i < sizeof(INIT_CMD); i++) {
if (INIT_CMD[i] == WAIT_MSEC) {
// Wait
k_sleep(K_MSEC(INIT_PARAM[i]));
} else {
// Transfer
tx_buf[0] = INIT_CMD[i];
tx_buf[1] = INIT_PARAM[i];
// write
err = write_bytes(spi, &spi_cfg, tx_buf, 2);
if (err) {
printk("Error writing to device! error code (%d)\n", err);
return;
}
}
}
tx_buf[0] = (UB0_ACCEL_XOUT_H | 0x80) & 0xfe;
tx_buf[1] = 0x00;
err = read_bytes(spi, &spi_cfg, tx_buf, 2, rx_buf, 14);
if (err) {
printk("Error reading from device! error code (%d)\n", err);
return;
}
}