I have to implement async communication between two nRF52832 chips. I am using two nRF52dk boards and nRF Connect SDK v1.8.0.
Following this case:
https://devzone.nordicsemi.com/f/nordic-q-a/69034/nrf52840-spi-slave-configuration-event_handler
Based on the spi_loopback as suggested on the case, I have managed to get a spi slave sample compiling and working in principle. Here it is the configuration and code:
SLAVE
prj.conf
# # Copyright (c) 2020 Nordic Semiconductor ASA # # SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic # # CONFIG_BOARD_ENABLE_CPUNET=y CONFIG_SPI=y CONFIG_MAIN_STACK_SIZE=4096 CONFIG_SPI_SLAVE=y CONFIG_SPI_ASYNC=y # Config logger CONFIG_LOG=y CONFIG_USE_SEGGER_RTT=y CONFIG_LOG_BACKEND_RTT=y CONFIG_LOG_BACKEND_UART=n CONFIG_PRINTK=y CONFIG_ASSERT=y CONFIG_LOG=y CONFIG_USE_SEGGER_RTT=y CONFIG_RTT_CONSOLE=y CONFIG_PRINTK=y
CMakeList.txt
#
# Copyright (c) 2020 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
#
cmake_minimum_required(VERSION 3.8.2)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/spm.conf")
set(spm_CONF_FILE
prj.conf
${CMAKE_CURRENT_LIST_DIR}/spm.conf
)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mcuboot.conf")
set(mcuboot_CONF_FILE
prj.conf
${CMAKE_CURRENT_LIST_DIR}/mcuboot.conf
)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${BOARD}.overlay")
set(mcuboot_DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${BOARD}.overlay")
endif()
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(03-spis)
target_sources(app PRIVATE src/main.c)
nrf52dk_nrf52832.overlay
&spi1 {
compatible = "nordic,nrf-spis";
status = "okay";
sck-pin = <22>;
mosi-pin = <23>;
miso-pin = <24>;
csn-pin = <25>;
def-char = <0xFF>;
};
main.c
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <sys/printk.h>
#include <drivers/spi.h>
#define DT_DRV_COMPAT nordic_nrf_spis
static const struct spi_config spi_cfg = {
.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_SLAVE |
SPI_MODE_CPOL | SPI_MODE_CPHA,
.frequency = 4000000,
.slave = 1,
};
const struct device *spi_dev;
#define SPIS_STACK_SIZE 500
#define SPIS_PRIORITY 5
// TODO K_FOREVER should be used in K_THREAD_DEFINE but causes an error
#define K_FOREVER_WORKAROUND -1
extern void spi_test_transceive(void *, void *, void *);
K_THREAD_DEFINE(spis_tid, SPIS_STACK_SIZE, spi_test_transceive, NULL, NULL, NULL,
SPIS_PRIORITY, 0, K_FOREVER_WORKAROUND);
static void spi_async_call_cb(struct k_poll_event *async_evt,
struct k_sem *caller_sem,
void *unused);
static struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig);
static struct k_poll_event async_evt =
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
K_POLL_MODE_NOTIFY_ONLY,
&async_sig);
static K_SEM_DEFINE(caller, 0, 1);
static int result = 1;
K_THREAD_DEFINE(async_thread, SPIS_STACK_SIZE,(k_thread_entry_t)spi_async_call_cb,
&async_evt, &caller, NULL, K_PRIO_COOP(7), 0, 0);
static void spi_init(void)
{
spi_dev = device_get_binding(DT_LABEL(DT_DRV_INST(0)));
printk("SPI Init\n");
printk("Device name: %s\n", DT_LABEL(DT_DRV_INST(0)));
if (spi_dev == NULL) {
printk("Could not get %s device\n", DT_LABEL(DT_DRV_INST(0)));
return;
}
printk("SPI CSN %d, MISO %d, MOSI %d, CLK %d\n",
DT_PROP(DT_DRV_INST(0), csn_pin),
DT_PROP(DT_DRV_INST(0), miso_pin),
DT_PROP(DT_DRV_INST(0), mosi_pin),
DT_PROP(DT_DRV_INST(0), sck_pin));
k_thread_start(spis_tid);
}
static void spi_async_call_cb(struct k_poll_event *async_evt,
struct k_sem *caller_sem,
void *unused)
{
int ret;
printk("SPI async callback started\n");
while (1) {
printk("Polling...\n");
ret = k_poll(async_evt, 1, K_FOREVER);
//zassert_false(ret, "one or more events are not ready");
result = async_evt->signal->result;
k_sem_give(caller_sem);
/* Reinitializing for next call */
async_evt->signal->signaled = 0U;
async_evt->state = K_POLL_STATE_NOT_READY;
}
}
void spi_test_transceive(void *unused1, void *unused2, void *unused3)
{
int ret;
static uint8_t tx_buffer[32] = { 's', 'p', 'i', 's', 'l',
'a', 'v', 'e', '\n' };
static uint8_t rx_buffer[32];
const struct spi_buf tx_buf = { .buf = tx_buffer,
.len = sizeof(tx_buffer) };
const struct spi_buf_set tx = { .buffers = &tx_buf, .count = 1 };
struct spi_buf rx_buf = { .buf = rx_buffer,
.len = sizeof(rx_buffer) };
const struct spi_buf_set rx = { .buffers = &rx_buf, .count = 1 };
printk("SPI Transcive Thread Started\n");
while (1) {
ret = spi_transceive_async(spi_dev, &spi_cfg, &tx, &rx, &async_sig);
if (ret == -ENOTSUP) {
printk("Not supported");
}
if (ret) {
printk("Code %d", ret);
//zassert_false(ret, "SPI transceive failed");
}
k_sem_take(&caller, K_FOREVER);
if (result) {
printk("Call code %d", ret);
//zassert_false(result, "SPI transceive failed");
}
else {
printk("byte received: %d\n", ret);
printk("TX buffer [0]: %x\n", tx_buffer[0]);
printk("RX buffer [0]: %x\n", rx_buffer[0]);
tx_buffer[0]++;
}
}
}
void main(void)
{
printk("SPIS Example\n");
spi_init();
}
MASTER
The problem comes when I tried to implement the master project. First, I implemented the following changes
1. Commented out this line in prj.conf
#CONFIG_SPI_SLAVE=y
2. Changed spi_config to the following:
static const struct spi_config spi_cfg = {
.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_MASTER |
SPI_MODE_CPOL | SPI_MODE_CPHA,
.frequency = 4000000,
.slave = 0,
.cs = NULL
};
Unfortunately this changes will bring about the below error:
Device name: SPI_1 Could not get SPI_1 device
I tried to follow the comments on this case:
but adding any of these lines to prj.conf will cause a cmake error:
CONFIG_SPI_NRFX=y CONFIG_SPI_0_NRF_SPIM=y
Any help getting a spi async master sample?
Thanks
