SDK Environment: nRF Connect SDK v1.7.1
Zephyr OS build v2.6.99-ncs1-1. This is the version that came with nRF Connect SDK v1.7.1
Target: Decawave DWM1001-DEV. This uses the nRF52832
I am using the Nordic nrfx_spim drivers in a zephyr program.
A event handler is set with nrfx_spim_init.
The same SPI transfer is repeated 1000 times with no added delay.
Occasionally after initiating a transfer with nrfx_spim_xfer the event handler is not called. I have set a very long timeout in the attached code.
The attached test program logs "SPI timeout" at random intervals. Usually within a few minutes.
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Modified from nrfx_spim.zip by Håkon
* See: https://devzone.nordicsemi.com/f/nordic-q-a/61900/clarification-on-intended-driver-to-communicating-with-generic-spi-device-on-nrf52-dk-running-zephyr
*/
#include <zephyr.h>
#include <device.h>
#include <string.h>
#include <drivers/gpio.h>
#include <nrfx_spim.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(main);
#define SLEEP_TIME 100 // ms
#define SPI_TIMEOUT 1000 // ms
const struct gpio_dt_spec heartbeat_led = GPIO_DT_SPEC_GET(DT_NODELABEL(led0_red), gpios);
const struct gpio_dt_spec test_j7_pin3 = {
.port = DEVICE_DT_GET(DT_NODELABEL(gpio0)),
.pin = 12, .dt_flags = GPIO_ACTIVE_HIGH};
#define NRFX_SPIM_SCK_PIN 16
#define NRFX_SPIM_MOSI_PIN 20
#define NRFX_SPIM_MISO_PIN 18
#define NRFX_SPIM_SS_PIN 17
#define SPI_INSTANCE 2 /**< SPI instance index. */
static const nrfx_spim_t spi = NRFX_SPIM_INSTANCE(SPI_INSTANCE); /**< SPI instance. */
static volatile bool spi_xfer_done = true; /**< Flag used to indicate that SPI instance completed the transfer. */
#define SPI_BUF_SIZE (255)
static uint8_t m_tx_buf[SPI_BUF_SIZE]; /**< TX buffer. */
static uint8_t m_rx_buf[SPI_BUF_SIZE]; /**< RX buffer. */
#define ISR_PRIORITY 5
void spim_event_handler(nrfx_spim_evt_t const * p_event, void * p_context)
{
spi_xfer_done = true;
}
void setup_spim(void)
{
nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG(NRFX_SPIM_SCK_PIN, NRFX_SPIM_MOSI_PIN,
NRFX_SPIM_MISO_PIN, NRFX_SPIM_SS_PIN);
spi_config.frequency = NRF_SPIM_FREQ_8M;
uint32_t err = nrfx_spim_init(&spi, &spi_config, spim_event_handler, NULL);
if (err != NRFX_SUCCESS) {
printk("nrfx err: %d\n", err);
return;
}
/* Zephyr IRQ wrapper, corresponds to NVIC_* functions */
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM2), ISR_PRIORITY, nrfx_isr, nrfx_spim_2_irq_handler, 0);
}
/*
* Setup output test pins for external monitoring.
*/
void testPin1Set()
{
gpio_pin_set_dt(&test_j7_pin3, 1);
}
void testPin1Clear()
{
gpio_pin_set_dt(&test_j7_pin3, 0);
}
void testPinsSetup()
{
gpio_pin_configure_dt(&test_j7_pin3, GPIO_OUTPUT_INACTIVE);
}
void main_thread(void)
{
testPinsSetup();
setup_spim();
LOG_INF("NRFX SPIM sample");
LOG_INF("Read DW1000 DWT_DEVICE_ID");
while (1)
{
k_msleep(SLEEP_TIME);
for (int i = 0; i < 1000; i++)
{
const int m_length = 5;
memset(m_tx_buf, 0, m_length);
memset(m_rx_buf, 0, m_length);
nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(m_tx_buf, m_length, m_rx_buf, m_length);
uint32_t ret = nrfx_spim_xfer(&spi, &xfer_desc, 0);
if (ret == NRFX_SUCCESS)
{
spi_xfer_done = false;
testPin1Set();
int64_t timeOutTime = k_uptime_get() + SPI_TIMEOUT;
while (!spi_xfer_done)
{
k_yield();
if (k_uptime_get() > timeOutTime)
{
LOG_INF("SPI timeout");
break;
}
}
testPin1Clear();
}
else
{
LOG_INF("nrfx_spim_xfer returned %i", ret);
}
}
// Expecting DWT_DEVICE_ID (0xDECA0130) //!< DW1000 MP device ID
LOG_INF("Result = %x", *((uint32_t*) &m_rx_buf[1]));
}
}
void heartbeat_thread(void)
{
bool ledState = false;
gpio_pin_configure_dt(&heartbeat_led, GPIO_OUTPUT);
for (;;)
{
k_msleep(500);
LOG_INF("toggle LED");
gpio_pin_set_dt(&heartbeat_led, ledState);
ledState = !ledState;
}
}
K_THREAD_DEFINE(main_thread_id, 4000, main_thread, NULL, NULL, NULL,
7, 0, 0);
K_THREAD_DEFINE(heartbeat_thread_id, 1024, heartbeat_thread, NULL, NULL, NULL,
7, 0, 0);
testPin1Set and testPin1Clear are for time profiling.
I have attached the complete project source code.