SAMD20: SPI driver is code-complete, but untested

This commit is contained in:
Gregory Nutt 2014-02-20 09:59:54 -06:00
parent e013c96358
commit 8bbf4f3ec8
7 changed files with 441 additions and 83 deletions

View File

@ -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).

View File

@ -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) */

View File

@ -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 */

View File

@ -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;

View File

@ -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).
*/

View File

@ -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
@ -717,6 +777,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
*
@ -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 = (uint32_t)*txptr++;
data = (uint16_t)*ptx8++;
}
else if (ptx16)
{
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;
}
}
}
@ -1131,6 +1363,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
*
@ -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 */
#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.
spi_pad_configure(priv);
/* Set an initial baud value. This will be changed by the upper-half
* driver as soon as it starts.
*/
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);
(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
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_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;
}

View File

@ -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