You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/01/08 15:02:16 UTC
[incubator-nuttx] branch pr56 updated: nrf52: add support for SPI
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch pr56
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/pr56 by this push:
new 6c711f0 nrf52: add support for SPI
new 6313226 Merge pull request #56 from raiden00pl/nrf52
6c711f0 is described below
commit 6c711f0c52ce3a53f58eb9361a8acefd38214294
Author: raiden00pl <ra...@gmail.com>
AuthorDate: Wed Jan 8 15:48:20 2020 +0100
nrf52: add support for SPI
nrf52: add support for GPIO interrupts
nrf52: add macros to decode GPIO PIN and GPIO PORT
nrf52: various cosmetic changes
nrf52: fix GPIO P1 memory address
boards/nrf52840-dk: add support for SPI
boards/nrf52840-dk: add support for LSM6DSL sensor
boards/nrf52840-dk: add support for SX127X radio
---
arch/arm/src/nrf52/Kconfig | 16 +-
arch/arm/src/nrf52/Make.defs | 12 +
arch/arm/src/nrf52/hardware/nrf52_gpio.h | 10 +-
arch/arm/src/nrf52/hardware/nrf52_gpiote.h | 8 +-
arch/arm/src/nrf52/hardware/nrf52_memorymap.h | 2 +-
arch/arm/src/nrf52/hardware/nrf52_spi.h | 10 +-
arch/arm/src/nrf52/hardware/nrf52_twi.h | 4 +-
arch/arm/src/nrf52/hardware/nrf52_uarte.h | 8 +-
arch/arm/src/nrf52/nrf52_gpio.c | 24 +-
arch/arm/src/nrf52/nrf52_gpio.h | 61 +-
arch/arm/src/nrf52/nrf52_gpiote.c | 287 ++++++
.../arm/src/nrf52/nrf52_gpiote.h | 67 +-
arch/arm/src/nrf52/nrf52_i2c.c | 16 +-
arch/arm/src/nrf52/nrf52_irq.c | 23 +-
arch/arm/src/nrf52/nrf52_lowputc.c | 17 +-
arch/arm/src/nrf52/nrf52_lowputc.h | 42 +-
arch/arm/src/nrf52/nrf52_spi.c | 1017 ++++++++++++++++++++
arch/arm/src/nrf52/nrf52_spi.h | 130 +++
boards/arm/nrf52/nrf52-feather/include/board.h | 2 +-
boards/arm/nrf52/nrf52832-dk/include/board.h | 2 +-
boards/arm/nrf52/nrf52840-dk/include/board.h | 24 +-
boards/arm/nrf52/nrf52840-dk/src/Makefile | 12 +
boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h | 46 +
boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c | 6 +
boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c | 78 +-
.../src/{nrf52_boot.c => nrf52_lsm6dsl.c} | 85 +-
boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c | 206 ++++
boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c | 225 +++++
boards/arm/nrf52/nrf52840-dongle/include/board.h | 2 +-
29 files changed, 2222 insertions(+), 220 deletions(-)
diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig
index b7024cd..2c92c39 100644
--- a/arch/arm/src/nrf52/Kconfig
+++ b/arch/arm/src/nrf52/Kconfig
@@ -118,6 +118,18 @@ config NRF52_SPI3_MASTER
select NRF52_SPI_MASTER
depends on NRF52_HAVE_SPI3_MASTER
+if NRF52_SPI_MASTER
+
+config NRF52_SPI_MASTER_INTERRUPTS
+ bool "SPI Master interrupts support"
+ default n
+
+endif
+
+config NRF52_GPIOTE
+ bool "GPIOTE (GPIO interrupts)"
+ default n
+
config NRF52_UART0
bool "UART0"
default n
@@ -220,8 +232,4 @@ config NRF52_PROGMEM
menu "GPIO Interrupt Configuration"
-config NRF52_GPIOIRQ
- bool "Support GPIO Interrupts"
- default n
-
endmenu # GPIO Interrupt Configuration
diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs
index 58ff7d6..e33aeed 100644
--- a/arch/arm/src/nrf52/Make.defs
+++ b/arch/arm/src/nrf52/Make.defs
@@ -101,6 +101,10 @@ ifneq ($(CONFIG_ARCH_IDLE_CUSTOM),y)
CHIP_CSRCS += nrf52_idle.c
endif
+ifeq ($(CONFIG_NRF52_GPIOTE),y)
+CHIP_CSRCS += nrf52_gpiote.c
+endif
+
ifeq ($(CONFIG_NRF52_UART),y)
CHIP_CSRCS += nrf52_serial.c
endif
@@ -117,3 +121,11 @@ ifeq ($(CONFIG_NRF52_RNG),y)
CHIP_CSRCS += nrf52_rng.c
endif
+ifeq ($(CONFIG_NRF52_SPI_MASTER),y)
+CHIP_CSRCS += nrf52_spi.c
+endif
+
+ifeq ($(CONFIG_NRF52_I2C_MASTER),y)
+CHIP_CSRCS += nrf52_i2c.c
+endif
+
diff --git a/arch/arm/src/nrf52/hardware/nrf52_gpio.h b/arch/arm/src/nrf52/hardware/nrf52_gpio.h
index 118e2f9..47a7751 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_gpio.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_gpio.h
@@ -48,8 +48,14 @@
* Pre-processor Definitions
************************************************************************************/
-#define NRF52_GPIO_PORT0 0
-#define NRF52_GPIO_NPORTS 1
+#ifdef CONFIG_ARCH_CHIP_NRF52840
+# define NRF52_GPIO_NPORTS 2
+# define NRF52_GPIO_PORT0 0
+# define NRF52_GPIO_PORT1 1
+#else
+# define NRF52_GPIO_PORT0 0
+# define NRF52_GPIO_NPORTS 1
+#endif
/* Register offsets *****************************************************************/
diff --git a/arch/arm/src/nrf52/hardware/nrf52_gpiote.h b/arch/arm/src/nrf52/hardware/nrf52_gpiote.h
index fe7528d..b313d5d 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_gpiote.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_gpiote.h
@@ -71,6 +71,10 @@
/* Register offsets for GPIOTE *********************************************/
+/* EVENT_IN Register */
+
+#define GPIOTE_EVENT_IN_EVENT (1 << 0) /* Bit 0: Event generated from pin */
+
/* INTENSET/INTENCLR Register */
#define GPIOTE_INT_IN_SHIFT 0 /* Bits 0-7: Enable interrupt for event IN[i] */
@@ -83,8 +87,8 @@
#define GPIOTE_CONFIG_MODE_SHIFT 0 /* Bits 0-1: Mode */
#define GPIOTE_CONFIG_MODE_MASK (0x3 << GPIOTE_CONFIG_MODE_SHIFT)
# define GPIOTE_CONFIG_MODE_DIS (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 0: Disabled */
-# define GPIOTE_CONFIG_MODE_EV (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 1: Event */
-# define GPIOTE_CONFIG_MODE_TS (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 2: Task */
+# define GPIOTE_CONFIG_MODE_EV (0x1 << GPIOTE_CONFIG_MODE_SHIFT) /* 1: Event */
+# define GPIOTE_CONFIG_MODE_TS (0x3 << GPIOTE_CONFIG_MODE_SHIFT) /* 2: Task */
#define GPIOTE_CONFIG_PSEL_SHIFT (8) /* Bits 8-12: GPIO number */
#define GPIOTE_CONFIG_PSEL_MASK (0x1f << GPIOTE_CONFIG_PSEL_SHIFT)
#define GPIOTE_CONFIG_PORT_SHIFT (13) /* Bit 13: GPIO port */
diff --git a/arch/arm/src/nrf52/hardware/nrf52_memorymap.h b/arch/arm/src/nrf52/hardware/nrf52_memorymap.h
index 3673c16..a741943 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_memorymap.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_memorymap.h
@@ -139,7 +139,7 @@
#define NRF52_GPIO_P0_BASE 0x50000000
#ifdef CONFIG_ARCH_CHIP_NRF52840
-# define NRF52_GPIO_P1_BASE 0x50003000
+# define NRF52_GPIO_P1_BASE 0x50000300
#endif
#ifdef CONFIG_ARCH_CHIP_NRF52840
diff --git a/arch/arm/src/nrf52/hardware/nrf52_spi.h b/arch/arm/src/nrf52/hardware/nrf52_spi.h
index 8b554ab..1972d00 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_spi.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_spi.h
@@ -171,7 +171,7 @@
/* PSELSCK Register */
#define SPIM_PSELSCK_PIN_SHIFT (0) /* Bits 0-4: SCK pin number */
-#define SPIM_PSELSCK_PIN_MASK (0xf << SPIM_PSELSCK_PIN_SHIFT)
+#define SPIM_PSELSCK_PIN_MASK (0x1f << SPIM_PSELSCK_PIN_SHIFT)
#define SPIM_PSELSCK_PORT_SHIFT (5) /* Bit 5: SCK port number */
#define SPIM_PSELSCK_PORT_MASK (0x1 << SPIM_PSELSCK_PORT_SHIFT)
#define SPIM_PSELSCK_CONNECTED (1 << 31) /* Bit 31: Connection */
@@ -180,7 +180,7 @@
/* PSELMOSI Register */
#define SPIM_PSELMOSI_PIN_SHIFT (0) /* Bits 0-4: MOSI pin number */
-#define SPIM_PSELMOSI_PIN_MASK (0xf << SPIM_PSELMOSI_PIN_SHIFT)
+#define SPIM_PSELMOSI_PIN_MASK (0x1f << SPIM_PSELMOSI_PIN_SHIFT)
#define SPIM_PSELMOSI_PORT_SHIFT (5) /* Bit 5: MOSI port number */
#define SPIM_PSELMOSI_PORT_MASK (0x1 << SPIM_PSELMOSI_PORT_SHIFT)
#define SPIM_PSELMOSI_CONNECTED (1 << 31) /* Bit 31: Connection */
@@ -189,7 +189,7 @@
/* PSELMISO Register */
#define SPIM_PSELMISO_PIN_SHIFT (0) /* Bits 0-4: MISO pin number */
-#define SPIM_PSELMISO_PIN_MASK (0xf << SPIM_PSELMISO_PIN_SHIFT)
+#define SPIM_PSELMISO_PIN_MASK (0x1f << SPIM_PSELMISO_PIN_SHIFT)
#define SPIM_PSELMISO_PORT_SHIFT (5) /* Bit 5: MISO port number */
#define SPIM_PSELMISO_PORT_MASK (0x1 << SPIM_PSELMISO_PORT_SHIFT)
#define SPIM_PSELMISO_CONNECTED (1 << 31) /* Bit 31: Connection */
@@ -198,7 +198,7 @@
/* PSELCSN Register */
#define SPIM_PSELCSN_PIN_SHIFT (0) /* Bits 0-4: CSN pin number */
-#define SPIM_PSELCSN_PIN_MASK (0xf << SPIM_PSELCSN_PIN_SHIFT)
+#define SPIM_PSELCSN_PIN_MASK (0x1f << SPIM_PSELCSN_PIN_SHIFT)
#define SPIM_PSELCSN_PORT_SHIFT (5) /* Bit 5: CSN port number */
#define SPIM_PSELCSN_PORT_MASK (0x1 << SPIM_PSELCSN_PORT_SHIFT)
#define SPIM_PSELCSN_CONNECTED (1 << 31) /* Bit 31: Connection */
@@ -245,7 +245,7 @@
/* PSELDCX Register */
#define SPIM_PSELDCX_PIN_SHIFT (0) /* Bits 0-4: DCX pin number */
-#define SPIM_PSELDCX_PIN_MASK (0xf << SPIM_PSELDCX_PIN_SHIFT)
+#define SPIM_PSELDCX_PIN_MASK (0x1f << SPIM_PSELDCX_PIN_SHIFT)
#define SPIM_PSELDCX_PORT_SHIFT (5) /* Bit 5: SCK port number */
#define SPIM_PSELDCX_PORT_MASK (0x1 << SPIM_PSELDCX_PORT_SHIFT)
#define SPIM_PSELDCX_CONNECTED (1 << 31) /* Bit 31: Connection */
diff --git a/arch/arm/src/nrf52/hardware/nrf52_twi.h b/arch/arm/src/nrf52/hardware/nrf52_twi.h
index e17d706..219ed20 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_twi.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_twi.h
@@ -150,7 +150,7 @@
/* PSELSCL Register */
#define TWIM_PSELSCL_PIN_SHIFT (0) /* Bits 0-4: SCL pin number */
-#define TWIM_PSELSCL_PIN_MASK (0xf << TWIM_PSELSCL_PIN_SHIFT)
+#define TWIM_PSELSCL_PIN_MASK (0x1f << TWIM_PSELSCL_PIN_SHIFT)
#define TWIM_PSELSCL_PORT_SHIFT (5) /* Bit 5: SCL port number */
#define TWIM_PSELSCL_PORT_MASK (0x1 << TWIM_PSELSCL_PORT_SHIFT)
#define TWIM_PSELSCL_CONNECTED (1 << 31) /* Bit 31: Connection */
@@ -159,7 +159,7 @@
/* PSELSDA Register */
#define TWIM_PSELSDA_PIN_SHIFT (0) /* Bits 0-4: SDA pin number */
-#define TWIM_PSELSDA_PIN_MASK (0xf << TWIM_PSELSDA_PIN_SHIFT)
+#define TWIM_PSELSDA_PIN_MASK (0x1f << TWIM_PSELSDA_PIN_SHIFT)
#define TWIM_PSELSDA_PORT_SHIFT (5) /* Bit 5: SDA port number */
#define TWIM_PSELSDA_PORT_MASK (0x1 << TWIM_PSELSDA_PORT_SHIFT)
#define TWIM_PSELSDA_CONNECTED (1 << 31) /* Bit 31: Connection */
diff --git a/arch/arm/src/nrf52/hardware/nrf52_uarte.h b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
index 3a0e05c..3d5a6e9 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_uarte.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
@@ -238,7 +238,7 @@
/* PSELRTS Register */
#define UART_PSELRTS_PIN_SHIFT (0) /* Bits 0-4: Pin number*/
-#define UART_PSELRTS_PIN_MASK (0xf << UART_PSELRTS_PIN_SHIFT)
+#define UART_PSELRTS_PIN_MASK (0x1f << UART_PSELRTS_PIN_SHIFT)
#define UART_PSELRTS_PORT_SHIFT (5) /* Bit 5: Port number */
#define UART_PSELRTS_PORT_MASK (0x1 << UART_PSELRTS_PORT_SHIFT)
#define UART_PSELRTS_CONNECT (1 << 31) /* Bit 31: Connection */
@@ -247,7 +247,7 @@
/* PSELTXD Register */
#define UART_PSELTXD_PIN_SHIFT (0) /* Bits 0-4: Pin number*/
-#define UART_PSELTXD_PIN_MASK (0xf << UART_PSELTXD_PIN_SHIFT)
+#define UART_PSELTXD_PIN_MASK (0x1f << UART_PSELTXD_PIN_SHIFT)
#define UART_PSELTXD_PORT_SHIFT (5) /* Bit 5: Port number */
#define UART_PSELTXD_PORT_MASK (0x1 << UART_PSELTXD_PORT_SHIFT)
#define UART_PSELTXD_CONNECT (1 << 31) /* Bit 31: Connection */
@@ -256,7 +256,7 @@
/* PSELCTS Register */
#define UART_PSELCTS_PIN_SHIFT (0) /* Bits 0-4: Pin number*/
-#define UART_PSELCTS_PIN_MASK (0xf << UART_PSELCTS_PIN_SHIFT)
+#define UART_PSELCTS_PIN_MASK (0x1f << UART_PSELCTS_PIN_SHIFT)
#define UART_PSELCTS_PORT_SHIFT (5) /* Bit 5: Port number */
#define UART_PSELCTS_PORT_MASK (0x1 << UART_PSELCTS_PORT_SHIFT)
#define UART_PSELCTS_CONNECT (1 << 31) /* Bit 31: Connection */
@@ -265,7 +265,7 @@
/* PSELRXD Register */
#define UART_PSELRXD_PIN_SHIFT (0) /* Bits 0-4: Pin number*/
-#define UART_PSELRXD_PIN_MASK (0xf << UART_PSELRXD_PIN_SHIFT)
+#define UART_PSELRXD_PIN_MASK (0x1f << UART_PSELRXD_PIN_SHIFT)
#define UART_PSELRXD_PORT_SHIFT (5) /* Bit 5: Port number */
#define UART_PSELRXD_PORT_MASK (0x1 << UART_PSELRXD_PORT_SHIFT)
#define UART_PSELRXD_CONNECT (1 << 31) /* Bit 31: Connection */
diff --git a/arch/arm/src/nrf52/nrf52_gpio.c b/arch/arm/src/nrf52/nrf52_gpio.c
index c5f29d0..2ccc1ef 100644
--- a/arch/arm/src/nrf52/nrf52_gpio.c
+++ b/arch/arm/src/nrf52/nrf52_gpio.c
@@ -186,7 +186,7 @@ int nrf52_gpio_config(nrf52_pinset_t cfgset)
* that pin.
*/
- pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+ pin = GPIO_PIN_DECODE(cfgset);
/* First, configure the port as a generic input so that we have a
* known starting point and consistent behavior during the re-
@@ -206,16 +206,6 @@ int nrf52_gpio_config(nrf52_pinset_t cfgset)
case GPIO_INPUT: /* GPIO input pin */
break; /* Already configured */
-#ifdef CONFIG_NRF52_GPIOIRQ
- case GPIO_INTFE: /* GPIO interrupt falling edge */
- case GPIO_INTRE: /* GPIO interrupt rising edge */
- case GPIO_INTBOTH: /* GPIO interrupt both edges */
- case GPIO_INTLOW: /* GPIO interrupt low level */
- case GPIO_INTHIGH: /* GPIO interrupt high level */
- nrf52_gpio_interrupt(cfgset);
- break;
-#endif
-
case GPIO_OUTPUT: /* GPIO outpout pin */
nrf52_gpio_output(cfgset, port, pin);
break;
@@ -244,8 +234,8 @@ int nrf52_gpio_unconfig(nrf52_pinset_t cfgset)
/* Get port and pin number */
- port = (cfgset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
- pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+ pin = GPIO_PIN_DECODE(cfgset);
+ port = GPIO_PORT_DECODE(cfgset);
/* Get address offset */
@@ -274,8 +264,8 @@ void nrf52_gpio_write(nrf52_pinset_t pinset, bool value)
/* Get port and pin number */
- pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
- port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ pin = GPIO_PIN_DECODE(pinset);
+ port = GPIO_PORT_DECODE(pinset);
/* Get register address */
@@ -310,8 +300,8 @@ bool nrf52_gpio_read(nrf52_pinset_t pinset)
/* Get port and pin number */
- port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
- pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+ pin = GPIO_PIN_DECODE(pinset);
+ port = GPIO_PORT_DECODE(pinset);
/* Get register address */
diff --git a/arch/arm/src/nrf52/nrf52_gpio.h b/arch/arm/src/nrf52/nrf52_gpio.h
index 612d0af..e03810d 100644
--- a/arch/arm/src/nrf52/nrf52_gpio.h
+++ b/arch/arm/src/nrf52/nrf52_gpio.h
@@ -176,6 +176,11 @@
# define GPIO_PIN31 (31 << GPIO_PIN_SHIFT)
# define GPIO_PIN(n) ((n) << GPIO_PIN_SHIFT)
+/* Helper macros */
+
+#define GPIO_PIN_DECODE(p) (((p) & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT)
+#define GPIO_PORT_DECODE(p) (((p) & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT)
+
/************************************************************************************
* Public Types
************************************************************************************/
@@ -201,21 +206,6 @@ extern "C"
************************************************************************************/
/************************************************************************************
- * Name: nrf52_gpio_irqinitialize
- *
- * Description:
- * Initialize logic to support interrupting GPIO pins. This function is called by
- * the OS inialization logic and is not a user interface.
- *
- ************************************************************************************/
-
-#ifdef CONFIG_NRF52_GPIOIRQ
-void nrf52_gpio_irqinitialize(void);
-#else
-# define nrf52_gpio_irqinitialize()
-#endif
-
-/************************************************************************************
* Name: nrf52_gpio_config
*
* Description:
@@ -236,47 +226,6 @@ int nrf52_gpio_config(nrf52_pinset_t cfgset);
int nrf52_gpio_unconfig(nrf52_pinset_t cfgset);
/************************************************************************************
- * Name: nrf52_gpio_interrupt
- *
- * Description:
- * Configure a GPIO interrupt pin based on bit-encoded description of the pin.
- * This function is called by nrf52_gpio_config to setup interrupting pins. It is
- * not a user interface.
- *
- ************************************************************************************/
-
-#ifdef CONFIG_NRF52_GPIOIRQ
-int nrf52_gpio_interrupt(nrf52_pinset_t pinset);
-#endif
-
-/************************************************************************************
- * Name: nrf52_gpio_irqno
- *
- * Description:
- * Returns the IRQ number that was associated with an interrupt pin after it was
- * configured.
- *
- ************************************************************************************/
-
-#ifdef CONFIG_NRF52_GPIOIRQ
-int nrf52_gpio_irqno(nrf52_pinset_t pinset);
-#endif
-
-/************************************************************************************
- * Name: nrf52_gpio_ackedge
- *
- * Description:
- * Acknowledge edge interrupts by clearing the associated bits in the rising and
- * falling registers. This acknowledgemment is, of course, not needed for level
- * interupts.
- *
- ************************************************************************************/
-
-#ifdef CONFIG_NRF52_GPIOIRQ
-int nrf52_gpio_ackedge(int irq);
-#endif
-
-/************************************************************************************
* Name: rnf52_gpio_write
*
* Description:
diff --git a/arch/arm/src/nrf52/nrf52_gpiote.c b/arch/arm/src/nrf52/nrf52_gpiote.c
new file mode 100644
index 0000000..3481711
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_gpiote.c
@@ -0,0 +1,287 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_gpiote.c
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * 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 NuttX 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 OWNER 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <string.h>
+
+#include <arch/irq.h>
+#include <nuttx/arch.h>
+
+#include "up_arch.h"
+
+#include "nrf52_gpio.h"
+#include "nrf52_gpiote.h"
+
+#include "hardware/nrf52_gpiote.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define GPIOTE_CHANNELS 8
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf52_gpiote_callback_s
+{
+ xcpt_t callback;
+ FAR void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Interrupt handlers attached to each GPIOTE */
+
+static struct nrf52_gpiote_callback_s g_gpiote_callbacks[GPIOTE_CHANNELS];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_gpiote_putreg
+ *
+ * Description:
+ * Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf52_gpiote_putreg(uint32_t offset, uint32_t value)
+{
+ putreg32(value, NRF52_GPIOTE_BASE + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_gpiote_getreg
+ *
+ * Description:
+ * Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf52_gpiote_getreg(uint32_t offset)
+{
+ return getreg32(NRF52_GPIOTE_BASE + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_gpiote_isr
+ *
+ * Description:
+ * Common GPIOTE interrupt handler
+ *
+ ****************************************************************************/
+
+static int nrf52_gpiote_isr(int irq, FAR void *context, FAR void *arg)
+{
+ uint32_t regval = 0;
+ int ret = OK;
+ int i = 0;
+
+ /* Scan all GPIOTE channels */
+
+ for (i = 0; i < GPIOTE_CHANNELS; i += 1)
+ {
+ /* Only if callback is registered */
+
+ if (g_gpiote_callbacks[i].callback != NULL)
+ {
+ /* Get input event register */
+
+ regval = nrf52_gpiote_getreg(NRF52_GPIOTE_EVENTS_IN_OFFSET(i));
+ if (regval == GPIOTE_EVENT_IN_EVENT)
+ {
+ /* Execute callback */
+
+ xcpt_t callback = g_gpiote_callbacks[i].callback;
+ FAR void *cbarg = g_gpiote_callbacks[i].arg;
+ ret = callback(irq, context, cbarg);
+
+ /* Clear event */
+
+ nrf52_gpiote_putreg(NRF52_GPIOTE_EVENTS_IN_OFFSET(i), 0);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_gpiosetevent
+ *
+ * Description:
+ * Sets/clears GPIO based event and interrupt triggers.
+ *
+ * Input Parameters:
+ * - pinset: GPIO pin configuration
+ * - risingedge: Enables interrupt on rising edges
+ * - fallingedge: Enables interrupt on falling edges
+ * - event: Generate event when set
+ * - func: When non-NULL, generate interrupt
+ * - arg: Argument passed to the interrupt callback
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure indicating the
+ * nature of the failure.
+ *
+ ****************************************************************************/
+
+int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
+ bool event, xcpt_t func, FAR void *arg)
+{
+ int ret = OK;
+ int i = 0;
+ int pin = 0;
+ int port = 0;
+ uint32_t regval = 0;
+ bool found = false;
+ irqstate_t flags;
+
+ /* Find available GPIOTE channel */
+
+ flags = enter_critical_section();
+
+ for (i = 0; i < GPIOTE_CHANNELS; i += 1)
+ {
+ if (g_gpiote_callbacks[i].callback == NULL)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ leave_critical_section(flags);
+
+ /* Return error if there is no free channel */
+
+ if (found == false)
+ {
+ ret = -ENODEV;
+ goto errout;
+ }
+
+ /* NOTE: GPIOTE module has priority over GPIO module
+ * so GPIO configuration will be ignored
+ */
+
+ /* Select GPIOTE pin */
+
+ pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+ port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+
+ regval = (pin << GPIOTE_CONFIG_PSEL_SHIFT);
+ regval |= (port << GPIOTE_CONFIG_PORT_SHIFT);
+
+ /* Select EVENT mode */
+
+ if (event || func)
+ {
+ regval |= GPIOTE_CONFIG_MODE_EV;
+ }
+
+ /* Select polarity */
+
+ if (risingedge == true && fallingedge == true)
+ {
+ regval |= GPIOTE_CONFIG_POL_TG;
+ }
+ else if (risingedge == true)
+ {
+ regval |= GPIOTE_CONFIG_POL_LTH;
+ }
+ else if (fallingedge == true)
+ {
+ regval |= GPIOTE_CONFIG_POL_HTL;
+ }
+
+ /* Write CONFIG register */
+
+ nrf52_gpiote_putreg(NRF52_GPIOTE_CONFIG_OFFSET(i), regval);
+
+ /* Enable interrupt for given event */
+
+ nrf52_gpiote_putreg(NRF52_GPIOTE_INTENSET_OFFSET, GPIOTE_INT_IN(i));
+
+ /* Connect callback */
+
+ g_gpiote_callbacks[i].callback = func;
+ g_gpiote_callbacks[i].arg = arg;
+
+errout:
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_gpiote_init
+ *
+ * Description:
+ * Initialize GPIOTE
+ *
+ ****************************************************************************/
+
+int nrf52_gpiote_init(void)
+{
+ /* Reset GPIOTE data */
+
+ memset(&g_gpiote_callbacks,
+ 0,
+ sizeof(struct nrf52_gpiote_callback_s)*GPIOTE_CHANNELS);
+
+ /* Attach GPIOTE interrupt handler */
+
+ irq_attach(NRF52_IRQ_GPIOTE, nrf52_gpiote_isr, NULL);
+ up_enable_irq(NRF52_IRQ_GPIOTE);
+
+ return OK;
+}
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c b/arch/arm/src/nrf52/nrf52_gpiote.h
similarity index 64%
copy from boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
copy to arch/arm/src/nrf52/nrf52_gpiote.h
index af1dca2..3b1e162 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
+++ b/arch/arm/src/nrf52/nrf52_gpiote.h
@@ -1,8 +1,8 @@
/****************************************************************************
- * boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
+ * arch/arm/src/nrf52/nrf52_gpiote.h
*
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gn...@nuttx.org>
+ * Author: Mateusz Szafoni <ra...@railab.me>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,64 +33,57 @@
*
****************************************************************************/
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_GPIOTE_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_GPIOTE_H
+
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
-#include <debug.h>
-
-#include <nuttx/board.h>
-#include <arch/board/board.h>
+#include <nuttx/irq.h>
-#include "up_arch.h"
-#include "up_internal.h"
+#include "chip.h"
-#include "nrf52840-dk.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
/****************************************************************************
- * Public Functions
+ * Public Function Prototypes
****************************************************************************/
/****************************************************************************
- * Name: nrf52_board_initialize
+ * Name: nrf52_gpiosetevent
*
* Description:
- * All NRF52xxx architectures must provide the following entry point.
- * This entry point is called early in the initialization -- after all
- * memory has been configured and mapped but before any devices have been
- * initialized.
+ * Sets/clears GPIO based event and interrupt triggers.
+ *
+ * Input Parameters:
+ * - pinset: gpio pin configuration
+ * - rising/falling edge: enables
+ * - event: generate event when set
+ * - func: when non-NULL, generate interrupt
+ * - arg: Argument passed to the interrupt callback
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure indicating the
+ * nature of the failure.
*
****************************************************************************/
-void nrf52_board_initialize(void)
-{
- /* Configure on-board LEDs if LED support has been selected. */
-
-#ifdef CONFIG_ARCH_LEDS
- board_autoled_initialize();
-#endif
-}
+int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge,
+ bool event, xcpt_t func, FAR void *arg);
/****************************************************************************
- * Name: board_late_initialize
+ * Name: nrf52_gpiote_init
*
* Description:
- * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional
- * initialization call will be performed in the boot-up sequence to a
- * function called board_late_initialize(). board_late_initialize() will be
- * called immediately after up_initialize() is called and just before the
- * initial application is started. This additional initialization phase
- * may be used, for example, to initialize board-specific device drivers.
+ * Initialize GPIOTE
*
****************************************************************************/
-#ifdef CONFIG_BOARD_LATE_INITIALIZE
-void board_late_initialize(void)
-{
- /* Perform board-specific initialization */
+int nrf52_gpiote_init(void);
- (void)nrf52_bringup();
-}
-#endif
+#endif /* __ARCH_ARM_SRC_NRF52_NRF52_GPIOTE_H */
diff --git a/arch/arm/src/nrf52/nrf52_i2c.c b/arch/arm/src/nrf52/nrf52_i2c.c
index 258917a..dd64971 100644
--- a/arch/arm/src/nrf52/nrf52_i2c.c
+++ b/arch/arm/src/nrf52/nrf52_i2c.c
@@ -310,6 +310,10 @@ static int nrf52_i2c_transfer(FAR struct i2c_master_s *dev,
#ifdef CONFIG_I2C_POLLED
while (nrf52_i2c_getreg(priv,
NRF52_TWIM_EVENTS_LASTTX_OFFSET) != 1);
+
+ /* Clear event */
+
+ nrf52_i2c_putreg(priv, NRF52_TWIM_EVENTS_LASTTX_OFFSET, 0);
#endif
/* TWIM stop */
@@ -321,6 +325,10 @@ static int nrf52_i2c_transfer(FAR struct i2c_master_s *dev,
#ifdef CONFIG_I2C_POLLED
while (nrf52_i2c_getreg(priv,
NRF52_TWIM_EVENTS_STOPPED_OFFSET) != 1);
+
+ /* Clear event */
+
+ nrf52_i2c_putreg(priv, NRF52_TWIM_EVENTS_STOPPED_OFFSET, 0);
#endif
}
else
@@ -425,8 +433,8 @@ static int nrf52_i2c_init(FAR struct nrf52_i2c_priv_s *priv)
/* Select SCL pin */
- pin = (priv->scl_pin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
- port = (priv->scl_pin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ pin = GPIO_PIN_DECODE(priv->scl_pin);
+ port = GPIO_PORT_DECODE(priv->scl_pin);
regval = (pin << TWIM_PSELSCL_PIN_SHIFT);
regval |= (port << TWIM_PSELSCL_PORT_SHIFT);
@@ -434,8 +442,8 @@ static int nrf52_i2c_init(FAR struct nrf52_i2c_priv_s *priv)
/* Select SDA pin */
- pin = (priv->sda_pin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
- port = (priv->sda_pin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ pin = GPIO_PIN_DECODE(priv->sda_pin);
+ port = GPIO_PORT_DECODE(priv->sda_pin);
regval = (pin << TWIM_PSELSDA_PIN_SHIFT);
regval |= (port << TWIM_PSELSDA_PORT_SHIFT);
diff --git a/arch/arm/src/nrf52/nrf52_irq.c b/arch/arm/src/nrf52/nrf52_irq.c
index 384e7c5..f80cd9d 100644
--- a/arch/arm/src/nrf52/nrf52_irq.c
+++ b/arch/arm/src/nrf52/nrf52_irq.c
@@ -53,8 +53,10 @@
#include "up_arch.h"
#include "up_internal.h"
-#include "nrf52_gpio.h"
#include "nrf52_irq.h"
+#ifdef CONFIG_NRF52_GPIOTE
+# include "nrf52_gpiote.h"
+#endif
/****************************************************************************
* Pre-processor Definitions
@@ -114,9 +116,12 @@ static void nrf52_dumpnvic(const char *msg, int irq)
irqinfo(" INTCTRL: %08x VECTAB: %08x\n",
getreg32(NVIC_INTCTRL), getreg32(NVIC_VECTAB));
#if 0
- irqinfo(" SYSH ENABLE MEMFAULT: %08x BUSFAULT: %08x USGFAULT: %08x SYSTICK: %08x\n",
- getreg32(NVIC_SYSHCON_MEMFAULTENA), getreg32(NVIC_SYSHCON_BUSFAULTENA),
- getreg32(NVIC_SYSHCON_USGFAULTENA), getreg32(NVIC_SYSTICK_CTRL_ENABLE));
+ irqinfo(" SYSH ENABLE MEMFAULT: %08x BUSFAULT: %08x \n",
+ getreg32(NVIC_SYSHCON_MEMFAULTENA),
+ getreg32(NVIC_SYSHCON_BUSFAULTENA));
+ irqinfo(" USGFAULT: %08x SYSTICK: %08x\n",
+ getreg32(NVIC_SYSHCON_USGFAULTENA),
+ getreg32(NVIC_SYSTICK_CTRL_ENABLE));
#endif
irqinfo(" IRQ ENABLE: %08x %08x\n",
getreg32(NVIC_IRQ0_31_ENABLE), getreg32(NVIC_IRQ32_63_ENABLE));
@@ -370,7 +375,9 @@ void up_irqinitialize(void)
/* Set the priority of the SVCall interrupt */
#ifdef CONFIG_ARCH_IRQPRIO
- /* up_prioritize_irq(NRF52_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN); */
+# if 0
+ up_prioritize_irq(NRF52_IRQ_PENDSV, NVIC_SYSH_PRIORITY_MIN);
+# endif
#endif
#ifdef CONFIG_ARMV7M_USEBASEPRI
@@ -413,10 +420,10 @@ void up_irqinitialize(void)
putreg32(regval, NVIC_DEMCR);
#endif
-#ifdef CONFIG_NRF52_GPIOIRQ
- /* Initialize GPIO interrupts */
+#ifdef CONFIG_NRF52_GPIOTE
+ /* Initialize GPIOTE */
- nrf52_gpio_irqinitialize();
+ nrf52_gpiote_init();
#endif
#ifndef CONFIG_SUPPRESS_INTERRUPTS
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.c b/arch/arm/src/nrf52/nrf52_lowputc.c
index 68f7600..212d1ab 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.c
+++ b/arch/arm/src/nrf52/nrf52_lowputc.c
@@ -114,8 +114,7 @@ static const struct uart_config_s g_console_config =
****************************************************************************/
#ifdef HAVE_UART_DEVICE
-static void nrf52_setbaud(uintptr_t base,
- FAR const struct uart_config_s *config)
+static void nrf52_setbaud(uintptr_t base, const struct uart_config_s *config)
{
uint32_t br = 0;
@@ -164,8 +163,7 @@ void nrf52_lowsetup(void)
****************************************************************************/
#ifdef HAVE_UART_DEVICE
-void nrf52_usart_configure(uintptr_t base,
- FAR const struct uart_config_s *config)
+void nrf52_usart_configure(uintptr_t base, const struct uart_config_s *config)
{
uint32_t pin = 0;
uint32_t port = 0;
@@ -186,8 +184,8 @@ void nrf52_usart_configure(uintptr_t base,
/* Setect TX pins for UART */
- pin = (config->txpin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
- port = (config->txpin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ pin = GPIO_PIN_DECODE(config->txpin);
+ port = GPIO_PORT_DECODE(config->txpin);
regval = (pin << UART_PSELTXD_PIN_SHIFT);
regval |= (port << UART_PSELTXD_PORT_SHIFT);
@@ -195,8 +193,8 @@ void nrf52_usart_configure(uintptr_t base,
/* Setect RX pins for UART */
- pin = (config->rxpin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
- port = (config->rxpin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+ pin = GPIO_PIN_DECODE(config->rxpin);
+ port = GPIO_PORT_DECODE(config->rxpin);
regval = (pin << UART_PSELRXD_PIN_SHIFT);
regval |= (port << UART_PSELRXD_PORT_SHIFT);
@@ -218,8 +216,7 @@ void nrf52_usart_configure(uintptr_t base,
****************************************************************************/
#ifdef HAVE_UART_DEVICE
-void nrf52_usart_disable(uintptr_t base,
- FAR const struct uart_config_s *config)
+void nrf52_usart_disable(uintptr_t base, const struct uart_config_s *config)
{
/* Disable interrupts */
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.h b/arch/arm/src/nrf52/nrf52_lowputc.h
index aac31d9..d587c3d 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.h
+++ b/arch/arm/src/nrf52/nrf52_lowputc.h
@@ -1,4 +1,4 @@
-/************************************************************************************
+/****************************************************************************
* arch/arm/src/nrf52/nrf52_lowputc.h
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
@@ -31,14 +31,14 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ************************************************************************************/
+ ****************************************************************************/
#ifndef __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H
#define __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H
-/************************************************************************************
+/****************************************************************************
* Included Files
- ************************************************************************************/
+ ****************************************************************************/
#include <nuttx/config.h>
@@ -46,9 +46,9 @@
#include <stdbool.h>
#include <nrf52_gpio.h>
-/************************************************************************************
+/****************************************************************************
* Public Types
- ************************************************************************************/
+ ****************************************************************************/
#ifdef HAVE_UART_DEVICE
/* This structure describes the configuration of an UART */
@@ -58,56 +58,56 @@ struct uart_config_s
uint32_t baud; /* Configured baud */
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (5-9) */
- bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
+ bool stopbits2; /* Configure with 2 stop bits instead of 1 */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
- bool iflow; /* true: Input flow control supported */
+ bool iflow; /* Input flow control supported */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
- bool oflow; /* true: Output flow control supported. */
+ bool oflow; /* Output flow control supported. */
#endif
nrf52_pinset_t txpin; /* TX pin */
nrf52_pinset_t rxpin; /* RX pin */
};
#endif
-/************************************************************************************
+/****************************************************************************
* Public Functions
- ************************************************************************************/
+ ****************************************************************************/
-/************************************************************************************
+/****************************************************************************
* Name: nrf52_lowsetup
*
* Description:
- * Called at the very beginning of _start. Performs low level initialization
- * including setup of the console UART. This UART initialization is done
- * early so that the serial console is available for debugging very early in
- * the boot sequence.
+ * Called at the very beginning of _start. Performs low level
+ * initialization including setup of the console UART. This UART
+ * initialization is done early so that the serial console is available
+ * for debugging very early in the boot sequence.
*
- ************************************************************************************/
+ ****************************************************************************/
void nrf52_lowsetup(void);
-/************************************************************************************
+/****************************************************************************
* Name: nrf52_usart_configure
*
* Description:
* Configure a UART for non-interrupt driven operation
*
- ************************************************************************************/
+ ****************************************************************************/
#ifdef HAVE_UART_DEVICE
void nrf52_usart_configure(uintptr_t base,
FAR const struct uart_config_s *config);
#endif
-/************************************************************************************
+/****************************************************************************
* Name: nrf52_usart_disable
*
* Description:
* Disable a UART. it will be necessary to again call
* nrf52_usart_configure() in order to use this UART channel again.
*
- ************************************************************************************/
+ ****************************************************************************/
#ifdef HAVE_UART_DEVICE
void nrf52_usart_disable(uintptr_t base,
diff --git a/arch/arm/src/nrf52/nrf52_spi.c b/arch/arm/src/nrf52/nrf52_spi.c
new file mode 100644
index 0000000..9b67e84
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_spi.c
@@ -0,0 +1,1017 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_spi.c
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * 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 NuttX 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 OWNER 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/semaphore.h>
+#include <arch/board/board.h>
+
+#include "up_arch.h"
+
+#include "nrf52_gpio.h"
+#include "nrf52_spi.h"
+
+#include "hardware/nrf52_spi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* I2C0/SPI0 and I2C1/SPI1 share the same peripherals */
+
+#if defined(CONFIG_NRF52_I2C0_MASTER) && defined(CONFIG_NRF52_SPI0_MASTER)
+# error Unsupported configuration I2C0 + SPI0
+#endif
+#if defined(CONFIG_NRF52_I2C1_MASTER) && defined(CONFIG_NRF52_SPI1_MASTER)
+# error Unsupported configuration I2C1 + SPI1
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf52_spidev_s
+{
+ struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
+ uint32_t base; /* Base address of SPI register */
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ uint32_t irq; /* SPI IRQ number */
+#endif
+ uint32_t sck_pin; /* SCK pin configuration */
+ uint32_t mosi_pin; /* MOSI pin configuration */
+ uint32_t miso_pin; /* MISO pin configuration */
+ uint32_t frequency; /* Requested clock frequency */
+ uint8_t mode; /* Mode 0,1,2,3 */
+
+ sem_t exclsem; /* Held while chip is selected for mutual exclusion */
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ sem_t sem_isr; /* Interrupt wait semaphore */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void nrf52_spi_putreg(FAR struct nrf52_spidev_s *priv,
+ uint32_t offset,
+ uint32_t value);
+static inline uint32_t nrf52_spi_getreg(FAR struct nrf52_spidev_s *priv,
+ uint32_t offset);
+
+/* SPI methods */
+
+static int nrf52_spi_lock(FAR struct spi_dev_s *dev, bool lock);
+static uint32_t nrf52_spi_setfrequency(FAR struct spi_dev_s *dev,
+ uint32_t frequency);
+static void nrf52_spi_setmode(FAR struct spi_dev_s *priv,
+ enum spi_mode_e mode);
+static void nrf52_spi_setbits(FAR struct spi_dev_s *priv, int nbits);
+#ifdef CONFIG_SPI_HWFEATURES
+static int nrf52_spi_hwfeatures(FAR struct spi_dev_s *dev,
+ spi_hwfeatures_t features);
+#endif
+static uint16_t nrf52_spi_send(FAR struct spi_dev_s *dev, uint16_t wd);
+static void nrf52_spi_exchange(FAR struct spi_dev_s *dev,
+ FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords);
+#ifndef CONFIG_SPI_EXCHANGE
+static void nrf52_spi_sndblock(FAR struct spi_dev_s *dev,
+ FAR const void *txbuffer,
+ size_t nwords);
+static void nrf52_spi_recvblock(FAR struct spi_dev_s *dev,
+ FAR void *rxbuffer,
+ size_t nwords);
+#endif
+
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+static int nrf52_spi_isr(int irq, FAR void *context, FAR void *arg);
+#endif
+
+/* Initialization */
+
+static int nrf52_spi_init(FAR struct nrf52_spidev_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* SPI0 */
+
+#ifdef CONFIG_NRF52_SPI0_MASTER
+static const struct spi_ops_s g_spi0ops =
+{
+ .lock = nrf52_spi_lock,
+ .select = nrf52_spi0select,
+ .setfrequency = nrf52_spi_setfrequency,
+ .setmode = nrf52_spi_setmode,
+ .setbits = nrf52_spi_setbits,
+# ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = nrf52_spi_hwfeatures,
+# endif
+ .status = nrf52_spi0status,
+# ifdef CONFIG_SPI_CMDDATA
+ .cmddata = nrf52_spi1cmddata,
+# endif
+ .send = nrf52_spi_send,
+# ifdef CONFIG_SPI_EXCHANGE
+ .exchange = nrf52_spi_exchange,
+# else
+ .sendlock = nrf52_spi_sendblock,
+ .recvblock = nrf52_spi_recvblock
+# endif
+};
+
+static struct nrf52_spidev_s g_spi0dev =
+{
+ .spidev =
+ {
+ &g_spi0ops
+ },
+
+ .base = NRF52_SPIM0_BASE,
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ .irq = NRF52_IRQ_SPI_TWI_0,
+#endif
+ .sck_pin = BOARD_SPI0_SCK_PIN,
+ .mosi_pin = BOARD_SPI0_MOSI_PIN,
+ .miso_pin = BOARD_SPI0_MISO_PIN,
+ .frequency = 0,
+ .mode = 0
+};
+#endif
+
+/* SPI1 */
+
+#ifdef CONFIG_NRF52_SPI1_MASTER
+static const struct spi_ops_s g_spi1ops =
+{
+ .lock = nrf52_spi_lock,
+ .select = nrf52_spi1select,
+ .setfrequency = nrf52_spi_setfrequency,
+ .setmode = nrf52_spi_setmode,
+ .setbits = nrf52_spi_setbits,
+# ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = nrf52_spi_hwfeatures,
+# endif
+ .status = nrf52_spi1status,
+# ifdef CONFIG_SPI_CMDDATA
+ .cmddata = nrf52_spi1cmddata,
+# endif
+ .send = nrf52_spi_send,
+# ifdef CONFIG_SPI_EXCHANGE
+ .exchange = nrf52_spi_exchange,
+# else
+ .sendlock = nrf52_spi_sendblock,
+ .recvblock = nrf52_spi_recvblock
+# endif
+};
+
+static struct nrf52_spidev_s g_spi1dev =
+{
+ .spidev =
+ {
+ &g_spi1ops
+ },
+
+ .base = NRF52_SPIM0_BASE,
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ .irq = NRF52_IRQ_SPI_TWI_1,
+#endif
+ .sck_pin = BOARD_SPI1_SCK_PIN,
+ .mosi_pin = BOARD_SPI1_MOSI_PIN,
+ .miso_pin = BOARD_SPI1_MISO_PIN,
+ .frequency = 0,
+ .mode = 0
+};
+#endif
+
+/* SPI2 */
+
+#ifdef CONFIG_NRF52_SPI2_MASTER
+static const struct spi_ops_s g_spi2ops =
+{
+ .lock = nrf52_spi_lock,
+ .select = nrf52_spi2select,
+ .setfrequency = nrf52_spi_setfrequency,
+ .setmode = nrf52_spi_setmode,
+ .setbits = nrf52_spi_setbits,
+# ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = nrf52_spi_hwfeatures,
+# endif
+ .status = nrf52_spi2status,
+# ifdef CONFIG_SPI_CMDDATA
+ .cmddata = nrf52_spi1cmddata,
+# endif
+ .send = nrf52_spi_send,
+# ifdef CONFIG_SPI_EXCHANGE
+ .exchange = nrf52_spi_exchange,
+# else
+ .sendlock = nrf52_spi_sendblock,
+ .recvblock = nrf52_spi_recvblock
+# endif
+};
+
+static struct nrf52_spidev_s g_spi2dev =
+{
+ .spidev =
+ {
+ &g_spi2ops
+ },
+
+ .base = NRF52_SPIM0_BASE,
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ .irq = NRF52_IRQ_SPI2,
+#endif
+ .sck_pin = BOARD_SPI2_SCK_PIN,
+ .mosi_pin = BOARD_SPI2_MOSI_PIN,
+ .miso_pin = BOARD_SPI2_MISO_PIN,
+ .frequency = 0,
+ .mode = 0
+};
+#endif
+
+/* SPI3 */
+
+#ifdef CONFIG_NRF52_SPI3_MASTER
+static const struct spi_ops_s g_spi3ops =
+{
+ .lock = nrf52_spi_lock,
+ .select = nrf52_spi3select,
+ .setfrequency = nrf52_spi_setfrequency,
+ .setmode = nrf52_spi_setmode,
+ .setbits = nrf52_spi_setbits,
+# ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = nrf52_spi_hwfeatures,
+# endif
+ .status = nrf52_spi3status,
+# ifdef CONFIG_SPI_CMDDATA
+ .cmddata = nrf52_spi1cmddata,
+# endif
+ .send = nrf52_spi_send,
+# ifdef CONFIG_SPI_EXCHANGE
+ .exchange = nrf52_spi_exchange,
+# else
+ .sendlock = nrf52_spi_sendblock,
+ .recvblock = nrf52_spi_recvblock
+# endif
+};
+
+static struct nrf52_spidev_s g_spi3dev =
+{
+ .spidev =
+ {
+ &g_spi3ops
+ },
+
+ .base = NRF52_SPIM0_BASE,
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ .irq = NRF52_IRQ_SPI3,
+#endif
+ .sck_pin = BOARD_SPI3_SCK_PIN,
+ .mosi_pin = BOARD_SPI3_MOSI_PIN,
+ .miso_pin = BOARD_SPI3_MISO_PIN,
+ .frequency = 0,
+ .mode = 0
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_spi_putreg
+ *
+ * Description:
+ * Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf52_spi_putreg(FAR struct nrf52_spidev_s *priv,
+ uint32_t offset,
+ uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_getreg
+ *
+ * Description:
+ * Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf52_spi_getreg(FAR struct nrf52_spidev_s *priv,
+ uint32_t offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_isr
+ *
+ * Description:
+ * Common SPI interrupt service routine
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+static int nrf52_spi_isr(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)arg;
+ uint32_t regval = 0;
+
+ /* Get interrupt event */
+
+ if (nrf52_spi_getreg(priv, NRF52_SPIM_EVENTS_END_OFFSET) == 1)
+ {
+ /* Transfer is complete */
+
+ nxsem_post(&priv->sem_isr);
+
+ /* Clear event */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_EVENTS_END_OFFSET, 0);
+ }
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf52_spi_init
+ *
+ * Description:
+ * Configure SPI
+ *
+ ****************************************************************************/
+
+static int nrf52_spi_init(FAR struct nrf52_spidev_s *priv)
+{
+ uint32_t regval = 0;
+ int pin = 0;
+ int port = 0;
+
+ /* Disable SPI */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_ENABLE_OFFSET, SPIM_ENABLE_DIS);
+
+ /* Configure SPI pins */
+
+ nrf52_gpio_config(priv->sck_pin);
+ nrf52_gpio_config(priv->mosi_pin);
+ nrf52_gpio_config(priv->miso_pin);
+
+ /* Select SCK pins */
+
+ pin = GPIO_PIN_DECODE(priv->sck_pin);
+ port = GPIO_PORT_DECODE(priv->sck_pin);
+
+ regval = (pin << SPIM_PSELSCK_PIN_SHIFT);
+ regval |= (port << SPIM_PSELSCK_PORT_SHIFT);
+ nrf52_spi_putreg(priv, NRF52_SPIM_PSELSCK_OFFSET, regval);
+
+ /* Select MOSI pins */
+
+ pin = GPIO_PIN_DECODE(priv->mosi_pin);
+ port = GPIO_PORT_DECODE(priv->mosi_pin);
+
+ regval = (pin << SPIM_PSELMOSI_PIN_SHIFT);
+ regval |= (port << SPIM_PSELMOSI_PORT_SHIFT);
+ nrf52_spi_putreg(priv, NRF52_SPIM_PSELMOSI_OFFSET, regval);
+
+ /* According to manual we have to write 0 to MOSI pin */
+
+ nrf52_gpio_write(priv->mosi_pin, false);
+
+ /* Select MISO pins */
+
+ pin = GPIO_PIN_DECODE(priv->miso_pin);
+ port = GPIO_PORT_DECODE(priv->miso_pin);
+
+ regval = (pin << SPIM_PSELMISO_PIN_SHIFT);
+ regval |= (port << SPIM_PSELMISO_PORT_SHIFT);
+ nrf52_spi_putreg(priv, NRF52_SPIM_PSELMISO_OFFSET, regval);
+
+ /* NOTE: Chip select pin must be configured by board-specific logic */
+
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ /* Enable interrupts for RX and TX done */
+
+ regval = SPIM_INT_END;
+ nrf52_spi_putreg(priv, NRF52_SPIM_INTENSET_OFFSET, regval);
+#endif
+
+ /* Enable SPI */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_ENABLE_OFFSET, SPIM_ENABLE_EN);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_lock
+ *
+ * Description:
+ * On SPI busses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the busses for a sequence of
+ * transfers. The bus should be locked before the chip is selected. After
+ * locking the SPI bus, the caller should then also call the setfrequency,
+ * setbits, and setmode methods to make sure that the SPI is properly
+ * configured for the device. If the SPI buss is being shared, then it
+ * may have been left in an incompatible state.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * lock - true: Lock spi bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int nrf52_spi_lock(FAR struct spi_dev_s *dev, bool lock)
+{
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+ int ret = OK;
+
+ if (lock)
+ {
+ /* Take the semaphore (perhaps waiting) */
+
+ do
+ {
+ ret = nxsem_wait(&priv->exclsem);
+
+ /* The only case that an error should occur here is if the wait
+ * was awakened by a signal.
+ */
+
+ DEBUGASSERT(ret == OK || ret == -EINTR);
+ }
+ while (ret == -EINTR);
+ }
+ else
+ {
+ (void)nxsem_post(&priv->exclsem);
+ ret = OK;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_setfrequency
+ *
+ * Description:
+ * Set the SPI frequency.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * frequency - The SPI frequency requested
+ *
+ * Returned Value:
+ * Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static uint32_t nrf52_spi_setfrequency(FAR struct spi_dev_s *dev,
+ uint32_t frequency)
+{
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+ uint32_t regval = 0;
+
+ if (priv->frequency == frequency)
+ {
+ /* We are already at this frequency */
+
+ return priv->frequency;
+ }
+
+ /* Frequencies are hardcoded */
+
+ switch (frequency)
+ {
+ case 125000:
+ {
+ regval = SPIM_FREQUENCY_125KBPS;
+ break;
+ }
+
+ case 250000:
+ {
+ regval = SPIM_FREQUENCY_250KBPS;
+ break;
+ }
+
+ case 500000:
+ {
+ regval = SPIM_FREQUENCY_500KBPS;
+ break;
+ }
+
+ case 1000000:
+ {
+ regval = SPIM_FREQUENCY_1MBPS;
+ break;
+ }
+
+ case 2000000:
+ {
+ regval = SPIM_FREQUENCY_2MBPS;
+ break;
+ }
+
+ case 4000000:
+ {
+ regval = SPIM_FREQUENCY_4MBPS;
+ break;
+ }
+
+ case 8000000:
+ {
+ regval = SPIM_FREQUENCY_8MBPS;
+ break;
+ }
+
+ default:
+ {
+ spierr("Frequency unsupported %d\n", frequency);
+ goto errout;
+ }
+ }
+
+ /* Write register */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_FREQUENCY_OFFSET, regval);
+
+ /* Save the frequency setting */
+
+ priv->frequency = frequency;
+
+ spiinfo("Frequency %d\n", frequency);
+
+errout:
+ return priv->frequency;
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_setmode
+ *
+ * Description:
+ * Set the SPI mode. see enum spi_mode_e for mode definitions
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * mode - The SPI mode requested
+ *
+ * Returned Value:
+ * Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+ uint32_t regval = 0;
+
+ spiinfo("mode=%d\n", mode);
+
+ /* Has the mode changed? */
+
+ if (mode != priv->mode)
+ {
+ regval = nrf52_spi_getreg(priv, NRF52_SPIM_CONFIG_OFFSET);
+ regval &= ~(SPIM_CONFIG_CPHA | SPIM_CONFIG_CPOL);
+
+ switch (mode)
+ {
+ case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */
+ {
+ break;
+ }
+
+ case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */
+ {
+ regval |= SPIM_CONFIG_CPHA;
+ break;
+ }
+
+ case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */
+ {
+ regval |= SPIM_CONFIG_CPOL;
+ break;
+ }
+
+ case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */
+ {
+ regval |= SPIM_CONFIG_CPHA;
+ regval |= SPIM_CONFIG_CPOL;
+ break;
+ }
+
+ default:
+ {
+ DEBUGASSERT(0);
+ return;
+ }
+ }
+
+ /* According to manual we have to set SCK pin output
+ * value the same as CPOL value
+ */
+
+ if (mode == SPIDEV_MODE2 || mode == SPIDEV_MODE3)
+ {
+ nrf52_gpio_write(priv->sck_pin, true);
+ }
+ else
+ {
+ nrf52_gpio_write(priv->sck_pin, false);
+ }
+
+ priv->mode = mode;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_setbits
+ *
+ * Description:
+ * Set the number of bits per word.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * nbits - The number of bits requested
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_setbits(FAR struct spi_dev_s *dev, int nbits)
+{
+ if (nbits != 8)
+ {
+ spierr("ERROR: nbits not supported: %d\n", nbits);
+ }
+
+ return;
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_hwfeatures
+ *
+ * Description:
+ * Set hardware-specific feature flags.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * features - H/W feature flags
+ *
+ * Returned Value:
+ * Zero (OK) if the selected H/W features are enabled; A negated errno
+ * value if any H/W feature is not supportable.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_HWFEATURES
+static int nrf52_spi_hwfeatures(FAR struct spi_dev_s *dev,
+ spi_hwfeatures_t features)
+{
+#ifdef CONFIG_SPI_BITORDER
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+ uint32_t setbits = 0;
+ uint32_t clrbits = 0;
+
+ spiinfo("features=%08x\n", features);
+
+ /* Transfer data LSB first? */
+
+ if ((features & HWFEAT_LSBFIRST) != 0)
+ {
+ setbits = SPIM_CONFIG_ORDER;
+ clrbits = 0;
+ }
+ else
+ {
+ setbits = 0;
+ clrbits = SPIM_CONFIG_ORDER;
+ }
+
+ regval = nrf52_spi_getreg(priv, NRF52_SPIM_CONFIG_OFFSET);
+ regval &= ~clrbits;
+ regval |= setbits;
+ nrf52_spi_putreg(priv, NRF52_SPIM_CONFIG_OFFSET, regval);
+
+#endif
+ /* Other H/W features are not supported */
+
+ return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: n4f52_spi_send
+ *
+ * Description:
+ * Exchange one word on SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * wd - The word to send. the size of the data is determined by the
+ * number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ * response
+ *
+ ****************************************************************************/
+
+static uint16_t nrf52_spi_send(FAR struct spi_dev_s *dev, uint16_t wd)
+{
+ uint16_t ret = 0;
+
+ /* Exchange one word on SPI */
+
+ nrf52_spi_exchange(dev, &wd, &ret, 1);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_exchange
+ *
+ * Description:
+ * Exchange a block of data on SPI without using DMA
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * txbuffer - A pointer to the buffer of data to be sent
+ * rxbuffer - A pointer to a buffer in which to receive data
+ * nwords - the length of data to be exchaned in units of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_exchange(FAR struct spi_dev_s *dev,
+ FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords)
+{
+ FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+ uint32_t regval = 0;
+
+ if (rxbuffer != NULL)
+ {
+ /* Write RXD data pointer */
+
+ regval = (uint32_t)rxbuffer;
+ nrf52_spi_putreg(priv, NRF52_SPIM_RXDPTR_OFFSET, regval);
+
+ /* Write number of bytes in RXD buffer */
+
+ regval = nwords;
+ nrf52_spi_putreg(priv, NRF52_SPIM_RXDMAXCNT_OFFSET, regval);
+ }
+
+ if (txbuffer != NULL)
+ {
+ /* Write TXD data pointer */
+
+ regval = (uint32_t)txbuffer;
+ nrf52_spi_putreg(priv, NRF52_SPIM_TXDPTR_OFFSET, regval);
+
+ /* Write number of bytes in TXD buffer */
+
+ regval = nwords;
+ nrf52_spi_putreg(priv, NRF52_SPIM_TXDMAXCNT_OFFSET, regval);
+ }
+
+ /* SPI start */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_TASK_START_OFFSET, SPIM_TASKS_START);
+
+#ifndef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ /* Wait for RX done and TX done */
+
+ while (nrf52_spi_getreg(priv, NRF52_SPIM_EVENTS_END_OFFSET) != 1);
+
+ /* Clear event */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_EVENTS_END_OFFSET, 0);
+#else
+ /* Wait for transfer complete */
+
+ nxsem_wait(&priv->sem_isr);
+#endif
+
+ /* SPI stop */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_TASK_STOP_OFFSET, SPIM_TASKS_STOP);
+
+ /* Wait for STOP event */
+
+ while (nrf52_spi_getreg(priv, NRF52_SPIM_EVENTS_STOPPED_OFFSET) != 1);
+
+ /* Clear event */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_EVENTS_STOPPED_OFFSET, 0);
+
+ /* Clear RX/TX DMA after tranfer */
+
+ nrf52_spi_putreg(priv, NRF52_SPIM_RXDPTR_OFFSET, 0);
+ nrf52_spi_putreg(priv, NRF52_SPIM_RXDMAXCNT_OFFSET, 0);
+ nrf52_spi_putreg(priv, NRF52_SPIM_TXDPTR_OFFSET, 0);
+ nrf52_spi_putreg(priv, NRF52_SPIM_TXDMAXCNT_OFFSET, 0);
+}
+
+#ifndef CONFIG_SPI_EXCHANGE
+
+/****************************************************************************
+ * Name: nrf52_spi_sndblock
+ *
+ * Description:
+ * Send a block of data on SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * txbuffer - A pointer to the buffer of data to be sent
+ * nwords - the length of data to send from the buffer in number of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_sndblock(FAR struct spi_dev_s *dev,
+ FAR const void *txbuffer,
+ size_t nwords)
+{
+ spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
+ return nrf52_spi_exchange(dev, txbuffer, NULL, nwords);
+}
+
+/****************************************************************************
+ * Name: nrf52_spi_recvblock
+ *
+ * Description:
+ * Receive a block of data from SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * rxbuffer - A pointer to the buffer in which to receive data
+ * nwords - the length of data that can be received in the buffer in
+ * number of words. The wordsize is determined by the number of
+ * bits-per-word selected for the SPI interface.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_recvblock(FAR struct spi_dev_s *dev,
+ FAR void *rxbuffer,
+ size_t nwords)
+{
+ spiinfo("txbuffer=%p nwords=%d\n", txbuffer, nwords);
+ return nrf52_spi_exchange(dev, txbuffer, NULL, nwords);
+}
+#endif /* CONFIG_SPI_EXCHANGE */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_spibus_initialize
+ *
+ * Description:
+ * Initialize the selected SPI port.
+ *
+ * Input Parameters:
+ * Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ * Valid SPI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct spi_dev_s *nrf52_spibus_initialize(int port)
+{
+ FAR struct nrf52_spidev_s *priv = NULL;
+
+ /* Get SPI driver data */
+
+ switch (port)
+ {
+#ifdef CONFIG_NRF52_SPI0_MASTER
+ case 0:
+ {
+ priv = &g_spi0dev;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_NRF52_SPI1_MASTER
+ case 1:
+ {
+ priv = &g_spi1dev;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_NRF52_SPI2_MASTER
+ case 2:
+ {
+ priv = &g_spi2dev;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_NRF52_SPI3_MASTER
+ case 3:
+ {
+ priv = &g_spi3dev;
+ break;
+ }
+#endif
+
+ default:
+ {
+ goto errout;
+ }
+ }
+
+ /* Initialize the SPI */
+
+ nrf52_spi_init(priv);
+
+ /* Initialize the SPI semaphore */
+
+ nxsem_init(&priv->exclsem, 0, 1);
+
+#ifdef CONFIG_NRF52_SPI_MASTER_INTERRUPTS
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&priv->sem_isr, 0, 0);
+ nxsem_setprotocol(&priv->sem_isr, SEM_PRIO_NONE);
+
+ /* Attach SPI interrupt */
+
+ irq_attach(priv->irq, nrf52_spi_isr, priv);
+ up_enable_irq(priv->irq);
+#endif
+
+errout:
+ return (FAR struct spi_dev_s *)priv;
+}
diff --git a/arch/arm/src/nrf52/nrf52_spi.h b/arch/arm/src/nrf52/nrf52_spi.h
new file mode 100644
index 0000000..c87e7db
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_spi.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_spi.h
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * 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 NuttX 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 OWNER 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_SPI_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_SPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/spi/spi.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_spibus_initialize
+ *
+ * Description:
+ * Initialize the selected SPI port.
+ *
+ * Input Parameters:
+ * Port number (for hardware that has multiple SPI interfaces)
+ *
+ * Returned Value:
+ * Valid SPI device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct spi_dev_s *nrf52_spibus_initialize(int port);
+
+/****************************************************************************
+ * Name: nrf52_spi0/1/...select and nrf52_spi0/1/...status
+ *
+ * Description:
+ * The external functions, nrf52_spi0/1/...select, nrf52_spi0/1/...status,
+ * and nrf52_spi0/1/...cmddata must be provided by board-specific logic.
+ * These are implementations of the select, status, and cmddata methods of
+ * the SPI interface defined by struct spi_ops_s (include/nuttx/spi/spi.h).
+ * All other methods (including nrf52_spibus_initialize()) are provided by
+ * common NRF52 logic. To use this common SPI logic on your board:
+ *
+ * 1. Provide logic in nrf52_boardinitialize() to configure SPI chip select
+ * pins.
+ * 2. Provide nrf52_spi0/1/...select() and nrf52_spi0/1/...status()
+ * functions in your board-specific logic. These functions will perform
+ * chip selection and status operations using GPIOs in the way your board
+ * is configured.
+ * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file,
+ * then provide nrf52_spi0/1/...cmddata() functions in your
+ * board-specific logic. These functions will perform cmd/data selection
+ * operations using GPIOs in the way your board is configured.
+ * 4. Add a calls to nrf52_spibus_initialize() in your low level application
+ * initialization logic
+ * 5. The handle returned by nrf52_spibus_initialize() may then be used to
+ * bind the SPI driver to higher level logic (e.g., calling
+ * mmcsd_spislotinitialize(), for example, will bind the SPI driver to
+ * the SPI MMC/SD driver).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI0_MASTER
+void nrf52_spi0select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected);
+uint8_t nrf52_spi0status(FAR struct spi_dev_s *dev, uint32_t devid);
+int nrf52_spi0cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+
+#ifdef CONFIG_NRF52_SPI1_MASTER
+void nrf52_spi1select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected);
+uint8_t nrf52_spi1status(FAR struct spi_dev_s *dev, uint32_t devid);
+int nrf52_spi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+
+#ifdef CONFIG_NRF52_SPI2_MASTER
+void nrf52_spi2select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected);
+uint8_t nrf52_spi2status(FAR struct spi_dev_s *dev, uint32_t devid);
+int nrf52_spi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+
+#ifdef CONFIG_NRF52_SPI3_MASTER
+void nrf52_spi3select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected);
+uint8_t nrf52_spi3status(FAR struct spi_dev_s *dev, uint32_t devid);
+int nrf52_spi3cmddata(FAR struct spi_dev_s *dev, uint32_t devid, bool cmd);
+#endif
+
+#endif /* __ARCH_ARM_SRC_NRF52_NRF52_SPI_H */
diff --git a/boards/arm/nrf52/nrf52-feather/include/board.h b/boards/arm/nrf52/nrf52-feather/include/board.h
index b50587b..6a69b9a 100644
--- a/boards/arm/nrf52/nrf52-feather/include/board.h
+++ b/boards/arm/nrf52/nrf52-feather/include/board.h
@@ -43,7 +43,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
-#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ)
+#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE)
# include <nuttx/irq.h>
#endif
diff --git a/boards/arm/nrf52/nrf52832-dk/include/board.h b/boards/arm/nrf52/nrf52832-dk/include/board.h
index 6488aba..2031729 100644
--- a/boards/arm/nrf52/nrf52832-dk/include/board.h
+++ b/boards/arm/nrf52/nrf52832-dk/include/board.h
@@ -43,7 +43,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
-#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ)
+#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE)
# include <nuttx/irq.h>
#endif
diff --git a/boards/arm/nrf52/nrf52840-dk/include/board.h b/boards/arm/nrf52/nrf52840-dk/include/board.h
index b207d04..6916d3b 100644
--- a/boards/arm/nrf52/nrf52840-dk/include/board.h
+++ b/boards/arm/nrf52/nrf52840-dk/include/board.h
@@ -43,7 +43,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
-#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ)
+#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE)
# include <nuttx/irq.h>
#endif
@@ -130,4 +130,26 @@
#define BOARD_UART1_RX_PIN (GPIO_INPUT | GPIO_PORT1 | GPIO_PIN(1))
#define BOARD_UART1_TX_PIN (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT1 | GPIO_PIN(2))
+/* SPI Pins *****************************************************************/
+
+/* SPI0 - Arduino PINs
+ * SPI0_SCK - P1.15 (P13)
+ * SPI0_MOSI - P1.13 (D11)
+ * SPI0_MISO - P1.14 (D12)
+ */
+
+#define BOARD_SPI0_SCK_PIN (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT1 | GPIO_PIN(15))
+#define BOARD_SPI0_MOSI_PIN (GPIO_OUTPUT | GPIO_PORT1 | GPIO_PIN(13))
+#define BOARD_SPI0_MISO_PIN (GPIO_INPUT | GPIO_PORT1 | GPIO_PIN(14))
+
+/* I2C Pins *****************************************************************/
+
+/* I2C0 (TWI0) - Arduino PINs
+ * I2C0_SCL - P0.27
+ * I2C0_SDA - P0.26
+ */
+
+#define BOARD_I2C0_SCL_PIN (GPIO_OUTPUT | GPIO_PORT0 | GPIO_PIN(27))
+#define BOARD_I2C0_SDA_PIN (GPIO_INPUT | GPIO_PORT0 | GPIO_PIN(26))
+
#endif /* __BOARDS_ARM_NRF52_NRF52840_DK_INCLUDE_BOARD_H */
diff --git a/boards/arm/nrf52/nrf52840-dk/src/Makefile b/boards/arm/nrf52/nrf52840-dk/src/Makefile
index b99bdec..53dd1d7 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/Makefile
+++ b/boards/arm/nrf52/nrf52840-dk/src/Makefile
@@ -52,4 +52,16 @@ ifeq ($(CONFIG_ARCH_BUTTONS),y)
CSRCS += nrf52_buttons.c
endif
+ifeq ($(CONFIG_NRF52_SPI_MASTER),y)
+CSRCS += nrf52_spi.c
+endif
+
+ifeq ($(CONFIG_SENSORS_LSM6DSL),y)
+CSRCS += nrf52_lsm6dsl.c
+endif
+
+ifeq ($(CONFIG_LPWAN_SX127X),y)
+CSRCS += nrf52_sx127x.c
+endif
+
include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
index 9744b8c..c209e1b 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
@@ -67,6 +67,16 @@
#define GPIO_BUTTON3 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(24))
#define GPIO_BUTTON4 (GPIO_INPUT | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN(25))
+/* Dragino LORA shield (v1.4) - RF98 module (based on SX127X)
+ * RESET - P1.11 (D9)
+ * CS - P1.12 (D10)
+ * DIO0 - P1.03 (D2)
+ */
+
+#define GPIO_SX127X_RESET (GPIO_PORT1 | GPIO_PIN(11))
+#define GPIO_SX127X_CS (GPIO_OUTPUT | GPIO_PORT1 | GPIO_PIN(12))
+#define GPIO_SX127X_DIO0 (GPIO_INPUT | GPIO_PORT1 | GPIO_PIN(3))
+
/****************************************************************************
* Public Types
****************************************************************************/
@@ -97,5 +107,41 @@
int nrf52_bringup(void);
+/****************************************************************************
+ * Name: nrf52_spidev_initialize
+ *
+ * Description:
+ * Called to configure SPI chip select GPIO pins for the
+ * nrf52840-dk board.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+void nrf52_spidev_initialize(void);
+#endif
+
+/*****************************************************************************
+ * Name: nrf52_lsm6dsl_initialize
+ *
+ * Description:
+ * Initialize I2C-based LSM6DSL.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SENSORS_LSM303AGR
+int nrf52_lsm6dsl_initialize(char *devpath);
+#endif
+
+/*****************************************************************************
+ * Name: nrf52_lpwaninitialize
+ *
+ * Description:
+ * Initialize SX127X LPWAN interaface.
+ ****************************************************************************/
+
+#ifdef CONFIG_LPWAN_SX127X
+int nrf52_lpwaninitialize(void);
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_NRF52_NRF52840_DK_SRC_NRF52840_DK_H */
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
index af1dca2..1e8bad1 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
@@ -71,6 +71,12 @@ void nrf52_board_initialize(void)
#ifdef CONFIG_ARCH_LEDS
board_autoled_initialize();
#endif
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+ /* Configure SPI chip selects */
+
+ nrf52_spidev_initialize();
+#endif
}
/****************************************************************************
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
index a5604a9..732efa2 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
@@ -46,11 +46,65 @@
# include <nuttx/leds/userled.h>
#endif
+#include "nrf52840-dk.h"
+
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
+ * Name: nrf52_i2c_register
+ *
+ * Description:
+ * Register one I2C drivers for the I2C tool.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SYSTEM_I2CTOOL)
+static void nrf52_i2c_register(int bus)
+{
+ struct i2c_master_s *i2c;
+ int ret;
+
+ i2c = nrf52_i2cbus_initialize(bus);
+ if (i2c == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to get I2C%d interface\n", bus);
+ }
+ else
+ {
+ ret = i2c_register(i2c, bus);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: Failed to register I2C%d driver: %d\n",
+ bus, ret);
+ nrf52_i2cbus_uninitialize(i2c);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf52_i2ctool
+ *
+ * Description:
+ * Register I2C drivers for the I2C tool.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_I2C) && defined(CONFIG_SYSTEM_I2CTOOL)
+static void nrf52_i2ctool(void)
+{
+#ifdef CONFIG_NRF52_I2C0
+ nrf52_i2c_register(0);
+#endif
+#ifdef CONFIG_NRF52_I2C1
+ nrf52_i2c_register(1);
+#endif
+}
+#endif
+
+/****************************************************************************
* Name: nrf52_bringup
*
* Description:
@@ -74,10 +128,32 @@ int nrf52_bringup(void)
ret = userled_lower_initialize(CONFIG_EXAMPLES_LEDS_DEVPATH);
if (ret < 0)
{
- syslog(LOG_ERR, "ERROR: userled_lower_initialize() failed: %d\n", ret);
+ syslog(LOG_ERR,
+ "ERROR: userled_lower_initialize() failed: %d\n",
+ ret);
}
#endif
+#ifdef CONFIG_SENSORS_LSM6DSL
+ ret = nrf52_lsm6dsl_initialize("/dev/lsm6dsl0");
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: Failed to initialize LSM6DSL driver: %d\n",
+ ret);
+ }
+#endif /* CONFIG_SENSORS_LSM6DSL */
+
+#ifdef CONFIG_LPWAN_SX127X
+ ret = nrf52_lpwaninitialize();
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: Failed to initialize wireless driver: %d\n",
+ ret);
+ }
+#endif /* CONFIG_LPWAN_SX127X */
+
UNUSED(ret);
return OK;
}
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c
similarity index 63%
copy from boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
copy to boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c
index af1dca2..7185662 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c
@@ -1,8 +1,8 @@
-/****************************************************************************
- * boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c
+/*****************************************************************************
+ * boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c
*
- * Copyright (C) 2019 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gn...@nuttx.org>
+ * Copyright (C) 2019 Greg Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,67 +30,68 @@
* 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.
- *
****************************************************************************/
-/****************************************************************************
+/*****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
+#include <nuttx/arch.h>
+#include <errno.h>
#include <debug.h>
#include <nuttx/board.h>
-#include <arch/board/board.h>
+#include "nrf52_i2c.h"
+#include "nrf52840-dk.h"
+#include <nuttx/sensors/lsm6dsl.h>
-#include "up_arch.h"
-#include "up_internal.h"
+/*****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
-#include "nrf52840-dk.h"
+#ifndef CONFIG_NRF52_I2C0_MASTER
+# error "LSM6DSL driver requires CONFIG_NRF52_I2C0_MASTER to be enabled"
+#endif
-/****************************************************************************
+/*****************************************************************************
* Public Functions
****************************************************************************/
-/****************************************************************************
- * Name: nrf52_board_initialize
+/*****************************************************************************
+ * Name: nrf52_lsm6dsl_initialize
*
* Description:
- * All NRF52xxx architectures must provide the following entry point.
- * This entry point is called early in the initialization -- after all
- * memory has been configured and mapped but before any devices have been
- * initialized.
- *
+ * Initialize I2C-based LSM6DSL.
****************************************************************************/
-void nrf52_board_initialize(void)
+int nrf52_lsm6dsl_initialize(char *devpath)
{
- /* Configure on-board LEDs if LED support has been selected. */
+ FAR struct i2c_master_s *i2c;
+ int ret = OK;
-#ifdef CONFIG_ARCH_LEDS
- board_autoled_initialize();
-#endif
-}
+ sninfo("Initializing LMS6DSL!\n");
-/****************************************************************************
- * Name: board_late_initialize
- *
- * Description:
- * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional
- * initialization call will be performed in the boot-up sequence to a
- * function called board_late_initialize(). board_late_initialize() will be
- * called immediately after up_initialize() is called and just before the
- * initial application is started. This additional initialization phase
- * may be used, for example, to initialize board-specific device drivers.
- *
- ****************************************************************************/
+#ifdef CONFIG_NRF52_I2C0_MASTER
+ i2c = nrf52_i2cbus_initialize(0);
+ if (i2c == NULL)
+ {
+ return -ENODEV;
+ }
-#ifdef CONFIG_BOARD_LATE_INITIALIZE
-void board_late_initialize(void)
-{
- /* Perform board-specific initialization */
+ sninfo("INFO: Initializing LMS6DSL accelero-gyro sensor over I2C%d\n", ret);
- (void)nrf52_bringup();
-}
+ ret = lsm6dsl_sensor_register(devpath, i2c, LSM6DSLACCEL_ADDR1);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to initialize LMS6DSL accelero-gyro driver %s\n",
+ devpath);
+ return -ENODEV;
+ }
+
+ sninfo("INFO: LMS6DSL sensor has been initialized successfully\n");
#endif
+
+ return ret;
+}
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c
new file mode 100644
index 0000000..2f66c20
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c
@@ -0,0 +1,206 @@
+/****************************************************************************
+ * boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c
+ *
+ * Copyright (C) 2019 Greg Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * 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 NuttX 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 OWNER 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/spi/spi.h>
+
+#include "up_arch.h"
+#include "chip.h"
+#include "nrf52_gpio.h"
+#include "nrf52_spi.h"
+
+#include "nrf52840-dk.h"
+#include <arch/board/board.h>
+
+#ifdef CONFIG_NRF52_SPI_MASTER
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_spidev_initialize
+ *
+ * Description:
+ * Called to configure SPI chip select GPIO pins for the Nucleo-144 board.
+ *
+ ****************************************************************************/
+
+void nrf52_spidev_initialize(void)
+{
+#ifdef CONFIG_NRF52_SPI0_MASTER
+# ifdef CONFIG_LPWAN_SX127X
+ /* Configure the SPI-based SX127X chip select GPIO */
+
+ spiinfo("Configure GPIO for SX127X SPI1/CS\n");
+
+ nrf52_gpio_config(GPIO_SX127X_CS);
+ nrf52_gpio_write(GPIO_SX127X_CS, true);
+# endif
+#endif
+}
+
+/****************************************************************************
+ * Name: nrf52_spi0/1/2/3/select and nrf52_spi0/1/2/3/status
+ *
+ * Description:
+ * The external functions, nrf52_spi0/1/2/3select and
+ * nrf52_spi0/1/2/3status must be provided by board-specific logic.
+ * They are implementations of the select and status methods of the SPI
+ * interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h).
+ * All other methods (including nrf52_spibus_initialize()) are provided
+ * by common NRF52 logic. To use this common SPI logic on your board:
+ *
+ * 1. Provide logic in nrf52_boardinitialize() to configure SPI chip select
+ * pins.
+ * 2. Provide nrf52_spi0/1/2/3select() and nrf52_spi0/1/2/3status()
+ * functions in your board-specific logic. These functions will perform
+ * chip selection and status operations using GPIOs in the way your
+ * board is configured.
+ * 3. Add a calls to nrf52_spibus_initialize() in your low level application
+ * initialization logic
+ * 4. The handle returned by nrf52_spibus_initialize() may then be used to
+ * bind the SPI driver to higher level logic (e.g., calling
+ * mmcsd_spislotinitialize(), for example, will bind the SPI driver to
+ * the SPI MMC/SD driver).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NRF52_SPI0_MASTER
+void nrf52_spi0select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected)
+{
+ spiinfo("devid: %08lx CS: %s\n",
+ (unsigned long)devid, selected ? "assert" : "de-assert");
+
+ switch (devid)
+ {
+#ifdef CONFIG_LPWAN_SX127X
+ case SPIDEV_LPWAN(0):
+ {
+ spiinfo("SX127X device %s\n",
+ selected ? "asserted" : "de-asserted");
+
+ /* Set the GPIO low to select and high to de-select */
+
+ nrf52_gpio_write(GPIO_SX127X_CS, !selected);
+ break;
+ }
+#endif
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+uint8_t nrf52_spi0status(FAR struct spi_dev_s *dev, uint32_t devid)
+{
+ uint8_t status = 0;
+
+ switch (devid)
+ {
+#ifdef CONFIG_LPWAN_SX127X
+ case SPIDEV_LPWAN(0):
+ {
+ status |= SPI_STATUS_PRESENT;
+ break;
+ }
+#endif
+
+ default:
+ {
+ break;
+ }
+ }
+
+ return status;
+}
+#endif
+
+#ifdef CONFIG_NRF52_SPI1_MASTER
+void nrf52_spi1select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected)
+{
+ spiinfo("devid: %08lx CS: %s\n",
+ (unsigned long)devid, selected ? "assert" : "de-assert");
+}
+
+uint8_t nrf52_spi1status(FAR struct spi_dev_s *dev, uint32_t devid)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_nrf52_SPI2_MASTER
+void nrf52_spi2select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected)
+{
+ spiinfo("devid: %08lx CS: %s\n",
+ (unsigned long)devid, selected ? "assert" : "de-assert");
+}
+
+uint8_t nrf52_spi2status(FAR struct spi_dev_s *dev, uint32_t devid)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_NRF52_SPI3_MASTER
+void nrf52_spi3select(FAR struct spi_dev_s *dev, uint32_t devid,
+ bool selected)
+{
+ spiinfo("devid: %08lx CS: %s\n",
+ (unsigned long)devid, selected ? "assert" : "de-assert");
+}
+
+uint8_t nrf52_spi3status(FAR struct spi_dev_s *dev, uint32_t devid)
+{
+ return 0;
+}
+#endif
+
+#endif /* CONFIG_NRF52_SPI_MASTER */
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c
new file mode 100644
index 0000000..74e695f
--- /dev/null
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c
@@ -0,0 +1,225 @@
+/****************************************************************************
+ * boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c
+ * This logic is specific for the RFM98 modules (433MHz)
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * 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 NuttX 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 OWNER 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/board.h>
+#include <nuttx/signal.h>
+#include <nuttx/wireless/lpwan/sx127x.h>
+#include <arch/board/board.h>
+
+#include "nrf52_gpio.h"
+#include "nrf52_gpiote.h"
+#include "nrf52_spi.h"
+
+#include "nrf52840-dk.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* SX127X on SPI0 bus */
+
+#define SX127X_SPI 0
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void sx127x_chip_reset(void);
+static int sx127x_opmode_change(int opmode);
+static int sx127x_freq_select(uint32_t freq);
+static int sx127x_pa_select(bool enable);
+static int sx127x_irq0_attach(xcpt_t isr, FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct sx127x_lower_s lower =
+{
+ .irq0attach = sx127x_irq0_attach,
+ .reset = sx127x_chip_reset,
+ .opmode_change = sx127x_opmode_change,
+ .freq_select = sx127x_freq_select,
+ .pa_select = sx127x_pa_select,
+ .pa_force = true
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sx127x_irq0_attach
+ ****************************************************************************/
+
+static int sx127x_irq0_attach(xcpt_t isr, FAR void *arg)
+{
+ wlinfo("Attach DIO0 IRQ\n");
+
+ /* IRQ on rising edge */
+
+ nrf52_gpiosetevent(GPIO_SX127X_DIO0, true, false, false, isr, arg);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sx127x_chip_reset
+ ****************************************************************************/
+
+static void sx127x_chip_reset(void)
+{
+ wlinfo("SX127X RESET\n");
+
+ /* Configure reset as output */
+
+ nrf52_gpio_config(GPIO_SX127X_RESET | GPIO_OUTPUT | GPIO_VALUE_ZERO);
+
+ /* Set pin to zero */
+
+ nrf52_gpio_write(GPIO_SX127X_RESET, false);
+
+ /* Wait 1 ms */
+
+ nxsig_usleep(1000);
+
+ /* Configure reset as input */
+
+ nrf52_gpio_config(GPIO_SX127X_RESET | GPIO_INPUT | GPIO_FLOAT);
+
+ /* Wait 10 ms */
+
+ nxsig_usleep(10000);
+}
+
+/****************************************************************************
+ * Name: sx127x_opmode_change
+ ****************************************************************************/
+
+static int sx127x_opmode_change(int opmode)
+{
+ /* Do nothing */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sx127x_freq_select
+ ****************************************************************************/
+
+static int sx127x_freq_select(uint32_t freq)
+{
+ int ret = OK;
+
+ /* NOTE: this depends on your module version */
+
+ if (freq > SX127X_HFBAND_THR)
+ {
+ ret = -EINVAL;
+ wlerr("HF band not supported\n");
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: sx127x_pa_select
+ ****************************************************************************/
+
+static int sx127x_pa_select(bool enable)
+{
+ int ret = OK;
+
+ /* Only PA_BOOST output connected to antenna */
+
+ if (enable == false)
+ {
+ ret = -EINVAL;
+ wlerr("Module supports only PA_BOOST pin,"
+ " so PA_SELECT must be enabled!\n");
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int nrf52_lpwaninitialize(void)
+{
+ FAR struct spi_dev_s *spidev;
+ int ret = OK;
+
+ wlinfo("Register the sx127x module\n");
+
+ /* Setup DIO0 */
+
+ nrf52_gpio_config(GPIO_SX127X_DIO0);
+
+ /* Init SPI bus */
+
+ spidev = nrf52_spibus_initialize(SX127X_SPI);
+ if (!spidev)
+ {
+ wlerr("ERROR: Failed to initialize SPI %d bus\n", SX127X_SPI);
+ ret = -ENODEV;
+ goto errout;
+ }
+
+ /* Initialize SX127X */
+
+ ret = sx127x_register(spidev, &lower);
+ if (ret < 0)
+ {
+ wlerr("ERROR: Failed to register sx127x\n");
+ goto errout;
+ }
+
+errout:
+ return ret;
+}
diff --git a/boards/arm/nrf52/nrf52840-dongle/include/board.h b/boards/arm/nrf52/nrf52840-dongle/include/board.h
index ebf2d34..105223f 100644
--- a/boards/arm/nrf52/nrf52840-dongle/include/board.h
+++ b/boards/arm/nrf52/nrf52840-dongle/include/board.h
@@ -43,7 +43,7 @@
#include <nuttx/config.h>
#include <stdbool.h>
-#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ)
+#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE)
# include <nuttx/irq.h>
#endif