This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new d66cb50  nrf52: add workaround to SPI Master 1 Byte transfer anomaly
d66cb50 is described below

commit d66cb505a53d453aa8c7ca0adaa09f98c59a5654
Author: raiden00pl <[email protected]>
AuthorDate: Mon May 25 14:33:48 2020 +0200

    nrf52: add workaround to SPI Master 1 Byte transfer anomaly
---
 arch/arm/src/nrf52/Kconfig              |  8 +++
 arch/arm/src/nrf52/hardware/nrf52_ppi.h | 63 +++++++++++++++++++++++
 arch/arm/src/nrf52/nrf52_spi.c          | 91 +++++++++++++++++++++++++++++++++
 3 files changed, 162 insertions(+)

diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig
index e2daee4..394006c 100644
--- a/arch/arm/src/nrf52/Kconfig
+++ b/arch/arm/src/nrf52/Kconfig
@@ -90,6 +90,14 @@ config NRF52_UART
        bool
        default n
 
+config NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+       bool "SPI Master 1 Byte transfer anomaly workaround"
+       depends on NRF52_SPI_MASTER && ARCH_FAMILY_NRF52832
+       default y
+       ---help---
+               Enable the workaround to fix SPI Master 1 byte transfer bug
+               which occurs in NRF52832 revision 1 and revision 2.
+
 menu "NRF52 Peripheral Selection"
 
 config NRF52_I2C0_MASTER
diff --git a/arch/arm/src/nrf52/hardware/nrf52_ppi.h 
b/arch/arm/src/nrf52/hardware/nrf52_ppi.h
new file mode 100644
index 0000000..012c008
--- /dev/null
+++ b/arch/arm/src/nrf52/hardware/nrf52_ppi.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/hardware/nrf52_ppi.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_PPI_H
+#define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_PPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf52_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets for PPI *************************************************/
+
+#define NRF52_PPI_TASK_CHGEN_OFFSET(x)       (0x000 + (x * 0x8))   /* Enable 
channel group x */
+#define NRF52_PPI_TASK_CHGDIS_OFFSET(x)      (0x004 + (x * 0x8))   /* Disable 
channel group x */
+#define NRF52_PPI_CHEN_OFFSET                (0x500)               /* Channel 
enable register */
+#define NRF52_PPI_CHENSET_OFFSET             (0x504)               /* Channel 
enable set register */
+#define NRF52_PPI_CHENCLR_OFFSET             (0x508)               /* Channel 
enable clear register*/
+#define NRF52_PPI_CHEEP_OFFSET(x)            (0x510 + (x * 0x8))   /* Channel 
x event end-point */
+#define NRF52_PPI_CHTEP_OFFSET(x)            (0x514 + (x * 0x8))   /* Channel 
x task end-point */
+#define NRF52_PPI_CHG_OFFSET(x)              (0x800 + (x * 0x4))   /* Channel 
group x */
+#define NRF52_PPI_FORKTEP_OFFSET(x)          (0x910 + (x * 0x4))   /* Channel 
x task end-point */
+
+/* Register addresses for PPI ***********************************************/
+
+#define NRF52_PPI_TASK_CHGEN(x)              (NRF52_PPI_BASE + 
NRF52_PPI_TASK_CHGEN_OFFSET(x))
+#define NRF52_PPI_TASK_CHGDIS(x)             (NRF52_PPI_BASE + 
NRF52_PPI_TASK_CHGDIS_OFFSET(x))
+#define NRF52_PPI_CHEN                       (NRF52_PPI_BASE + 
NRF52_PPI_CHEN_OFFSET)
+#define NRF52_PPI_CHENSET                    (NRF52_PPI_BASE + 
NRF52_PPI_CHENSET_OFFSET)
+#define NRF52_PPI_CHENCLR                    (NRF52_PPI_BASE + 
NRF52_PPI_CHENCLR_OFFSET)
+#define NRF52_PPI_CHEEP(x)                   (NRF52_PPI_BASE + 
NRF52_PPI_CHEEP_OFFSET(x))
+#define NRF52_PPI_CHTEP(x)                   (NRF52_PPI_BASE + 
NRF52_PPI_CHTEP_OFFSET(x))
+#define NRF52_PPI_CHG(x)                     (NRF52_PPI_BASE + 
NRF52_PPI_CHG_OFFSET(x))
+#define NRF52_PPI_FORKTEP(x)                 (NRF52_PPI_BASE + 
NRF52_PPI_FORKTEP_OFFSET(x))
+
+/* Register Bitfield Definitions for PPI ************************************/
+
+#define PPI_CHEN_CH(x)                       (1 << x)              /* Enable 
or disable channel x */
+
+#endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_PPI_H */
diff --git a/arch/arm/src/nrf52/nrf52_spi.c b/arch/arm/src/nrf52/nrf52_spi.c
index 73970f2..f6fb8b0 100644
--- a/arch/arm/src/nrf52/nrf52_spi.c
+++ b/arch/arm/src/nrf52/nrf52_spi.c
@@ -54,6 +54,11 @@
 
 #include "hardware/nrf52_spi.h"
 
