[nrf52840] add SPI Slave support (#2632)

This commit is contained in:
jciupis
2018-03-28 16:46:11 +01:00
committed by Jonathan Hui
parent 976f7a4078
commit 138aee3e50
7 changed files with 386 additions and 1 deletions
+10 -1
View File
@@ -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
+2
View File
@@ -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 \
+26
View File
@@ -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.
*
+9
View File
@@ -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)
+234
View File
@@ -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;
}
}
}