You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/09/07 05:25:48 UTC

incubator-mynewt-core git commit: MYNEWT-3: Add HAL SPI for nrf51. Fix nr52 hal spi bug when using non-blocking API

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/sterly_refactor e0864b5e8 -> aab7b2a25


MYNEWT-3: Add HAL SPI for nrf51. Fix nr52 hal spi bug when using non-blocking API


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/aab7b2a2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/aab7b2a2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/aab7b2a2

Branch: refs/heads/sterly_refactor
Commit: aab7b2a25bc6d42391603606fa26461c595f9a95
Parents: e0864b5
Author: William San Filippo <wi...@runtime.io>
Authored: Tue Sep 6 22:19:25 2016 -0700
Committer: William San Filippo <wi...@runtime.io>
Committed: Tue Sep 6 22:19:25 2016 -0700

----------------------------------------------------------------------
 apps/sblinky/src/main.c                         |  52 +-
 hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h  |   2 +-
 .../include/bsp/nrf_drv_config.h                |  18 +-
 hw/bsp/nrf51dk-16kbram/src/os_bsp.c             |  35 +-
 hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h     |  18 +-
 hw/bsp/nrf51dk/src/os_bsp.c                     |  35 +-
 hw/hal/include/hal/hal_spi.h                    |  15 +-
 hw/mcu/nordic/nrf51xxx/src/hal_spi.c            | 974 +++++++++++++++++++
 hw/mcu/nordic/nrf52xxx/src/hal_spi.c            |  57 +-
 9 files changed, 1145 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/apps/sblinky/src/main.c
----------------------------------------------------------------------
diff --git a/apps/sblinky/src/main.c b/apps/sblinky/src/main.c
index fb2c697..aff72eb 100755
--- a/apps/sblinky/src/main.c
+++ b/apps/sblinky/src/main.c
@@ -48,7 +48,9 @@ nrf_drv_adc_channel_t g_nrf_adc_chan =
 #include <adc_nrf52/adc_nrf52.h>
 #include "nrf_drv_saadc.h"
 nrf_drv_saadc_config_t adc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
+#endif
 
+#if defined(NRF52) || defined(NRF51)
 /* The spi txrx callback */
 struct sblinky_spi_cb_arg
 {
@@ -124,7 +126,7 @@ sblinky_spi_irqm_handler(void *arg, int len)
     }
 }
 