+#ifdef CONFIG_NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+#  include "hardware/nrf52_gpiote.h"
+#  include "hardware/nrf52_ppi.h"
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -67,6 +72,13 @@
 #  error Unsupported configuration I2C1 + SPI1
 #endif
 
+/* Reserve PPI channel and GPIOTE channel for 1 byte transfer workaround */
+
+#ifdef CONFIG_NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+#  define SPI_1B_WORKAROUND_PPI_CHAN    (18)
+#  define SPI_1B_WORKAROUND_GPIOTE_CHAN (7)
+#endif
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -771,6 +783,71 @@ static uint32_t nrf52_spi_send(FAR struct spi_dev_s *dev, 
uint32_t wd)
   return ret;
 }
 
+#ifdef CONFIG_NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+
+/****************************************************************************
+ * Name: n4f52_spi_1b_workaround
+ *
+ * Description:
+ *   Workaround to fix SPI Master 1 byte transfer for NRF52832.
+ *
+ * Input Parameters:
+ *   dev    - Device-specific state data
+ *   enable - Enable/disable workaround
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void nrf52_spi_1b_workaround(FAR struct spi_dev_s *dev, bool enable)
+{
+  FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
+  uint32_t pin  = 0;
+  uint32_t port = 0;
+
+  pin = (priv->sck_pin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+  port = (priv->sck_pin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+
+  if (enable == true)
+    {
+      /* Create an event when SCK toggles */
+
+      putreg32((GPIOTE_CONFIG_MODE_EV |
+                pin << GPIOTE_CONFIG_PSEL_SHIFT |
+                port << GPIOTE_CONFIG_PORT_SHIFT |
+                GPIOTE_CONFIG_POL_TG),
+               NRF52_GPIOTE_CONFIG(SPI_1B_WORKAROUND_GPIOTE_CHAN));
+
+      /* Stop the SPIM instance when SCK toggles */
+
+      putreg32(NRF52_GPIOTE_EVENTS_IN(SPI_1B_WORKAROUND_GPIOTE_CHAN),
+               NRF52_PPI_CHEEP(SPI_1B_WORKAROUND_PPI_CHAN));
+
+      putreg32((priv->base + NRF52_SPIM_TASK_STOP_OFFSET),
+               NRF52_PPI_CHTEP(SPI_1B_WORKAROUND_PPI_CHAN));
+
+      /* Enable PPI channel */
+
+      modifyreg32(NRF52_PPI_CHEN, 0,
+                  PPI_CHEN_CH(SPI_1B_WORKAROUND_PPI_CHAN));
+    }
+  else
+    {
+      /* Disable event */
+
+      putreg32(0, NRF52_GPIOTE_CONFIG(SPI_1B_WORKAROUND_GPIOTE_CHAN));
+      putreg32(0, NRF52_PPI_CHEEP(SPI_1B_WORKAROUND_PPI_CHAN));
+      putreg32(0, NRF52_PPI_CHTEP(SPI_1B_WORKAROUND_PPI_CHAN));
+
+      /* Disable PPI channel */
+
+      modifyreg32(NRF52_PPI_CHEN,
+                  PPI_CHEN_CH(SPI_1B_WORKAROUND_PPI_CHAN), 0);
+    }
+}
+#endif
+
 /****************************************************************************
  * Name: nrf52_spi_exchange
  *
@@ -797,6 +874,13 @@ static void nrf52_spi_exchange(FAR struct spi_dev_s *dev,
   FAR struct nrf52_spidev_s *priv = (FAR struct nrf52_spidev_s *)dev;
   uint32_t regval = 0;
 
+#ifdef CONFIG_NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+  if (nwords <= 1)
+    {
+      nrf52_spi_1b_workaround(dev, true);
+    }
+#endif
+
   if (rxbuffer != NULL)
     {
       /* Write RXD data pointer */
@@ -859,6 +943,13 @@ static void nrf52_spi_exchange(FAR struct spi_dev_s *dev,
   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);
+
+#ifdef CONFIG_NRF52_SPI_MASTER_WORKAROUND_1BYTE_TRANSFER
+  if (nwords <= 1)
+    {
+      nrf52_spi_1b_workaround(dev, false);
+    }
+#endif
 }
 
 #ifndef CONFIG_SPI_EXCHANGE

Reply via email to