mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 23:57:47 +00:00
[nrf52840] add SPI Slave support (#2632)
This commit is contained in:
@@ -45,7 +45,6 @@ GCCVersion = $(shell expr `$(CC) -dumpversion | cut -f1 -d.
|
||||
configure_OPTIONS = \
|
||||
--enable-cli-app=all \
|
||||
--enable-ncp-app=all \
|
||||
--with-ncp-bus=uart \
|
||||
--enable-diag \
|
||||
--with-examples=nrf52840 \
|
||||
--enable-linker-map \
|
||||
@@ -56,6 +55,12 @@ ifdef SRC_PATH
|
||||
configure_OPTIONS += --srcdir="$(SRC_PATH)"
|
||||
endif
|
||||
|
||||
ifeq ($(NCP_SPI),1)
|
||||
configure_OPTIONS += --with-ncp-bus=spi
|
||||
else
|
||||
configure_OPTIONS += --with-ncp-bus=uart
|
||||
endif
|
||||
|
||||
TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST))))..
|
||||
AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))..
|
||||
|
||||
@@ -99,6 +104,10 @@ ifeq ($(USB),1)
|
||||
COMMONCFLAGS += -DUSB_CDC_AS_SERIAL_TRANSPORT=1
|
||||
endif
|
||||
|
||||
ifeq ($(DISABLE_SPI),1)
|
||||
COMMONCFLAGS += -DSPIS_TRANSPORT_DISABLE=1
|
||||
endif
|
||||
|
||||
ifeq ($(shell expr $(GCCVersion) \>= 7), 1)
|
||||
COMMONCFLAGS += -Wno-expansion-to-defined
|
||||
endif
|
||||
|
||||
@@ -88,6 +88,7 @@ PLATFORM_COMMON_SOURCES
|
||||
radio.c \
|
||||
random.c \
|
||||
temp.c \
|
||||
spi-slave.c \
|
||||
uart.c \
|
||||
usb-cdc-uart.c \
|
||||
$(NULL)
|
||||
@@ -312,6 +313,7 @@ noinst_HEADERS
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_ppi.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_power.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_rng.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_spis.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_uart.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/hal/nrf_usbd.h \
|
||||
$(top_srcdir)/third_party/NordicSemiconductor/nrfx/mdk/compiler_abstraction.h \
|
||||
|
||||
@@ -48,6 +48,32 @@ $ make -f examples/Makefile-nrf52840 USB=1
|
||||
Note, that if Windows 7 or earlier is used, an additional USB CDC driver has to be loaded.
|
||||
It can be found in third_party/NordicSemiconductor/libraries/usb/nordic_cdc_acm_example.inf
|
||||
|
||||
## Native SPI Slave support
|
||||
|
||||
You can build the libraries with support for native SPI Slave.
|
||||
To do so, build the libraries with the following parameter:
|
||||
```
|
||||
$ make -f examples/Makefile-nrf52840 NCP_SPI=1
|
||||
```
|
||||
|
||||
With this option enabled, SPI communication between the NCP example and wpantund is possible
|
||||
(provided that the wpantund host supports SPI Master). To achieve that, an appropriate SPI device
|
||||
should be chosen in wpantund configuration file, `/etc/wpantund.conf`. You can find an example below.
|
||||
```
|
||||
Config:NCP:SocketPath "system:/usr/bin/spi-hdlc-adapter --gpio-int /sys/class/gpio/gpio25 /dev/spidev0.0"
|
||||
```
|
||||
|
||||
[spi-hdlc-adapter][spi-hdlc-adapter]
|
||||
is a tool that can be used to perform communication between NCP and wpantund over SPI.
|
||||
In the above example it is assumed that `spi-hdlc-adapter` is installed in `/usr/bin`.
|
||||
|
||||
The default SPI Slave pin configuration for nRF52840 is defined in `examples/platforms/nrf52840/platform-config.h`.
|
||||
|
||||
Note that the native SPI Slave support is not intended to be used with Engineering sample A of the nRF52840 chip due to
|
||||
single transfer size limitation.
|
||||
|
||||
[spi-hdlc-adapter]: https://github.com/openthread/openthread/tree/master/tools/spi-hdlc-adapter
|
||||
|
||||
## Flashing the binaries
|
||||
|
||||
Flash the compiled binaries onto nRF52840 using `nrfjprog` which is
|
||||
|
||||
@@ -317,6 +317,94 @@
|
||||
#define LOG_TIMESTAMP_ENABLE 1
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* @section SPI Slave configuration.
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @def SPIS Instance.
|
||||
*/
|
||||
#ifndef SPIS_INSTANCE
|
||||
#define SPIS_INSTANCE NRF_SPIS0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS mode.
|
||||
*
|
||||
* @brief Possible values:
|
||||
* \ref NRF_SPIS_MODE_0 - SCK active high, sample on leading edge of clock.
|
||||
* \ref NRF_SPIS_MODE_1 - SCK active high, sample on trailing edge of clock.
|
||||
* \ref NRF_SPIS_MODE_2 - SCK active low, sample on leading edge of clock.
|
||||
* \ref NRF_SPIS_MODE_3 - SCK active low, sample on trailing edge of clock.
|
||||
*/
|
||||
#ifndef SPIS_MODE
|
||||
#define SPIS_MODE NRF_SPIS_MODE_0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS bit orders.
|
||||
*
|
||||
* @brief Possible values:
|
||||
* \ref NRF_SPIS_BIT_ORDER_MSB_FIRST - Most significant bit shifted out first.
|
||||
* \ref NRF_SPIS_BIT_ORDER_LSB_FIRST - Least significant bit shifted out first.
|
||||
*/
|
||||
#ifndef SPIS_BIT_ORDER
|
||||
#define SPIS_BIT_ORDER NRF_SPIS_BIT_ORDER_MSB_FIRST
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS Interrupt number.
|
||||
*/
|
||||
#ifndef SPIS_IRQN
|
||||
#define SPIS_IRQN SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS Interrupt priority.
|
||||
*/
|
||||
#ifndef SPIS_IRQ_PRIORITY
|
||||
#define SPIS_IRQ_PRIORITY 6
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS MOSI Pin.
|
||||
*/
|
||||
#ifndef SPIS_PIN_MOSI
|
||||
#define SPIS_PIN_MOSI 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS MISO Pin.
|
||||
*/
|
||||
#ifndef SPIS_PIN_MISO
|
||||
#define SPIS_PIN_MISO 28
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS SCK Pin.
|
||||
*/
|
||||
#ifndef SPIS_PIN_SCK
|
||||
#define SPIS_PIN_SCK 3
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS CSN Pin.
|
||||
*/
|
||||
#ifndef SPIS_PIN_CSN
|
||||
#define SPIS_PIN_CSN 29
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def SPIS Host IRQ Pin.
|
||||
*/
|
||||
#ifndef SPIS_PIN_HOST_IRQ
|
||||
#define SPIS_PIN_HOST_IRQ 30
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* @section USB driver configuration.
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* @def USB_HOST_UART_CONFIG_DELAY_MS
|
||||
*
|
||||
|
||||
@@ -107,6 +107,23 @@ void nrf5LogInit(void);
|
||||
*/
|
||||
void nrf5LogDeinit(void);
|
||||
|
||||
/**
|
||||
* Initialization of SPI Slave driver.
|
||||
*
|
||||
*/
|
||||
void nrf5SpiSlaveInit(void);
|
||||
|
||||
/**
|
||||
* Deinitialization of SPI Slave driver.
|
||||
*
|
||||
*/
|
||||
void nrf5SpiSlaveDeinit(void);
|
||||
|
||||
/**
|
||||
* Function for processing SPI Slave driver.
|
||||
*/
|
||||
void nrf5SpiSlaveProcess(void);
|
||||
|
||||
/**
|
||||
* Initialization of Misc module.
|
||||
*
|
||||
|
||||
@@ -79,6 +79,9 @@ void PlatformInit(int argc, char *argv[])
|
||||
nrf5AlarmInit();
|
||||
nrf5RandomInit();
|
||||
nrf5UartInit();
|
||||
#ifndef SPIS_TRANSPORT_DISABLE
|
||||
nrf5SpiSlaveInit();
|
||||
#endif
|
||||
nrf5MiscInit();
|
||||
nrf5CryptoInit();
|
||||
nrf5RadioInit();
|
||||
@@ -91,6 +94,9 @@ void PlatformDeinit(void)
|
||||
nrf5RadioDeinit();
|
||||
nrf5CryptoDeinit();
|
||||
nrf5MiscDeinit();
|
||||
#ifndef SPIS_TRANSPORT_DISABLE
|
||||
nrf5SpiSlaveDeinit();
|
||||
#endif
|
||||
nrf5UartDeinit();
|
||||
nrf5RandomDeinit();
|
||||
nrf5AlarmDeinit();
|
||||
@@ -111,6 +117,9 @@ void PlatformProcessDrivers(otInstance *aInstance)
|
||||
nrf5RadioProcess(aInstance);
|
||||
nrf5UartProcess();
|
||||
nrf5TempProcess();
|
||||
#ifndef SPIS_TRANSPORT_DISABLE
|
||||
nrf5SpiSlaveProcess();
|
||||
#endif
|
||||
}
|
||||
|
||||
__WEAK void PlatformEventSignalPending(void)
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the OpenThread platform abstraction for SPIS communication.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <utils/code_utils.h>
|
||||
#include <openthread/types.h>
|
||||
#include <openthread/platform/spi-slave.h>
|
||||
|
||||
#include <hal/nrf_gpio.h>
|
||||
#include <hal/nrf_spis.h>
|
||||
#include <platform-nrf5.h>
|
||||
|
||||
/**
|
||||
* SPI Slave transaction variables.
|
||||
*/
|
||||
static void * sContext = NULL;
|
||||
static uint8_t * sOutputBuf = NULL;
|
||||
static uint16_t sOutputBufLen = 0;
|
||||
static uint8_t * sInputBuf = NULL;
|
||||
static uint16_t sInputBufLen = 0;
|
||||
static bool sRequestTransactionFlag = false;
|
||||
static bool sFurtherProcessingFlag = false;
|
||||
static otPlatSpiSlaveTransactionProcessCallback sProcessCallback = NULL;
|
||||
static otPlatSpiSlaveTransactionCompleteCallback sCompleteCallback = NULL;
|
||||
|
||||
void nrf5SpiSlaveInit(void)
|
||||
{
|
||||
/* Intentionally empty. */
|
||||
}
|
||||
|
||||
void nrf5SpiSlaveDeinit(void)
|
||||
{
|
||||
sOutputBuf = NULL;
|
||||
sOutputBufLen = 0;
|
||||
sInputBuf = NULL;
|
||||
sInputBufLen = 0;
|
||||
sRequestTransactionFlag = false;
|
||||
|
||||
otPlatSpiSlaveDisable();
|
||||
}
|
||||
|
||||
void nrf5SpiSlaveProcess(void)
|
||||
{
|
||||
otEXPECT(sFurtherProcessingFlag == true);
|
||||
|
||||
/* Clear further processing flag. */
|
||||
sFurtherProcessingFlag = false;
|
||||
|
||||
/* Perform any further processing if necessary. */
|
||||
sProcessCallback(sContext);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError otPlatSpiSlaveEnable(otPlatSpiSlaveTransactionCompleteCallback aCompleteCallback,
|
||||
otPlatSpiSlaveTransactionProcessCallback aProcessCallback,
|
||||
void * aContext)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
/* Check if SPI Slave interface is already enabled. */
|
||||
otEXPECT_ACTION(sCompleteCallback == NULL, error = OT_ERROR_ALREADY);
|
||||
|
||||
/* Set up MISO/MOSI/SCK/CSN and Host IRQ. */
|
||||
nrf_gpio_cfg_input(SPIS_PIN_MISO, NRF_GPIO_PIN_NOPULL);
|
||||
nrf_gpio_cfg_input(SPIS_PIN_MOSI, NRF_GPIO_PIN_NOPULL);
|
||||
nrf_gpio_cfg_input(SPIS_PIN_SCK, NRF_GPIO_PIN_NOPULL);
|
||||
nrf_gpio_cfg_input(SPIS_PIN_CSN, NRF_GPIO_PIN_NOPULL);
|
||||
nrf_gpio_pin_set(SPIS_PIN_HOST_IRQ);
|
||||
nrf_gpio_cfg_output(SPIS_PIN_HOST_IRQ);
|
||||
|
||||
nrf_spis_pins_set(SPIS_INSTANCE, SPIS_PIN_SCK, SPIS_PIN_MOSI, SPIS_PIN_MISO, SPIS_PIN_CSN);
|
||||
|
||||
/* Set buffer pointers. */
|
||||
nrf_spis_rx_buffer_set(SPIS_INSTANCE, NULL, 0);
|
||||
nrf_spis_tx_buffer_set(SPIS_INSTANCE, NULL, 0);
|
||||
|
||||
/* Configure SPIS Mode and Bit order. */
|
||||
nrf_spis_configure(SPIS_INSTANCE, SPIS_MODE, SPIS_BIT_ORDER);
|
||||
|
||||
/* Use 0xFF character to indicate that there is no transmit buffer set up or overflow occured
|
||||
as described in API documentation. */
|
||||
nrf_spis_def_set(SPIS_INSTANCE, 0xFF);
|
||||
nrf_spis_orc_set(SPIS_INSTANCE, 0xFF);
|
||||
|
||||
/* Clear SPIS specific events. */
|
||||
nrf_spis_event_clear(SPIS_INSTANCE, NRF_SPIS_EVENT_END);
|
||||
nrf_spis_event_clear(SPIS_INSTANCE, NRF_SPIS_EVENT_ACQUIRED);
|
||||
|
||||
/* Enable interrupts for ACQUIRED and END events. */
|
||||
nrf_spis_int_enable(SPIS_INSTANCE, (NRF_SPIS_INT_ACQUIRED_MASK | NRF_SPIS_INT_END_MASK));
|
||||
|
||||
/* Configure NVIC to handle SPIS interrupts. */
|
||||
NVIC_SetPriority(SPIS_IRQN, SPIS_IRQ_PRIORITY);
|
||||
NVIC_ClearPendingIRQ(SPIS_IRQN);
|
||||
NVIC_EnableIRQ(SPIS_IRQN);
|
||||
|
||||
/* Enable SPI slave device. */
|
||||
nrf_spis_enable(SPIS_INSTANCE);
|
||||
|
||||
/* Set proper callback and context. */
|
||||
sProcessCallback = aProcessCallback;
|
||||
sCompleteCallback = aCompleteCallback;
|
||||
sContext = aContext;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void otPlatSpiSlaveDisable(void)
|
||||
{
|
||||
/* Disable interrupts for ACQUIRED and END events. */
|
||||
nrf_spis_int_disable(SPIS_INSTANCE, (NRF_SPIS_INT_ACQUIRED_MASK | NRF_SPIS_INT_END_MASK));
|
||||
|
||||
/* Disable NVIC interrupt. */
|
||||
NVIC_DisableIRQ(SPIS_IRQN);
|
||||
|
||||
/* Disable SPIS instance. */
|
||||
nrf_spis_disable(SPIS_INSTANCE);
|
||||
}
|
||||
|
||||
otError otPlatSpiSlavePrepareTransaction(uint8_t *aOutputBuf,
|
||||
uint16_t aOutputBufLen,
|
||||
uint8_t *aInputBuf,
|
||||
uint16_t aInputBufLen,
|
||||
bool aRequestTransactionFlag)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
nrf_spis_semstat_t semaphore_status = nrf_spis_semaphore_status_get(SPIS_INSTANCE);
|
||||
|
||||
otEXPECT_ACTION(sCompleteCallback != NULL, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
otEXPECT_ACTION(((semaphore_status != NRF_SPIS_SEMSTAT_SPIS) && (semaphore_status != NRF_SPIS_SEMSTAT_CPUPENDING)),
|
||||
error = OT_ERROR_BUSY);
|
||||
|
||||
if (aOutputBuf != NULL)
|
||||
{
|
||||
sOutputBuf = aOutputBuf;
|
||||
sOutputBufLen = aOutputBufLen;
|
||||
}
|
||||
|
||||
if (aInputBuf != NULL)
|
||||
{
|
||||
sInputBuf = aInputBuf;
|
||||
sInputBufLen = aInputBufLen;
|
||||
}
|
||||
|
||||
sRequestTransactionFlag = aRequestTransactionFlag;
|
||||
|
||||
/* Trigger acquired event. */
|
||||
nrf_spis_task_trigger(SPIS_INSTANCE, NRF_SPIS_TASK_ACQUIRE);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt handler of SPIS peripherial.
|
||||
*/
|
||||
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
|
||||
{
|
||||
/* Check for SPI semaphore acquired event. */
|
||||
if (nrf_spis_event_check(SPIS_INSTANCE, NRF_SPIS_EVENT_ACQUIRED))
|
||||
{
|
||||
nrf_spis_event_clear(SPIS_INSTANCE, NRF_SPIS_EVENT_ACQUIRED);
|
||||
|
||||
/* Set actual TX/RX buffers. */
|
||||
nrf_spis_tx_buffer_set(SPIS_INSTANCE, sOutputBuf, sOutputBufLen);
|
||||
nrf_spis_rx_buffer_set(SPIS_INSTANCE, sInputBuf, sInputBufLen);
|
||||
|
||||
if (sRequestTransactionFlag)
|
||||
{
|
||||
/* Interrupt pin is active low. */
|
||||
nrf_gpio_pin_clear(SPIS_PIN_HOST_IRQ);
|
||||
}
|
||||
|
||||
/* Trigger RELEASE event immediately. */
|
||||
nrf_spis_task_trigger(SPIS_INSTANCE, NRF_SPIS_TASK_RELEASE);
|
||||
}
|
||||
|
||||
/* Check for SPI transaction complete event. */
|
||||
if (nrf_spis_event_check(SPIS_INSTANCE, NRF_SPIS_EVENT_END))
|
||||
{
|
||||
nrf_spis_event_clear(SPIS_INSTANCE, NRF_SPIS_EVENT_END);
|
||||
|
||||
if (sRequestTransactionFlag)
|
||||
{
|
||||
nrf_gpio_pin_set(SPIS_PIN_HOST_IRQ);
|
||||
}
|
||||
|
||||
/* Discard all transactions until buffers are updated. */
|
||||
nrf_spis_tx_buffer_set(SPIS_INSTANCE, sOutputBuf, 0);
|
||||
nrf_spis_rx_buffer_set(SPIS_INSTANCE, sInputBuf, 0);
|
||||
|
||||
/* Execute application callback. */
|
||||
if (sCompleteCallback(sContext, sOutputBuf, sOutputBufLen, sInputBuf, sInputBufLen,
|
||||
nrf_spis_rx_amount_get(SPIS_INSTANCE)))
|
||||
{
|
||||
/* Further processing is required. */
|
||||
sFurtherProcessingFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user