From 46348a29bbb92fb38f4f0b028c12e396e5916fe3 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 16 Feb 2014 11:34:32 -0600 Subject: [PATCH] SAMD20: The basic port is complete but still untested --- arch/arm/src/samd/Make.defs | 2 +- arch/arm/src/samd/chip/sam_sercom.h | 84 +++ arch/arm/src/samd/chip/sam_usart.h | 1 + arch/arm/src/samd/sam_lowputc.c | 37 +- arch/arm/src/samd/sam_lowputc.h | 14 + arch/arm/src/samd/sam_serial.c | 1067 +++++++++++++++++++++++++++ arch/arm/src/samd/sam_serial.h | 1 - arch/arm/src/samd/sam_start.c | 2 +- arch/arm/src/samd/sam_usart.h | 1 - 9 files changed, 1204 insertions(+), 5 deletions(-) create mode 100644 arch/arm/src/samd/chip/sam_sercom.h create mode 100644 arch/arm/src/samd/sam_serial.c diff --git a/arch/arm/src/samd/Make.defs b/arch/arm/src/samd/Make.defs index 029433fb7f..ae7ed8964b 100644 --- a/arch/arm/src/samd/Make.defs +++ b/arch/arm/src/samd/Make.defs @@ -69,7 +69,7 @@ endif CHIP_ASRCS = CHIP_CSRCS = sam_clockconfig.c sam_idle.c sam_irq.c sam_lowputc.c -CHIP_CSRCS += sam_port.c sam_start.c sam_timerisr.c sam_usart.c +CHIP_CSRCS += sam_port.c sam_serial.c sam_start.c sam_timerisr.c sam_usart.c ifeq ($(CONFIG_NUTTX_KERNEL),y) CHIP_CSRCS += sam_userspace.c diff --git a/arch/arm/src/samd/chip/sam_sercom.h b/arch/arm/src/samd/chip/sam_sercom.h new file mode 100644 index 0000000000..7e097589c0 --- /dev/null +++ b/arch/arm/src/samd/chip/sam_sercom.h @@ -0,0 +1,84 @@ +/******************************************************************************************** + * arch/arm/src/samd/chip/sam_sercom.h + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * References: + * "Atmel SAM D20J / SAM D20G / SAM D20E ARM-Based Microcontroller + * Datasheet", 42129J–SAM–12/2013 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ********************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMD_CHIP_SAM_SERCOM_H +#define __ARCH_ARM_SRC_SAMD_CHIP_SAM_SERCOM_H + +/******************************************************************************************** + * Included Files + ********************************************************************************************/ + +#include + +#include "chip.h" + +/******************************************************************************************** + * Pre-processor Definitions + ********************************************************************************************/ +/* Two generic clocks are used by the SERCOM: GCLK_SERCOMx_CORE and GCLK_SERCOMx_SLOW. The + * core clock (GCLK_SERCOMx_CORE) is required to clock the SERCOM while operating as a + * master, while the slow clock (GCLK_SERCOMx_SLOW) is only required for certain functions. + * SERCOM modules must share the same slow GCLK channel ID. + * + * The baud-rate generator runs off the GCLK_SERCOMx_CORE clock (or, optionally, external + * clock). + */ + +#define SERCOM_GCLK_ID_SLOW 12 +#define SERCOM_GCLK_ID_CORE(n) (13+(n)) +# define SERCOM0_GCLK_ID_CORE 13 +# define SERCOM1_GCLK_ID_CORE 14 +# define SERCOM2_GCLK_ID_CORE 15 +# define SERCOM3_GCLK_ID_CORE 16 +# define SERCOM4_GCLK_ID_CORE 17 +# define SERCOM5_GCLK_ID_CORE 18 + +/******************************************************************************************** + * Public Types + ********************************************************************************************/ + +/******************************************************************************************** + * Public Data + ********************************************************************************************/ + +/******************************************************************************************** + * Public Functions + ********************************************************************************************/ + +#endif /* __ARCH_ARM_SRC_SAMD_CHIP_SAM_SERCOM_H */ diff --git a/arch/arm/src/samd/chip/sam_usart.h b/arch/arm/src/samd/chip/sam_usart.h index c202c6f8f0..03539d0dc6 100644 --- a/arch/arm/src/samd/chip/sam_usart.h +++ b/arch/arm/src/samd/chip/sam_usart.h @@ -130,6 +130,7 @@ /* Control A register */ +#define USART_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */ #define USART_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */ #define USART_CTRLA_MODE_SHIFT (2) /* Bits 2-4: Operating Mode */ #define USART_CTRLA_MODE_MASK (7 << USART_CTRLA_MODE_SHIFT) diff --git a/arch/arm/src/samd/sam_lowputc.c b/arch/arm/src/samd/sam_lowputc.c index b98088df96..f998d19e03 100644 --- a/arch/arm/src/samd/sam_lowputc.c +++ b/arch/arm/src/samd/sam_lowputc.c @@ -61,6 +61,7 @@ #include "chip/sam_usart.h" #include "sam_usart.h" +#include "sam_lowputc.h" /**************************************************************************** * Pre-processor Definitions @@ -455,17 +456,51 @@ int sam_usart_initialize(const struct sam_usart_config_s * const config) irqstate_t flags; int ret; + /* Reset the SERCOM so that we know that it is in its initial state */ + + flags = irqsave(); + sam_usart_reset(config); + /* Just invoke the internal implementation, but with interrupts disabled * so that the operation is atomic. */ - flags = irqsave(); ret = sam_usart_internal(config); irqrestore(flags); return ret; } #endif +/**************************************************************************** + * Name: sam_usart_reset + * + * Description: + * Reset the USART SERCOM. This restores all SERCOM register to the + * initial state and disables the SERCOM. + * + *****************************************************************************/ + +#ifdef HAVE_USART +void sam_usart_reset(const struct sam_usart_config_s * const config) +{ + uintptr_t regaddr = config->base + SAM_USART_CTRLA_OFFSET; + uint32_t regval; + + /* Reset the SERCOM by setting the SWRST bit in the CTRLA register. When + * the reset completes, the SERCOM will registers will be restored to there + * initial state and the SERCOM will be disabled. + */ + + regval = getreg32(regaddr); + regval |= USART_CTRLA_SWRST; + putreg32(regval, regaddr); + + /* Wait for the reset to complete */ + + while ((getreg32(regaddr) & USART_CTRLA_SWRST) != 0); +} +#endif + /**************************************************************************** * Name: sam_lowputc * diff --git a/arch/arm/src/samd/sam_lowputc.h b/arch/arm/src/samd/sam_lowputc.h index cefd3ea03a..6b7036ed98 100644 --- a/arch/arm/src/samd/sam_lowputc.h +++ b/arch/arm/src/samd/sam_lowputc.h @@ -95,6 +95,20 @@ struct sam_usart_config_s; int sam_usart_initialize(const struct sam_usart_config_s * const config); #endif +/**************************************************************************** + * Name: sam_usart_reset + * + * Description: + * Reset the USART SERCOM. This restores all SERCOM register to the + * initial state and disables the SERCOM. + * + *****************************************************************************/ + +#ifdef HAVE_USART +struct sam_usart_config_s; +void sam_usart_reset(const struct sam_usart_config_s * const config); +#endif + /**************************************************************************** * Name: sam_lowputc * diff --git a/arch/arm/src/samd/sam_serial.c b/arch/arm/src/samd/sam_serial.c new file mode 100644 index 0000000000..8ed18db04d --- /dev/null +++ b/arch/arm/src/samd/sam_serial.c @@ -0,0 +1,1067 @@ +/**************************************************************************** + * arch/arm/src/samd/sam_serial.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "up_arch.h" +#include "up_internal.h" +#include "os_internal.h" + +#include "chip.h" +#include "sam_config.h" +#include "chip/sam_usart.h" +#include "sam_usart.h" +#include "sam_lowputc.h" +#include "sam_serial.h" + +#ifdef HAVE_USART + +/**************************************************************************** + * Definitions + ****************************************************************************/ +/* If we are not using the serial driver for the console, then we still must + * provide some minimal implementation of up_putc. + */ + +#ifdef USE_SERIALDRIVER + +/* Which USART with be tty0/console and which tty1? tty2? tty3? tty4? tty5? */ + +/* First pick the console and ttys0. This could be any of USART0-5 */ + +#if defined(CONFIG_USART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart0port /* USART0 is console */ +# define TTYS0_DEV g_usart0port /* USART0 is ttyS0 */ +# define USART0_ASSIGNED 1 +#elif defined(CONFIG_USART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart1port /* USART1 is console */ +# define TTYS0_DEV g_usart1port /* USART1 is ttyS0 */ +# define USART1_ASSIGNED 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart2port /* USART2 is console */ +# define TTYS0_DEV g_usart2port /* USART2 is ttyS0 */ +# define USART2_ASSIGNED 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart3port /* USART3 is console */ +# define TTYS0_DEV g_usart3port /* USART3 is ttyS0 */ +# define USART3_ASSIGNED 1 +#elif defined(CONFIG_USART4_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart4port /* USART4 is console */ +# define TTYS0_DEV g_usart4port /* USART4 is ttyS0 */ +# define USART4_ASSIGNED 1 +#elif defined(CONFIG_USART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_usart5port /* USART5 is console */ +# define TTYS5_DEV g_usart5port /* USART5 is ttyS0 */ +#else +# undef CONSOLE_DEV /* No console */ +# if defined(SAMD_HAVE_USART0) +# define TTYS0_DEV g_usart0port /* USART0 is ttyS0 */ +# define USART0_ASSIGNED 1 +# elif defined(SAMD_HAVE_USART1) +# define TTYS0_DEV g_usart1port /* USART1 is ttyS0 */ +# define USART1_ASSIGNED 1 +# elif defined(SAMD_HAVE_USART2) +# define TTYS0_DEV g_usart2port /* USART2 is ttyS0 */ +# define USART2_ASSIGNED 1 +# elif defined(SAMD_HAVE_USART3) +# define TTYS0_DEV g_usart3port /* USART3 is ttyS0 */ +# define USART3_ASSIGNED 1 +# elif defined(SAMD_HAVE_USART4) +# define TTYS0_DEV g_usart4port /* USART4 is ttyS0 */ +# define USART4_ASSIGNED 1 +# elif defined(SAMD_HAVE_USART5) +# define TTYS0_DEV g_usart5port /* USART5 is ttyS0 */ +# define USART5_ASSIGNED 1 +# endif +#endif + +/* Pick ttys1. This could be any of USART0-5 excluding the console USART. */ + +#if defined(SAMD_HAVE_USART0) && !defined(USART0_ASSIGNED) +# define TTYS1_DEV g_usart0port /* USART0 is ttyS1 */ +# define USART0_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART1) && !defined(USART1_ASSIGNED) +# define TTYS1_DEV g_usart1port /* USART1 is ttyS1 */ +# define USART1_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART2) && !defined(USART2_ASSIGNED) +# define TTYS1_DEV g_usart2port /* USART2 is ttyS1 */ +# define USART2_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART3) && !defined(USART3_ASSIGNED) +# define TTYS1_DEV g_usart3port /* USART3 is ttyS1 */ +# define USART3_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART4) && !defined(USART4_ASSIGNED) +# define TTYS1_DEV g_usart4port /* USART4 is ttyS1 */ +# define USART4_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART5) && !defined(USART5_ASSIGNED) +# define TTYS1_DEV g_usart5port /* USART5 is ttyS1 */ +# define USART5_ASSIGNED 1 +#endif + +/* Pick ttys2. This could be one of USART1-5. It can't be USART0 + * because that was either assigned as ttyS0 or ttys1. One of these + * could also be the console. + */ + +#if defined(SAMD_HAVE_USART1) && !defined(USART1_ASSIGNED) +# define TTYS2_DEV g_usart1port /* USART1 is ttyS2 */ +# define USART1_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART2) && !defined(USART2_ASSIGNED) +# define TTYS2_DEV g_usart2port /* USART2 is ttyS2 */ +# define USART2_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART3) && !defined(USART3_ASSIGNED) +# define TTYS2_DEV g_usart3port /* USART3 is ttyS2 */ +# define USART3_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART4) && !defined(USART4_ASSIGNED) +# define TTYS2_DEV g_usart4port /* USART4 is ttyS2 */ +# define USART4_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART5) && !defined(USART5_ASSIGNED) +# define TTYS2_DEV g_usart5port /* USART5 is ttyS2 */ +# define USART5_ASSIGNED 1 +#endif + +/* Pick ttys3. This could be one of USART2-5. It can't be USART0-1 because + * those have already been assigned to ttsyS0, 1, or 2. One of + * USART2-5 could also be the console. + */ + +#if defined(SAMD_HAVE_USART2) && !defined(USART2_ASSIGNED) +# define TTYS3_DEV g_usart2port /* USART2 is ttyS3 */ +# define USART2_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART3) && !defined(USART3_ASSIGNED) +# define TTYS3_DEV g_usart3port /* USART3 is ttyS3 */ +# define USART3_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART4) && !defined(USART4_ASSIGNED) +# define TTYS3_DEV g_usart4port /* USART4 is ttyS3 */ +# define USART4_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART5) && !defined(USART5_ASSIGNED) +# define TTYS3_DEV g_usart5port /* USART5 is ttyS3 */ +# define USART5_ASSIGNED 1 +#endif + +/* Pick ttys4. This could be one of USART3-5. It can't be USART0-2 + * because those have already been assigned to ttsyS0, 1, 2 or 3. One of + * USART3-5 could also be the console. + */ + +#if defined(SAMD_HAVE_USART3) && !defined(USART3_ASSIGNED) +# define TTYS4_DEV g_usart3port /* USART3 is ttyS4 */ +# define USART3_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART4) && !defined(USART4_ASSIGNED) +# define TTYS4_DEV g_usart4port /* USART4 is ttyS4 */ +# define USART4_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART5) && !defined(USART5_ASSIGNED) +# define TTYS4_DEV g_usart5port /* USART5 is ttyS4 */ +# define USART5_ASSIGNED 1 +#endif + +/* Pick ttys5. This could be one of USART4-5. It can't be USART0-3 + * because those have already been assigned to ttsyS0, 1, 2, 3 or 4. + * One of USART4-5 could also be the console. + */ + +#if defined(SAMD_HAVE_USART4) && !defined(USART4_ASSIGNED) +# define TTYS5_DEV g_usart4port /* USART4 is ttyS5 */ +# define USART4_ASSIGNED 1 +#elif defined(SAMD_HAVE_USART5) && !defined(USART5_ASSIGNED) +# define TTYS5_DEV g_usart5port /* USART5 is ttyS5 */ +# define USART5_ASSIGNED 1 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sam_dev_s +{ + /* Common USART configuration */ + + const struct sam_usart_config_s * const config; + + /* Information unique to the serial driver */ + + xcpt_t handler; /* Interrupt handler */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Support functions */ + +static inline uint8_t + sam_serialin8(struct sam_dev_s *priv, int offset); +static inline void + sam_serialout8(struct sam_dev_s *priv, int offset, + uint8_t regval); +static inline uint16_t + sam_serialin16(struct sam_dev_s *priv, int offset); +static inline void + sam_serialout16(struct sam_dev_s *priv, int offset, + uint16_t regval); +static void sam_disableallints(struct sam_dev_s *priv); +static int sam_interrupt(struct uart_dev_s *dev); + +#ifdef SAMD_HAVE_USART0 +static int sam_usart0_interrupt(int irq, void *context); +#endif +#ifdef SAMD_HAVE_USART1 +static int sam_usart1_interrupt(int irq, void *context); +#endif +#ifdef SAMD_HAVE_USART2 +static int sam_usart2_interrupt(int irq, void *context); +#endif +#ifdef SAMD_HAVE_USART3 +static int sam_usart3_interrupt(int irq, void *context); +#endif +#ifdef SAMD_HAVE_USART4 +static int sam_usart4_interrupt(int irq, void *context); +#endif +#ifdef SAMD_HAVE_USART5 +static int sam_usart5_interrupt(int irq, void *context); +#endif + +/* UART methods */ + +static int sam_setup(struct uart_dev_s *dev); +static void sam_shutdown(struct uart_dev_s *dev); +static int sam_attach(struct uart_dev_s *dev); +static void sam_detach(struct uart_dev_s *dev); +static int sam_ioctl(struct file *filep, int cmd, unsigned long arg); +static int sam_receive(struct uart_dev_s *dev, uint32_t *status); +static void sam_rxint(struct uart_dev_s *dev, bool enable); +static bool sam_rxavailable(struct uart_dev_s *dev); +static void sam_send(struct uart_dev_s *dev, int ch); +static void sam_txint(struct uart_dev_s *dev, bool enable); +static bool sam_txempty(struct uart_dev_s *dev); + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +static const struct uart_ops_s g_uart_ops = +{ + .setup = sam_setup, + .shutdown = sam_shutdown, + .attach = sam_attach, + .detach = sam_detach, + .ioctl = sam_ioctl, + .receive = sam_receive, + .rxint = sam_rxint, + .rxavailable = sam_rxavailable, + .send = sam_send, + .txint = sam_txint, + .txready = sam_txempty, + .txempty = sam_txempty, +}; + +/* I/O buffers */ + +#ifdef SAMD_HAVE_USART0 +static char g_usart0rxbuffer[CONFIG_USART0_RXBUFSIZE]; +static char g_usart0txbuffer[CONFIG_USART0_TXBUFSIZE]; +#endif +#ifdef SAMD_HAVE_USART1 +static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE]; +static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE]; +#endif +#ifdef SAMD_HAVE_USART2 +static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; +static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE]; +#endif +#ifdef SAMD_HAVE_USART3 +static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; +static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE]; +#endif +#ifdef SAMD_HAVE_USART4 +static char g_usart4rxbuffer[CONFIG_USART4_RXBUFSIZE]; +static char g_usart4txbuffer[CONFIG_USART4_TXBUFSIZE]; +#endif +#ifdef SAMD_HAVE_USART5 +static char g_usart5rxbuffer[CONFIG_USART5_RXBUFSIZE]; +static char g_usart5txbuffer[CONFIG_USART5_TXBUFSIZE]; +#endif + +/* This describes the state of the USART0 port. */ + +#ifdef SAMD_HAVE_USART0 +static struct sam_dev_s g_usart0priv = +{ + .config = &g_usart0config, + .handler = sam_usart0_interrupt, +}; + +static uart_dev_t g_usart0port = +{ + .recv = + { + .size = CONFIG_USART0_RXBUFSIZE, + .buffer = g_usart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART0_TXBUFSIZE, + .buffer = g_usart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart0priv, +}; +#endif + +/* This describes the state of the USART1 port. */ + +#ifdef SAMD_HAVE_USART1 +static struct sam_dev_s g_usart1priv = +{ + .config = &g_usart1config, + .handler = sam_usart1_interrupt, +}; + +static uart_dev_t g_usart1port = +{ + .recv = + { + .size = CONFIG_USART1_RXBUFSIZE, + .buffer = g_usart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART1_TXBUFSIZE, + .buffer = g_usart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart1priv, +}; +#endif + +/* This describes the state of the USART2 port. */ + +#ifdef SAMD_HAVE_USART2 +static struct sam_dev_s g_usart2priv = +{ + .config = &g_usart2config, + .handler = sam_usart2_interrupt, +}; + +static uart_dev_t g_usart2port = +{ + .recv = + { + .size = CONFIG_USART2_RXBUFSIZE, + .buffer = g_usart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART2_TXBUFSIZE, + .buffer = g_usart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart2priv, +}; +#endif + +/* This describes the state of the USART3 port. */ + +#ifdef SAMD_HAVE_USART3 +static struct sam_dev_s g_usart3priv = +{ + .config = &g_usart3config, + .handler = sam_usart3_interrupt, +}; + +static uart_dev_t g_usart3port = +{ + .recv = + { + .size = CONFIG_USART3_RXBUFSIZE, + .buffer = g_usart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART3_TXBUFSIZE, + .buffer = g_usart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart3priv, +}; +#endif + +/* This describes the state of the USART4 port. */ + +#ifdef SAMD_HAVE_USART4 +static struct sam_dev_s g_usart4priv = +{ + .config = &g_usart4config, + .handler = sam_usart4_interrupt, +}; + +static uart_dev_t g_usart4port = +{ + .recv = + { + .size = CONFIG_USART4_RXBUFSIZE, + .buffer = g_usart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART4_TXBUFSIZE, + .buffer = g_usart4txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart4priv, +}; +#endif + +/* This describes the state of the USART5 port. */ + +#ifdef SAMD_HAVE_USART5 +static struct sam_dev_s g_usart5priv = +{ + .config = &g_usart5config, + .handler = sam_usart5_interrupt, +}; + +static uart_dev_t g_usart5port = +{ + .recv = + { + .size = CONFIG_USART5_RXBUFSIZE, + .buffer = g_usart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_USART5_TXBUFSIZE, + .buffer = g_usart5txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_usart5priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_serialin8 + ****************************************************************************/ + +static inline uint8_t sam_serialin8(struct sam_dev_s *priv, int offset) +{ + return getreg8(priv->config->base + offset); +} + +/**************************************************************************** + * Name: sam_serialout8 + ****************************************************************************/ + +static inline void sam_serialout8(struct sam_dev_s *priv, int offset, + uint8_t regval) +{ + putreg8(regval, priv->config->base + offset); +} + +/**************************************************************************** + * Name: sam_serialin16 + ****************************************************************************/ + +static inline uint16_t sam_serialin16(struct sam_dev_s *priv, int offset) +{ + return getreg16(priv->config->base + offset); +} + +/**************************************************************************** + * Name: sam_serialout16 + ****************************************************************************/ + +static inline void sam_serialout16(struct sam_dev_s *priv, int offset, + uint16_t regval) +{ + putreg16(regval, priv->config->base + offset); +} + +/**************************************************************************** + * Name: sam_disableallints + ****************************************************************************/ + +static void sam_disableallints(struct sam_dev_s *priv) +{ + /* Disable all interrupts */ + + sam_serialout8(priv, SAM_USART_INTENCLR_OFFSET, USART_INT_ALL); +} + +/**************************************************************************** + * Name: sam_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 uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int sam_interrupt(struct uart_dev_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 USART usarts (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 bytes */ + + uart_recvchars(dev); + } + + /* 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 */ + + uart_xmitchars(dev); + } + + return OK; +} + +/**************************************************************************** + * Name: sam_usartN_interrupt + * + * Description: + * Handle each SERCOM USART interrupt by calling the common interrupt + * handling logic with the USART-specific state. + * + ****************************************************************************/ + +#ifdef SAMD_HAVE_USART0 +static int sam_usart0_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart0port); +} +#endif + +#ifdef SAMD_HAVE_USART1 +static int sam_usart1_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart1port); +} +#endif + +#ifdef SAMD_HAVE_USART2 +static int sam_usart2_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart2port); +} +#endif + +#ifdef SAMD_HAVE_USART3 +static int sam_usart3_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart3port); +} +#endif + +#ifdef SAMD_HAVE_USART4 +static int sam_usart4_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart4port); +} +#endif + +#ifdef SAMD_HAVE_USART5 +static int sam_usart5_interrupt(int irq, void *context) +{ + return sam_interrupt(&g_usart5port); +} +#endif + +/**************************************************************************** + * Name: sam_setup + * + * Description: + * Configure the USART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +static int sam_setup(struct uart_dev_s *dev) +{ +#ifndef CONFIG_SUPPRESS_UART_CONFIG + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + + /* Configure the SERCOM as a USART */ + + return sam_usart_initialize(priv->config); +#else + return OK; +#endif +} + +/**************************************************************************** + * Name: sam_shutdown + * + * Description: + * Disable the USART. This method is called when the serial port is + * closed + * + ****************************************************************************/ + +static void sam_shutdown(struct uart_dev_s *dev) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + + /* Resetting the SERCOM restores all registers to the reget state and + * disables the SERCOM. + */ + + sam_usart_reset(priv->config); +} + +/**************************************************************************** + * Name: sam_attach + * + * Description: + * Configure the USART to operation in interrupt driven mode. This method + * is called when the serial port is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supports multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int sam_attach(struct uart_dev_s *dev) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + const struct sam_usart_config_s * const config = priv->config; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(config->irq, priv->handler); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the USART + */ + + up_enable_irq(config->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: sam_detach + * + * Description: + * Detach USART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void sam_detach(struct uart_dev_s *dev) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + const struct sam_usart_config_s * const config = priv->config; + + up_disable_irq(config->irq); + irq_detach(config->irq); +} + +/**************************************************************************** + * Name: sam_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int sam_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct sam_dev_s *user = (struct sam_dev_s*)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct sam_dev_s)); + } + } + break; +#endif + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: sam_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the USART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +static int sam_receive(struct uart_dev_s *dev, uint32_t *status) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + + /* Return read status */ + + *status = (uint32_t)sam_serialin16(priv, SAM_USART_STATUS_OFFSET); + + /* Then return the actual received byte */ + + return (int)sam_serialin16(priv, SAM_USART_DATA_OFFSET); +} + +/**************************************************************************** + * Name: sam_rxint + * + * Description: + * Call to enable or disable RXRDY interrupts + * + ****************************************************************************/ + +static void sam_rxint(struct uart_dev_s *dev, bool enable) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + + if (enable) + { + /* Receive an interrupt when their is anything in the Rx data register */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + sam_serialout8(priv, SAM_USART_INTENSET_OFFSET, USART_INT_RXC); +#endif + } + else + { + sam_serialout8(priv, SAM_USART_INTENCLR_OFFSET, USART_INT_RXC); + } +} + +/**************************************************************************** + * Name: sam_rxavailable + * + * Description: + * Return true if the receive holding register is not empty + * + ****************************************************************************/ + +static bool sam_rxavailable(struct uart_dev_s *dev) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + return ((sam_serialin8(priv, SAM_USART_INTFLAG_OFFSET) & USART_INT_RXC) != 0); +} + +/**************************************************************************** + * Name: sam_send + * + * Description: + * This method will send one byte on the USART + * + ****************************************************************************/ + +static void sam_send(struct uart_dev_s *dev, int ch) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + sam_serialout16(priv, SAM_USART_DATA_OFFSET, (uint16_t)ch); +} + +/**************************************************************************** + * Name: sam_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void sam_txint(struct uart_dev_s *dev, bool enable) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + irqstate_t flags; + + flags = irqsave(); + if (enable) + { + /* Set to receive an interrupt when the TX holding register register + * is empty + */ + +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + sam_serialout8(priv, SAM_USART_INTENSET_OFFSET, USART_INT_DRE); + + /* Fake a TX interrupt here by just calling uart_xmitchars() with + * interrupts disabled (note this may recurse). + */ + + uart_xmitchars(dev); + +#endif + } + else + { + /* Disable the TX interrupt */ + + sam_serialout8(priv, SAM_USART_INTENCLR_OFFSET, USART_INT_DRE); + } + + irqrestore(flags); +} + +/**************************************************************************** + * Name: sam_txempty + * + * Description: + * Return true if the transmit holding and shift registers are empty + * + ****************************************************************************/ + +static bool sam_txempty(struct uart_dev_s *dev) +{ + struct sam_dev_s *priv = (struct sam_dev_s*)dev->priv; + return ((sam_serialin8(priv, SAM_USART_INTFLAG_OFFSET) & USART_INT_DRE) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_earlyserialinit + * + * Description: + * Performs the low level USART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before sam_serialinit. + * + ****************************************************************************/ + +void up_earlyserialinit(void) +{ + /* Disable all USARTS */ + + sam_disableallints(TTYS0_DEV.priv); +#ifdef TTYS1_DEV + sam_disableallints(TTYS1_DEV.priv); +#endif +#ifdef TTYS2_DEV + sam_disableallints(TTYS2_DEV.priv); +#endif +#ifdef TTYS3_DEV + sam_disableallints(TTYS3_DEV.priv); +#endif +#ifdef TTYS4_DEV + sam_disableallints(TTYS4_DEV.priv); +#endif +#ifdef TTYS5_DEV + sam_disableallints(TTYS5_DEV.priv); +#endif + + /* Configuration whichever one is the console */ + +#ifdef HAVE_SERIAL_CONSOLE + CONSOLE_DEV.isconsole = true; + sam_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that sam_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ + /* Register the console */ + +#ifdef HAVE_SERIAL_CONSOLE + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif + + /* Register all USARTs */ + + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#endif +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +#ifdef TTYS3_DEV + (void)uart_register("/dev/ttyS3", &TTYS3_DEV); +#endif +#ifdef TTYS4_DEV + (void)uart_register("/dev/ttyS4", &TTYS4_DEV); +#endif +#ifdef TTYS5_DEV + (void)uart_register("/dev/ttyS5", &TTYS5_DEV); +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_SERIAL_CONSOLE + irqstate_t flags; + + /* All interrupts must be disabled to prevent re-entrancy and to prevent + * interrupts from firing in the serial driver code. + */ + + flags = irqsave(); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + sam_lowputc('\r'); + } + + sam_lowputc(ch); + irqrestore(flags); +#endif + return ch; +} + +#else /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_SERIAL_CONSOLE + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + sam_lowputc('\r'); + } + + sam_lowputc(ch); +#endif + return ch; +} + +#endif /* USE_SERIALDRIVER */ +#endif /* HAVE_USART */ + diff --git a/arch/arm/src/samd/sam_serial.h b/arch/arm/src/samd/sam_serial.h index 0afd1b249e..182ae064a1 100644 --- a/arch/arm/src/samd/sam_serial.h +++ b/arch/arm/src/samd/sam_serial.h @@ -43,7 +43,6 @@ #include #include "sam_config.h" -#include "chip/sam_sercom.h" /************************************************************************************ * Pre-processor Definitions diff --git a/arch/arm/src/samd/sam_start.c b/arch/arm/src/samd/sam_start.c index 81e4cf0c26..8f749339b6 100644 --- a/arch/arm/src/samd/sam_start.c +++ b/arch/arm/src/samd/sam_start.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/samd/sam_start.c * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without diff --git a/arch/arm/src/samd/sam_usart.h b/arch/arm/src/samd/sam_usart.h index 7ea7ada2aa..acd2450520 100644 --- a/arch/arm/src/samd/sam_usart.h +++ b/arch/arm/src/samd/sam_usart.h @@ -83,7 +83,6 @@ struct sam_usart_config_s uint8_t bits; /* Number of bits (5-9) */ uint8_t irq; /* SERCOM IRQ number */ 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 */ port_pinset_t pad0; /* Pin configuration for PAD0 */