-#if 0
+#if 1
 static void
 sblinky_spi_tx_vals(int spi_num, uint8_t *buf, int len)
 {
@@ -147,6 +149,13 @@ sblinky_spi_tx_vals(int spi_num, uint8_t *buf, int len)
 uint8_t g_spi_tx_buf[32];
 uint8_t g_spi_rx_buf[32];
 
+/* XXX: This is an ugly hack for now. */
+#ifdef NRF51
+#define SPI_SLAVE_ID    (1)
+#else
+#define SPI_SLAVE_ID    (0)
+#endif
+
 void
 sblinky_spi_irqs_handler(void *arg, int len)
 {
@@ -167,6 +176,7 @@ sblinky_spi_irqs_handler(void *arg, int len)
 void
 sblinky_spi_cfg(int spi_num)
 {
+    int spi_id;
     struct hal_spi_settings my_spi;
 
 #ifdef BSP_CFG_SPI_MASTER
@@ -177,6 +187,7 @@ sblinky_spi_cfg(int spi_num)
     my_spi.word_size = HAL_SPI_WORD_SIZE_8BIT;
     my_spi.txrx_cb_func = NULL;
     my_spi.txrx_cb_arg = NULL;
+    spi_id = 0;
 #endif
 
 #ifdef BSP_CFG_SPI_SLAVE
@@ -187,8 +198,9 @@ sblinky_spi_cfg(int spi_num)
     my_spi.word_size = HAL_SPI_WORD_SIZE_8BIT;
     my_spi.txrx_cb_func = sblinky_spi_irqs_handler;
     my_spi.txrx_cb_arg = spi_cb_arg;
+    spi_id = SPI_SLAVE_ID;
 #endif
-    hal_spi_config(0, &my_spi);
+    hal_spi_config(spi_id, &my_spi);
 }
 
 struct adc_dev my_dev;
@@ -299,31 +311,31 @@ task1_handler(void *arg)
     sblinky_spi_cfg(0);
     hal_spi_enable(0);
 
-#if 0
+#if 1
     /* Send some bytes in a non-blocking manner to SPI using tx val */
-    spi_tx_buf[0] = 0xde;
-    spi_tx_buf[1] = 0xad;
-    spi_tx_buf[2] = 0xbe;
-    spi_tx_buf[3] = 0xef;
-    sblinky_spi_tx_vals(0, spi_tx_buf, 4);
+    g_spi_tx_buf[0] = 0xde;
+    g_spi_tx_buf[1] = 0xad;
+    g_spi_tx_buf[2] = 0xbe;
+    g_spi_tx_buf[3] = 0xef;
+    sblinky_spi_tx_vals(0, g_spi_tx_buf, 4);
 
     /* Send blocking with txrx interface */
     for (i = 0; i < 32; ++i) {
-        spi_tx_buf[i] = i + 1;
+        g_spi_tx_buf[i] = i + 1;
     }
-    memset(spi_rx_buf, 0x55, 32);
-    rc = hal_spi_txrx(0, spi_tx_buf, spi_rx_buf, 32);
+    memset(g_spi_rx_buf, 0x55, 32);
+    rc = hal_spi_txrx(0, g_spi_tx_buf, g_spi_rx_buf, 32);
     assert(!rc);
 
     /* Now send with no rx buf and make sure it dont change! */
     for (i = 0; i < 32; ++i) {
-        spi_tx_buf[i] = (uint8_t)(i + 32);
+        g_spi_tx_buf[i] = (uint8_t)(i + 32);
     }
-    memset(spi_rx_buf, 0xAA, 32);
-    rc = hal_spi_txrx(0, spi_tx_buf, NULL, 32);
+    memset(g_spi_rx_buf, 0xAA, 32);
+    rc = hal_spi_txrx(0, g_spi_tx_buf, NULL, 32);
     assert(!rc);
     for (i = 0; i < 32; ++i) {
-        if (spi_rx_buf[i] != 0xAA) {
+        if (g_spi_rx_buf[i] != 0xAA) {
             assert(0);
         }
     }
@@ -338,15 +350,15 @@ task1_handler(void *arg)
 #endif
 
 #ifdef BSP_CFG_SPI_SLAVE
-    sblinky_spi_cfg(0);
-    hal_spi_enable(0);
+    sblinky_spi_cfg(SPI_SLAVE_ID);
+    hal_spi_enable(SPI_SLAVE_ID);
 
     /* Make the default character 0xAA */
-    hal_spi_slave_set_def_tx_val(0, 0xAA);
+    hal_spi_slave_set_def_tx_val(SPI_SLAVE_ID, 0xAA);
 
     /* Setup a buffer to receive into */
     memset(g_spi_tx_buf, 0xEE, 32);
-    rc = hal_spi_txrx(0, g_spi_tx_buf, g_spi_rx_buf, 32);
+    rc = hal_spi_txrx(SPI_SLAVE_ID, g_spi_tx_buf, g_spi_rx_buf, 32);
     assert(rc == 0);
 #endif
 
@@ -425,7 +437,7 @@ task2_handler(void *arg)
 #ifdef BSP_CFG_SPI_SLAVE
         /* transmit back what we just received */
         memcpy(g_spi_tx_buf, g_spi_rx_buf, 32);
-        rc = hal_spi_txrx(0, g_spi_tx_buf, g_spi_rx_buf, 32);
+        rc = hal_spi_txrx(SPI_SLAVE_ID, g_spi_tx_buf, g_spi_rx_buf, 32);
         assert(rc == 0);
 #endif
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h
----------------------------------------------------------------------
diff --git a/hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h b/hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h
index b3fc35a..173193a 100644
--- a/hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h
+++ b/hw/bsp/bmd300eval/include/bsp/nrf_drv_config.h
@@ -208,7 +208,7 @@
 
 #if (SPI0_ENABLED == 1)
 #define SPI0_USE_EASY_DMA 1
-
+#define SPI0_CONFIG_CSN_PIN         22 /* Note: not defined by SDK */
 #define SPI0_CONFIG_SCK_PIN         23
 #define SPI0_CONFIG_MOSI_PIN        24
 #define SPI0_CONFIG_MISO_PIN        25

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/bsp/nrf51dk-16kbram/include/bsp/nrf_drv_config.h
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf51dk-16kbram/include/bsp/nrf_drv_config.h b/hw/bsp/nrf51dk-16kbram/include/bsp/nrf_drv_config.h
index d178ec0..f97fb5c 100644
--- a/hw/bsp/nrf51dk-16kbram/include/bsp/nrf_drv_config.h
+++ b/hw/bsp/nrf51dk-16kbram/include/bsp/nrf_drv_config.h
@@ -208,10 +208,11 @@
 
 #if (SPI0_ENABLED == 1)
 #define SPI0_USE_EASY_DMA 0
-
-#define SPI0_CONFIG_SCK_PIN         2
-#define SPI0_CONFIG_MOSI_PIN        3
-#define SPI0_CONFIG_MISO_PIN        4
+/* NOTE: SCK definitions match NRF51 DK product brief */
+#define SPI0_CONFIG_CSN_PIN         24 /* Note: not defined by SDK */
+#define SPI0_CONFIG_SCK_PIN         29
+#define SPI0_CONFIG_MOSI_PIN        25
+#define SPI0_CONFIG_MISO_PIN        28
 #define SPI0_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
 
 #define SPI0_INSTANCE_INDEX 0
@@ -257,12 +258,13 @@
 #define SPIS0_INSTANCE_INDEX 0
 #endif
 
-#define SPIS1_ENABLED 0
+#define SPIS1_ENABLED 1
 
 #if (SPIS1_ENABLED == 1)
-#define SPIS1_CONFIG_SCK_PIN         2
-#define SPIS1_CONFIG_MOSI_PIN        3
-#define SPIS1_CONFIG_MISO_PIN        4
+#define SPIS1_CONFIG_CSN_PIN         24 /* Note: not defined by SDK */
+#define SPIS1_CONFIG_SCK_PIN         29
+#define SPIS1_CONFIG_MOSI_PIN        25
+#define SPIS1_CONFIG_MISO_PIN        28
 #define SPIS1_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
 
 #define SPIS1_INSTANCE_INDEX SPIS0_ENABLED

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/bsp/nrf51dk-16kbram/src/os_bsp.c
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf51dk-16kbram/src/os_bsp.c b/hw/bsp/nrf51dk-16kbram/src/os_bsp.c
index 4cef8f8..3602224 100644
--- a/hw/bsp/nrf51dk-16kbram/src/os_bsp.c
+++ b/hw/bsp/nrf51dk-16kbram/src/os_bsp.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -16,8 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#include <assert.h>
 #include <hal/flash_map.h>
 #include <hal/hal_bsp.h>
+#include <hal/hal_spi.h>
+#ifdef BSP_CFG_SPI_MASTER
+#include "nrf_drv_spi.h"
+#endif
+#ifdef BSP_CFG_SPI_SLAVE
+#include "nrf_drv_spis.h"
+#endif
+#include "nrf_drv_config.h"
+#include <app_util_platform.h>
 
 static struct flash_area bsp_flash_areas[] = {
     [FLASH_AREA_BOOTLOADER] = {
@@ -67,6 +77,15 @@ bsp_imgr_current_slot(void)
 void
 bsp_init(void)
 {
+#ifdef BSP_CFG_SPI_MASTER
+    int rc;
+    nrf_drv_spi_config_t spi_cfg = NRF_DRV_SPI_DEFAULT_CONFIG(0);
+#endif
+#ifdef BSP_CFG_SPI_SLAVE
+    int rc;
+    nrf_drv_spis_config_t spi_cfg = NRF_DRV_SPIS_DEFAULT_CONFIG(1);
+#endif
+
     /*
      * XXX this reference is here to keep this function in.
      */
@@ -77,4 +96,18 @@ bsp_init(void)
       sizeof(bsp_flash_areas) / sizeof(bsp_flash_areas[0]));
 
     bsp_hal_init();
+
+#ifdef BSP_CFG_SPI_MASTER
+    /*  We initialize one SPI interface as a master. */
+    rc = hal_spi_init(0, &spi_cfg, HAL_SPI_TYPE_MASTER);
+    assert(rc == 0);
+#endif
+
+#ifdef BSP_CFG_SPI_SLAVE
+    /*  We initialize one SPI interface as a master. */
+    spi_cfg.csn_pin = SPIS1_CONFIG_CSN_PIN;
+    spi_cfg.csn_pullup = NRF_GPIO_PIN_PULLUP;
+    rc = hal_spi_init(1, &spi_cfg, HAL_SPI_TYPE_SLAVE);
+    assert(rc == 0);
+#endif
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h b/hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h
index d178ec0..f97fb5c 100644
--- a/hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h
+++ b/hw/bsp/nrf51dk/include/bsp/nrf_drv_config.h
@@ -208,10 +208,11 @@
 
 #if (SPI0_ENABLED == 1)
 #define SPI0_USE_EASY_DMA 0
-
-#define SPI0_CONFIG_SCK_PIN         2
-#define SPI0_CONFIG_MOSI_PIN        3
-#define SPI0_CONFIG_MISO_PIN        4
+/* NOTE: SCK definitions match NRF51 DK product brief */
+#define SPI0_CONFIG_CSN_PIN         24 /* Note: not defined by SDK */
+#define SPI0_CONFIG_SCK_PIN         29
+#define SPI0_CONFIG_MOSI_PIN        25
+#define SPI0_CONFIG_MISO_PIN        28
 #define SPI0_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
 
 #define SPI0_INSTANCE_INDEX 0
@@ -257,12 +258,13 @@
 #define SPIS0_INSTANCE_INDEX 0
 #endif
 
-#define SPIS1_ENABLED 0
+#define SPIS1_ENABLED 1
 
 #if (SPIS1_ENABLED == 1)
-#define SPIS1_CONFIG_SCK_PIN         2
-#define SPIS1_CONFIG_MOSI_PIN        3
-#define SPIS1_CONFIG_MISO_PIN        4
+#define SPIS1_CONFIG_CSN_PIN         24 /* Note: not defined by SDK */
+#define SPIS1_CONFIG_SCK_PIN         29
+#define SPIS1_CONFIG_MOSI_PIN        25
+#define SPIS1_CONFIG_MISO_PIN        28
 #define SPIS1_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
 
 #define SPIS1_INSTANCE_INDEX SPIS0_ENABLED

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/bsp/nrf51dk/src/os_bsp.c
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf51dk/src/os_bsp.c b/hw/bsp/nrf51dk/src/os_bsp.c
index ffa5b51..6d0800d 100644
--- a/hw/bsp/nrf51dk/src/os_bsp.c
+++ b/hw/bsp/nrf51dk/src/os_bsp.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -16,8 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#include <assert.h>
 #include <hal/flash_map.h>
 #include <hal/hal_bsp.h>
+#include <hal/hal_spi.h>
+#ifdef BSP_CFG_SPI_MASTER
+#include "nrf_drv_spi.h"
+#endif
+#ifdef BSP_CFG_SPI_SLAVE
+#include "nrf_drv_spis.h"
+#endif
+#include "nrf_drv_config.h"
+#include <app_util_platform.h>
 
 static struct flash_area bsp_flash_areas[] = {
     [FLASH_AREA_BOOTLOADER] = {
@@ -67,6 +77,15 @@ bsp_imgr_current_slot(void)
 void
 bsp_init(void)
 {
+#ifdef BSP_CFG_SPI_MASTER
+    int rc;
+    nrf_drv_spi_config_t spi_cfg = NRF_DRV_SPI_DEFAULT_CONFIG(0);
+#endif
+#ifdef BSP_CFG_SPI_SLAVE
+    int rc;
+    nrf_drv_spis_config_t spi_cfg = NRF_DRV_SPIS_DEFAULT_CONFIG(1);
+#endif
+
     /*
      * XXX this reference is here to keep this function in.
      */
@@ -77,4 +96,18 @@ bsp_init(void)
       sizeof(bsp_flash_areas) / sizeof(bsp_flash_areas[0]));
 
     bsp_hal_init();
+
+#ifdef BSP_CFG_SPI_MASTER
+    /*  We initialize one SPI interface as a master. */
+    rc = hal_spi_init(0, &spi_cfg, HAL_SPI_TYPE_MASTER);
+    assert(rc == 0);
+#endif
+
+#ifdef BSP_CFG_SPI_SLAVE
+    /*  We initialize one SPI interface as a master. */
+    spi_cfg.csn_pin = SPIS1_CONFIG_CSN_PIN;
+    spi_cfg.csn_pullup = NRF_GPIO_PIN_PULLUP;
+    rc = hal_spi_init(1, &spi_cfg, HAL_SPI_TYPE_SLAVE);
+    assert(rc == 0);
+#endif
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/hal/include/hal/hal_spi.h
----------------------------------------------------------------------
diff --git a/hw/hal/include/hal/hal_spi.h b/hw/hal/include/hal/hal_spi.h
index a064b63..09d0f18 100644
--- a/hw/hal/include/hal/hal_spi.h
+++ b/hw/hal/include/hal/hal_spi.h
@@ -135,18 +135,19 @@ int hal_spi_disable(int spi_num);
 uint16_t hal_spi_tx_val(int spi_num, uint16_t val);
 
 /**
- * Non-blocking call to send a buffer and also store the received values.
- * For both the master and slave, the txrx callback is executed at interrupt
- * context when the buffer is sent.
+ * Sends a buffer and also stores the received values. This is always a
+ * non-blocking call for a spi slave. It is a blocking call if the callback is
+ * NULL; non-blocking if callback is set. For both the master and slave, the
+ * txrx callback is executed at interrupt context when the buffer is sent.
  *     MASTER: master sends all the values in the buffer and stores the
  *             stores the values in the receive buffer if rxbuf is not NULL.
  *             The txbuf parameter cannot be NULL
  *     SLAVE: Slave preloads the data to be sent to the master (values
  *            stored in txbuf) and places received data from master in rxbuf (if
- *            not NULL). No callback per received value; txrx callback when len
- *            values are transferred or master de-asserts chip select. If
- *            txbuf is NULL, the slave transfers its default byte. Both rxbuf
- *            and txbuf cannot be NULL.
+ *            not NULL). The txrx callback occurs when len values are
+ *            transferred or master de-asserts chip select. If txbuf is NULL,
+ *            the slave transfers its default byte. Both rxbuf and txbuf cannot
+ *            be NULL.
  *
  * @param spi_num   SPI interface to use
  * @param txbuf     Pointer to buffer where values to transmit are stored.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/mcu/nordic/nrf51xxx/src/hal_spi.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf51xxx/src/hal_spi.c b/hw/mcu/nordic/nrf51xxx/src/hal_spi.c
new file mode 100644
index 0000000..6ac5083
--- /dev/null
+++ b/hw/mcu/nordic/nrf51xxx/src/hal_spi.c
@@ -0,0 +1,974 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <hal/hal_spi.h>
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <hal/hal_spi.h>
+#include <bsp/cmsis_nvic.h>
+#include <nrf.h>
+#include <nrf_spi.h>
+#include <nrf_spis.h>
+#include <nrf_drv_spi.h>
+#include <nrf_drv_spis.h>
+#include <nrf_drv_common.h>
+#include <app_util_platform.h>
+
+/* XXX:
+ * 1) what about stats?
+ * 2) Dealing with errors (OVERFLOW, OVERREAD)
+ * 3) Dont think I need dummy_rx as I can set master RX maxcnt to zero.
+ */
+
+/* The maximum number of SPI interfaces we will allow */
+#define NRF51_HAL_SPI_MAX (2)
+
+/* Used to disable all interrupts */
+#define NRF_SPI_IRQ_DISABLE_ALL 0xFFFFFFFF
+
+/*
+ *  Slave states
+ *
+ *  IDLE: Slave not ready to be used. If master attempts to access
+ *        slave it will receive the default character
+ *  ACQ_SEM: Slave is attempting to acquire semaphore.
+ *  READY: Slave is ready for master to send it data
+ *
+ */
+#define HAL_SPI_SLAVE_STATE_IDLE        (0)
+#define HAL_SPI_SLAVE_STATE_ACQ_SEM     (1)
+#define HAL_SPI_SLAVE_STATE_READY       (2)
+
+struct nrf51_hal_spi {
+    uint8_t spi_xfr_flag;   /* Master only */
+    uint8_t slave_state;    /* Slave only */
+    uint16_t nhs_buflen;
+    uint16_t nhs_rxd_bytes;
+    uint16_t nhs_txd_bytes;
+    struct hal_spi_settings spi_cfg; /* Slave and master */
+    union {
+        nrf_drv_spi_t   spim;
+        nrf_drv_spis_t  spis;
+    } nhs_spi;
+
+    uint8_t *nhs_txbuf;
+    uint8_t *nhs_rxbuf;
+};
+
+#if SPI0_ENABLED
+struct nrf51_hal_spi nrf51_hal_spi0;
+#endif
+#if SPI1_ENABLED || SPIS1_ENABLED
+struct nrf51_hal_spi nrf51_hal_spi1;
+#endif
+
+struct nrf51_hal_spi *nrf51_hal_spis[NRF51_HAL_SPI_MAX] = {
+#if SPI0_ENABLED
+    &nrf51_hal_spi0,
+#else
+    NULL,
+#endif
+#if SPI1_ENABLED || SPIS1_ENABLED
+    &nrf51_hal_spi1
+#else
+    NULL
+#endif
+};
+
+#if SPI0_ENABLED
+nrf_drv_spi_t inst_spi0_m = NRF_DRV_SPI_INSTANCE(0);
+#endif
+#if SPI1_ENABLED
+nrf_drv_spi_t inst_spi1_m = NRF_DRV_SPI_INSTANCE(1);
+#endif
+#if SPIS1_ENABLED
+nrf_drv_spis_t inst_spi1_s = NRF_DRV_SPIS_INSTANCE(1);
+#endif
+
+#define NRF51_HAL_SPI_RESOLVE(__n, __v)         \
+    if ((__n) >= NRF51_HAL_SPI_MAX) {           \
+        rc = EINVAL;                            \
+        goto err;                               \
+    }                                           \
+    (__v) = nrf51_hal_spis[(__n)];              \
+    if ((__v) == NULL) {                        \
+        rc = EINVAL;                            \
+        goto err;                               \
+    }
+
+#if (SPI0_ENABLED || SPI1_ENABLED)
+static void
+nrf51_irqm_handler(struct nrf51_hal_spi *spi)
+{
+    NRF_SPI_Type *p_spi;
+
+    /* XXX: what if not in a transfer? */
+
+    p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+    if (nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {
+        nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+        if (spi->nhs_rxbuf) {
+            spi->nhs_rxbuf[spi->nhs_rxd_bytes] = nrf_spi_rxd_get(p_spi);
+        }
+        ++spi->nhs_rxd_bytes;
+        if (spi->nhs_rxd_bytes == spi->nhs_buflen) {
+            if (spi->spi_cfg.txrx_cb_func) {
+                spi->spi_cfg.txrx_cb_func(spi->spi_cfg.txrx_cb_arg,
+                                          spi->nhs_buflen);
+            }
+            spi->spi_xfr_flag = 0;
+        }
+        if (spi->nhs_txd_bytes != spi->nhs_buflen) {
+            nrf_spi_txd_set(p_spi, spi->nhs_txbuf[spi->nhs_txd_bytes]);
+            ++spi->nhs_txd_bytes;
+        }
+    }
+}
+#endif
+
+#if (SPIS1_ENABLED)
+static void
+nrf51_irqs_handler(struct nrf51_hal_spi *spi)
+{
+    uint8_t xfr_len;
+    NRF_SPIS_Type *p_spis;
+
+    p_spis = spi->nhs_spi.spis.p_reg;
+
+    /* Semaphore acquired event */
+    if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ACQUIRED)) {
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
+
+        if (spi->slave_state == HAL_SPI_SLAVE_STATE_ACQ_SEM) {
+            if (spi->nhs_txbuf == NULL) {
+                nrf_spis_tx_buffer_set(p_spis, 0, 0);
+            } else {
+                nrf_spis_tx_buffer_set(p_spis, spi->nhs_txbuf, spi->nhs_buflen);
+            }
+
+            if (spi->nhs_rxbuf == NULL) {
+                nrf_spis_rx_buffer_set(p_spis, 0, 0);
+            } else {
+                nrf_spis_rx_buffer_set(p_spis, spi->nhs_rxbuf, spi->nhs_buflen);
+            }
+            nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_RELEASE);
+            spi->slave_state = HAL_SPI_SLAVE_STATE_READY;
+        }
+    }
+
+    /* SPI transaction complete */
+    if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_END)) {
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
+        if (spi->slave_state == HAL_SPI_SLAVE_STATE_READY) {
+            if (spi->spi_cfg.txrx_cb_func) {
+                /* Get transfer length */
+                if (spi->nhs_txbuf == NULL) {
+                    xfr_len = nrf_spis_rx_amount_get(p_spis);
+                } else {
+                    xfr_len = nrf_spis_tx_amount_get(p_spis);
+                }
+                spi->spi_cfg.txrx_cb_func(spi->spi_cfg.txrx_cb_arg, xfr_len);
+            }
+            spi->slave_state = HAL_SPI_SLAVE_STATE_IDLE;
+        }
+    }
+
+}
+#endif
+
+/* Interrupt handlers for SPI ports */
+#if SPI0_ENABLED
+void
+nrf51_spi0_irq_handler(void)
+{
+    if (nrf51_hal_spi0.spi_cfg.spi_type == HAL_SPI_TYPE_MASTER) {
+        nrf51_irqm_handler(&nrf51_hal_spi0);
+    } else {
+        assert(0);
+    }
+}
+#endif
+
+#if SPI1_ENABLED || SPIS1_ENABLED
+void
+nrf51_spi1_irq_handler(void)
+{
+    if (nrf51_hal_spi1.spi_cfg.spi_type == HAL_SPI_TYPE_MASTER) {
+#if SPI1_ENABLED
+        nrf51_irqm_handler(&nrf51_hal_spi1);
+#else
+        assert(0);
+#endif
+    } else {
+#if SPIS1_ENABLED
+        nrf51_irqs_handler(&nrf51_hal_spi1);
+#else
+        assert(0);
+#endif
+    }
+}
+#endif
+
+static int
+hal_spi_config_master(struct nrf51_hal_spi *spi,
+                      struct hal_spi_settings *settings)
+{
+    int rc;
+    NRF_SPI_Type *p_spi;
+    nrf_spi_frequency_t frequency;
+    nrf_spi_mode_t spi_mode;
+    nrf_spi_bit_order_t bit_order;
+
+    p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+    memcpy(&spi->spi_cfg, settings, sizeof(*settings));
+
+    /* Only 8-bit word sizes supported. */
+    switch (settings->word_size) {
+        case HAL_SPI_WORD_SIZE_8BIT:
+            break;
+        default:
+            rc = EINVAL;
+            goto err;
+    }
+
+    switch (settings->data_mode) {
+        case HAL_SPI_MODE0:
+            spi_mode = NRF_SPI_MODE_0;
+            break;
+        case HAL_SPI_MODE1:
+            spi_mode = NRF_SPI_MODE_1;
+            break;
+        case HAL_SPI_MODE2:
+            spi_mode = NRF_SPI_MODE_2;
+            break;
+        case HAL_SPI_MODE3:
+            spi_mode = NRF_SPI_MODE_3;
+            break;
+        default:
+            spi_mode = 0;
+            break;
+    }
+
+    switch (settings->data_order) {
+        case HAL_SPI_MSB_FIRST:
+            bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST;
+            break;
+        case HAL_SPI_LSB_FIRST:
+            bit_order = NRF_SPI_BIT_ORDER_LSB_FIRST;
+            break;
+        default:
+            bit_order = 0;
+            break;
+    }
+    nrf_spi_configure(p_spi, spi_mode, bit_order);
+
+    switch (settings->baudrate) {
+        case 125:
+            frequency = NRF_SPI_FREQ_125K;
+            break;
+        case 250:
+            frequency = NRF_SPI_FREQ_250K;
+            break;
+        case 500:
+            frequency = NRF_SPI_FREQ_500K;
+            break;
+        case 1000:
+            frequency = NRF_SPI_FREQ_1M;
+            break;
+        case 2000:
+            frequency = NRF_SPI_FREQ_2M;
+            break;
+        case 4000:
+            frequency = NRF_SPI_FREQ_4M;
+            break;
+        case 8000:
+            frequency = NRF_SPI_FREQ_8M;
+            break;
+        default:
+            rc = EINVAL;
+            goto err;
+    }
+    nrf_spi_frequency_set(p_spi, frequency);
+
+    return (0);
+err:
+    return (rc);
+}
+
+static int
+hal_spi_config_slave(struct nrf51_hal_spi *spi,
+                     struct hal_spi_settings *settings)
+{
+    int rc;
+    NRF_SPIS_Type *p_spis;
+    nrf_spis_mode_t spi_mode;
+    nrf_spis_bit_order_t bit_order;
+
+    p_spis = spi->nhs_spi.spis.p_reg;
+
+    spi_mode = 0;
+    switch (settings->data_mode) {
+        case HAL_SPI_MODE0:
+            spi_mode = NRF_SPIS_MODE_0;
+            break;
+        case HAL_SPI_MODE1:
+            spi_mode = NRF_SPIS_MODE_1;
+            break;
+        case HAL_SPI_MODE2:
+            spi_mode = NRF_SPIS_MODE_2;
+            break;
+        case HAL_SPI_MODE3:
+            spi_mode = NRF_SPIS_MODE_3;
+            break;
+    }
+
+    bit_order = 0;
+    switch (settings->data_order) {
+        case HAL_SPI_MSB_FIRST:
+            bit_order = NRF_SPIS_BIT_ORDER_MSB_FIRST;
+            break;
+        case HAL_SPI_LSB_FIRST:
+            bit_order = NRF_SPIS_BIT_ORDER_LSB_FIRST;
+            break;
+    }
+    nrf_spis_configure(p_spis, spi_mode, bit_order);
+
+    /* Only 8-bit word sizes supported. */
+    switch (settings->word_size) {
+        case HAL_SPI_WORD_SIZE_8BIT:
+            break;
+        default:
+            rc = EINVAL;
+            goto err;
+    }
+    return (0);
+
+err:
+    return (rc);
+}
+
+static int
+hal_spi_init_master(nrf_drv_spi_t *p_instance,
+                    nrf_drv_spi_config_t *p_config,
+                    nrf_drv_irq_handler_t handler)
+{
+    uint32_t mosi_pin;
+    uint32_t miso_pin;
+    NRF_SPI_Type *p_spi;
+
+#if PERIPHERAL_RESOURCE_SHARING_ENABLED
+    if (nrf_drv_common_per_res_acquire(p_instance->p_registers,
+                                       handler) != NRF_SUCCESS) {
+        return NRF_ERROR_BUSY;
+    }
+#endif
+
+    /* Configure pins used by the peripheral:
+       - SCK - output with initial value corresponding with the SPI mode used:
+       0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
+       according to the reference manual guidelines this pin and its input
+       buffer must always be connected for the SPI to work.
+    */
+    if (p_config->mode <= NRF_DRV_SPI_MODE_1) {
+        nrf_gpio_pin_clear(p_config->sck_pin);
+    } else {
+        nrf_gpio_pin_set(p_config->sck_pin);
+    }
+
+    NRF_GPIO->PIN_CNF[p_config->sck_pin] =
+        (GPIO_PIN_CNF_DIR_Output        << GPIO_PIN_CNF_DIR_Pos)
+      | (GPIO_PIN_CNF_INPUT_Connect     << GPIO_PIN_CNF_INPUT_Pos)
+      | (GPIO_PIN_CNF_PULL_Disabled     << GPIO_PIN_CNF_PULL_Pos)
+      | (GPIO_PIN_CNF_DRIVE_S0S1        << GPIO_PIN_CNF_DRIVE_Pos)
+      | (GPIO_PIN_CNF_SENSE_Disabled    << GPIO_PIN_CNF_SENSE_Pos);
+
+    /* - MOSI (optional) - output with initial value 0 */
+    if (p_config->mosi_pin != NRF_DRV_SPI_PIN_NOT_USED) {
+        mosi_pin = p_config->mosi_pin;
+        nrf_gpio_pin_clear(mosi_pin);
+        nrf_gpio_cfg_output(mosi_pin);
+    } else {
+        mosi_pin = NRF_SPI_PIN_NOT_CONNECTED;
+    }
+
+    /* - MISO (optional) - input*/
+    if (p_config->miso_pin != NRF_DRV_SPI_PIN_NOT_USED) {
+        miso_pin = p_config->miso_pin;
+        nrf_gpio_cfg_input(miso_pin, NRF_GPIO_PIN_NOPULL);
+    } else {
+        miso_pin = NRF_SPI_PIN_NOT_CONNECTED;
+    }
+    p_spi = (NRF_SPI_Type *)p_instance->p_registers;
+    nrf_spi_pins_set(p_spi, p_config->sck_pin, mosi_pin, miso_pin);
+    nrf_spi_frequency_set(p_spi, (nrf_spi_frequency_t)p_config->frequency);
+    nrf_spi_configure(p_spi ,(nrf_spi_mode_t)p_config->mode,
+                      (nrf_spi_bit_order_t)p_config->bit_order);
+    nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
+    NVIC_SetVector(p_instance->irq, (uint32_t)handler);
+    nrf_drv_common_irq_enable(p_instance->irq, p_config->irq_priority);
+
+    return NRF_SUCCESS;
+}
+
+static int
+hal_spi_init_slave(nrf_drv_spis_t *p_instance,
+                   nrf_drv_spis_config_t *p_config,
+                   nrf_drv_irq_handler_t handler)
+{
+    uint32_t mosi_pin;
+    uint32_t miso_pin;
+    NRF_SPIS_Type *p_spis;
+
+#if PERIPHERAL_RESOURCE_SHARING_ENABLED
+    if (nrf_drv_common_per_res_acquire(p_instance->p_reg,
+                                       handler) != NRF_SUCCESS) {
+        return NRF_ERROR_BUSY;
+    }
+#endif
+
+    if ((uint32_t)p_config->mode > (uint32_t)NRF_DRV_SPIS_MODE_3) {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    if (p_config->miso_pin != NRF_DRV_SPIS_PIN_NOT_USED) {
+        nrf_gpio_cfg(p_config->miso_pin,
+                    NRF_GPIO_PIN_DIR_INPUT,
+                    NRF_GPIO_PIN_INPUT_CONNECT,
+                    NRF_GPIO_PIN_NOPULL,
+                    p_config->miso_drive,
+                    NRF_GPIO_PIN_NOSENSE);
+        miso_pin = p_config->miso_pin;
+    } else {
+        miso_pin = NRF_SPIS_PIN_NOT_CONNECTED;
+    }
+
+    if (p_config->mosi_pin != NRF_DRV_SPIS_PIN_NOT_USED) {
+        nrf_gpio_cfg(p_config->mosi_pin,
+                     NRF_GPIO_PIN_DIR_INPUT,
+                     NRF_GPIO_PIN_INPUT_CONNECT,
+                     NRF_GPIO_PIN_NOPULL,
+                     NRF_GPIO_PIN_S0S1,
+                     NRF_GPIO_PIN_NOSENSE);
+        mosi_pin = p_config->mosi_pin;
+    } else {
+        mosi_pin = NRF_SPIS_PIN_NOT_CONNECTED;
+    }
+
+    nrf_gpio_cfg(p_config->csn_pin,
+                 NRF_GPIO_PIN_DIR_INPUT,
+                 NRF_GPIO_PIN_INPUT_CONNECT,
+                 p_config->csn_pullup,
+                 NRF_GPIO_PIN_S0S1,
+                 NRF_GPIO_PIN_NOSENSE);
+
+    nrf_gpio_cfg(p_config->sck_pin,
+                 NRF_GPIO_PIN_DIR_INPUT,
+                 NRF_GPIO_PIN_INPUT_CONNECT,
+                 NRF_GPIO_PIN_NOPULL,
+                 NRF_GPIO_PIN_S0S1,
+                 NRF_GPIO_PIN_NOSENSE);
+
+    p_spis = (NRF_SPIS_Type *)p_instance->p_reg;
+    nrf_spis_pins_set(p_spis, p_config->sck_pin, mosi_pin, miso_pin, p_config->csn_pin);
+    nrf_spis_configure(p_spis, (nrf_spis_mode_t) p_config->mode,
+                               (nrf_spis_bit_order_t) p_config->bit_order);
+
+    /* Configure DEF and ORC characters. */
+    nrf_spis_def_set(p_spis, p_config->def);
+    nrf_spis_orc_set(p_spis, p_config->orc);
+
+    /* Disable interrupt and clear any interrupt events */
+    nrf_spis_int_disable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK | NRF_SPIS_INT_END_MASK);
+    nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
+    nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
+
+    /* Enable END_ACQUIRE shortcut. */
+    nrf_spis_shorts_enable(p_spis, NRF_SPIS_SHORT_END_ACQUIRE);
+    NVIC_SetVector(p_instance->irq, (uint32_t)handler);
+    nrf_drv_common_irq_enable(p_instance->irq, p_config->irq_priority);
+
+    return NRF_SUCCESS;
+}
+
+static void
+hal_spi_master_send_first(NRF_SPI_Type *p_spi, uint8_t txval)
+{
+    while (nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {
+        (void)nrf_spi_rxd_get(p_spi);
+        nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+    }
+    nrf_spi_txd_set(p_spi, txval);
+}
+
+/**
+ * Initialize the SPI interface
+ *
+ *
+ * @param spi_num
+ * @param cfg
+ * @param spi_type
+ *
+ * @return int
+ */
+int
+hal_spi_init(int spi_num, void *cfg, uint8_t spi_type)
+{
+    int rc;
+    struct nrf51_hal_spi *spi;
+    nrf_drv_irq_handler_t irq_handler;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    /* Check for valid arguments */
+    rc = EINVAL;
+    if (cfg == NULL) {
+        goto err;
+    }
+
+    if ((spi_type != HAL_SPI_TYPE_MASTER) && (spi_type != HAL_SPI_TYPE_SLAVE)) {
+        goto err;
+    }
+
+    irq_handler = NULL;
+    spi->spi_cfg.spi_type  = spi_type;
+    if (spi_num == 0) {
+#if SPI0_ENABLED
+        irq_handler = nrf51_spi0_irq_handler;
+        if (spi_type == HAL_SPI_TYPE_MASTER) {
+            memcpy(&spi->nhs_spi.spim, &inst_spi0_m, sizeof(inst_spi0_m));
+        } else {
+            assert(0);
+        }
+#else
+        goto err;
+#endif
+    } else if (spi_num == 1) {
+#if SPI1_ENABLED || SPIS1_ENABLED
+        irq_handler = nrf51_spi1_irq_handler;
+        if (spi_type == HAL_SPI_TYPE_MASTER) {
+#if SPI1_ENABLED
+            memcpy(&spi->nhs_spi.spim, &inst_spi1_m, sizeof(inst_spi0_m));
+#else
+            assert(0);
+#endif
+        } else {
+#if SPIS1_ENABLED
+            memcpy(&spi->nhs_spi.spis, &inst_spi1_s, sizeof(inst_spi1_s));
+#else
+            assert(0);
+#endif
+        }
+#else
+        goto err;
+#endif
+    } else {
+        goto err;
+    }
+
+    if (spi_type == HAL_SPI_TYPE_MASTER) {
+        rc = hal_spi_init_master(&spi->nhs_spi.spim,
+                                 (nrf_drv_spi_config_t *)cfg,
+                                 irq_handler);
+
+
+    } else {
+        rc = hal_spi_init_slave(&spi->nhs_spi.spis,
+                                (nrf_drv_spis_config_t *)cfg,
+                                irq_handler);
+    }
+
+err:
+    return (rc);
+}
+
+int
+hal_spi_config(int spi_num, struct hal_spi_settings *settings)
+{
+    int rc;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    spi->spi_cfg.txrx_cb_func = settings->txrx_cb_func;
+    spi->spi_cfg.txrx_cb_arg = settings->txrx_cb_arg;
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        rc = hal_spi_config_master(spi, settings);
+    } else {
+        rc = hal_spi_config_slave(spi, settings);
+    }
+
+err:
+    return (rc);
+}
+
+/**
+ * Enables the SPI. This does not start a transmit or receive operation;
+ * it is used for power mgmt. Cannot be called when a SPI transfer is in
+ * progress.
+ *
+ * @param spi_num
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_enable(int spi_num)
+{
+    int rc;
+    NRF_SPIS_Type *p_spis;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+        /* We need to enable this in blocking or non-blocking mode */
+        if (spi->spi_cfg.txrx_cb_func) {
+            nrf_spi_event_clear(p_spi, NRF_SPI_INT_READY_MASK);
+            nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
+        }
+        nrf_spi_enable(p_spi);
+    } else {
+        if (spi->spi_cfg.txrx_cb_func == NULL) {
+            rc = EINVAL;
+            goto err;
+        }
+
+        p_spis = spi->nhs_spi.spis.p_reg;
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
+        nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK | NRF_SPIS_INT_END_MASK);
+        nrf_spis_enable(p_spis);
+    }
+    rc = 0;
+
+err:
+    return rc;
+}
+
+/**
+ * Disables the SPI. Used for power mgmt. It will halt any current SPI transfers
+ * in progress.
+ *
+ * @param spi_num
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_disable(int spi_num)
+{
+    int rc;
+    NRF_SPIS_Type *p_spis;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+        nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
+        spi->spi_xfr_flag = 0;
+        nrf_spi_disable(p_spi);
+    } else {
+        p_spis = spi->nhs_spi.spis.p_reg;
+        nrf_spis_int_disable(p_spis, NRF_SPI_IRQ_DISABLE_ALL);
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
+        nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
+        nrf_spis_disable(p_spis);
+        spi->slave_state = HAL_SPI_SLAVE_STATE_IDLE;
+        spi->nhs_txbuf = NULL;
+        spi->nhs_rxbuf = NULL;
+    }
+    rc = 0;
+
+err:
+    return rc;
+}
+
+/**
+ * Blocking call to send a value on the SPI. Returns the value received from the
+ * SPI.
+ *
+ * MASTER: Sends the value and returns the received value from the slave.
+ * SLAVE: Sets the value to send to the master when the master transfers a
+ *        value. This value will be sent until another call to hal_spi_tx_val()
+ *        is made. The return code is ignored for a slave.\ufffd
+ *
+ * @param spi_num
+ * @param val
+ *
+ * @return uint16_t Value received on SPI interface from slave. Returns 0xFFFF
+ * if called when SPI configured as a Slave.
+ */
+uint16_t hal_spi_tx_val(int spi_num, uint16_t val)
+{
+    int rc;
+    uint16_t retval;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        p_spi = (NRF_SPI_Type *) spi->nhs_spi.spim.p_registers;
+        nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+        nrf_spi_txd_set(p_spi, (uint8_t) val);
+        while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {}
+        nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+        retval = (uint16_t)nrf_spi_rxd_get(p_spi);
+    } else {
+        retval = 0xFFFF;
+    }
+
+    return retval;
+
+err:
+    return rc;
+}
+
+/**
+ * Sets the txrx callback (executed at interrupt context) when the
+ * buffer is transferred by the master or the slave using the hal_spi_rxtx API.
+ * This callback is also called when the SPI is a slave and chip select is
+ * de-asserted and there is data available in the receive buffer.
+ *
+ * If the callback is NULL, the SPI will be in blocking mode; otherwise it is
+ * in non-blocking mode.
+ *
+ * Cannot be called when the SPI is enabled.
+ *
+ * @param spi_num   SPI interface on which to set callback
+ * @param txrx_cb   Pointer to callback function. NULL to set into blocking mode
+ * @param arg       Argument passed to callback function.
+ *
+ * @return int 0 on success, -1 if spi is already enabled.
+ */
+int
+hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg)
+{
+    int rc;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    /*
+     * This looks odd, but the ENABLE register is in the same location for
+     * SPIM, SPI and SPIS
+     */
+    p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+    if (p_spi->ENABLE != 0) {
+        rc = -1;
+    } else {
+        spi->spi_cfg.txrx_cb_func = txrx_cb;
+        spi->spi_cfg.txrx_cb_arg = arg;
+        rc = 0;
+    }
+
+err:
+    return rc;
+}
+
+/**
+ * Send a buffer and also store the received values. This call can be either
+ * blocking or non-blocking for the master; it is always non-blocking for slave.
+ * In non-blocking mode, the txrx callback is executed at interrupt context when
+ * the buffer is sent.
+ *     MASTER: master sends all the values in the buffer and stores the
+ *             stores the values in the receive buffer if rxbuf is not NULL.
+ *             The txbuf parameter cannot be NULL.
+ *     SLAVE: Slave preloads the data to be sent to the master (values
+ *            stored in txbuf) and places received data from master in rxbuf (if
+ *            not NULL).  The txrx callback when len values are transferred or
+ *            master de-asserts chip select. If txbuf is NULL, the slave
+ *            transfers its default byte. Both rxbuf and txbuf cannot be NULL.
+ *
+ * @param spi_num   SPI interface to use
+ * @param txbuf     Pointer to buffer where values to transmit are stored.
+ * @param rxbuf     Pointer to buffer to store values received from peer. Can
+ *                  be NULL.
+ * @param len       Number of values to be transferred.
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int len)
+{
+    int i;
+    int rc;
+    int txcnt;
+    uint8_t *txd, *rxd;
+    uint8_t rxval;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    rc = EINVAL;
+    if (!len || (len > 255)) {
+        goto err;
+    }
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        p_spi = (NRF_SPI_Type *) spi->nhs_spi.spim.p_registers;
+        if (spi->spi_cfg.txrx_cb_func) {
+            /* Must have a txbuf for master! */
+            if (txbuf == NULL) {
+                goto err;
+            }
+
+            /* Not allowed if transfer in progress */
+            if (spi->spi_xfr_flag) {
+                rc = -1;
+                goto err;
+            }
+
+            spi->nhs_buflen = (uint16_t)len;
+            spi->nhs_txbuf = txbuf;
+            spi->nhs_rxbuf = rxbuf;
+            spi->nhs_rxd_bytes = 0;
+            txd = (uint8_t *)txbuf;
+            hal_spi_master_send_first(p_spi, txd[0]);
+            spi->nhs_txd_bytes = 1;
+            if (len > 1) {
+                nrf_spi_txd_set(p_spi, txd[1]);
+                ++spi->nhs_txd_bytes;
+            }
+            nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
+        } else {
+            /* Blocking spi transfer */
+            txd = (uint8_t *)txbuf;
+            hal_spi_master_send_first(p_spi, txd[0]);
+            txcnt = len - 1;
+            rxd = (uint8_t *)rxbuf;
+            for (i = 0; i < len; ++i) {
+                if (txcnt) {
+                    ++txd;
+                    nrf_spi_txd_set(p_spi, *txd);
+                    --txcnt;
+                }
+                while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {}
+                nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+                rxval = nrf_spi_rxd_get(p_spi);
+                if (rxbuf) {
+                    *rxd = rxval;
+                    ++rxd;
+                }
+            }
+        }
+    } else {
+        /* Must have txbuf and rxbuf */
+        if ((txbuf == NULL) && (rxbuf == NULL)) {
+            goto err;
+        }
+
+        /*
+         * Ready the slave for a transfer. Do not allow this to be called
+         * if the slave has already been readied or is requesting the
+         * semaphore
+         */
+        if (spi->slave_state != HAL_SPI_SLAVE_STATE_IDLE) {
+            rc = -1;
+            goto err;
+        }
+
+        spi->nhs_rxbuf = rxbuf;
+        spi->nhs_txbuf = txbuf;
+        spi->nhs_buflen = len;
+        spi->slave_state = HAL_SPI_SLAVE_STATE_ACQ_SEM;
+        nrf_spis_task_trigger(spi->nhs_spi.spis.p_reg, NRF_SPIS_TASK_ACQUIRE);
+    }
+    return 0;
+
+err:
+    return rc;
+}
+
+/**
+ * Sets the default value transferred by the slave.
+ *
+ * @param spi_num SPI interface to use
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)
+{
+    int rc;
+    NRF_SPIS_Type *p_spis;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_SLAVE) {
+        p_spis = spi->nhs_spi.spis.p_reg;
+        nrf_spis_def_set(p_spis, (uint8_t) val);
+        rc = 0;
+    } else {
+        rc = EINVAL;
+    }
+
+err:
+    return rc;
+}
+
+/**
+ * This aborts the current transfer but keeps the spi enabled. Should only
+ * be used when the SPI is in non-blocking mode.
+ *
+ * @param spi_num   SPI interface on which transfer should be aborted.
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ *
+ * NOTE: does not return an error if no transfer was in progress.
+ */
+int
+hal_spi_abort(int spi_num)
+{
+    int rc;
+    NRF_SPI_Type *p_spi;
+    struct nrf51_hal_spi *spi;
+
+    NRF51_HAL_SPI_RESOLVE(spi_num, spi);
+
+    rc = 0;
+    if (spi->spi_cfg.txrx_cb_func == NULL) {
+        goto err;
+    }
+
+    if (spi->spi_cfg.spi_type  == HAL_SPI_TYPE_MASTER) {
+        p_spi = (NRF_SPI_Type *)spi->nhs_spi.spim.p_registers;
+        if (spi->spi_xfr_flag) {
+            nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
+            nrf_spi_disable(p_spi);
+            nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
+            spi->spi_xfr_flag = 0;
+            nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
+        }
+    } else {
+        /* Only way I can see doing this is to disable, then re-enable */
+        hal_spi_disable(spi_num);
+        hal_spi_enable(spi_num);
+    }
+
+err:
+    return rc;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aab7b2a2/hw/mcu/nordic/nrf52xxx/src/hal_spi.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_spi.c b/hw/mcu/nordic/nrf52xxx/src/hal_spi.c
index ec3e8bf..9b0e5c2 100644
--- a/hw/mcu/nordic/nrf52xxx/src/hal_spi.c
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_spi.c
@@ -73,20 +73,20 @@ struct nrf52_hal_spi {
     uint8_t *slave_rxbuf;
 };
 
-#if SPI0_ENABLED
+#if SPI0_ENABLED || SPIS0_ENABLED
 struct nrf52_hal_spi nrf52_hal_spi0;
 #endif
-#if SPI1_ENABLED
+#if SPI1_ENABLED || SPIS1_ENABLED
 struct nrf52_hal_spi nrf52_hal_spi1;
 #endif
 
 struct nrf52_hal_spi *nrf52_hal_spis[NRF52_HAL_SPI_MAX] = {
-#if SPI0_ENABLED
+#if SPI0_ENABLED || SPIS0_ENABLED
     &nrf52_hal_spi0,
 #else
     NULL,
 #endif
-#if SPI1_ENABLED
+#if SPI1_ENABLED || SPIS1_ENABLED
     &nrf52_hal_spi1
 #else
     NULL
@@ -95,10 +95,14 @@ struct nrf52_hal_spi *nrf52_hal_spis[NRF52_HAL_SPI_MAX] = {
 
 #if SPI0_ENABLED
 nrf_drv_spi_t inst_spi0_m = NRF_DRV_SPI_INSTANCE(0);
-nrf_drv_spis_t inst_spi0_s = NRF_DRV_SPIS_INSTANCE(0);
 #endif
 #if SPI1_ENABLED
 nrf_drv_spi_t inst_spi1_m = NRF_DRV_SPI_INSTANCE(1);
+#endif
+#if SPIS0_ENABLED
+nrf_drv_spis_t inst_spi0_s = NRF_DRV_SPIS_INSTANCE(0);
+#endif
+#if SPIS1_ENABLED
 nrf_drv_spis_t inst_spi1_s = NRF_DRV_SPIS_INSTANCE(1);
 #endif
 
@@ -119,19 +123,25 @@ nrf52_irqm_handler(struct nrf52_hal_spi *spi)
 {
     NRF_SPIM_Type *p_spim;
 
-    /* XXX: what if not in a transfer? */
-
     p_spim = spi->nhs_spi.spim.p_registers;
     if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)) {
         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
+
+        /* Should not occur but if no transfer just leave  */
+        if (spi->spi_xfr_flag == 0) {
+            return;
+        }
+
         if (spi->spi_cfg.txrx_cb_func) {
             spi->spi_cfg.txrx_cb_func(spi->spi_cfg.txrx_cb_arg,
                                       p_spim->TXD.AMOUNT);
-            spi->spi_xfr_flag = 0;
         }
+        spi->spi_xfr_flag = 0;
     }
 }
+#endif
 
+#if (SPIS0_ENABLED || SPIS1_ENABLED)
 static void
 nrf52_irqs_handler(struct nrf52_hal_spi *spi)
 {
@@ -182,7 +192,7 @@ nrf52_irqs_handler(struct nrf52_hal_spi *spi)
 #endif
 
 /* Interrupt handlers for SPI ports */
-#if SPI0_ENABLED
+#if SPI0_ENABLED || SPIS0_ENABLED
 void
 nrf52_spi0_irq_handler(void)
 {
@@ -194,11 +204,11 @@ nrf52_spi0_irq_handler(void)
 }
 #endif
 
-#if SPI1_ENABLED
+#if SPI1_ENABLED || SPIS1_ENABLED
 void
 nrf52_spi1_irq_handler(void)
 {
-    if (nrf52_hal_spi0.spi_cfg.spi_type == HAL_SPI_TYPE_MASTER) {
+    if (nrf52_hal_spi1.spi_cfg.spi_type == HAL_SPI_TYPE_MASTER) {
         nrf52_irqm_handler(&nrf52_hal_spi1);
     } else {
         nrf52_irqs_handler(&nrf52_hal_spi1);
@@ -529,23 +539,39 @@ hal_spi_init(int spi_num, void *cfg, uint8_t spi_type)
     irq_handler = NULL;
     spi->spi_cfg.spi_type  = spi_type;
     if (spi_num == 0) {
-#if SPI0_ENABLED
+#if SPI0_ENABLED || SPIS0_ENABLED
         irq_handler = nrf52_spi0_irq_handler;
         if (spi_type == HAL_SPI_TYPE_MASTER) {
+#if SPI0_ENABLED
             memcpy(&spi->nhs_spi.spim, &inst_spi0_m, sizeof(inst_spi0_m));
+#else
+            assert(0);
+#endif
         } else {
+#if SPIS0_ENABLED
             memcpy(&spi->nhs_spi.spis, &inst_spi0_s, sizeof(inst_spi0_s));
+#else
+            assert(0);
+#endif
         }
 #else
         goto err;
 #endif
     } else if (spi_num == 1) {
-#if SPI1_ENABLED
+#if SPI1_ENABLED || SPIS1_ENABLED
         irq_handler = nrf52_spi1_irq_handler;
         if (spi_type == HAL_SPI_TYPE_MASTER) {
-            memcpy(&spi->nhs_spi.spim, &inst_spi1_m, sizeof(inst_spi0_m));
+#if SPI1_ENABLED
+            memcpy(&spi->nhs_spi.spim, &inst_spi1_m, sizeof(inst_spi1_m));
+#else
+            assert(0);
+#endif
         } else {
-            memcpy(&spi->nhs_spi.spis, &inst_spi1_s, sizeof(inst_spi0_s));
+#if SPIS1_ENABLED
+            memcpy(&spi->nhs_spi.spis, &inst_spi1_s, sizeof(inst_spi1_s));
+#else
+            assert(0);
+#endif
         }
 #else
         goto err;
@@ -817,6 +843,7 @@ hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int len)
                 rc = -1;
                 goto err;
             }
+            spi->spi_xfr_flag = 1;
 
             p_spim = spi->nhs_spi.spim.p_registers;
             nrf_spim_tx_buffer_set(p_spim, txbuf, len);