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