summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-02-20 09:59:54 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-02-20 09:59:54 -0600
commit2ffd874a9f6a20142aeab550483a444d36c968e4 (patch)
tree42c2c6a860b2d1c6e5f9321ef016ba23500e885c
parent8a3770294f1d76d264494d67c9b4ef91275ee344 (diff)
downloadnuttx-2ffd874a9f6a20142aeab550483a444d36c968e4.tar.gz
nuttx-2ffd874a9f6a20142aeab550483a444d36c968e4.tar.bz2
nuttx-2ffd874a9f6a20142aeab550483a444d36c968e4.zip
SAMD20: SPI driver is code-complete, but untested
-rw-r--r--nuttx/ChangeLog2
-rw-r--r--nuttx/arch/arm/src/samd/chip/sam_spi.h17
-rw-r--r--nuttx/arch/arm/src/samd/sam_lowputc.c4
-rw-r--r--nuttx/arch/arm/src/samd/sam_sercom.h4
-rw-r--r--nuttx/arch/arm/src/samd/sam_serial.c2
-rw-r--r--nuttx/arch/arm/src/samd/sam_spi.c394
-rw-r--r--nuttx/configs/samd20-xplained/include/board.h99
7 files changed, 440 insertions, 82 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 3e6236588..2e57c8f86 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -6626,4 +6626,6 @@
a lot of missing logic (2014-2-19).
* arch/arm/src/lm/lm_lowputc.c and lm_serial.c: Several errors
are unmasked with UARTs > UART2 are enabled. From gosha (2014-2-19).
+ * arch/arm/src/samd/sam_spi.c: The SPI driver is code complete,
+ but untested (2014-2-19).
diff --git a/nuttx/arch/arm/src/samd/chip/sam_spi.h b/nuttx/arch/arm/src/samd/chip/sam_spi.h
index c5d78a90d..71202790e 100644
--- a/nuttx/arch/arm/src/samd/chip/sam_spi.h
+++ b/nuttx/arch/arm/src/samd/chip/sam_spi.h
@@ -145,15 +145,18 @@
# define SPI_CTRLA_MODE_MASTER (3 << SPI_CTRLA_MODE_SHIFT) /* SPI master operation */
#define SPI_CTRLA_RUNSTDBY (1 << 7) /* Bit 7: Run in standby */
#define SPI_CTRLA_IBON (1 << 8) /* Bit 8: Immediate BUFOVF notification */
-#define SPI_CTRLA_DOPO (1 << 16) /* Bit 16: Data out pinout */
-# define SPI_CTRLA_DOPAD0 (0)
-# define SPI_CTRLA_DOPAD2 SPI_CTRLA_DOPO
+#define SPI_CTRLA_DOPO_SHIFT (16) /* Bit 16-17: Data out pinout */
+#define SPI_CTRLA_DOPO_MASK (3 << SPI_CTRLA_DOPO_SHIFT) /* Bit 16-17: Data out pinout */
+# define SPI_CTRLA_DOPO_DOPAD012 (0 << SPI_CTRLA_DOPO_SHIFT) /* D0=PAD0 SCK=PAD1 SS=PAD2 */
+# define SPI_CTRLA_DOPO_DOPAD231 (1 << SPI_CTRLA_DOPO_SHIFT) /* D0=PAD2 SCK=PAD3 SS=PAD1 */
+# define SPI_CTRLA_DOPO_DOPAD312 (2 << SPI_CTRLA_DOPO_SHIFT) /* D0=PAD3 SCK=PAD1 SS=PAD2 */
+# define SPI_CTRLA_DOPO_DOPAD031 (3 << SPI_CTRLA_DOPO_SHIFT) /* D0=PAD0 SCK=PAD3 SS=PAD1 */
#define SPI_CTRLA_DIPO_SHIFT (20) /* Bits 20-21: Data in pinout */
#define SPI_CTRLA_DIPO_MASK (3 << SPI_CTRLA_DIPO_SHIFT)
-# define SPI_CTRLA_DIPAD0 (0 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD[0] for DI */
-# define SPI_CTRLA_DIPAD1 (1 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD[1] for DI */
-# define SPI_CTRLA_DIPAD2 (2 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD[2] for DI */
-# define SPI_CTRLA_DIPAD3 (3 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD[3] for DI */
+# define SPI_CTRLA_DIPAD0 (0 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD0 for DI */
+# define SPI_CTRLA_DIPAD1 (1 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD1 for DI */
+# define SPI_CTRLA_DIPAD2 (2 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD2 for DI */
+# define SPI_CTRLA_DIPAD3 (3 << SPI_CTRLA_DIPO_SHIFT) /* SERCOM PAD3 for DI */
#define SPI_CTRLA_FORM_SHIFT (24) /* Bits 24-27: Frame format */
#define SPI_CTRLA_FORM_MASK (7 << SPI_CTRLA_FORM_SHIFT)
# define SPI_CTRLA_FORM_SPI (0 << SPI_CTRLA_FORM_SHIFT) /* SPI frame (no address) */
diff --git a/nuttx/arch/arm/src/samd/sam_lowputc.c b/nuttx/arch/arm/src/samd/sam_lowputc.c
index 1b22d558b..e2548e70b 100644
--- a/nuttx/arch/arm/src/samd/sam_lowputc.c
+++ b/nuttx/arch/arm/src/samd/sam_lowputc.c
@@ -56,6 +56,8 @@
#include "sam_config.h"
+#include <arch/board/board.h>
+
#include "chip/sam_pm.h"
#include "chip/sam_gclk.h"
#include "chip/sam_usart.h"
@@ -301,7 +303,7 @@ int sam_usart_internal(const struct sam_usart_config_s * const config)
/* Configure the GCLKs for the SERCOM module */
sercom_coreclk_configure(config->sercom, config->gclkgen, false);
- sercom_slowclk_configure(config->gclkgen);
+ sercom_slowclk_configure(BOARD_SERCOM_SLOW_GCLKGEN);
/* Set USART configuration according to the board configuration */
diff --git a/nuttx/arch/arm/src/samd/sam_sercom.h b/nuttx/arch/arm/src/samd/sam_sercom.h
index 77dd9363c..1a179e974 100644
--- a/nuttx/arch/arm/src/samd/sam_sercom.h
+++ b/nuttx/arch/arm/src/samd/sam_sercom.h
@@ -44,7 +44,9 @@
#include <stdbool.h>
+#include "up_arch.h"
#include "sam_config.h"
+#include "chip/sam_pm.h"
/****************************************************************************
* Pre-processor Definitions
@@ -85,7 +87,7 @@ extern "C"
*
****************************************************************************/
-static inline int sercom_enable(int sercom)
+static inline void sercom_enable(int sercom)
{
uint32_t regval;
diff --git a/nuttx/arch/arm/src/samd/sam_serial.c b/nuttx/arch/arm/src/samd/sam_serial.c
index 4665befb1..65092a0db 100644
--- a/nuttx/arch/arm/src/samd/sam_serial.c
+++ b/nuttx/arch/arm/src/samd/sam_serial.c
@@ -561,7 +561,7 @@ static int sam_interrupt(struct uart_dev_s *dev)
uint8_t intflag;
uint8_t inten;
- /* Get the set of pending USART usarts (we are only interested in the
+ /* Get the set of pending USART interrupts (we are only interested in the
* unmasked interrupts).
*/
diff --git a/nuttx/arch/arm/src/samd/sam_spi.c b/nuttx/arch/arm/src/samd/sam_spi.c
index 58be9f423..2b81ee797 100644
--- a/nuttx/arch/arm/src/samd/sam_spi.c
+++ b/nuttx/arch/arm/src/samd/sam_spi.c
@@ -114,7 +114,9 @@ struct sam_spidev_s
/* Fixed configuration */
uint8_t sercom; /* Identifies the SERCOM peripheral */
+#if 0 /* Not used */
uint8_t irq; /* SERCOM IRQ number */
+#endif
uint8_t gclkgen; /* Source GCLK generator */
port_pinset_t pad0; /* Pin configuration for PAD0 */
port_pinset_t pad1; /* Pin configuration for PAD1 */
@@ -123,6 +125,9 @@ struct sam_spidev_s
uint32_t muxconfig; /* Pad multiplexing configuration */
uint32_t srcfreq; /* Source clock frequency */
uintptr_t base; /* SERCOM base address */
+#if 0 /* Not used */
+ xcpt_t handler; /* SERCOM interrupt handler */
+#endif
/* Dynamic configuration */
@@ -151,29 +156,54 @@ struct sam_spidev_s
/* Helpers */
#ifdef CONFIG_SAMD_SPI_REGDEBUG
-static bool spi_checkreg(struct sam_spidev_s *spi, bool wr,
+static bool spi_checkreg(struct sam_spidev_s *priv, bool wr,
uint32_t regval, uint32_t regaddr);
#else
-# define spi_checkreg(spi,wr,regval,regaddr) (false)
+# define spi_checkreg(priv,wr,regval,regaddr) (false)
#endif
-static uint8_t spi_getreg8(struct sam_spidev_s *spi,
+static uint8_t spi_getreg8(struct sam_spidev_s *priv,
unsigned int offset);
-static void spi_putreg8(struct sam_spidev_s *spi, uint8_t regval,
+static void spi_putreg8(struct sam_spidev_s *priv, uint8_t regval,
unsigned int offset);
-static uint16_t spi_getreg16(struct sam_spidev_s *spi,
+static uint16_t spi_getreg16(struct sam_spidev_s *priv,
unsigned int offset);
-static void spi_putreg16(struct sam_spidev_s *spi, uint16_t regval,
+static void spi_putreg16(struct sam_spidev_s *priv, uint16_t regval,
unsigned int offset);
-static uint32_t spi_getreg32(struct sam_spidev_s *spi,
+static uint32_t spi_getreg32(struct sam_spidev_s *priv,
unsigned int offset);
-static void spi_putreg32(struct sam_spidev_s *spi, uint32_t regval,
+static void spi_putreg32(struct sam_spidev_s *priv, uint32_t regval,
unsigned int offset);
#if defined(CONFIG_DEBUG_SPI) && defined(CONFIG_DEBUG_VERBOSE)
-static void spi_dumpregs(struct sam_spidev_s *spi, const char *msg);
+static void spi_dumpregs(struct sam_spidev_s *priv, const char *msg);
#else
-# define spi_dumpregs(spi,msg)
+# define spi_dumpregs(priv,msg)
+#endif
+
+/* Interrupt handling */
+
+#if 0 /* Not used */
+static int spi_interrupt(struct sam_spidev_s *dev);
+
+#ifdef SAMD_HAVE_USART0
+static int spi0_interrupt(int irq, void *context);
+#endif
+#ifdef SAMD_HAVE_USART1
+static int spi1_interrupt(int irq, void *context);
+#endif
+#ifdef SAMD_HAVE_USART2
+static int spi2_interrupt(int irq, void *context);
+#endif
+#ifdef SAMD_HAVE_USART3
+static int spi3_interrupt(int irq, void *context);
+#endif
+#ifdef SAMD_HAVE_USART4
+static int spi4_interrupt(int irq, void *context);
+#endif
+#ifdef SAMD_HAVE_USART5
+static int spi5_interrupt(int irq, void *context);
+#endif
#endif
/* SPI methods */
@@ -234,7 +264,9 @@ static struct sam_spidev_s g_spi0dev =
{
.ops = &g_spi0ops,
.sercom = 0,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM0,
+#endif
.gclkgen = (BOARD_SERCOM0_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM0_PINMAP_PAD0,
.pad1 = BOARD_SERCOM0_PINMAP_PAD1,
@@ -243,6 +275,9 @@ static struct sam_spidev_s g_spi0dev =
.muxconfig = BOARD_SERCOM0_MUXCONFIG,
.srcfreq = BOARD_SERCOM0_FREQUENCY,
.base = SAM_SERCOM0_BASE,
+#if 0 /* Not used */
+ .handler = spi0_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -281,7 +316,9 @@ static struct sam_spidev_s g_spi1dev =
{
.ops = &g_spi1ops,
.sercom = 1,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM1,
+#endif
.gclkgen = (BOARD_SERCOM1_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM1_PINMAP_PAD0,
.pad1 = BOARD_SERCOM1_PINMAP_PAD1,
@@ -290,6 +327,9 @@ static struct sam_spidev_s g_spi1dev =
.muxconfig = BOARD_SERCOM1_MUXCONFIG,
.srcfreq = BOARD_SERCOM1_FREQUENCY,
.base = SAM_SERCOM1_BASE,
+#if 0 /* Not used */
+ .handler = spi1_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -328,7 +368,9 @@ static struct sam_spidev_s g_spi2dev =
{
.ops = &g_spi1ops,
.sercom = 2,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM2,
+#endif
.gclkgen = (BOARD_SERCOM2_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM2_PINMAP_PAD0,
.pad1 = BOARD_SERCOM2_PINMAP_PAD1,
@@ -337,6 +379,9 @@ static struct sam_spidev_s g_spi2dev =
.muxconfig = BOARD_SERCOM2_MUXCONFIG,
.srcfreq = BOARD_SERCOM2_FREQUENCY,
.base = SAM_SERCOM2_BASE,
+#if 0 /* Not used */
+ .handler = spi2_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -375,7 +420,9 @@ static struct sam_spidev_s g_spi3dev =
{
.ops = &g_spi3ops,
.sercom = 3,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM3,
+#endif
.gclkgen = (BOARD_SERCOM3_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM3_PINMAP_PAD0,
.pad1 = BOARD_SERCOM3_PINMAP_PAD1,
@@ -384,6 +431,9 @@ static struct sam_spidev_s g_spi3dev =
.muxconfig = BOARD_SERCOM3_MUXCONFIG,
.srcfreq = BOARD_SERCOM3_FREQUENCY,
.base = SAM_SERCOM3_BASE,
+#if 0 /* Not used */
+ .handler = spi3_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -422,7 +472,9 @@ static struct sam_spidev_s g_spi4dev =
{
.ops = &g_spi4ops,
.sercom = 4,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM4,
+#endif
.gclkgen = (BOARD_SERCOM4_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM4_PINMAP_PAD0,
.pad1 = BOARD_SERCOM4_PINMAP_PAD1,
@@ -431,6 +483,9 @@ static struct sam_spidev_s g_spi4dev =
.muxconfig = BOARD_SERCOM4_MUXCONFIG,
.srcfreq = BOARD_SERCOM4_FREQUENCY,
.base = SAM_SERCOM4_BASE,
+#if 0 /* Not used */
+ .handler = spi4_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -469,7 +524,9 @@ static struct sam_spidev_s g_spi5dev =
{
.ops = &g_spi5ops,
.sercom = 5,
+#if 0 /* Not used */
.irq = SAM_IRQ_SERCOM5,
+#endif
.gclkgen = (BOARD_SERCOM5_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.pad0 = BOARD_SERCOM5_PINMAP_PAD0,
.pad1 = BOARD_SERCOM5_PINMAP_PAD1,
@@ -478,6 +535,9 @@ static struct sam_spidev_s g_spi5dev =
.muxconfig = BOARD_SERCOM5_MUXCONFIG,
.srcfreq = BOARD_SERCOM5_FREQUENCY,
.base = SAM_SERCOM5_BASE,
+#if 0 /* Not used */
+ .handler = spi5_interrupt,
+#endif
#ifndef CONFIG_SPI_OWNBUS
.spilock = SEM_INITIALIZER(1),
#endif
@@ -718,6 +778,115 @@ static void spi_dumpregs(struct sam_spidev_s *priv, const char *msg)
#endif
/****************************************************************************
+ * Name: spi_interrupt
+ *
+ * Description:
+ * This is the USART interrupt handler. It will be invoked when an
+ * interrupt received on the 'irq' It should call uart_transmitchars or
+ * uart_receivechar to perform the appropriate data transfers. The
+ * interrupt handling logic must be able to map the 'irq' number into the
+ * approprite sam_spidev_s structure in order to call these functions.
+ *
+ ****************************************************************************/
+
+#if 0 /* Not used */
+static int spi_interrupt(struct sam_spidev_s *dev)
+{
+ struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv;;
+ uint8_t pending;
+ uint8_t intflag;
+ uint8_t inten;
+
+ /* Get the set of pending SPI interrupts (we are only interested in the
+ * unmasked interrupts).
+ */
+
+ intflag = sam_serialin8(priv, SAM_USART_INTFLAG_OFFSET);
+ inten = sam_serialin8(priv, SAM_USART_INTENCLR_OFFSET);
+ pending = intflag & inten;
+
+ /* Handle an incoming, receive byte. The RXC flag is set when there is
+ * unread data in DATA register. This flag is cleared by reading the DATA
+ * register (or by disabling the receiver).
+ */
+
+ if ((pending & USART_INT_RXC) != 0)
+ {
+ /* Received data ready... process incoming SPI ata */
+#warning Missing logic
+ }
+
+ /* Handle outgoing, transmit bytes. The DRE flag is set when the DATA
+ * register is empty and ready to be written. This flag is cleared by
+ * writing new data to the DATA register. If there is no further data to
+ * be transmitted, the serial driver will disable TX interrupts, prohibit
+ * further interrupts until TX interrupts are re-enabled.
+ */
+
+ if ((pending & USART_INT_DRE) != 0)
+ {
+ /* Transmit data register empty ... process outgoing bytes */
+#warning Missing logic
+ }
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: spiN_interrupt
+ *
+ * Description:
+ * Handle each SERCOM USART interrupt by calling the common interrupt
+ * handling logic with the USART-specific state.
+ *
+ ****************************************************************************/
+
+#if 0 /* Not used */
+#ifdef SAMD_HAVE_USART0
+static int spi0_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi0dev);
+}
+#endif
+
+#ifdef SAMD_HAVE_USART1
+static int spi1_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi1dev);
+}
+#endif
+
+#ifdef SAMD_HAVE_USART2
+static int spi2_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi2dev);
+}
+#endif
+
+#ifdef SAMD_HAVE_USART3
+static int spi3_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi3dev);
+}
+#endif
+
+#ifdef SAMD_HAVE_USART4
+static int spi4_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi4dev);
+}
+#endif
+
+#ifdef SAMD_HAVE_USART5
+static int spi5_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spi5dev);
+}
+#endif
+#endif
+
+/****************************************************************************
* Name: spi_lock
*
* Description:
@@ -784,10 +953,23 @@ static int spi_lock(struct spi_dev_s *dev, bool lock)
static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency)
{
struct sam_spidev_s *priv =(struct sam_spidev_s *)dev;
+ uint32_t maxfreq;
uint32_t actual;
+ uint32_t baud;
spivdbg("sercom=%d frequency=%d\n", priv->sercom, frequency);
+ /* Check if the configured BAUD is within the valid range */
+
+ maxfreq = (priv->srcfreq >> 1);
+ if (frequency > maxfreq)
+ {
+ /* Set the frequency to the maximum */
+
+ spidbg("ERROR: Cannot realize frequency: %ld\n", (long)frequency);
+ frequency = maxfreq;
+ }
+
/* Check if the requested frequency is the same as the frequency selection */
#ifndef CONFIG_SPI_OWNBUS
@@ -799,15 +981,33 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency)
}
#endif
- /* Configure SPI to a frequency as close as possible to the requested
- * frequency.
+ /* For synchronous mode, the BAUAD rate (Fbaud) is generated from the
+ * source clock frequency (Fref) as follows:
+ *
+ * Fbaud = Fref / (2 * (BAUD + 1))
+ *
+ * Or
+ *
+ * BAUD = (Fref / (2 * Fbaud)) - 1
+ *
+ * Where BAUD <= 255
*/
-#warning Missing logic
+
+ baud = ((priv->srcfreq + frequency) / (frequency << 1)) - 1;
+
+ /* Verify that the resulting if BAUD divisor is within range */
+
+ if (baud > 255)
+ {
+ spidbg("ERROR: BAUD is out of range: %ld\n", (long)baud);
+ baud = 255;
+ }
+
+ spi_putreg8(priv, (uint8_t)baud, SAM_SPI_BAUD_OFFSET);
/* Calculate the new actual frequency */
-#warning Missing logic
- spivdbg("actual=%d\n", offset, regval, actual);
+ actual = priv->srcfreq / ((baud + 1) << 1);
/* Save the frequency setting */
@@ -816,7 +1016,7 @@ static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency)
priv->actual = actual;
#endif
- spidbg("Frequency %d->%d\n", frequency, actual);
+ spivdbg("Frequency %d->%d\n", frequency, actual);
return actual;
}
@@ -909,13 +1109,6 @@ static void spi_setbits(struct spi_dev_s *dev, int nbits)
spivdbg("sercom=%d nbits=%d\n", priv->sercom, nbits);
DEBUGASSERT(priv && nbits > 7 && nbits < 10);
- /* NOTE: The logic in spi_send and in spi_exchange only handles 8-bit
- * data at the present time. So the following extra assertion is a
- * reminder that we have to fix that someday.
- */
-
- DEBUGASSERT(nbits == 8); /* Temporary -- FIX ME */
-
/* Has the number of bits changed? */
#ifndef CONFIG_SPI_OWNBUS
@@ -1001,12 +1194,28 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
void *rxbuffer, size_t nwords)
{
struct sam_spidev_s *priv = (struct sam_spidev_s *)dev;
- cont uint8_t *txptr = (const uint8_t *)txbuffer;
- uint8_t *rxptr = (uint8_t *)rxbuffer;
+ const uint16_t *ptx16 = NULL;
+ const uint8_t *ptx8 = NULL;
+ uint16_t *prx16 = NULL;
+ uint8_t *prx8 = NULL;
uint16_t data;
spivdbg("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords);
+ /* Set up data receive and transmit pointers */
+
+ wide = ;
+ if (priv->nbits > 8)
+ {
+ ptx16 = (const uint16_t *)txbuffer;
+ prx16 = (uint16_t *)rxbuffer;
+ }
+ else
+ {
+ ptx8 = (const uint8_t *)txbuffer;
+ prx8 = (uint8_t *)rxbuffer;
+ }
+
/* Loop, sending each word in the user-provided data buffer.
*
* Note 1: Right now, this only deals with 8-bit words. If the SPI
@@ -1040,13 +1249,17 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
{
/* Get the data to send (0xff if there is no data source) */
- if (txptr)
+ if (ptx8)
+ {
+ data = (uint16_t)*ptx8++;
+ }
+ else if (ptx16)
{
- data = (uint32_t)*txptr++;
+ data = *ptx16++;
}
else
{
- data = 0xffff;
+ data = 0x01ff;
}
/* Wait for any previous data written to the DATA register to be
@@ -1063,14 +1276,33 @@ static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
while ((spi_getreg32(priv, SAM_SPI_INTFLAG_OFFSET) & SPI_INT_RXC) == 0);
+ /* Check for data overflow. The BUFOVF bit provides the status of the
+ * next DATA to be read. On buffer overflow, the corresponding DATA
+ * will be 0.
+ */
+
+ data = spi_getreg16(priv, SAM_SPI_STATUS_OFFSET);
+ if (data & SPI_STATUS_BUFOVF) != 0)
+ {
+ spidbg("ERROR: Buffer overflow!\n");
+
+ /* Clear the buffer overflow flag */
+
+ spi_putreg(priv, data, SAM_SPI_STATUS_OFFSET);
+ }
+
/* Read the received data from the SPI DATA Register..
* TODO: The following only works if nbits <= 8.
*/
data = spi_getreg16(priv, SAM_SPI_DATA_OFFSET);
- if (rxptr)
+ if (prx8)
{
- *rxptr++ = (uint8_t)data;
+ *prx8++ = (uint8_t)data;
+ }
+ else if (prx16)
+ {
+ *prx16++ = (uint16_t)data;
}
}
}
@@ -1132,6 +1364,19 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords)
#endif
/****************************************************************************
+ * Name: spi_wait_synchronization
+ *
+ * Description:
+ * Wait until the SERCOM SPI reports that it is synchronized.
+ *
+ ****************************************************************************/
+
+static void spi_wait_synchronization(struct sam_spidev_s *priv)
+{
+ while ((getreg16(priv->base + SAM_USART_STATUS_OFFSET) & USART_STATUS_SYNCBUSY) != 0);
+}
+
+/****************************************************************************
* Name: spi_pad_configure
*
* Description:
@@ -1186,10 +1431,9 @@ struct spi_dev_s *up_spiinitialize(int port)
{
struct sam_spidev_s *priv;
irqstate_t flags;
-#ifndef CONFIG_SPI_OWNBUS
uint32_t regval;
- unsigned int offset;
-#endif
+ uint32_t baud;
+ int ret;
/* Get the port state structure */
@@ -1247,36 +1491,84 @@ struct spi_dev_s *up_spiinitialize(int port)
return NULL;
}
- /* Enable clocking to the SPI SERCOM */
+ /* Enable clocking to the SERCOM module in PM */
- flags = irqsave();
-#warning Missing logic
+ flags = irqsave();
+ sercom_enable(priv->sercom);
- /* Configure multiplexed pins as connected on the board. */
-#warning Missing logic
+ /* Configure the GCLKs for the SERCOM module */
- /* Execute a software reset of the SPI SERCOM */
-#warning Missing logic
+ sercom_coreclk_configure(priv->sercom, priv->gclkgen, false);
+ sercom_slowclk_configure(BOARD_SERCOM_SLOW_GCLKGEN);
- /* Configure the SPI SERCOM */
-#warning Missing logic
+ /* Set the SERCOM in SPI master mode */
- /* And enable the SPI */
-#warning Missing logic
+ regval = spi_getreg32(priv, SAM_SPI_CTRLA_OFFSET);
+ regval &= ~SPI_CTRLA_MODE_MASK;
+ regval |= SPI_CTRLA_MODE_MASTER;
+ spi_putreg32(priv, regval, SAM_SPI_CTRLA_OFFSET);
- spi_dumpregs(priv, "After initialization");
+ /* Configure pads */
+
+ spi_pad_configure(priv);
+
+ /* Set an initial baud value. This will be changed by the upper-half
+ * driver as soon as it starts.
+ */
+
+ (void)spi_setfrequency((struct spi_dev_s *)priv, 400000);
+
+ /* Set MSB first data order and the configured pad mux setting,
+ * Note that SPI mode 0 are assumed initially.
+ */
+
+ regval = (SPI_DATA_ORDER_MSB | priv->muxconfig);
+ spi_putreg8(priv, regval, SAM_SPI_CTRLA_OFFSET);
+
+ /* Enable the receiver. Note that 8-bit data width is assumed initially */
+
+ regval = SPI_CTRLB_RXEN;
+ spi_putreg8(priv, regval, SAM_SPI_CTRLB_OFFSET);
#ifndef CONFIG_SPI_OWNBUS
- /* Set to mode=0 and nbits=8 and some initial frequency. It is only
- * critical to do this if CONFIG_SPI_OWNBUS is not defined because in
- * that case, the SPI will only be reconfigured if there is a change.
+ priv->nbits = nbits;
+#endif
+
+ /* Wait until the synchronization is complete */
+
+ spi_wait_synchronization(priv);
+
+ /* Enable SPI */
+
+ regval = spi_getreg32(priv, SAM_SPI_CTRLA_OFFSET);
+ regval |= SPI_CTRLA_ENABLE;
+ spi_putreg32(priv, regval, SAM_SPI_CTRLA_OFFSET);
+
+ /* Disable all interrupts at the SPI source and clear all pending
+ * status that we can.
*/
- spi_setmode((struct spi_dev_s *)priv, SPIDEV_MODE0);
- spi_setfrequency((struct spi_dev_s *)priv, 400000);
- spi_setbits((struct spi_dev_s *)priv, 8);
+ spi_putreg8(priv, SPI_INT_ALL, SAM_SPI_INTENCLR_OFFSET);
+ spi_putreg8(priv, SPI_INT_ALL, SAM_SPI_INTFLAG_OFFSET);
+ spi_putreg16(priv, SPI_STATUS_CLRALL, SAM_SPI_STATUS_OFFSET);
+
+#if 0 /* Not used */
+ /* Attach and enable the SERCOM interrupt handler */
+
+ ret = irq_attach(priv->irq, priv->handler);
+ if (ret < 0)
+ {
+ spidbg("ERROR: Failed to attach interrupt: %d\n", irq);
+ return NULL;
+ }
+
+ /* Enable SERCOM interrupts at the NVIC */
+
+ up_enable_irq(priv->irq);
#endif
+ spi_dumpregs(priv, "After initialization");
+ irqrestore(flags);
return (struct spi_dev_s *)priv;
}
diff --git a/nuttx/configs/samd20-xplained/include/board.h b/nuttx/configs/samd20-xplained/include/board.h
index 7b04891a0..a17d630ad 100644
--- a/nuttx/configs/samd20-xplained/include/board.h
+++ b/nuttx/configs/samd20-xplained/include/board.h
@@ -355,7 +355,65 @@
#endif
/* SERCOM definitions ***************************************************************/
-/* SERCOM4 is available on connectors EXT1, EXT2, and EXT3
+/* This is the source clock generator for the GCLK_SERCOM_SLOW clock that is common
+ * to all SERCOM modules.
+ */
+
+#define BOARD_SERCOM_SLOW_GCLKGEN (GCLK_CLKCTRL_GEN0 >> GCLK_CLKCTRL_GEN_SHIFT)
+
+/* SERCOM0 SPI is available on EXT1
+ *
+ * PIN PORT SERCOM FUNCTION
+ * --- ------------------ -----------
+ * 15 PA5 SERCOM0 PAD1 SPI SS
+ * 16 PA6 SERCOM0 PAD2 SPI MOSI
+ * 17 PA4 SERCOM0 PAD0 SPI MISO
+ * 18 PA7 SERCOM0 PAD3 SPI SCK
+ */
+
+#define BOARD_SERCOM0_CLKGEN GCLK_CLKCTRL_GEN0
+#define BOARD_SERCOM0_MUX_SETTING (SPI_CTRLA_DOPO_DOPAD231 | SPI_CTRLA_DIPAD0)
+#define BOARD_SERCOM0_PINMUX_PAD0 PINMUX_PA04D_SERCOM0_PAD0 /* SPI_MISO */
+#define BOARD_SERCOM0_PINMUX_PAD1 0 /* microSD_SS */
+#define BOARD_SERCOM0_PINMUX_PAD2 PINMUX_PA06D_SERCOM0_PAD2 /* SPI_MOSI */
+#define BOARD_SERCOM0_PINMUX_PAD3 PINMUX_PA07D_SERCOM0_PAD3 /* SPI_SCK */
+
+/* SERCOM1 SPI is available on EXT2
+ *
+ * PIN PORT SERCOM FUNCTION
+ * --- ------------------ -----------
+ * 15 PA17 SERCOM1 PAD1 SPI SS
+ * 16 PA18 SERCOM1 PAD2 SPI MOSI
+ * 17 PA16 SERCOM1 PAD0 SPI MISO
+ * 18 PA19 SERCOM1 PAD3 SPI SCK
+ */
+
+#define BOARD_SERCOM1_CLKGEN GCLK_CLKCTRL_GEN0
+#define BOARD_SERCOM1_MUX_SETTING (SPI_CTRLA_DOPO_DOPAD231 | SPI_CTRLA_DIPAD0)
+#define BOARD_SERCOM1_PINMUX_PAD0 PINMUX_PA16C_SERCOM1_PAD0 /* SPI_MISO */
+#define BOARD_SERCOM1_PINMUX_PAD1 0 /* microSD_SS */
+#define BOARD_SERCOM1_PINMUX_PAD2 PINMUX_PA18C_SERCOM1_PAD2 /* SPI_MOSI */
+#define BOARD_SERCOM1_PINMUX_PAD3 PINMUX_PA19C_SERCOM1_PAD3 /* SPI_SCK */
+
+/* The SAMD20 Xplained Pro contains an Embedded Debugger (EDBG) that can be
+ * used to program and debug the ATSAMD20J18A using Serial Wire Debug (SWD).
+ * The Embedded debugger also include a Virtual COM port interface over
+ * SERCOM3. Virtual COM port connections:
+ *
+ * PA24 SERCOM3 / USART TXD
+ * PA25 SERCOM3 / USART RXD
+ */
+
+#define BOARD_SERCOM3_GCLKGEN GCLK_CLKCTRL_GEN0
+#define BOARD_SERCOM3_MUXCONFIG (USART_CTRLA_RXPAD3 | USART_CTRLA_TXPAD2)
+#define BOARD_SERCOM3_PINMAP_PAD0 0
+#define BOARD_SERCOM3_PINMAP_PAD1 0
+#define BOARD_SERCOM3_PINMAP_PAD2 PORT_SERCOM3_PAD2_1 /* USART TX */
+#define BOARD_SERCOM3_PINMAP_PAD3 PORT_SERCOM3_PAD3_1 /* USART RX */
+
+#define BOARD_SERCOM3_FREQUENCY BOARD_GCLK0_FREQUENCY
+
+/* The SERCOM4 USART is available on connectors EXT1, EXT2, and EXT3
*
* PIN EXT1 EXT2 EXT3 GPIO Function
* ---- ---- ---- ---- ------------------
@@ -374,43 +432,42 @@
#if defined(CONFIG_SAMD20_XPLAINED_USART4_EXT1)
# define BOARD_SERCOM4_MUXCONFIG (USART_CTRLA_RXPAD1 | USART_CTRLA_TXPAD0)
-# define BOARD_SERCOM4_PINMAP_PAD0 PORT_SERCOM4_PAD0_3
-# define BOARD_SERCOM4_PINMAP_PAD1 PORT_SERCOM4_PAD1_3
+# define BOARD_SERCOM4_PINMAP_PAD0 PORT_SERCOM4_PAD0_3 /* USART TX */
+# define BOARD_SERCOM4_PINMAP_PAD1 PORT_SERCOM4_PAD1_3 /* USART RX */
# define BOARD_SERCOM4_PINMAP_PAD2 0
# define BOARD_SERCOM4_PINMAP_PAD3 0
#elif defined(CONFIG_SAMD20_XPLAINED_USART4_EXT2)
# define BOARD_SERCOM4_MUXCONFIG (USART_CTRLA_RXPAD1 | USART_CTRLA_TXPAD0)
-# define BOARD_SERCOM4_PINMAP_PAD0 PORT_SERCOM4_PAD0_1
-# define BOARD_SERCOM4_PINMAP_PAD1 PORT_SERCOM4_PAD1_1
+# define BOARD_SERCOM4_PINMAP_PAD0 PORT_SERCOM4_PAD0_1 /* USART TX */
+# define BOARD_SERCOM4_PINMAP_PAD1 PORT_SERCOM4_PAD1_1 /* USART RX */
# define BOARD_SERCOM4_PINMAP_PAD2 0
# define BOARD_SERCOM4_PINMAP_PAD3 0
#else /* if defined(CONFIG_SAMD20_XPLAINED_USART4_EXT3) */
# define BOARD_SERCOM4_MUXCONFIG (USART_CTRLA_RXPAD3 | USART_CTRLA_TXPAD2)
# define BOARD_SERCOM4_PINMAP_PAD0 0
# define BOARD_SERCOM4_PINMAP_PAD1 0
-# define BOARD_SERCOM4_PINMAP_PAD2 PORT_SERCOM4_PAD2_3
-# define BOARD_SERCOM4_PINMAP_PAD3 PORT_SERCOM4_PAD3_3
+# define BOARD_SERCOM4_PINMAP_PAD2 PORT_SERCOM4_PAD2_3 /* USART TX */
+# define BOARD_SERCOM4_PINMAP_PAD3 PORT_SERCOM4_PAD3_3 /* USART RX */
#endif
#define BOARD_SERCOM4_FREQUENCY BOARD_GCLK0_FREQUENCY
-/* The SAMD20 Xplained Pro contains an Embedded Debugger (EDBG) that can be
- * used to program and debug the ATSAMD20J18A using Serial Wire Debug (SWD).
- * The Embedded debugger also include a Virtual COM port interface over
- * SERCOM3. Virtual COM port connections:
+/* SERCOM5 SPI is available on EXT3
*
- * PA24 SERCOM3 / USART TXD
- * PA25 SERCOM3 / USART RXD
+ * PIN PORT SERCOM FUNCTION
+ * --- ------------------ -----------
+ * 15 PB17 SERCOM5 PAD1 SPI SS
+ * 16 PB22 SERCOM5 PAD2 SPI MOSI
+ * 17 PB16 SERCOM5 PAD0 SPI MISO
+ * 18 PB23 SERCOM5 PAD3 SPI SCK
*/
-#define BOARD_SERCOM3_GCLKGEN GCLK_CLKCTRL_GEN0
-#define BOARD_SERCOM3_MUXCONFIG (USART_CTRLA_RXPAD3 | USART_CTRLA_TXPAD2)
-#define BOARD_SERCOM3_PINMAP_PAD0 0
-#define BOARD_SERCOM3_PINMAP_PAD1 0
-#define BOARD_SERCOM3_PINMAP_PAD2 PORT_SERCOM3_PAD2_1
-#define BOARD_SERCOM3_PINMAP_PAD3 PORT_SERCOM3_PAD3_1
-
-#define BOARD_SERCOM3_FREQUENCY BOARD_GCLK0_FREQUENCY
+#define BOARD_SERCOM5_CLKGEN GCLK_CLKCTRL_GEN0
+#define BOARD_SERCOM5_MUX_SETTING (SPI_CTRLA_DOPO_DOPAD231 | SPI_CTRLA_DIPAD0)
+#define BOARD_SERCOM5_PINMUX_PAD0 PINMUX_PB16C_SERCOM5_PAD0 /* SPI_MISO */
+#define BOARD_SERCOM5_PINMUX_PAD1 0 /* microSD_SS */
+#define BOARD_SERCOM5_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 /* SPI_MOSI */
+#define BOARD_SERCOM5_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 /* SPI_SCK */
/* LED definitions ******************************************************************/
/* There are three LEDs on board the SAMD20 Xplained Pro board: The EDBG