summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/samd
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-02-16 09:42:29 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-02-16 09:42:29 -0600
commitf8461f63db16041fe03271b5c1944e79c10f89a2 (patch)
tree7bc7a90a7a4e97f8b359abc3809cbeac1d13ac37 /nuttx/arch/arm/src/samd
parent1d6dcf00768446524ee16b5e1343f0337ba4ac91 (diff)
downloadnuttx-f8461f63db16041fe03271b5c1944e79c10f89a2.tar.gz
nuttx-f8461f63db16041fe03271b5c1944e79c10f89a2.tar.bz2
nuttx-f8461f63db16041fe03271b5c1944e79c10f89a2.zip
SAMD20: Completes low-level USART logic
Diffstat (limited to 'nuttx/arch/arm/src/samd')
-rw-r--r--nuttx/arch/arm/src/samd/chip/sam_usart.h9
-rw-r--r--nuttx/arch/arm/src/samd/sam_lowputc.c240
-rw-r--r--nuttx/arch/arm/src/samd/sam_usart.c12
-rw-r--r--nuttx/arch/arm/src/samd/sam_usart.h16
4 files changed, 224 insertions, 53 deletions
diff --git a/nuttx/arch/arm/src/samd/chip/sam_usart.h b/nuttx/arch/arm/src/samd/chip/sam_usart.h
index 322d5bf37..c202c6f8f 100644
--- a/nuttx/arch/arm/src/samd/chip/sam_usart.h
+++ b/nuttx/arch/arm/src/samd/chip/sam_usart.h
@@ -47,11 +47,12 @@
#include <nuttx/config.h>
#include "chip.h"
+#include "chip/sam_sercom.h"
/********************************************************************************************
* Pre-processor Definitions
********************************************************************************************/
-/* USART register offsets ********************************************************************/
+/* USART register offsets *******************************************************************/
#define SAM_USART_CTRLA_OFFSET 0x0000 /* Control A register */
#define SAM_USART_CTRLB_OFFSET 0x0000 /* Control B register */
@@ -63,7 +64,7 @@
#define SAM_USART_STATUS_OFFSET 0x0000 /* Status register */
#define SAM_USART_DATA_OFFSET 0x0000 /* Data register */
-/* USART register addresses ******************************************************************/
+/* USART register addresses *****************************************************************/
#define SAM_USART0_CTRLA (SAM_SERCOM0_BASE+SAM_USART_CTRLA_OFFSET)
#define SAM_USART0_CTRLB (SAM_SERCOM0_BASE+SAM_USART_CTRLB_OFFSET)
@@ -125,7 +126,7 @@
#define SAM_USART5_STATUS (SAM_SERCOM5_BASE+SAM_USART_STATUS_OFFSET)
#define SAM_USART5_DATA (SAM_SERCOM5_BASE+SAM_USART_DATA_OFFSET)
-/* USART register bit definitions ************************************************************/
+/* USART register bit definitions ***********************************************************/
/* Control A register */
@@ -193,6 +194,8 @@
#define USART_INT_RXC (1 << 2) /* Bit 2: Receive complete interrupt */
#define USART_INT_RXS (1 << 3) /* Bit 3: Receive start interrupt */
+#define USART_INT_ALL (0x0f)
+
/* Status register */
#define USART_STATUS_PERR (1 << 0) /* Bit 0: Parity error */
diff --git a/nuttx/arch/arm/src/samd/sam_lowputc.c b/nuttx/arch/arm/src/samd/sam_lowputc.c
index 7c10b61ec..b98088df9 100644
--- a/nuttx/arch/arm/src/samd/sam_lowputc.c
+++ b/nuttx/arch/arm/src/samd/sam_lowputc.c
@@ -55,8 +55,11 @@
#include "up_arch.h"
#include "sam_config.h"
+
#include "chip/sam_pm.h"
+#include "chip/sam_gclk.h"
#include "chip/sam_usart.h"
+
#include "sam_usart.h"
/****************************************************************************
@@ -100,11 +103,80 @@ sam_wait_synchronization(const struct sam_usart_config_s * const config)
****************************************************************************/
#ifdef HAVE_USART
-static inline int
+static inline void
sam_gclk_configure(const struct sam_usart_config_s * const config)
{
-#warning Missing logic
- return -ENOSYS;
+ uint8_t regval;
+ uint8_t glckcore;
+
+ /* Set up the SERCOMn_GCLK_ID_CORE clock */
+
+ glckcore = (uint8_t)SERCOM_GCLK_ID_CORE(config->sercom);
+ regval = (glckcore << GCLK_CLKCTRL_ID_SHIFT);
+
+ /* Select and disable generic clock channel */
+
+ putreg8(regval, SAM_GCLK_CLKCTRL);
+
+ /* Wait for clock to become disabled */
+
+ while ((getreg8(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0);
+
+ /* Select the SERCOMn_GCLK_ID_CORE clock generator */
+
+ regval |= config->gclkgen << GCLK_CLKCTRL_GEN_SHIFT;
+
+#if 0 /* Not yet supported */
+ /* Enable write lock if requested to prevent further modification */
+
+ if (config->wrlock)
+ {
+ regval |= GCLK_CLKCTRL_WRTLOCK;
+ }
+#endif
+
+ /* Write the new configuration */
+
+ putreg8(regval, SAM_GCLK_CLKCTRL);
+
+ /* Enable the GCLK */
+
+ regval |= GCLK_CLKCTRL_CLKEN;
+ putreg8(regval, SAM_GCLK_CLKCTRL);
+
+ /* Set up the SERCOM_GCLK_ID_SLOW clock */
+
+ regval = (SERCOM_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_SHIFT);
+
+ /* Select and disable generic clock channel */
+
+ putreg8(regval, SAM_GCLK_CLKCTRL);
+
+ /* Wait for clock to become disabled */
+
+ while ((getreg8(SAM_GCLK_CLKCTRL) & GCLK_CLKCTRL_CLKEN) != 0);
+
+ /* Select the SERCOM_GCLK_ID_SLOW clock generator */
+
+ regval |= config->gclkgen << GCLK_CLKCTRL_GEN_SHIFT;
+
+#if 0 /* Not yet supported */
+ /* Enable write lock if requested to prevent further modification */
+
+ if (config->wrlock)
+ {
+ regval |= GCLK_CLKCTRL_WRTLOCK;
+ }
+#endif
+
+ /* Write the new configuration */
+
+ putreg8(regval, SAM_GCLK_CLKCTRL);
+
+ /* Enable the GCLK */
+
+ regval |= GCLK_CLKCTRL_CLKEN;
+ putreg8(regval, SAM_GCLK_CLKCTRL);
}
#endif
@@ -142,11 +214,15 @@ sam_usart_configure(const struct sam_usart_config_s * const config)
return -ERANGE;
}
+ /* Disable all USART interrupts */
+
+ putreg8(USART_INT_ALL, config->base + SAM_USART_INTENCLR_OFFSET);
+
/* Wait until synchronization is complete */
sam_wait_synchronization(config);
- /* Set baud val */
+ /* Set baud divisor */
putreg16((uint16_t)baud, config->base + SAM_USART_BAUD_OFFSET);
@@ -223,7 +299,7 @@ sam_usart_configure(const struct sam_usart_config_s * const config)
/* Write configuration to CTRLB */
- putreg32(ctrlb, SAM_USART5_CTRLB);
+ putreg32(ctrlb, config->base + SAM_USART_CTRLB_OFFSET);
/* Wait until synchronization is complete */
@@ -231,7 +307,7 @@ sam_usart_configure(const struct sam_usart_config_s * const config)
/* Write configuration to CTRLA */
- putreg32(ctrlb, SAM_USART5_CTRLA);
+ putreg32(ctrlb, config->base + SAM_USART_CTRLA_OFFSET);
return OK;
}
#endif
@@ -245,11 +321,98 @@ sam_usart_configure(const struct sam_usart_config_s * const config)
****************************************************************************/
#ifdef HAVE_USART
-static inline int
+static inline void
sam_pad_configure(const struct sam_usart_config_s * const config)
{
-#warning Missing logic
- return -ENOSYS;
+ /* Configure SERCOM pads */
+
+ if (config->pad0 != 0)
+ {
+ sam_configport(config->pad0);
+ }
+
+ if (config->pad1 != 0)
+ {
+ sam_configport(config->pad1);
+ }
+
+ if (config->pad2 != 0)
+ {
+ sam_configport(config->pad2);
+ }
+
+ if (config->pad3 != 0)
+ {
+ sam_configport(config->pad3);
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_usart_internal
+ *
+ * Description:
+ * Set the configuration of a SERCOM for provided USART configuration.
+ * This configures the SERCOM as a USART, but does not configure USART
+ * interrupts or enable the USART.
+ *
+ *****************************************************************************/
+
+#ifdef HAVE_USART
+int sam_usart_internal(const struct sam_usart_config_s * const config)
+{
+ uint32_t regval;
+ int ret;
+
+ /* Enable clocking to the SERCOM module in PM */
+
+ regval = getreg32(SAM_PM_APBCMASK);
+ regval |= PM_APBCMASK_SERCOM(config->sercom);
+ putreg32(regval, SAM_PM_APBCMASK);
+
+ /* Configure the GCCLK for the SERCOM module */
+
+ sam_gclk_configure(config);
+
+ /* Set configuration according to the board configuration */
+
+ ret = sam_usart_configure(config);
+ if (ret == OK)
+ {
+ /* Configure USART pins */
+
+ sam_pad_configure(config);
+ }
+
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_usart_enable
+ *
+ * Description:
+ * Enable the SERCOM USART (without enabling interrupts).
+ *
+ ****************************************************************************/
+
+#ifdef HAVE_USART
+static inline void
+sam_usart_enable(const struct sam_usart_config_s * const config)
+{
+ uintptr_t regaddr;
+ uint32_t regval;
+
+ /* Wait until synchronization is complete */
+
+ sam_wait_synchronization(config);
+
+ /* Enable USART module */
+
+ regaddr = config->base + SAM_USART_CTRLA_OFFSET;
+ regval = getreg32(regaddr);
+ regval |= USART_CTRLA_ENABLE;
+ putreg32(regval, regaddr);
}
#endif
@@ -268,7 +431,12 @@ sam_pad_configure(const struct sam_usart_config_s * const config)
void sam_lowsetup(void)
{
-#warning Missing logic
+#ifdef HAVE_SERIAL_CONSOLE
+ /* Configure and enable the console USART */
+
+ VERIFY(sam_usart_internal(&g_consoleconfig));
+ sam_usart_enable(&g_consoleconfig);
+#endif
}
/****************************************************************************
@@ -284,34 +452,17 @@ void sam_lowsetup(void)
#ifdef HAVE_USART
int sam_usart_initialize(const struct sam_usart_config_s * const config)
{
- uint32_t regval;
+ irqstate_t flags;
int ret;
- /* Enable clocking to the SERCOM module in PM */
-
- regval = getreg32(SAM_PM_APBCMASK);
- regval |= PM_APBCMASK_SERCOM(config->sercom);
- putreg32(regval, SAM_PM_APBCMASK);
-
- /* Configure the GCCLK for the SERCOM module */
-
- ret = sam_gclk_configure(config);
- if (ret < 0)
- {
- return ret;
- }
+ /* Just invoke the internal implementation, but with interrupts disabled
+ * so that the operation is atomic.
+ */
- /* Set configuration according to the board configuration */
-
- ret = sam_usart_configure(config);
- if(ret < 0)
- {
- return ret;
- }
-
- /* Configure USART pins */
-
- return sam_pad_configure(config);
+ flags = irqsave();
+ ret = sam_usart_internal(config);
+ irqrestore(flags);
+ return ret;
}
#endif
@@ -326,6 +477,23 @@ int sam_usart_initialize(const struct sam_usart_config_s * const config)
#ifdef HAVE_SERIAL_CONSOLE
void sam_lowputc(uint32_t ch)
{
-#warning Missing logic
+ uintptr_t base = g_consoleconfig.base;
+ uintptr_t intflag = base + SAM_USART_INTFLAG_OFFSET;
+
+ /* Wait for the USART to be ready for new TX data */
+
+ while ((getreg8(intflag) & USART_INT_DRE) == 0);
+
+ /* Wait until synchronization is complete */
+
+ sam_wait_synchronization(&g_consoleconfig);
+
+ /* Write data to USART module */
+
+ putreg16((uint16_t)ch, base + SAM_USART_DATA_OFFSET);
+
+ /* Wait until data is sent */
+
+ while ((getreg8(intflag) & USART_INT_TXC) == 0);
}
#endif
diff --git a/nuttx/arch/arm/src/samd/sam_usart.c b/nuttx/arch/arm/src/samd/sam_usart.c
index dae8c851b..426d8a4f7 100644
--- a/nuttx/arch/arm/src/samd/sam_usart.c
+++ b/nuttx/arch/arm/src/samd/sam_usart.c
@@ -65,7 +65,7 @@ const struct sam_usart_config_s g_usart0config =
.parity = CONFIG_USART0_PARITY,
.bits = CONFIG_USART0_BITS,
.irq = SAM_IRQ_SERCOM0,
- .gclk = (BOARD_SERCOM0_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM0_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART0_2STOP,
.baud = CONFIG_USART0_BAUD,
.pad0 = BOARD_SERCOM0_PINMAP_PAD0,
@@ -85,7 +85,7 @@ const struct sam_usart_config_s g_usart1config =
.parity = CONFIG_USART1_PARITY,
.bits = CONFIG_USART1_BITS,
.irq = SAM_IRQ_SERCOM1,
- .gclk = (BOARD_SERCOM1_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM1_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART1_2STOP,
.baud = CONFIG_USART1_BAUD,
.pad0 = BOARD_SERCOM1_PINMAP_PAD0,
@@ -105,7 +105,7 @@ const struct sam_usart_config_s g_usart2config =
.parity = CONFIG_USART2_PARITY,
.bits = CONFIG_USART2_BITS,
.irq = SAM_IRQ_SERCOM2,
- .gclk = (BOARD_SERCOM2_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM2_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART2_2STOP,
.baud = CONFIG_USART2_BAUD,
.pad0 = BOARD_SERCOM2_PINMAP_PAD0,
@@ -125,7 +125,7 @@ const struct sam_usart_config_s g_usart3config =
.parity = CONFIG_USART3_PARITY,
.bits = CONFIG_USART3_BITS,
.irq = SAM_IRQ_SERCOM3,
- .gclk = (BOARD_SERCOM3_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM3_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART3_2STOP,
.baud = CONFIG_USART3_BAUD,
.pad0 = BOARD_SERCOM3_PINMAP_PAD0,
@@ -145,7 +145,7 @@ const struct sam_usart_config_s g_usart4config =
.parity = CONFIG_USART4_PARITY,
.bits = CONFIG_USART4_BITS,
.irq = SAM_IRQ_SERCOM4,
- .gclk = (BOARD_SERCOM4_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM4_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART4_2STOP,
.baud = CONFIG_USART4_BAUD,
.pad0 = BOARD_SERCOM4_PINMAP_PAD0,
@@ -165,7 +165,7 @@ const struct sam_usart_config_s g_usart5config =
.parity = CONFIG_USART5_PARITY,
.bits = CONFIG_USART5_BITS,
.irq = SAM_IRQ_SERCOM5,
- .gclk = (BOARD_SERCOM5_SRCGCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
+ .gclkgen = (BOARD_SERCOM5_GCLKGEN >> GCLK_CLKCTRL_GEN_SHIFT),
.stopbits2 = CONFIG_USART5_2STOP,
.baud = CONFIG_USART5_BAUD,
.pad0 = BOARD_SERCOM5_PINMAP_PAD0,
diff --git a/nuttx/arch/arm/src/samd/sam_usart.h b/nuttx/arch/arm/src/samd/sam_usart.h
index 9d63e3563..7ea7ada2a 100644
--- a/nuttx/arch/arm/src/samd/sam_usart.h
+++ b/nuttx/arch/arm/src/samd/sam_usart.h
@@ -56,19 +56,19 @@
/* Pick the console USART configuration */
#if defined(CONFIG_USART0_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart0config)
+# define g_consoleconfig (g_usart0config)
#elif defined(CONFIG_USART1_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart1config)
+# define g_consoleconfig (g_usart1config)
#elif defined(CONFIG_USART2_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart2config)
+# define g_consoleconfig (g_usart2config)
#elif defined(CONFIG_USART3_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart3config)
+# define g_consoleconfig (g_usart3config)
#elif defined(CONFIG_USART4_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart4config)
+# define g_consoleconfig (g_usart4config)
#elif defined(CONFIG_USART5_SERIAL_CONSOLE)
-# define g_consoleconfig (&g_usart5config)
+# define g_consoleconfig (g_usart5config)
#else
-# undef g_consoleconfig
+# undef g_consoleconfig
#endif
/************************************************************************************
@@ -82,7 +82,7 @@ struct sam_usart_config_s
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (5-9) */
uint8_t irq; /* SERCOM IRQ number */
- uint8_t gclk; /* Source GCLK generator */
+ uint8_t gclkgen; /* Source GCLK generator */
bool isconsole; /* True: The USART is the console device */
bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */
uint32_t baud; /* Configured baud */