0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

nRF Connect SDK:SPIM(本物)

Last updated at Posted at 2023-01-19

SDK 2.xで一度書いた

SPIMについてはSDK 2.xになったときに一度記事を書いています。

が、この時に書いたものはまだNRFXのAPIを直接叩いています。つい最近、NRFXのAPIを使わない形のTWIMを記事にしましたが、SPIMも同様にNRFXのAPIを直接叩かない形(HAL)があるはずだよね・・・ということで調べてみました。

TWIMの場合はAPIを直接叩くプログラムが動かなかったので仕方がなく・・・。

SPIMも同様にサンプルがある

TWIMと同じようにSPIMにもサンプルがあります。しかも同じ富士通のFRAM(笑)です。
image.png

説明は省略

サンプルプロジェクトそのものの説明は省略します。読みたい人は読んでください。
ところで今頃気が付きましたが、このサンプルプロジェクトってCSを制御していないですね。気になったのでICの仕様を調べてみましたがちゃんとCSピンはあるみたいです。

当たり前か・・・

例によって

私のサンプルプロジェクトではInvensenseのICM-2064xを動かします。これは手元にあってお手軽に扱える評価ボードがこれしかないからという理由によるものです。ですので、ソースコード中にはIC固有の情報表記が多々出てきますが、そこらへんは無視するか自分で調べてください。

まずはペリフェラルの設定

何度も出てきていますが、評価ボード(正確には評価ボード用に用意されたDeviceTree)を使うとペリフェラルの設定が固定されてしまっているためOverlayを使って設定を変えてあげる必要があります。今回はSPIM0を使いたいのでTWIM0をdisableにした上でSPIM0を有効にしています。

app.overlay
// 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を変えながら動かすというのも簡単にできそうです。

僕はそもそもそんなハードウェア作りませんけどね・・・めんどくさいから(笑)

main.c
/*
 * 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;
	}
}

リードもちゃんとできています。
SPIM.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?