I have been trying to figure out how to use SPI on nRF Connect SDK. I cannot find a simple enough example to get started other than the convoluted SPI flash example or the BME280 and similar ones.
Should I use some specific nRF SPI library? I would prefer to make this library universal.
I have been using nRF52840-DK for development and I am trying to port miguelbalboa / rfid to Zephyr, this is my code:
mfrc522.c
#include "mfrc522.h"
#include <logging/log.h>
LOG_MODULE_REGISTER(mfrc522, LOG_LEVEL_DBG);
#include <devicetree.h>
#include <drivers/gpio.h>
#include <drivers/spi.h>
#define SPI_DEV DT_LABEL(DT_NODELABEL(spi0))
#define MFRC522_IRQ_NODE DT_ALIAS(led2)
#define MFRC522_IRQ DT_GPIO_LABEL(MFRC522_IRQ_NODE, gpios)
#define MFRC522_IRQ_PIN DT_GPIO_PIN(MFRC522_IRQ_NODE, gpios)
#define MFRC522_IRQ_FLAGS DT_GPIO_FLAGS(MFRC522_IRQ_NODE, gpios)
#define MFRC522_CS_NODE DT_ALIAS(led3)
#define MFRC522_CS DT_GPIO_LABEL(MFRC522_CS_NODE, gpios)
#define MFRC522_CS_PIN DT_GPIO_PIN(MFRC522_CS_NODE, gpios)
#define MFRC522_CS_FLAGS DT_GPIO_FLAGS(MFRC522_CS_NODE, gpios)
const struct device *spi_dev;
const struct device *reset_dev;
const struct device *irq_dev;
const struct device *cs_dev;
const struct spi_cs_control mfrc522_cs = {
.gpio_dev = cs_dev,
.gpio_pin = MFRC522_CS_PIN,
.delay = 0,
.gpio_dt_flags = MFRC522_CS_FLAGS,
};
const struct spi_config spi_conf = {
.frequency = 20000000,
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_LINES_SINGLE,
.slave = 0,
.cs = &mfrc522_cs,
};
void init_peripherals(){
cs_dev = device_get_binding(MFRC522_CS);
if (cs_dev == NULL)
{
return;
}
if (gpio_pin_configure(cs_dev, MFRC522_CS_PIN, GPIO_OUTPUT_HIGH | MFRC522_CS_FLAGS) < 0)
{
return;
}
spi_dev = device_get_binding(SPI_DEV);
if (!spi_dev) {
return;
}
k_msleep(1);
}
uint8_t MFRC522_ReadRegister(uint8_t reg) {
struct spi_buf_set tx_bufs;
struct spi_buf_set rx_bufs;
struct spi_buf txb;
struct spi_buf rxb;
uint16_t command = 0x80 | reg;
txb.buf = &command;
txb.len = 1;
tx_bufs.buffers = (const struct spi_buf *)&txb;
tx_bufs.count = 1;
rxb.buf = NULL;
rxb.len = 1;
rx_bufs.buffers = (const struct spi_buf *)&rxb;
rx_bufs.count = 1;
spi_transceive(spi_dev, &spi_conf, &tx_bufs, &rx_bufs);
return *(uint8_t *)rx_bufs.buffers->buf;
}
void MFRC522_WriteRegister(uint8_t reg, uint8_t value){
struct spi_buf_set tx_bufs;
struct spi_buf txb;
uint8_t command;
command = reg;
txb.buf = &command;
txb.len = 1;
tx_bufs.buffers = (const struct spi_buf *)&txb;
tx_bufs.count = 1;
LOG_DBG("Sending SPI command");
spi_write(spi_dev, &spi_conf, &tx_bufs);
LOG_DBG("SPI written");
}
void MFRC522_Reset(){
MFRC522_WriteRegister(CommandReg, SoftReset); // Issue the SoftReset command.
LOG_DBG("Reset command sent");
uint8_t count = 0;
do {
// Wait for the PowerDown bit in CommandReg to be cleared (max 3x50ms)
k_msleep(50);
} while ((MFRC522_ReadRegister(CommandReg) & (1 << 4)) && (++count) < 3);
}
void MFRC522_Antenna_On(){
uint8_t value = MFRC522_ReadRegister(TxControlReg);
if ((value & 0x03) != 0x03) {
MFRC522_WriteRegister(TxControlReg, value | 0x03);
}
}
void MRFRC522_init()
{
LOG_DBG("Initializing");
init_peripherals();
LOG_DBG("Initialized");
MFRC522_Reset();
LOG_DBG("Reset done");
MFRC522_WriteRegister(TxModeReg, 0x00);
MFRC522_WriteRegister(RxModeReg, 0x00);
MFRC522_WriteRegister(ModWidthReg, 0x26);
MFRC522_WriteRegister(TModeReg, 0x80);
MFRC522_WriteRegister(TPrescalerReg, 0xA9);
MFRC522_WriteRegister(TReloadRegH, 0x03);
MFRC522_WriteRegister(TReloadRegL, 0xE8);
MFRC522_WriteRegister(TxASKReg, 0x40);
MFRC522_WriteRegister(ModeReg, 0x3D);
MFRC522_Antenna_On();
}
mfrc522.h
//Page 0 ==> Command and Status #define Page0_Reserved_1 0x00 #define CommandReg 0x01 #define ComIEnReg 0x02 #define DivIEnReg 0x03 #define ComIrqReg 0x04 #define DivIrqReg 0x05 #define ErrorReg 0x06 #define Status1Reg 0x07 #define Status2Reg 0x08 #define FIFODataReg 0x09 #define FIFOLevelReg 0x0A #define WaterLevelReg 0x0B #define ControlReg 0x0C #define BitFramingReg 0x0D #define CollReg 0x0E #define Page0_Reserved_2 0x0F //Page 1 ==> Command #define Page1_Reserved_1 0x10 #define ModeReg 0x11 #define TxModeReg 0x12 #define RxModeReg 0x13 #define TxControlReg 0x14 #define TxASKReg 0x15 #define TxSelReg 0x16 #define RxSelReg 0x17 #define RxThresholdReg 0x18 #define DemodReg 0x19 #define Page1_Reserved_2 0x1A #define Page1_Reserved_3 0x1B #define MfTxReg 0x1C #define MfRxReg 0x1D #define Page1_Reserved_4 0x1E #define SerialSpeedReg 0x1F //Page 2 ==> CFG #define Page2_Reserved_1 0x20 #define CRCResultReg_1 0x21 #define CRCResultReg_2 0x22 #define Page2_Reserved_2 0x23 #define ModWidthReg 0x24 #define Page2_Reserved_3 0x25 #define RFCfgReg 0x26 #define GsNReg 0x27 #define CWGsPReg 0x28 #define ModGsPReg 0x29 #define TModeReg 0x2A #define TPrescalerReg 0x2B #define TReloadRegH 0x2C #define TReloadRegL 0x2D #define TCounterValReg_1 0x2E #define TCounterValReg_2 0x2F //Page 3 ==> TestRegister #define Page3_Reserved_1 0x30 #define TestSel1Reg 0x31 #define TestSel2Reg 0x32 #define TestPinEnReg 0x33 #define TestPinValueReg 0x34 #define TestBusReg 0x35 #define AutoTestReg 0x36 #define VersionReg 0x37 #define AnalogTestReg 0x38 #define TestDAC1Reg 0x39 #define TestDAC2Reg 0x3A #define TestADCReg 0x3B #define Page3_Reserved_2 0x3C #define Page3_Reserved_3 0x3D #define Page3_Reserved_4 0x3E #define Page3_Reserved_5 0x3F // Commands #define SoftReset 0x0F void MRFRC522_init();
main.c
#include <logging/log.h>
LOG_MODULE_REGISTER(door_opener, LOG_LEVEL_DBG);
#include "io.h"
#include "coap.h"
#include "mfrc522.h"
#include <errno.h>
#include <sys/printk.h>
#include <sys/byteorder.h>
#include <zephyr.h>
void main(void)
{
int r = 0;
LOG_DBG("Initializing IO");
initialize_io();
LOG_DBG("IO initialized");
//r = start_coap_server();
if (r < 0){
LOG_DBG("Failed to start CoAP Server");
return;
} else {
LOG_DBG("Started CoAP Server successfully");
}
MRFRC522_init();
while (1)
{
//r = process_client_request();
check_button();
}
}
prj.conf
CONFIG_GPIO=y CONFIG_SPI=y CONFIG_MAIN_STACK_SIZE=4096 CONFIG_NEWLIB_LIBC=y # Logging CONFIG_LOG=y
error:
mfrc522.c:28:17: error: initializer element is not constant 28 | .gpio_dev = cs_dev,
When I move the spi_conf and spi_cs_control initializers to WriteRegister and ReadRegister I get the following on the serial port:
[00:00:00.256,652] <dbg> mfrc522.MRFRC522_init: Initializing [00:00:00.256,683] <dbg> mfrc522.MRFRC522_init: Initialized [00:00:00.256,683] <dbg> mfrc522.MFRC522_WriteRegister: Sending SPI command [00:00:00.256,683] <err> os: ***** MPU FAULT ***** [00:00:00.256,683] <err> os: Instruction Access Violation [00:00:00.256,713] <err> os: r0/a1: 0x00000000 r1/a2: 0x200024ec r2/a3: 0x200024d0 [00:00:00.256,713] <err> os: r3/a4: 0x00000000 r12/ip: 0x20000114 r14/lr: 0x0000068f [00:00:00.256,713] <err> os: xpsr: 0x81000000 [00:00:00.256,713] <err> os: Faulting instruction address (r15/pc): 0xabf7fbb4 [00:00:00.256,713] <err> os: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0 [00:00:00.256,744] <err> os: Current thread: 0x20000328 (unknown) [00:00:01.732,177] <err> fatal_error: Resetting system