This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf_drv_spi_transfer() single register read/write example

I struggled for a while with this: the SDK documentation and the example application did not explain a common use case: reading and writing single-byte registers in a peripheral chip. Various posts give clues without providing complete examples, so I've made a working example, replacing all of the code in the \examples\peripheral\spi example. In my case I am using a SX1276 LoRa radio chip. I offer the code here, with plenty of comments, in case it is useful for others.

#include "nrf_drv_spi.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "boards.h"
#include "app_error.h"
#include <string.h>
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define SPI_INSTANCE  0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
static uint8_t       m_tx_buf[2];    /**< TX buffer. */
static uint8_t       m_rx_buf[2];    /**< RX buffer. */
static ret_code_t 	 err_code;


// Registers in an SX1276 SPI device
#define REG_LR_VERSION		0x42
#define REG_LR_FRFLSB 		0x08
#define REG_VERSION_VALUE 	0x12

// Read from an SPI device
static uint8_t spiRead(uint8_t regAddress) {
	m_tx_buf[0] = regAddress & 0x7f; 	// SX1276 interprets bit 7 as write enable
	m_tx_buf[1] = 0; 					// don't care

    nrf_gpio_pin_clear(SPI_SS_PIN);		// Manual control of the chip select pin
    err_code = nrf_drv_spi_transfer(&spi, ( uint8_t* )&m_tx_buf, 2, ( uint8_t* )&m_rx_buf, 2);
    nrf_gpio_pin_set(SPI_SS_PIN);

    APP_ERROR_CHECK(err_code);

    return m_rx_buf[1];		// Discard m_rx_buf[0]
}

// Write to an SPI device
static void spiWrite(uint8_t regAddress, uint8_t value) {
	m_tx_buf[0] = regAddress | 0x80;	// SX1276 interprets bit 7 as write enable
	m_tx_buf[1] = value;

    nrf_gpio_pin_clear(SPI_SS_PIN);		// Manual control of the chip select pin
    err_code = nrf_drv_spi_transfer(&spi, ( uint8_t* )&m_tx_buf, 2, NULL, 0); // NULL seems OK on writes
    nrf_gpio_pin_set(SPI_SS_PIN);

    APP_ERROR_CHECK(err_code);
}

int main(void) {
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    // Pins are defined in sdk_config.h
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;	// will be controlled by our code
    spi_config.miso_pin = SPI_MISO_PIN;
    spi_config.mosi_pin = SPI_MOSI_PIN;
    spi_config.sck_pin  = SPI_SCK_PIN;

    // Now enable a pin to work as the chip select
    nrf_gpio_cfg_output(SPI_SS_PIN);
    nrf_gpio_pin_set(SPI_SS_PIN);

	// Specify blocking operation
	APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, NULL, NULL));

	NRF_LOG_INFO(" ");
	NRF_LOG_INFO("***** SPI example started. *****");
	NRF_LOG_FLUSH();

	while (1) {
		// This is a read-only register containing a chip ID
		NRF_LOG_INFO("Read Version Register: 0x%02x. Expected 0x%02x", spiRead(REG_LR_VERSION), REG_VERSION_VALUE);
		NRF_LOG_INFO(" ");

		// Try writing then reading each bit in turn to/from a read/write register: REG_LR_FRFLSB
		for (int i=0; i<8; i++) {
			spiWrite( REG_LR_FRFLSB, 0x01 << i );
			NRF_LOG_INFO("Wrote 0x%02x, read 0x%02x", 0x01 << i, spiRead( REG_LR_FRFLSB));
		}
		NRF_LOG_INFO(" ");
		NRF_LOG_FLUSH();
		nrf_delay_ms(2000);		// Let's not go too fast
	}
}

Related