From f8461f63db16041fe03271b5c1944e79c10f89a2 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 16 Feb 2014 09:42:29 -0600 Subject: SAMD20: Completes low-level USART logic --- nuttx/arch/arm/src/samd/chip/sam_usart.h | 9 +- nuttx/arch/arm/src/samd/sam_lowputc.c | 240 ++++++++++++++++++++++++++----- nuttx/arch/arm/src/samd/sam_usart.c | 12 +- nuttx/arch/arm/src/samd/sam_usart.h | 16 +-- 4 files changed, 224 insertions(+), 53 deletions(-) (limited to 'nuttx/arch/arm/src/samd') 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 #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 */ -- cgit v1.2.3