From f51e478ad857f7a1f2efd72b6a0524cb7e8b9856 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 8 Jan 2020 15:48:20 +0100 Subject: [PATCH] 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 +++++ arch/arm/src/nrf52/nrf52_gpiote.h | 89 ++ 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 +++ .../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 + .../arm/nrf52/nrf52840-dk/src/nrf52840-dk.h | 46 + boards/arm/nrf52/nrf52840-dk/src/nrf52_boot.c | 6 + .../arm/nrf52/nrf52840-dk/src/nrf52_bringup.c | 78 +- .../arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c | 97 ++ boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c | 206 ++++ .../arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c | 225 ++++ .../arm/nrf52/nrf52840-dongle/include/board.h | 2 +- 29 files changed, 2335 insertions(+), 141 deletions(-) create mode 100644 arch/arm/src/nrf52/nrf52_gpiote.c create mode 100644 arch/arm/src/nrf52/nrf52_gpiote.h create mode 100644 arch/arm/src/nrf52/nrf52_spi.c create mode 100644 arch/arm/src/nrf52/nrf52_spi.h create mode 100644 boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c create mode 100644 boards/arm/nrf52/nrf52840-dk/src/nrf52_spi.c create mode 100644 boards/arm/nrf52/nrf52840-dk/src/nrf52_sx127x.c diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig index b7024cde83..2c92c39b05 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 58ff7d6872..e33aeed523 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 118e2f9d54..47a77515f4 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 fe7528daf4..b313d5dbf9 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 3673c1629f..a7419436f4 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 8b554ab1be..1972d003c6 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 e17d70689c..219ed20dc3 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 3a0e05cc0f..3d5a6e9eaa 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 c5f29d0304..2ccc1ef5e8 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 612d0af7de..e03810d8a6 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 ************************************************************************************/ @@ -200,21 +205,6 @@ extern "C" * Public Functions ************************************************************************************/ -/************************************************************************************ - * 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 * @@ -235,47 +225,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 * diff --git a/arch/arm/src/nrf52/nrf52_gpiote.c b/arch/arm/src/nrf52/nrf52_gpiote.c new file mode 100644 index 0000000000..34817111fd --- /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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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/arch/arm/src/nrf52/nrf52_gpiote.h b/arch/arm/src/nrf52/nrf52_gpiote.h new file mode 100644 index 0000000000..3b1e162f72 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_gpiote.h @@ -0,0 +1,89 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_gpiote.h + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * 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_GPIOTE_H +#define __ARCH_ARM_SRC_NRF52_NRF52_GPIOTE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_gpiosetevent + * + * Description: + * 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. + * + ****************************************************************************/ + +int nrf52_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, + bool event, xcpt_t func, FAR void *arg); + +/**************************************************************************** + * Name: nrf52_gpiote_init + * + * Description: + * Initialize GPIOTE + * + ****************************************************************************/ + +int nrf52_gpiote_init(void); + +#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 258917ab20..dd64971bfc 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 384e7c552a..f80cd9d0f7 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 68f7600798..212d1ab849 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 aac31d9f99..d587c3d8b1 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 @@ -46,9 +46,9 @@ #include #include -/************************************************************************************ +/**************************************************************************** * 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 0000000000..9b67e84115 --- /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 + * + * 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 + +#include +#include + +#include +#include +#include +#include + +#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 0000000000..c87e7dbf26 --- /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 + * + * 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 +#include + +#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 b50587b0f0..6a69b9a35a 100644 --- a/boards/arm/nrf52/nrf52-feather/include/board.h +++ b/boards/arm/nrf52/nrf52-feather/include/board.h @@ -43,7 +43,7 @@ #include #include -#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ) +#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE) # include #endif diff --git a/boards/arm/nrf52/nrf52832-dk/include/board.h b/boards/arm/nrf52/nrf52832-dk/include/board.h index 6488aba2b6..2031729365 100644 --- a/boards/arm/nrf52/nrf52832-dk/include/board.h +++ b/boards/arm/nrf52/nrf52832-dk/include/board.h @@ -43,7 +43,7 @@ #include #include -#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ) +#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE) # include #endif diff --git a/boards/arm/nrf52/nrf52840-dk/include/board.h b/boards/arm/nrf52/nrf52840-dk/include/board.h index b207d04162..6916d3b1f5 100644 --- a/boards/arm/nrf52/nrf52840-dk/include/board.h +++ b/boards/arm/nrf52/nrf52840-dk/include/board.h @@ -43,7 +43,7 @@ #include #include -#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ) +#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE) # include #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 b99bdec9f1..53dd1d7ff5 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 9744b8cea5..c209e1bb05 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 af1dca26c1..1e8bad17a7 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 a5604a924d..732efa2d5c 100644 --- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c +++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c @@ -46,10 +46,64 @@ # include #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 * @@ -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_lsm6dsl.c b/boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c new file mode 100644 index 0000000000..7185662202 --- /dev/null +++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c @@ -0,0 +1,97 @@ +/***************************************************************************** + * boards/arm/nrf52/nrf52840-dk/src/nrf52_lsm6dsl.c + * + * Copyright (C) 2019 Greg Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * 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 +#include + +#include +#include + +#include +#include "nrf52_i2c.h" +#include "nrf52840-dk.h" +#include + +/***************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_NRF52_I2C0_MASTER +# error "LSM6DSL driver requires CONFIG_NRF52_I2C0_MASTER to be enabled" +#endif + +/***************************************************************************** + * Public Functions + ****************************************************************************/ + +/***************************************************************************** + * Name: nrf52_lsm6dsl_initialize + * + * Description: + * Initialize I2C-based LSM6DSL. + ****************************************************************************/ + +int nrf52_lsm6dsl_initialize(char *devpath) +{ + FAR struct i2c_master_s *i2c; + int ret = OK; + + sninfo("Initializing LMS6DSL!\n"); + +#ifdef CONFIG_NRF52_I2C0_MASTER + i2c = nrf52_i2cbus_initialize(0); + if (i2c == NULL) + { + return -ENODEV; + } + + sninfo("INFO: Initializing LMS6DSL accelero-gyro sensor over I2C%d\n", ret); + + 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 0000000000..2f66c20318 --- /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 + * + * 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 + +#include +#include +#include +#include + +#include + +#include "up_arch.h" +#include "chip.h" +#include "nrf52_gpio.h" +#include "nrf52_spi.h" + +#include "nrf52840-dk.h" +#include + +#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 0000000000..74e695ff9d --- /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 + * + * 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 ebf2d348fb..105223fdc5 100644 --- a/boards/arm/nrf52/nrf52840-dongle/include/board.h +++ b/boards/arm/nrf52/nrf52840-dongle/include/board.h @@ -43,7 +43,7 @@ #include #include -#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIO_IRQ) +#if defined(CONFIG_ARCH_IRQBUTTONS) && defined(CONFIG_NRF52_GPIOTE) # include #endif