You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/08/18 15:42:57 UTC
[incubator-nuttx] 02/02: arch: samd5e5 : Oneshot,
freerun and tickless available support. All support runs on
Timer/Counter (TC). Some fixes in external interrupt controller (EIC) and
clockconfig.
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit f5912b5cbad3b7a731231d778ccc101da6f3c353
Author: leomarradke <le...@falker.com.br>
AuthorDate: Fri Aug 14 15:23:40 2020 -0300
arch: samd5e5 : Oneshot, freerun and tickless available support. All support runs on Timer/Counter (TC).
Some fixes in external interrupt controller (EIC) and clockconfig.
Testing:
- Build check only.
Signed-off-by: Leomar Mateus Radke <le...@falker.com.br>
---
arch/arm/Kconfig | 1 +
arch/arm/src/samd5e5/Kconfig | 72 ++
arch/arm/src/samd5e5/hardware/sam_eic.h | 40 +-
arch/arm/src/samd5e5/hardware/sam_tc.h | 479 +++++++++++
arch/arm/src/samd5e5/sam_clockconfig.c | 439 +++++-----
arch/arm/src/samd5e5/sam_eic.c | 35 +-
arch/arm/src/samd5e5/sam_eic.h | 2 +
arch/arm/src/samd5e5/sam_freerun.c | 259 ++++++
arch/arm/src/samd5e5/sam_freerun.h | 151 ++++
arch/arm/src/samd5e5/sam_oneshot.c | 459 +++++++++++
arch/arm/src/samd5e5/sam_oneshot.h | 212 +++++
arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c | 336 ++++++++
arch/arm/src/samd5e5/sam_port.h | 15 +-
arch/arm/src/samd5e5/sam_tc.c | 1143 ++++++++++++++++++++++++++
arch/arm/src/samd5e5/sam_tc.h | 367 +++++++++
arch/arm/src/samd5e5/sam_tickless.c | 409 +++++++++
arch/arm/src/samd5e5/sam_timerisr.c | 4 +-
boards/arm/samd5e5/metro-m4/include/board.h | 15 +
18 files changed, 4185 insertions(+), 253 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b55e225..cb53dd7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -258,6 +258,7 @@ config ARCH_CHIP_SAML2X
config ARCH_CHIP_SAMD5X
bool "Microchip SAMD5x"
select ARCH_CORTEXM4
+ select ARCH_HAVE_TICKLESS
---help---
Microchip SAMD5X (ARM Cortex-M4)
diff --git a/arch/arm/src/samd5e5/Kconfig b/arch/arm/src/samd5e5/Kconfig
index 85ae19b..f2c45b1 100644
--- a/arch/arm/src/samd5e5/Kconfig
+++ b/arch/arm/src/samd5e5/Kconfig
@@ -321,6 +321,10 @@ config SAMD5E5_HAVE_SERCOM7
bool
default n
+config SAMD5E5_HAVE_TC
+ bool
+ default n
+
config SAMD5E5_HAVE_TC4
bool
default n
@@ -341,6 +345,22 @@ config SAMD5E5_SERCOM
bool
default n
+config SAMD5E5_TC
+ bool
+ default y
+
+config SAMD5E5_HAVE_TC4
+ bool
+ default n
+
+config SAMD5E5_HAVE_TC5
+ bool
+ default n
+
+config SAMD5E5_HAVE_TC6
+ bool
+ default n
+
config SAMD5E5_AC
bool "Analog Comparator"
default n
@@ -429,38 +449,90 @@ config SAMD5E5_SERCOM7
config SAMD5E5_TC0
bool "Timer/Counter 0"
default n
+ depends on SAMD5E5_TC
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC1
bool "Timer/Counter 1"
default n
+ depends on SAMD5E5_TC
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC2
bool "Timer/Counter 2"
default n
+ depends on SAMD5E5_TC
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC3
bool "Timer/Counter 3"
default n
+ depends on SAMD5E5_TC
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC4
bool "Timer/Counter 4"
default n
depends on SAMD5E5_HAVE_TC4
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC5
bool "Timer/Counter 5"
default n
depends on SAMD5E5_HAVE_TC5
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC6
bool "Timer/Counter 6"
default n
depends on SAMD5E5_HAVE_TC6
+ select SAMD5E5_HAVE_TC
config SAMD5E5_TC7
bool "Timer/Counter 7"
default n
depends on SAMD5E5_HAVE_TC7
+ select SAMD5E5_HAVE_TC
+
+config SAMD5E5_ONESHOT
+ bool "TC one-shot wrapper"
+ default n if !SCHED_TICKLESS
+ default y if SCHED_TICKLESS
+ ---help---
+ Enable a wrapper around the low level timer/counter functions to
+ support one-shot timer.
+
+config SAMD5E5_FREERUN
+ bool "TC free-running wrapper"
+ default n if !SCHED_TICKLESS
+ default y if SCHED_TICKLESS
+ ---help---
+ Enable a wrapper around the low level timer/counter functions to
+ support a free-running timer.
+
+if SCHED_TICKLESS
+
+config SAMD5E5_TICKLESS_ONESHOT
+ int "Tickless one-shot timer channel"
+ default 2
+ range 0 7
+ ---help---
+ If the Tickless OS feature is enabled, the one clock must be
+ assigned to provided the one-shot timer needed by the OS.
+ NOTE: Use even timers (0, 2 or 4) because timers are program
+ in 32-bit mode (1, 3 and 5 are slaves).
+
+config SAMD5E5_TICKLESS_FREERUN
+ int "Tickless free-running timer channel"
+ default 4
+ range 0 7
+ ---help---
+ If the Tickless OS feature is enabled, the one clock must be
+ assigned to provided the free-running timer needed by the OS.
+ NOTE: Use even timers (0, 2 or 4) because timers are program
+ in 32-bit mode (1, 3 and 5 are slaves).
+
+endif
config SAMD5E5_USB
bool "USB"
diff --git a/arch/arm/src/samd5e5/hardware/sam_eic.h b/arch/arm/src/samd5e5/hardware/sam_eic.h
index 52fcbda..026293d 100644
--- a/arch/arm/src/samd5e5/hardware/sam_eic.h
+++ b/arch/arm/src/samd5e5/hardware/sam_eic.h
@@ -51,7 +51,7 @@
/* EIC register offsets *********************************************************************/
#define SAM_EIC_CTRLA_OFFSET 0x0000 /* Control A register */
-#define SAM_EIC_NMITRCL_OFFSET 0x0001 /* Non-maskable interrupt control register */
+#define SAM_EIC_NMICTRL_OFFSET 0x0001 /* Non-maskable interrupt control register */
#define SAM_EIC_NMIFLAG_OFFSET 0x0002 /* Non-maskable interrupt flasg status and clear register */
#define SAM_EIC_SYNCBUSY_OFFSET 0x0004 /* Synchronization busy register */
#define SAM_EIC_EVCTRL_OFFSET 0x0008 /* Event control register */
@@ -68,7 +68,7 @@
/* EIC register addresses *******************************************************************/
#define SAM_EIC_CTRLA (SAM_EIC_BASE + SAM_EIC_CTRLA_OFFSET)
-#define SAM_EIC_NMITRCL (SAM_EIC_BASE + SAM_EIC_NMITRCL_OFFSET)
+#define SAM_EIC_NMICTRL (SAM_EIC_BASE + SAM_EIC_NMICTRL_OFFSET)
#define SAM_EIC_NMIFLAG (SAM_EIC_BASE + SAM_EIC_NMIFLAG_OFFSET)
#define SAM_EIC_SYNCBUSY (SAM_EIC_BASE + SAM_EIC_SYNCBUSY_OFFSET)
#define SAM_EIC_EVCTRL (SAM_EIC_BASE + SAM_EIC_EVCTRL_OFFSET)
@@ -86,9 +86,9 @@
/* Control A register */
-#define EIC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */
-#define EIC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */
-#define EIC_CTRLA_CKSEL (1 << 4) /* Bit 4: Clock selection */
+#define EIC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */
+#define EIC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */
+#define EIC_CTRLA_CKSEL (1 << 4) /* Bit 4: Clock selection */
# define EIC_CTRLA_CKSEL_GCLK_EIC (0) /* 0=EIC clocked by GCLK_EIC */
# define EIC_CTRLA_CKSEL_CLK_ULP32K EIC_CTRLA_CKSEL /* 1=EIC clocked by CLK_ULP32K */
@@ -102,8 +102,8 @@
# define EIC_NMITRCL_NMISENSE_BOTH (3 << EIC_NMITRCL_NMISENSE_SHIFT) /* Both edge detection */
# define EIC_NMITRCL_NMISENSE_HIGH (4 << EIC_NMITRCL_NMISENSE_SHIFT) /* High level detection */
# define EIC_NMITRCL_NMISENSE_LOW (5 << EIC_NMITRCL_NMISENSE_SHIFT) /* Low level detection */
-#define EIC_NMITRCL_NMIFLTEN (1 << 3) /* Bit 3: Non-maskable interrupt filter enable */
-#define EIC_NMITRCL_ASYNC (1 << 4) /* Bit 4: Asynchronous edge detection mode */
+#define EIC_NMITRCL_NMIFLTEN (1 << 3) /* Bit 3: Non-maskable interrupt filter enable */
+#define EIC_NMITRCL_ASYNC (1 << 4) /* Bit 4: Asynchronous edge detection mode */
/* Non-maskable interrupt flas status and clear register */
@@ -142,7 +142,7 @@
/* Configuration 0 register */
-#define EIC_CONFIG0_FILTEN(n) (3 + ((n) << 2)) /* Filter n enable, n=0-7 */
+#define EIC_CONFIG0_FILTEN(n) (0x8 << ((n) << 2)) /* Filter n enable, n=0-7 */
#define EIC_CONFIG0_SENSE_SHIFT(n) ((n) << 2) /* Filter n input sense, n=0-7 */
#define EIC_CONFIG0_SENSE_MASK(n) (7 << EIC_CONFIG0_SENSE_SHIFT(n))
# define EIC_CONFIG0_SENSE_NONE(n) (0 << EIC_CONFIG0_SENSE_SHIFT(n)) /* No detection */
@@ -154,7 +154,7 @@
/* Configuration 1 register */
-#define EIC_CONFIG1_FILTEN(n) (3 + (((n) - 8) << 2)) /* Filter n enable, n=8-15 */
+#define EIC_CONFIG1_FILTEN(n) (0x8 << (((n) - 8) << 2)) /* Filter n enable, n=8-15 */
#define EIC_CONFIG1_SENSE_SHIFT(n) (((n) - 8) << 2) /* Filter n input sense, n=8-17 */
#define EIC_CONFIG1_SENSE_MASK(n) (7 << EIC_CONFIG1_SENSE_SHIFT(n))
# define EIC_CONFIG1_SENSE_NONE(n) (0 << EIC_CONFIG1_SENSE_SHIFT(n)) /* No detection */
@@ -198,10 +198,10 @@
# define EIC_DPRESCALER_PRESCALER0_DIV64 (5 << EIC_DPRESCALER_PRESCALER0_SHIFT) /* EIC clock divided by 64 */
# define EIC_DPRESCALER_PRESCALER0_DIV128 (6 << EIC_DPRESCALER_PRESCALER0_SHIFT) /* EIC clock divided by 128 */
# define EIC_DPRESCALER_PRESCALER0_DIV256 (7 << EIC_DPRESCALER_PRESCALER0_SHIFT) /* EIC clock divided by 256 */
-#define EIC_DPRESCALER_STATES0 (1 << 3) /* Bit 3: Debouncer number of states. EXTINT 0-7 */
-# define EIC_DPRESCALER_STATES0_3 (0) /* 3 low frequency samples */
-# define EIC_DPRESCALER_STATES0_7 EIC_DPRESCALER_STATES0 /* 7 low frequency samples */
-#define EIC_DPRESCALER_PRESCALER1_SHIFT (4) /* Bitx 4-6: Debouncer Prescaler. EXTINT 8-15 */
+#define EIC_DPRESCALER_STATES0 (1 << 3) /* Bit 3: Debouncer number of states. EXTINT 0-7 */
+# define EIC_DPRESCALER_STATES0_3 (0) /* 3 low frequency samples */
+# define EIC_DPRESCALER_STATES0_7 EIC_DPRESCALER_STATES0 /* 7 low frequency samples */
+#define EIC_DPRESCALER_PRESCALER1_SHIFT (4) /* Bitx 4-6: Debouncer Prescaler. EXTINT 8-15 */
#define EIC_DPRESCALER_PRESCALER1_MASK (7 << EIC_DPRESCALER_PRESCALER1_SHIFT)
# define EIC_DPRESCALER_PRESCALER1_DIV2 (0 << EIC_DPRESCALER_PRESCALER1_SHIFT) /* EIC clock divided by 2 */
# define EIC_DPRESCALER_PRESCALER1_DIV4 (1 << EIC_DPRESCALER_PRESCALER1_SHIFT) /* EIC clock divided by 4 */
@@ -211,12 +211,12 @@
# define EIC_DPRESCALER_PRESCALER1_DIV64 (5 << EIC_DPRESCALER_PRESCALER1_SHIFT) /* EIC clock divided by 64 */
# define EIC_DPRESCALER_PRESCALER1_DIV128 (6 << EIC_DPRESCALER_PRESCALER1_SHIFT) /* EIC clock divided by 128 */
# define EIC_DPRESCALER_PRESCALER1_DIV256 (7 << EIC_DPRESCALER_PRESCALER1_SHIFT) /* EIC clock divided by 256 */
-#define EIC_DPRESCALER_STATES1 (1 << 7) /* Bit 7: Debouncer number of states. EXTINT 8-15 */
-# define EIC_DPRESCALER_STATES1_3 (0) /* 3 low frequency samples */
-# define EIC_DPRESCALER_STATES1_7 EIC_DPRESCALER_STATES1 /* 7 low frequency samples */
-#define EIC_DPRESCALER_TICKON (1 << 16) /* Bit 16: Pin Sampler frequency selection */
-# define EIC_DPRESCALER_TICKON_GCLKEIC (0) /* Bounce sampler uses GCLK_EIC */
-# define EIC_DPRESCALER_TICKON_LFCLK EIC_DPRESCALER_TICKON /* Bounce sampler uses low frequency clock */
+#define EIC_DPRESCALER_STATES1 (1 << 7) /* Bit 7: Debouncer number of states. EXTINT 8-15 */
+# define EIC_DPRESCALER_STATES1_3 (0) /* 3 low frequency samples */
+# define EIC_DPRESCALER_STATES1_7 EIC_DPRESCALER_STATES1 /* 7 low frequency samples */
+#define EIC_DPRESCALER_TICKON (1 << 16) /* Bit 16: Pin Sampler frequency selection */
+# define EIC_DPRESCALER_TICKON_GCLKEIC (0) /* Bounce sampler uses GCLK_EIC */
+# define EIC_DPRESCALER_TICKON_LFCLK EIC_DPRESCALER_TICKON /* Bounce sampler uses low frequency clock */
/* Pin state */
@@ -249,7 +249,7 @@
********************************************************************************************/
/********************************************************************************************
- * Public Functions
+ * Public Functions Prototypes
********************************************************************************************/
#endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_EIC_H */
diff --git a/arch/arm/src/samd5e5/hardware/sam_tc.h b/arch/arm/src/samd5e5/hardware/sam_tc.h
new file mode 100644
index 0000000..46121e2
--- /dev/null
+++ b/arch/arm/src/samd5e5/hardware/sam_tc.h
@@ -0,0 +1,479 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/hardware/sam_tc.h
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMD5E5_CHIP_SAMD_TC_H
+#define __ARCH_ARM_SRC_SAMD5E5_CHIP_SAMD_TC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hardware/sam_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* TC - COUNTx mode register offsets */
+
+#define SAM_TC_CTRLA_OFFSET 0x0000 /* Control A register */
+#define SAM_TC_CTRLBCLR_OFFSET 0x0004 /* Control B clear register */
+#define SAM_TC_CTRLBSET_OFFSET 0x0005 /* Control B Set register */
+#define SAM_TC_EVCTRL_OFFSET 0x0006 /* Event Control registerr */
+#define SAM_TC_INTENCLR_OFFSET 0x0008 /* Interrupt Enable Clear register */
+#define SAM_TC_INTENSET_OFFSET 0x0009 /* Interrupt Enable Set register */
+#define SAM_TC_INTFLAG_OFFSET 0x000A /* Interrupt Flag Status and Clear register */
+#define SAM_TC_STATUS_OFFSET 0x000B /* Status register */
+#define SAM_TC_WAVE_OFFSET 0x000C /* Waveform Generation Control register */
+#define SAM_TC_DRVCTRL_OFFSET 0x000D /* Driver Control register */
+#define SAM_TC_DBGCTRL_OFFSET 0x000F /* Debug Control register */
+#define SAM_TC_SYNCBUSY_OFFSET 0x0010 /* Synchronization Busy register*/
+#define SAM_TC_COUNT_OFFSET 0x0014 /* Counter Value register */
+
+/* TC-8bits mode register offsets */
+
+#define SAM_TC_COUNT8_PER_OFFSET 0x001B /* Period Value, 8-bit Mode register */
+#define SAM_TC_COUNT8_CC0_OFFSET 0x001C /* Channel 0 Compare/Capture Value, 8-bit Mode register */
+#define SAM_TC_COUNT8_CC1_OFFSET 0x001D /* Channel 1 Compare/Capture Value, 8-bit Mode register */
+#define SAM_TC_COUNT8_PERBUF_OFFSET 0x002F /* Period Buffer Value, 8-bit Mode register */
+#define SAM_TC_COUNT8_CCBUF0_OFFSET 0x0030 /* Channel 0 Compare Buffer Value, 8-bit Mode register */
+#define SAM_TC_COUNT8_CCBUF1_OFFSET 0x0031 /* Channel 1 Compare Buffer Value, 8-bit Mode register */
+
+/* TC-16bits mode register offsets */
+
+#define SAM_TC_COUNT16_CC0_OFFSET 0x001C /* Channel 0 Compare/Capture Value, 16-bit Mode register */
+#define SAM_TC_COUNT16_CC1_OFFSET 0x001E /* Channel 1 Compare/Capture Value, 16-bit Mode register */
+#define SAM_TC_COUNT16_CCBUF0_OFFSET 0x0030 /* Channel 0 Compare Buffer Value, 16-bit Mode register */
+#define SAM_TC_COUNT16_CCBUF1_OFFSET 0x0032 /* Channel 1 Compare Buffer Value, 16-bit Mode register */
+
+/* TC-32bits mode register offsets */
+
+#define SAM_TC_COUNT32_CC0_OFFSET 0x001C /* Channel 0 Compare/Capture Value, 32-bit Mode register */
+#define SAM_TC_COUNT32_CC1_OFFSET 0x0020 /* Channel 1 Compare/Capture Value, 32-bit Mode register */
+#define SAM_TC_COUNT32_CCBUF0_OFFSET 0x0030 /* Channel 0 Compare Buffer Value, 32-bit Mode register */
+#define SAM_TC_COUNT32_CCBUF1_OFFSET 0x0034 /* Channel 1 Compare Buffer Value, 32-bit Mode register */
+
+/* TCx register addresses */
+
+#define SAM_TC0_CTRLA (SAM_TC0_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC0_CTRLBCLR (SAM_TC0_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC0_CTRLBSET (SAM_TC0_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC0_EVCTRL (SAM_TC0_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC0_INTENCLR (SAM_TC0_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC0_INTENSET (SAM_TC0_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC0_INTFLAG (SAM_TC0_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC0_STATUS (SAM_TC0_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC0_WAVE (SAM_TC0_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC0_DRVCTRL (SAM_TC0_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC0_DBGCTRL (SAM_TC0_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC0_SYNCBUSY (SAM_TC0_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC0_COUNT (SAM_TC0_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC0_COUNT8_PER (SAM_TC0_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC0_COUNT8_CC0 (SAM_TC0_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC0_COUNT8_CC1 (SAM_TC0_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC0_COUNT8_PERBUF (SAM_TC0_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC0_COUNT8_CCBUF0 (SAM_TC0_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC0_COUNT8_CCBUF1 (SAM_TC0_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC0_COUNT16_CC0 (SAM_TC0_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC0_COUNT16_CC1 (SAM_TC0_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC0_COUNT16_CCBUF0 (SAM_TC0_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC0_COUNT16_CCBUF1 (SAM_TC0_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC0_COUNT32_CC0 (SAM_TC0_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC0_COUNT32_CC1 (SAM_TC0_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC0_COUNT32_CCBUF0 (SAM_TC0_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC0_COUNT32_CCBUF1 (SAM_TC0_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC1_CTRLA (SAM_TC1_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC1_CTRLBCLR (SAM_TC1_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC1_CTRLBSET (SAM_TC1_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC1_EVCTRL (SAM_TC1_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC1_INTENCLR (SAM_TC1_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC1_INTENSET (SAM_TC1_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC1_INTFLAG (SAM_TC1_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC1_STATUS (SAM_TC1_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC1_WAVE (SAM_TC1_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC1_DRVCTRL (SAM_TC1_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC1_DBGCTRL (SAM_TC1_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC1_SYNCBUSY (SAM_TC1_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC1_COUNT (SAM_TC1_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC1_COUNT8_PER (SAM_TC1_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC1_COUNT8_CC0 (SAM_TC1_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC1_COUNT8_CC1 (SAM_TC1_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC1_COUNT8_PERBUF (SAM_TC1_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC1_COUNT8_CCBUF0 (SAM_TC1_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC1_COUNT8_CCBUF1 (SAM_TC1_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC1_COUNT16_CC0 (SAM_TC1_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC1_COUNT16_CC1 (SAM_TC1_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC1_COUNT16_CCBUF0 (SAM_TC1_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC1_COUNT16_CCBUF1 (SAM_TC1_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC1_COUNT32_CC0 (SAM_TC1_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC1_COUNT32_CC1 (SAM_TC1_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC1_COUNT32_CCBUF0 (SAM_TC1_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC1_COUNT32_CCBUF1 (SAM_TC1_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC2_CTRLA (SAM_TC2_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC2_CTRLBCLR (SAM_TC2_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC2_CTRLBSET (SAM_TC2_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC2_EVCTRL (SAM_TC2_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC2_INTENCLR (SAM_TC2_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC2_INTENSET (SAM_TC2_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC2_INTFLAG (SAM_TC2_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC2_STATUS (SAM_TC2_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC2_WAVE (SAM_TC2_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC2_DRVCTRL (SAM_TC2_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC2_DBGCTRL (SAM_TC2_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC2_SYNCBUSY (SAM_TC2_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC2_COUNT (SAM_TC2_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC2_COUNT8_PER (SAM_TC2_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC2_COUNT8_CC0 (SAM_TC2_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC2_COUNT8_CC1 (SAM_TC2_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC2_COUNT8_PERBUF (SAM_TC2_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC2_COUNT8_CCBUF0 (SAM_TC2_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC2_COUNT8_CCBUF1 (SAM_TC2_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC2_COUNT16_CC0 (SAM_TC2_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC2_COUNT16_CC1 (SAM_TC2_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC2_COUNT16_CCBUF0 (SAM_TC2_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC2_COUNT16_CCBUF1 (SAM_TC2_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC2_COUNT32_CC0 (SAM_TC2_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC2_COUNT32_CC1 (SAM_TC2_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC2_COUNT32_CCBUF0 (SAM_TC2_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC2_COUNT32_CCBUF1 (SAM_TC2_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC3_CTRLA (SAM_TC3_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC3_CTRLBCLR (SAM_TC3_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC3_CTRLBSET (SAM_TC3_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC3_EVCTRL (SAM_TC3_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC3_INTENCLR (SAM_TC3_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC3_INTENSET (SAM_TC3_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC3_INTFLAG (SAM_TC3_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC3_STATUS (SAM_TC3_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC3_WAVE (SAM_TC3_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC3_DRVCTRL (SAM_TC3_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC3_DBGCTRL (SAM_TC3_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC3_SYNCBUSY (SAM_TC3_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC3_COUNT (SAM_TC3_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC3_COUNT8_PER (SAM_TC3_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC3_COUNT8_CC0 (SAM_TC3_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC3_COUNT8_CC1 (SAM_TC3_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC3_COUNT8_PERBUF (SAM_TC3_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC3_COUNT8_CCBUF0 (SAM_TC3_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC3_COUNT8_CCBUF1 (SAM_TC3_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC3_COUNT16_CC0 (SAM_TC3_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC3_COUNT16_CC1 (SAM_TC3_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC3_COUNT16_CCBUF0 (SAM_TC3_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC3_COUNT16_CCBUF1 (SAM_TC3_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC3_COUNT32_CC0 (SAM_TC3_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC3_COUNT32_CC1 (SAM_TC3_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC3_COUNT32_CCBUF0 (SAM_TC3_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC3_COUNT32_CCBUF1 (SAM_TC3_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC4_CTRLA (SAM_TC4_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC4_CTRLBCLR (SAM_TC4_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC4_CTRLBSET (SAM_TC4_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC4_EVCTRL (SAM_TC4_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC4_INTENCLR (SAM_TC4_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC4_INTENSET (SAM_TC4_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC4_INTFLAG (SAM_TC4_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC4_STATUS (SAM_TC4_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC4_WAVE (SAM_TC4_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC4_DRVCTRL (SAM_TC4_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC4_DBGCTRL (SAM_TC4_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC4_SYNCBUSY (SAM_TC4_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC4_COUNT (SAM_TC4_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC4_COUNT8_PER (SAM_TC4_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC4_COUNT8_CC0 (SAM_TC4_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC4_COUNT8_CC1 (SAM_TC4_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC4_COUNT8_PERBUF (SAM_TC4_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC4_COUNT8_CCBUF0 (SAM_TC4_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC4_COUNT8_CCBUF1 (SAM_TC4_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC4_COUNT16_CC0 (SAM_TC4_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC4_COUNT16_CC1 (SAM_TC4_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC4_COUNT16_CCBUF0 (SAM_TC4_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC4_COUNT16_CCBUF1 (SAM_TC4_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC4_COUNT32_CC0 (SAM_TC4_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC4_COUNT32_CC1 (SAM_TC4_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC4_COUNT32_CCBUF0 (SAM_TC4_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC4_COUNT32_CCBUF1 (SAM_TC4_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC5_CTRLA (SAM_TC5_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC5_CTRLBCLR (SAM_TC5_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC5_CTRLBSET (SAM_TC5_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC5_EVCTRL (SAM_TC5_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC5_INTENCLR (SAM_TC5_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC5_INTENSET (SAM_TC5_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC5_INTFLAG (SAM_TC5_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC5_STATUS (SAM_TC5_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC5_WAVE (SAM_TC5_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC5_DRVCTRL (SAM_TC5_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC5_DBGCTRL (SAM_TC5_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC5_SYNCBUSY (SAM_TC5_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC5_COUNT (SAM_TC5_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC5_COUNT8_PER (SAM_TC5_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC5_COUNT8_CC0 (SAM_TC5_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC5_COUNT8_CC1 (SAM_TC5_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC5_COUNT8_PERBUF (SAM_TC5_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC5_COUNT8_CCBUF0 (SAM_TC5_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC5_COUNT8_CCBUF1 (SAM_TC5_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC5_COUNT16_CC0 (SAM_TC5_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC5_COUNT16_CC1 (SAM_TC5_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC5_COUNT16_CCBUF0 (SAM_TC5_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC5_COUNT16_CCBUF1 (SAM_TC5_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC5_COUNT32_CC0 (SAM_TC5_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC5_COUNT32_CC1 (SAM_TC5_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC5_COUNT32_CCBUF0 (SAM_TC5_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC5_COUNT32_CCBUF1 (SAM_TC5_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+/****************************************************************************
+ * Not used
+ ****************************************************************************/
+
+/****************************************************************************
+#define SAM_TC6_CTRLA (SAM_TC6_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC6_CTRLBCLR (SAM_TC6_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC6_CTRLBSET (SAM_TC6_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC6_EVCTRL (SAM_TC6_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC6_INTENCLR (SAM_TC6_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC6_INTENSET (SAM_TC6_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC6_INTFLAG (SAM_TC6_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC6_STATUS (SAM_TC6_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC6_WAVE (SAM_TC6_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC6_DRVCTRL (SAM_TC6_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC6_DBGCTRL (SAM_TC6_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC6_SYNCBUSY (SAM_TC6_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC6_COUNT (SAM_TC6_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC6_COUNT8_PER (SAM_TC6_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC6_COUNT8_CC0 (SAM_TC6_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC6_COUNT8_CC1 (SAM_TC6_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC6_COUNT8_PERBUF (SAM_TC6_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC6_COUNT8_CCBUF0 (SAM_TC6_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC6_COUNT8_CCBUF1 (SAM_TC6_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC6_COUNT16_CC0 (SAM_TC6_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC6_COUNT16_CC1 (SAM_TC6_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC6_COUNT16_CCBUF0 (SAM_TC6_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC6_COUNT16_CCBUF1 (SAM_TC6_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC6_COUNT32_CC0 (SAM_TC6_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC6_COUNT32_CC1 (SAM_TC6_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC6_COUNT32_CCBUF0 (SAM_TC6_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC6_COUNT32_CCBUF1 (SAM_TC6_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+#define SAM_TC7_CTRLA (SAM_TC7_BASE+SAM_TC_CTRLA_OFFSET)
+#define SAM_TC7_CTRLBCLR (SAM_TC7_BASE+SAM_TC_CTRLBCLR_OFFSET)
+#define SAM_TC7_CTRLBSET (SAM_TC7_BASE+SAM_TC_CTRLBSET_OFFSET)
+#define SAM_TC7_EVCTRL (SAM_TC7_BASE+SAM_TC_EVCTRL_OFFSET)
+#define SAM_TC7_INTENCLR (SAM_TC7_BASE+SAM_TC_INTENCLR_OFFSET)
+#define SAM_TC7_INTENSET (SAM_TC7_BASE+SAM_TC_INTENSET_OFFSET)
+#define SAM_TC7_INTFLAG (SAM_TC7_BASE+SAM_TC_INTFLAG_OFFSET)
+#define SAM_TC7_STATUS (SAM_TC7_BASE+SAM_TC_STATUS_OFFSET)
+#define SAM_TC7_WAVE (SAM_TC7_BASE+SAM_TC_WAVE_OFFSET)
+#define SAM_TC7_DRVCTRL (SAM_TC7_BASE+SAM_TC_DRVCTRL_OFFSET)
+#define SAM_TC7_DBGCTRL (SAM_TC7_BASE+SAM_TC_DBGCTRL_OFFSET)
+#define SAM_TC7_SYNCBUSY (SAM_TC7_BASE+SAM_TC_SYNCBUSY_OFFSET)
+#define SAM_TC7_COUNT (SAM_TC7_BASE+SAM_TC_COUNT_OFFSET)
+#define SAM_TC7_COUNT8_PER (SAM_TC7_BASE+SAM_TC_COUNT8_PER_OFFSET)
+#define SAM_TC7_COUNT8_CC0 (SAM_TC7_BASE+SAM_TC_COUNT8_CC0_OFFSET)
+#define SAM_TC7_COUNT8_CC1 (SAM_TC7_BASE+SAM_TC_COUNT8_CC1_OFFSET)
+#define SAM_TC7_COUNT8_PERBUF (SAM_TC7_BASE+SAM_TC_COUNT8_PERBUF_OFFSET)
+#define SAM_TC7_COUNT8_CCBUF0 (SAM_TC7_BASE+SAM_TC_COUNT8_CCBUF0_OFFSET)
+#define SAM_TC7_COUNT8_CCBUF1 (SAM_TC7_BASE+SAM_TC_COUNT8_CCBUF1_OFFSET)
+#define SAM_TC7_COUNT16_CC0 (SAM_TC7_BASE+SAM_TC_COUNT16_CC0_OFFSET)
+#define SAM_TC7_COUNT16_CC1 (SAM_TC7_BASE+SAM_TC_COUNT16_CC1_OFFSET)
+#define SAM_TC7_COUNT16_CCBUF0 (SAM_TC7_BASE+SAM_TC_COUNT16_CCBUF0_OFFSET)
+#define SAM_TC7_COUNT16_CCBUF1 (SAM_TC7_BASE+SAM_TC_COUNT16_CCBUF1_OFFSET)
+#define SAM_TC7_COUNT32_CC0 (SAM_TC7_BASE+SAM_TC_COUNT32_CC0_OFFSET)
+#define SAM_TC7_COUNT32_CC1 (SAM_TC7_BASE+SAM_TC_COUNT32_CC1_OFFSET)
+#define SAM_TC7_COUNT32_CCBUF0 (SAM_TC7_BASE+SAM_TC_COUNT32_CCBUF0_OFFSET)
+#define SAM_TC7_COUNT32_CCBUF1 (SAM_TC7_BASE+SAM_TC_COUNT32_CCBUF1_OFFSET)
+
+ ****************************************************************************/
+
+/* TC register bit definitions */
+
+/* Control A register */
+
+#define TC_CTRLA_SWRST (1 << 0) /* Bit 0: Software reset */
+#define TC_CTRLA_ENABLE (1 << 1) /* Bit 1: Enable */
+#define TC_CTRLA_DISABLE (0 << 1) /* Bit 1: Disable */
+#define TC_CTRLA_MODE_SHIFT (2)
+#define TC_CTRLA_MODE_MASK (3 << TC_CTRLA_MODE_SHIFT)
+#define TC_CTRLA_MODE_COUNT16 (0 << TC_CTRLA_MODE_SHIFT)
+#define TC_CTRLA_MODE_COUNT8 (1 << TC_CTRLA_MODE_SHIFT)
+#define TC_CTRLA_MODE_COUNT32 (2 << TC_CTRLA_MODE_SHIFT)
+#define TC_CTRLA_PRESCSYNC_SHIFT (4)
+#define TC_CTRLA_PRESCSYNC_MASK (3 << TC_CTRLA_PRESCSYNC_SHIFT)
+#define TC_CTRLA_PRESCSYNC_GCLK (0 << TC_CTRLA_PRESCSYNC_SHIFT)
+#define TC_CTRLA_PRESCSYNC_PRESC (1 << TC_CTRLA_PRESCSYNC_SHIFT)
+#define TC_CTRLA_PRESCSYNC_RESYNC (2 << TC_CTRLA_PRESCSYNC_SHIFT)
+#define TC_CTRLA_RUNSTDBY (1 << 6)
+#define TC_CTRLA_ONDEMAND (1 << 7)
+#define TC_CTRLA_PRESCALER_SHIFT (8)
+#define TC_CTRLA_PRESCALER_MASK (7 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER(n) ((uint32_t)(n) << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV1 (0 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV2 (1 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV4 (2 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV8 (3 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV16 (4 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV64 (5 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV256 (6 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_PRESCALER_DIV1024 (7 << TC_CTRLA_PRESCALER_SHIFT)
+#define TC_CTRLA_ALOCK (1 << 11)
+#define TC_CTRLA_CAPTEN0_SHIFT (16) /* (TC_CTRLA) Capture Channel 0 Enable */
+#define TC_CTRLA_CAPTEN0 (1 << TC_CTRLA_CAPTEN0_SHIFT)
+#define TC_CTRLA_CAPTEN1_SHIFT (17) /* (TC_CTRLA) Capture Channel 1 Enable */
+#define TC_CTRLA_CAPTEN1 (1 << TC_CTRLA_CAPTEN1_SHIFT)
+#define TC_CTRLA_COPEN0_SHIFT (20) /* (TC_CTRLA) Capture On Pin 0 Enable */
+#define TC_CTRLA_COPEN0 (1 << TC_CTRLA_COPEN1_SHIFT)
+#define TC_CTRLA_COPEN1_SHIFT (21) /* (TC_CTRLA) Capture On Pin 1 Enable */
+#define TC_CTRLA_COPEN1 (1 << TC_CTRLA_CAPTEN1_SHIFT)
+#define TC_CTRLA_CAPTMODE0_SHIFT (24) /* (TC_CTRLA) Capture Mode Channel 0 */
+#define TC_CTRLA_CAPTMODE0_MASK (3 << TC_CTRLA_CAPTMODE0_SHIFT)
+#define TC_CTRLA_CAPTMODE0_CAPTD (0 << TC_CTRLA_CAPTMODE0_SHIFT) /* (TC_CTRLA) Default capture */
+#define TC_CTRLA_CAPTMODE0_CAPTMIN (1 << TC_CTRLA_CAPTMODE0_SHIFT) /* (TC_CTRLA) Minimum capture */
+#define TC_CTRLA_CAPTMODE0_CAPTMAX (2 << TC_CTRLA_CAPTMODE0_SHIFT) /* (TC_CTRLA) Maximum capture */
+#define TC_CTRLA_CAPTMODE1_SHIFT (27) /* (TC_CTRLA) Capture Mode Channel 0 */
+#define TC_CTRLA_CAPTMODE1_MASK (3 << TC_CTRLA_CAPTMODE1_SHIFT)
+#define TC_CTRLA_CAPTMODE1_CAPTD (0 << TC_CTRLA_CAPTMODE1_SHIFT) /* (TC_CTRLA) Default capture */
+#define TC_CTRLA_CAPTMODE1_CAPTMIN (1 << TC_CTRLA_CAPTMODE1_SHIFT) /* (TC_CTRLA) Minimum capture */
+#define TC_CTRLA_CAPTMODE1_CAPTMAX (2 << TC_CTRLA_CAPTMODE1_SHIFT) /* (TC_CTRLA) Maximum capture */
+
+/* Control B Clear register */
+
+#define TC_CTRLBCLR_DIR (1 << 0)
+#define TC_CTRLBCLR_LUPD (1 << 1)
+#define TC_CTRLBCLR_ONESHOT (1 << 2)
+#define TC_CTRLBCLR_CMD_SHIFT (5)
+#define TC_CTRLBCLR_CMD_MASK (7 << TC_CTRLBCLR_CMD_SHIFT)
+#define TC_CTRLBCLR_CMD_NONE (0 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) No action */
+#define TC_CTRLBCLR_CMD_RETRIGGER (1 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) Force a start, restart or retrigger */
+#define TC_CTRLBCLR_CMD_STOP (2 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) Force a stop */
+#define TC_CTRLBCLR_CMD_UPDATE (3 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) Force update of double-buffered register */
+#define TC_CTRLBCLR_CMD_READSYNC (4 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) Force a read synchronization of COUNT */
+#define TC_CTRLBCLR_CMD_DMAOS (5 << TC_CTRLBCLR_CMD_SHIFT) /* (TC_CTRLBCLR) One-shot DMA trigger */
+
+/* Control B Set register */
+
+#define TC_CTRLBSET_DIR (1 << 0)
+#define TC_CTRLBSET_LUPD (1 << 1)
+#define TC_CTRLBSET_ONESHOT (1 << 2)
+#define TC_CTRLBSET_CMD_SHIFT (5)
+#define TC_CTRLBSET_CMD_MASK (7 << TC_CTRLBSET_CMD_SHIFT)
+#define TC_CTRLBSET_CMD_NONE (0 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) No action */
+#define TC_CTRLBSET_CMD_RETRIGGER (1 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) Force a start, restart or retrigger */
+#define TC_CTRLBSET_CMD_STOP (2 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) Force a stop */
+#define TC_CTRLBSET_CMD_UPDATE (3 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) Force update of double-buffered register */
+#define TC_CTRLBSET_CMD_READSYNC (4 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) Force a read synchronization of COUNT */
+#define TC_CTRLBSET_CMD_DMAOS (5 << TC_CTRLBSET_CMD_SHIFT) /* (TC_CTRLBCLR) One-shot DMA trigger */
+
+/* Event control register */
+
+#define TC_EVCTRL_EVACT_SHIFT (0)
+#define TC_EVCTRL_EVACT_MASK (7 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_OFF (0 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_RETRIGGER (1 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_COUNT (2 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_START (3 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_STAMP (4 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_PPW (5 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_PWP (6 << TC_EVCTRL_EVACT_SHIFT)
+# define TC_EVCTRL_EVACT_PW (7 << TC_EVCTRL_EVACT_SHIFT)
+#define TC_EVCTRL_TCINV (1 << 4)
+#define TC_EVCTRL_TCEI (1 << 5)
+#define TC_EVCTRL_OVFEO (1 << 8)
+#define TC_EVCTRL_MCEO0 (1 << 12)
+#define TC_EVCTRL_MCEO1 (1 << 13)
+
+/* TC_INTENCLR : Interrupt Enable Clear */
+
+#define TC_INTENCLR_OVF (1 << 0) /* (TC_INTENCLR) OVF Interrupt Disable */
+#define TC_INTENCLR_ERR (1 << 1) /* (TC_INTENCLR) ERR Interrupt Disable */
+#define TC_INTENCLR_MC0 (1 << 4) /* (TC_INTENCLR) MC Interrupt Disable 0 */
+#define TC_INTENCLR_MC1 (1 << 5) /* (TC_INTENCLR) MC Interrupt Disable 1 */
+
+/* TC_INTENSET : Interrupt Enable Set */
+
+#define TC_INTENSET_OVF (1 << 0) /* (TC_INTENCLR) OVF Interrupt Disable */
+#define TC_INTENSET_ERR (1 << 1) /* (TC_INTENCLR) ERR Interrupt Disable */
+#define TC_INTENSET_MC0 (1 << 4) /* (TC_INTENCLR) MC Interrupt Disable 0 */
+#define TC_INTENSET_MC1 (1 << 5) /* (TC_INTENCLR) MC Interrupt Disable 1 */
+
+/* TC_INTFLAG : Interrupt Flag Status and Clear */
+
+#define TC_INTFLAG_OVF (1 << 0) /* (TC_INTENCLR) OVF Interrupt Disable */
+#define TC_INTFLAG_ERR (1 << 1) /* (TC_INTENCLR) ERR Interrupt Disable */
+#define TC_INTFLAG_MC0 (1 << 4) /* (TC_INTENCLR) MC Interrupt Disable 0 */
+#define TC_INTFLAG_MC1 (1 << 5) /* (TC_INTENCLR) MC Interrupt Disable 1 */
+#define TC_INTFLAG_ALL (TC_INTFLAG_OVF | TC_INTFLAG_ERR | TC_INTFLAG_MC0 | TC_INTFLAG_MC1)
+
+/* Status register */
+
+#define TC_STATUS_STOP (1 << 0)
+#define TC_STATUS_SLAVE (1 << 1)
+#define TC_STATUS_PERBUFV (1 << 3)
+#define TC_STATUS_CCBUFV0 (1 << 4)
+#define TC_STATUS_CCBUFV1 (1 << 5)
+
+/* TC_WAVE : Waveform Generation Control */
+
+#define TC_WAVE_WAVEGEN_SHIFT (0) /* (TC_WAVE) Waveform Generation Mode */
+#define TC_WAVE_WAVEGEN_Msk (3 << TC_WAVE_WAVEGEN_SHIFT)
+
+#define TC_WAVE_WAVEGEN_NFRQ (0 << TC_WAVE_WAVEGEN_SHIFT) /* (TC_WAVE) Normal frequency */
+#define TC_WAVE_WAVEGEN_MFRQ (1 << TC_WAVE_WAVEGEN_SHIFT) /* (TC_WAVE) Match frequency */
+#define TC_WAVE_WAVEGEN_NPWM (2 << TC_WAVE_WAVEGEN_SHIFT) /* (TC_WAVE) Normal PWM */
+#define TC_WAVE_WAVEGEN_MPWM (3 << TC_WAVE_WAVEGEN_SHIFT) /* (TC_WAVE) Match PWM */
+
+/* TC_DRVCTRL : Control C */
+
+#define TC_DRVCTRL_INVEN0 (1 << 0 /* (TC_DRVCTRL) Output Waveform Invert Enable 0 */
+#define TC_DRVCTRL_INVEN1 (1 << 1) /* (TC_DRVCTRL) Output Waveform Invert Enable 1 */
+
+/* TC_DBGCTRL : Debug Control */
+
+#define TC_DBGCTRL_DBGRUN (1 << 0) /* (TC_DBGCTRL) Run During Debug */
+
+/* TC_SYNCBUSY : Synchronization Status */
+
+#define TC_SYNCBUSY_SWRST (1 << 0) /* (TC_SYNCBUSY) swrst */
+#define TC_SYNCBUSY_ENABLE (1 << 1) /* (TC_SYNCBUSY) enable */
+#define TC_SYNCBUSY_CTRLB (1 << 2) /* (TC_SYNCBUSY) CTRLB */
+#define TC_SYNCBUSY_STATUS (1 << 3) /* (TC_SYNCBUSY) STATUS */
+#define TC_SYNCBUSY_COUNT (1 << 4) /* (TC_SYNCBUSY) Counter */
+#define TC_SYNCBUSY_CC0 (1 << 6) /* (TC_SYNCBUSY) Compare Channel 0 */
+#define TC_SYNCBUSY_CC1 (1 << 7) /* (TC_SYNCBUSY) Compare Channel 1 */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+#endif /* __ARCH_ARM_SRC_SAMD5E5_CHIP_SAMD_TC_H */
diff --git a/arch/arm/src/samd5e5/sam_clockconfig.c b/arch/arm/src/samd5e5/sam_clockconfig.c
index c795527..a27a61f 100644
--- a/arch/arm/src/samd5e5/sam_clockconfig.c
+++ b/arch/arm/src/samd5e5/sam_clockconfig.c
@@ -82,209 +82,209 @@ static const struct sam_clockconfig_s g_initial_clocking =
.gclkset2 = BOARD_GCLK_SET2,
.cpu_frequency = BOARD_CPU_FREQUENCY,
#if BOARD_HAVE_XOSC32K != 0
- .xosc32k =
- {
- .enable = BOARD_XOSC32K_ENABLE,
- .highspeed = BOARD_XOSC32K_HIGHSPEED,
- .extalen = BOARD_XOSC32K_XTALEN,
- .en32k = BOARD_XOSC32K_EN32K,
- .en1k = BOARD_XOSC32K_EN1K,
- .runstdby = BOARD_XOSC32K_RUNSTDBY,
- .ondemand = BOARD_XOSC32K_ONDEMAND,
- .cfden = BOARD_XOSC32K_CFDEN,
- .cfdeo = BOARD_XOSC32K_CFDEO,
- .caliben = BOARD_XOSC32K_CALIBEN,
- .startup = BOARD_XOSC32K_STARTUP,
- .calib = BOARD_XOSC32K_CALIB,
- .rtcsel = BOARD_XOSC32K_RTCSEL,
- },
+ .xosc32k =
+ {
+ .enable = BOARD_XOSC32K_ENABLE,
+ .highspeed = BOARD_XOSC32K_HIGHSPEED,
+ .extalen = BOARD_XOSC32K_XTALEN,
+ .en32k = BOARD_XOSC32K_EN32K,
+ .en1k = BOARD_XOSC32K_EN1K,
+ .runstdby = BOARD_XOSC32K_RUNSTDBY,
+ .ondemand = BOARD_XOSC32K_ONDEMAND,
+ .cfden = BOARD_XOSC32K_CFDEN,
+ .cfdeo = BOARD_XOSC32K_CFDEO,
+ .caliben = BOARD_XOSC32K_CALIBEN,
+ .startup = BOARD_XOSC32K_STARTUP,
+ .calib = BOARD_XOSC32K_CALIB,
+ .rtcsel = BOARD_XOSC32K_RTCSEL,
+ },
#endif
#if BOARD_HAVE_XOSC0 != 0
- .xosc0 =
- {
- .enable = BOARD_XOSC0_ENABLE,
- .extalen = BOARD_XOSC0_XTALEN,
- .runstdby = BOARD_XOSC0_RUNSTDBY,
- .ondemand = BOARD_XOSC0_ONDEMAND,
- .lowgain = BOARD_XOSC0_LOWGAIN,
- .enalc = BOARD_XOSC0_ENALC,
- .cfden = BOARD_XOSC0_CFDEN,
- .startup = BOARD_XOSC0_STARTUP,
- .xosc_frequency = BOARD_XOSC0_FREQUENCY,
- },
+ .xosc0 =
+ {
+ .enable = BOARD_XOSC0_ENABLE,
+ .extalen = BOARD_XOSC0_XTALEN,
+ .runstdby = BOARD_XOSC0_RUNSTDBY,
+ .ondemand = BOARD_XOSC0_ONDEMAND,
+ .lowgain = BOARD_XOSC0_LOWGAIN,
+ .enalc = BOARD_XOSC0_ENALC,
+ .cfden = BOARD_XOSC0_CFDEN,
+ .startup = BOARD_XOSC0_STARTUP,
+ .xosc_frequency = BOARD_XOSC0_FREQUENCY,
+ },
#endif
#if BOARD_HAVE_XOSC1 != 0
- .xosc1 =
- {
- .enable = BOARD_XOSC1_ENABLE,
- .extalen = BOARD_XOSC1_XTALEN,
- .runstdby = BOARD_XOSC1_RUNSTDBY,
- .ondemand = BOARD_XOSC1_ONDEMAND,
- .lowgain = BOARD_XOSC1_LOWGAIN,
- .enalc = BOARD_XOSC1_ENALC,
- .cfden = BOARD_XOSC1_CFDEN,
- .startup = BOARD_XOSC1_STARTUP,
- .xosc_frequency = BOARD_XOSC1_FREQUENCY,
- },
+ .xosc1 =
+ {
+ .enable = BOARD_XOSC1_ENABLE,
+ .extalen = BOARD_XOSC1_XTALEN,
+ .runstdby = BOARD_XOSC1_RUNSTDBY,
+ .ondemand = BOARD_XOSC1_ONDEMAND,
+ .lowgain = BOARD_XOSC1_LOWGAIN,
+ .enalc = BOARD_XOSC1_ENALC,
+ .cfden = BOARD_XOSC1_CFDEN,
+ .startup = BOARD_XOSC1_STARTUP,
+ .xosc_frequency = BOARD_XOSC1_FREQUENCY,
+ },
#endif
- .dfll =
- {
- .enable = BOARD_DFLL_ENABLE,
- .runstdby = BOARD_DFLL_RUNSTDBY,
- .ondemand = BOARD_DFLL_ONDEMAND,
- .mode = BOARD_DFLL_MODE,
- .stable = BOARD_DFLL_STABLE,
- .llaw = BOARD_DFLL_LLAW,
- .usbcrm = BOARD_DFLL_USBCRM,
- .ccdis = BOARD_DFLL_CCDIS,
- .qldis = BOARD_DFLL_QLDIS,
- .bplckc = BOARD_DFLL_BPLCKC,
- .waitlock = BOARD_DFLL_WAITLOCK,
- .caliben = BOARD_DFLL_CALIBEN,
- .gclklock = BOARD_DFLL_GCLKLOCK,
- .fcalib = BOARD_DFLL_FCALIB,
- .ccalib = BOARD_DFLL_CCALIB,
- .fstep = BOARD_DFLL_FSTEP,
- .cstep = BOARD_DFLL_CSTEP,
- .gclk = BOARD_DFLL_GCLK,
- .mul = BOARD_DFLL_MUL
- },
- .dpll =
- {
- {
- .enable = BOARD_DPLL0_ENABLE,
- .dcoen = BOARD_DPLL0_DCOEN,
- .lbypass = BOARD_DPLL0_LBYPASS,
- .wuf = BOARD_DPLL0_WUF,
- .runstdby = BOARD_DPLL0_RUNSTDBY,
- .ondemand = BOARD_DPLL0_ONDEMAND,
- .reflock = BOARD_DPLL0_REFLOCK,
- .refclk = BOARD_DPLL0_REFCLK,
- .ltime = BOARD_DPLL0_LTIME,
- .filter = BOARD_DPLL0_FILTER,
- .dcofilter = BOARD_DPLL0_DCOFILTER,
- .gclk = BOARD_DPLL0_GCLK,
- .ldrfrac = BOARD_DPLL0_LDRFRAC,
- .ldrint = BOARD_DPLL0_LDRINT,
- .div = BOARD_DPLL0_DIV
- },
- {
- .enable = BOARD_DPLL1_ENABLE,
- .dcoen = BOARD_DPLL1_DCOEN,
- .lbypass = BOARD_DPLL1_LBYPASS,
- .wuf = BOARD_DPLL1_WUF,
- .runstdby = BOARD_DPLL1_RUNSTDBY,
- .ondemand = BOARD_DPLL1_ONDEMAND,
- .reflock = BOARD_DPLL1_REFLOCK,
- .refclk = BOARD_DPLL1_REFCLK,
- .ltime = BOARD_DPLL1_LTIME,
- .filter = BOARD_DPLL1_FILTER,
- .dcofilter = BOARD_DPLL1_DCOFILTER,
- .gclk = BOARD_DPLL1_GCLK,
- .ldrfrac = BOARD_DPLL1_LDRFRAC,
- .ldrint = BOARD_DPLL1_LDRINT,
- .div = BOARD_DPLL1_DIV
- }
- },
- .gclk =
- {
- {
- .enable = BOARD_GCLK0_ENABLE,
- .oov = BOARD_GCLK0_OOV,
- .oe = BOARD_GCLK0_OE,
- .runstdby = BOARD_GCLK0_RUNSTDBY,
- .source = BOARD_GCLK0_SOURCE,
- .div = BOARD_GCLK0_DIV
- },
- {
- .enable = BOARD_GCLK1_ENABLE,
- .oov = BOARD_GCLK1_OOV,
- .oe = BOARD_GCLK1_OE,
- .runstdby = BOARD_GCLK1_RUNSTDBY,
- .source = BOARD_GCLK1_SOURCE,
- .div = BOARD_GCLK1_DIV
- },
- {
- .enable = BOARD_GCLK2_ENABLE,
- .oov = BOARD_GCLK2_OOV,
- .oe = BOARD_GCLK2_OE,
- .runstdby = BOARD_GCLK2_RUNSTDBY,
- .source = BOARD_GCLK2_SOURCE,
- .div = BOARD_GCLK2_DIV
- },
- {
- .enable = BOARD_GCLK3_ENABLE,
- .oov = BOARD_GCLK3_OOV,
- .oe = BOARD_GCLK3_OE,
- .runstdby = BOARD_GCLK3_RUNSTDBY,
- .source = BOARD_GCLK3_SOURCE,
- .div = BOARD_GCLK3_DIV
- },
- {
- .enable = BOARD_GCLK4_ENABLE,
- .oov = BOARD_GCLK4_OOV,
- .oe = BOARD_GCLK4_OE,
- .runstdby = BOARD_GCLK4_RUNSTDBY,
- .source = BOARD_GCLK4_SOURCE,
- .div = BOARD_GCLK4_DIV
- },
- {
- .enable = BOARD_GCLK5_ENABLE,
- .oov = BOARD_GCLK5_OOV,
- .oe = BOARD_GCLK5_OE,
- .runstdby = BOARD_GCLK5_RUNSTDBY,
- .source = BOARD_GCLK5_SOURCE,
- .div = BOARD_GCLK5_DIV
- },
- {
- .enable = BOARD_GCLK6_ENABLE,
- .oov = BOARD_GCLK6_OOV,
- .oe = BOARD_GCLK6_OE,
- .runstdby = BOARD_GCLK6_RUNSTDBY,
- .source = BOARD_GCLK6_SOURCE,
- .div = BOARD_GCLK6_DIV
- },
- {
- .enable = BOARD_GCLK7_ENABLE,
- .oov = BOARD_GCLK7_OOV,
- .oe = BOARD_GCLK7_OE,
- .runstdby = BOARD_GCLK7_RUNSTDBY,
- .source = BOARD_GCLK7_SOURCE,
- .div = BOARD_GCLK7_DIV
- },
- {
- .enable = BOARD_GCLK8_ENABLE,
- .oov = BOARD_GCLK8_OOV,
- .oe = BOARD_GCLK8_OE,
- .runstdby = BOARD_GCLK8_RUNSTDBY,
- .source = BOARD_GCLK8_SOURCE,
- .div = BOARD_GCLK8_DIV
- },
- {
- .enable = BOARD_GCLK9_ENABLE,
- .oov = BOARD_GCLK9_OOV,
- .oe = BOARD_GCLK9_OE,
- .runstdby = BOARD_GCLK9_RUNSTDBY,
- .source = BOARD_GCLK9_SOURCE,
- .div = BOARD_GCLK9_DIV
- },
- {
- .enable = BOARD_GCLK10_ENABLE,
- .oov = BOARD_GCLK10_OOV,
- .oe = BOARD_GCLK10_OE,
- .runstdby = BOARD_GCLK10_RUNSTDBY,
- .source = BOARD_GCLK10_SOURCE,
- .div = BOARD_GCLK10_DIV
- },
- {
- .enable = BOARD_GCLK11_ENABLE,
- .oov = BOARD_GCLK11_OOV,
- .oe = BOARD_GCLK11_OE,
- .runstdby = BOARD_GCLK11_RUNSTDBY,
- .source = BOARD_GCLK11_SOURCE,
- .div = BOARD_GCLK11_DIV
- }
- }
+ .dfll =
+ {
+ .enable = BOARD_DFLL_ENABLE,
+ .runstdby = BOARD_DFLL_RUNSTDBY,
+ .ondemand = BOARD_DFLL_ONDEMAND,
+ .mode = BOARD_DFLL_MODE,
+ .stable = BOARD_DFLL_STABLE,
+ .llaw = BOARD_DFLL_LLAW,
+ .usbcrm = BOARD_DFLL_USBCRM,
+ .ccdis = BOARD_DFLL_CCDIS,
+ .qldis = BOARD_DFLL_QLDIS,
+ .bplckc = BOARD_DFLL_BPLCKC,
+ .waitlock = BOARD_DFLL_WAITLOCK,
+ .caliben = BOARD_DFLL_CALIBEN,
+ .gclklock = BOARD_DFLL_GCLKLOCK,
+ .fcalib = BOARD_DFLL_FCALIB,
+ .ccalib = BOARD_DFLL_CCALIB,
+ .fstep = BOARD_DFLL_FSTEP,
+ .cstep = BOARD_DFLL_CSTEP,
+ .gclk = BOARD_DFLL_GCLK,
+ .mul = BOARD_DFLL_MUL
+ },
+ .dpll =
+ {
+ {
+ .enable = BOARD_DPLL0_ENABLE,
+ .dcoen = BOARD_DPLL0_DCOEN,
+ .lbypass = BOARD_DPLL0_LBYPASS,
+ .wuf = BOARD_DPLL0_WUF,
+ .runstdby = BOARD_DPLL0_RUNSTDBY,
+ .ondemand = BOARD_DPLL0_ONDEMAND,
+ .reflock = BOARD_DPLL0_REFLOCK,
+ .refclk = BOARD_DPLL0_REFCLK,
+ .ltime = BOARD_DPLL0_LTIME,
+ .filter = BOARD_DPLL0_FILTER,
+ .dcofilter = BOARD_DPLL0_DCOFILTER,
+ .gclk = BOARD_DPLL0_GCLK,
+ .ldrfrac = BOARD_DPLL0_LDRFRAC,
+ .ldrint = BOARD_DPLL0_LDRINT,
+ .div = BOARD_DPLL0_DIV
+ },
+ {
+ .enable = BOARD_DPLL1_ENABLE,
+ .dcoen = BOARD_DPLL1_DCOEN,
+ .lbypass = BOARD_DPLL1_LBYPASS,
+ .wuf = BOARD_DPLL1_WUF,
+ .runstdby = BOARD_DPLL1_RUNSTDBY,
+ .ondemand = BOARD_DPLL1_ONDEMAND,
+ .reflock = BOARD_DPLL1_REFLOCK,
+ .refclk = BOARD_DPLL1_REFCLK,
+ .ltime = BOARD_DPLL1_LTIME,
+ .filter = BOARD_DPLL1_FILTER,
+ .dcofilter = BOARD_DPLL1_DCOFILTER,
+ .gclk = BOARD_DPLL1_GCLK,
+ .ldrfrac = BOARD_DPLL1_LDRFRAC,
+ .ldrint = BOARD_DPLL1_LDRINT,
+ .div = BOARD_DPLL1_DIV
+ }
+ },
+ .gclk =
+ {
+ {
+ .enable = BOARD_GCLK0_ENABLE,
+ .oov = BOARD_GCLK0_OOV,
+ .oe = BOARD_GCLK0_OE,
+ .runstdby = BOARD_GCLK0_RUNSTDBY,
+ .source = BOARD_GCLK0_SOURCE,
+ .div = BOARD_GCLK0_DIV
+ },
+ {
+ .enable = BOARD_GCLK1_ENABLE,
+ .oov = BOARD_GCLK1_OOV,
+ .oe = BOARD_GCLK1_OE,
+ .runstdby = BOARD_GCLK1_RUNSTDBY,
+ .source = BOARD_GCLK1_SOURCE,
+ .div = BOARD_GCLK1_DIV
+ },
+ {
+ .enable = BOARD_GCLK2_ENABLE,
+ .oov = BOARD_GCLK2_OOV,
+ .oe = BOARD_GCLK2_OE,
+ .runstdby = BOARD_GCLK2_RUNSTDBY,
+ .source = BOARD_GCLK2_SOURCE,
+ .div = BOARD_GCLK2_DIV
+ },
+ {
+ .enable = BOARD_GCLK3_ENABLE,
+ .oov = BOARD_GCLK3_OOV,
+ .oe = BOARD_GCLK3_OE,
+ .runstdby = BOARD_GCLK3_RUNSTDBY,
+ .source = BOARD_GCLK3_SOURCE,
+ .div = BOARD_GCLK3_DIV
+ },
+ {
+ .enable = BOARD_GCLK4_ENABLE,
+ .oov = BOARD_GCLK4_OOV,
+ .oe = BOARD_GCLK4_OE,
+ .runstdby = BOARD_GCLK4_RUNSTDBY,
+ .source = BOARD_GCLK4_SOURCE,
+ .div = BOARD_GCLK4_DIV
+ },
+ {
+ .enable = BOARD_GCLK5_ENABLE,
+ .oov = BOARD_GCLK5_OOV,
+ .oe = BOARD_GCLK5_OE,
+ .runstdby = BOARD_GCLK5_RUNSTDBY,
+ .source = BOARD_GCLK5_SOURCE,
+ .div = BOARD_GCLK5_DIV
+ },
+ {
+ .enable = BOARD_GCLK6_ENABLE,
+ .oov = BOARD_GCLK6_OOV,
+ .oe = BOARD_GCLK6_OE,
+ .runstdby = BOARD_GCLK6_RUNSTDBY,
+ .source = BOARD_GCLK6_SOURCE,
+ .div = BOARD_GCLK6_DIV
+ },
+ {
+ .enable = BOARD_GCLK7_ENABLE,
+ .oov = BOARD_GCLK7_OOV,
+ .oe = BOARD_GCLK7_OE,
+ .runstdby = BOARD_GCLK7_RUNSTDBY,
+ .source = BOARD_GCLK7_SOURCE,
+ .div = BOARD_GCLK7_DIV
+ },
+ {
+ .enable = BOARD_GCLK8_ENABLE,
+ .oov = BOARD_GCLK8_OOV,
+ .oe = BOARD_GCLK8_OE,
+ .runstdby = BOARD_GCLK8_RUNSTDBY,
+ .source = BOARD_GCLK8_SOURCE,
+ .div = BOARD_GCLK8_DIV
+ },
+ {
+ .enable = BOARD_GCLK9_ENABLE,
+ .oov = BOARD_GCLK9_OOV,
+ .oe = BOARD_GCLK9_OE,
+ .runstdby = BOARD_GCLK9_RUNSTDBY,
+ .source = BOARD_GCLK9_SOURCE,
+ .div = BOARD_GCLK9_DIV
+ },
+ {
+ .enable = BOARD_GCLK10_ENABLE,
+ .oov = BOARD_GCLK10_OOV,
+ .oe = BOARD_GCLK10_OE,
+ .runstdby = BOARD_GCLK10_RUNSTDBY,
+ .source = BOARD_GCLK10_SOURCE,
+ .div = BOARD_GCLK10_DIV
+ },
+ {
+ .enable = BOARD_GCLK11_ENABLE,
+ .oov = BOARD_GCLK11_OOV,
+ .oe = BOARD_GCLK11_OE,
+ .runstdby = BOARD_GCLK11_RUNSTDBY,
+ .source = BOARD_GCLK11_SOURCE,
+ .div = BOARD_GCLK11_DIV
+ }
+ }
};
/****************************************************************************
@@ -317,7 +317,7 @@ static void sam_set_waitstates(const struct sam_clockconfig_s *config)
{
DEBUGASSERT(config->waitstates < 16);
modifyreg16(SAM_NVMCTRL_CTRLA, NVMCTRL_CTRLA_RWS_MASK,
- NVMCTRL_CTRLA_RWS(config->waitstates) );
+ NVMCTRL_CTRLA_RWS(config->waitstates));
}
/****************************************************************************
@@ -422,9 +422,9 @@ static void sam_xosc32k_configure(const struct sam_xosc32_config_s *config)
static uint32_t sam_xoscctrl(const struct sam_xosc_config_s *config)
{
uint32_t regval;
- uint8_t cfdpresc;
- uint8_t imult;
- uint8_t iptat;
+ uint32_t cfdpresc;
+ uint32_t imult;
+ uint8_t iptat = 3;
/* Some settings determined by the crystal frequency */
@@ -446,7 +446,7 @@ static uint32_t sam_xoscctrl(const struct sam_xosc_config_s *config)
imult = 5;
iptat = 3;
}
- else if (config->xosc_frequency > 8000000)
+ else
{
cfdpresc = 3;
imult = 4;
@@ -455,7 +455,7 @@ static uint32_t sam_xoscctrl(const struct sam_xosc_config_s *config)
/* Get the XOSCTCTL register *configuration */
- regval = OSCCTRL_XOSCCTRL_IPTAT(ipta) | OSCCTRL_XOSCCTRL_IMULT(imult) |
+ regval = OSCCTRL_XOSCCTRL_IPTAT(iptat) | OSCCTRL_XOSCCTRL_IMULT(imult) |
OSCCTRL_XOSCCTRL_STARTUP(config->startup) |
OSCCTRL_XOSCCTRL_CFDPRESC(cfdpresc);
@@ -504,15 +504,15 @@ static uint32_t sam_xoscctrl(const struct sam_xosc_config_s *config)
#endif
/****************************************************************************
- * Name: sam_xosc32k_configure
+ * Name: sam_xosc0_configure
*
* Description:
- * Configure XOSC32K
+ * Configure XOSC0K
*
****************************************************************************/
#if BOARD_HAVE_XOSC0 != 0
-static void sam_xosc0_configure(const struct sam_clockconfig_s *config)
+static void sam_xosc0_configure(const struct sam_xosc_config_s *config)
{
uint32_t regval;
@@ -521,11 +521,11 @@ static void sam_xosc0_configure(const struct sam_clockconfig_s *config)
regval = sam_xoscctrl(config);
putreg32(regval, SAM_OSCCTRL_XOSCCTRL0);
- /* Wait for XOSC32 to become ready if it was enabled */
+ /* Wait for XOSC0 to become ready if it was enabled */
if (config->enable)
{
- while (getreg32(SAM_OSCCTRL_STATUS) & OSCCTRL_INT_XOSCRDY0) == 0)
+ while ((getreg32(SAM_OSCCTRL_STATUS) & OSCCTRL_INT_XOSCRDY0) == 0)
{
}
}
@@ -534,14 +534,14 @@ static void sam_xosc0_configure(const struct sam_clockconfig_s *config)
if (config->ondemand)
{
- regval = getre32(SAM_OSCCTRL_XOSCCTRL0)
+ regval = getreg32(SAM_OSCCTRL_XOSCCTRL0);
regval |= OSCCTRL_XOSCCTRL_ONDEMAND;
putreg32(regval, SAM_OSCCTRL_XOSCCTRL0);
}
}
#endif
-#if BOARD_HAVE_XOSC0 != 0
+#if BOARD_HAVE_XOSC1 != 0
void sam_xosc1_configure(const struct sam_xosc_config_s *config)
{
uint32_t regval;
@@ -551,11 +551,11 @@ void sam_xosc1_configure(const struct sam_xosc_config_s *config)
regval = sam_xoscctrl(config);
putreg32(regval, SAM_OSCCTRL_XOSCCTRL1);
- /* Wait for XOSC32 to become ready if it was enabled */
+ /* Wait for XOSC1 to become ready if it was enabled */
if (config->enable)
{
- while (getreg32(SAM_OSCCTRL_STATUS) & OSCCTRL_INT_XOSCRDY1) == 0)
+ while ((getreg32(SAM_OSCCTRL_STATUS) & OSCCTRL_INT_XOSCRDY1) == 0)
{
}
}
@@ -564,7 +564,7 @@ void sam_xosc1_configure(const struct sam_xosc_config_s *config)
if (config->ondemand)
{
- regval = getre32(SAM_OSCCTRL_XOSCCTRL1)
+ regval = getreg32(SAM_OSCCTRL_XOSCCTRL1);
regval |= OSCCTRL_XOSCCTRL_ONDEMAND;
putreg32(regval, SAM_OSCCTRL_XOSCCTRL1);
}
@@ -782,8 +782,9 @@ static void sam_dfll_ready(const struct sam_dfll_config_s *config)
uint32_t regval32;
uint8_t regval8;
- /* Check if the mode bit was set, i.e., we are in closed-loop mode. If so
- * wait for the DFLL to be ready for and for the coarse lock to be obtained.
+ /* Check if the mode bit was set, i.e., we are in closed-loop mode. If so
+ * wait for the DFLL to be ready for and for the coarse lock to be
+ * obtained.
*/
regval8 = getreg8(SAM_OSCCTRL_DPLL0CTRLB);
@@ -828,7 +829,7 @@ static void sam_dfll_gclkready(const struct sam_dfll_config_s *config)
{
}
- /* Set the source of GCLK0 to the configured source. */
+ /* Set the source of GCLK0 to to the configured source. */
regval32 = getreg32(SAM_GCLK_GENCTRL(0));
regval32 &= ~GCLK_GENCTRL_SRC_MASK;
@@ -854,7 +855,9 @@ static void sam_dpll_gclkchannel(uint8_t chan,
if (config->refclk == 0 && !sam_gclk_chan_locked(chan))
{
- /* Yes.. configure the GCLK channel that will be used as refclk source */
+ /* Yes.. configure the GCLK channel that will be used as
+ * refclk source.
+ */
sam_gclk_chan_enable(chan, config->gclk, (bool)config->reflock);
}
diff --git a/arch/arm/src/samd5e5/sam_eic.c b/arch/arm/src/samd5e5/sam_eic.c
index bdd0049..3a2d177 100644
--- a/arch/arm/src/samd5e5/sam_eic.c
+++ b/arch/arm/src/samd5e5/sam_eic.c
@@ -49,6 +49,7 @@
#include "sam_periphclks.h"
#include "sam_port.h"
#include "sam_eic.h"
+#include "hardware/sam_pac.h"
#include <arch/board/board.h>
@@ -135,7 +136,7 @@ int sam_eic_initialize(void)
/* Configure the EIC APB clock */
- sam_apb_eic_enableperiph();
+ sam_apb_eic_enableperiph(); /* SAM_MCLK_APBAMASK(MCLK_APBAMASK_EIC) */
/* Use the selected GCLK_EIC. Some optional functions need a peripheral
* clock, which can either be a generic clock (GCLK_EIC, for wider
@@ -144,13 +145,13 @@ int sam_eic_initialize(void)
* and enabled before using the peripheral.
*/
- regaddr = SAM_GCLK_PCHCTRL(GCLK_CHAN_EIC);
+ regaddr = SAM_GCLK_PCHCTRL(GCLK_CHAN_EIC); /* (GCLK_CHAN_EIC) */
regval = GCLK_PCHCTRL_GEN(BOARD_GCLK_EIC) | GCLK_PCHCTRL_CHEN;
putreg32(regval, regaddr);
/* Enable the EIC, selecting clocking via the GCLK_EIC */
- putreg8(EIC_CTRLA_ENABLE | EIC_CTRLA_ENABLE, SAM_EIC_CTRLA);
+ putreg8(EIC_CTRLA_ENABLE, SAM_EIC_CTRLA);
sam_eic_syncwait();
sam_eic_dumpregs();
@@ -179,6 +180,11 @@ int sam_eic_configure(uint8_t eirq, port_pinset_t pinset)
uint32_t val;
uint32_t config;
+ /* Disable the EIC: 23.6.2.1 */
+
+ putreg8(0, SAM_EIC_CTRLA);
+ sam_eic_syncwait();
+
/* Determine which of the CONFIG[0:1] registers to write to */
if (eirq < 8)
@@ -196,6 +202,11 @@ int sam_eic_configure(uint8_t eirq, port_pinset_t pinset)
val = EIC_CONFIG0_SENSE_FALL(eirq);
}
+ if ((pinset & PORT_INT_HIGH) != 0)
+ {
+ val = EIC_CONFIG0_SENSE_HIGH(eirq);
+ }
+
val |= EIC_CONFIG0_FILTEN(eirq);
}
else /* if (eirq < 16) */
@@ -213,7 +224,14 @@ int sam_eic_configure(uint8_t eirq, port_pinset_t pinset)
val = EIC_CONFIG1_SENSE_FALL(eirq);
}
- val |= EIC_CONFIG1_FILTEN(eirq);
+ if ((pinset & PORT_INT_HIGH) != 0)
+ {
+ val = EIC_CONFIG1_SENSE_HIGH(eirq);
+ }
+
+ config = getreg32(SAM_EIC_EVCTRL);
+ config |= EIC_EXTINT(eirq);
+ putreg32(config, SAM_EIC_EVCTRL);
}
/* Write the new config to the CONFIGn register */
@@ -222,9 +240,10 @@ int sam_eic_configure(uint8_t eirq, port_pinset_t pinset)
config |= val;
putreg32(config, reg);
- /* Enable interrupt generation for this pin */
+ /* Enable the EIC, selecting clocking via the GCLK_EIC */
- putreg32(EIC_EXTINT(eirq), SAM_EIC_INTENSET);
+ putreg8(EIC_CTRLA_ENABLE, SAM_EIC_CTRLA);
+ sam_eic_syncwait();
sam_eic_dumpregs();
return OK;
@@ -248,7 +267,9 @@ int sam_eic_irq_ack(int irq)
{
int eirq = irq - SAM_IRQ_EXTINT0;
- putreg32(EIC_EXTINT(eirq), SAM_EIC_INTENCLR);
+ irqinfo("sam_eic_irq_ack: irq=%d eirq=%d EIC_EXTINT=0x%x\n", irq,
+ eirq, EIC_EXTINT(eirq));
+ putreg32(EIC_EXTINT(eirq), SAM_EIC_INTFLAG);
return OK;
}
diff --git a/arch/arm/src/samd5e5/sam_eic.h b/arch/arm/src/samd5e5/sam_eic.h
index 6b32abd..be64b7e 100644
--- a/arch/arm/src/samd5e5/sam_eic.h
+++ b/arch/arm/src/samd5e5/sam_eic.h
@@ -114,6 +114,8 @@ int sam_eic_configure(uint8_t eirq, port_pinset_t pinset);
int sam_eic_irq_ack(int irq);
+void sam_eic_dumpregs(void);
+
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/arch/arm/src/samd5e5/sam_freerun.c b/arch/arm/src/samd5e5/sam_freerun.c
new file mode 100644
index 0000000..91d68e9
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_freerun.c
@@ -0,0 +1,259 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_freerun.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+
+#include "sam_freerun.h"
+
+#ifdef CONFIG_SAMD5E5_FREERUN
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_freerun_handler
+ *
+ * Description:
+ * Timer interrupt callback. When the freerun timer counter overflows,
+ * this interrupt will occur. We will just increment an overflow count.
+ *
+ * Input Parameters:
+ * tch - The handle that represents the timer state
+ * arg - An opaque argument provided when the interrupt was registered
+ * sr - The value of the timer interrupt status register at the time
+ * that the interrupt occurred.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sam_freerun_handler(TC_HANDLE tch, void *arg, uint32_t sr)
+{
+ struct sam_freerun_s *freerun = (struct sam_freerun_s *)arg;
+
+ DEBUGASSERT(freerun && freerun->overflow < UINT16_MAX);
+ freerun->overflow++;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_freerun_initialize
+ *
+ * Description:
+ * Initialize the freerun timer wrapper
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure
+ * chan Timer counter channel to be used. See the TC_CHAN*
+ * definitions in arch/arm/src/samd5e5/sam_tc.h.
+ * resolution The required resolution of the timer in units of
+ * microseconds. NOTE that the range is restricted to the
+ * range of uint16_t (excluding zero).
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_initialize(struct sam_freerun_s *freerun, int chan,
+ uint16_t resolution)
+{
+ uint32_t frequency;
+
+ tmrinfo("chan=%d resolution=%d usec\n", chan, resolution);
+ DEBUGASSERT(freerun && resolution > 0);
+
+ /* Get the TC frequency the corresponds to the requested resolution */
+
+ frequency = USEC_PER_SEC / (uint32_t)resolution;
+
+ freerun->tch = sam_tc_allocate(chan, frequency);
+ if (!freerun->tch)
+ {
+ tmrerr("ERROR: Failed to allocate timer channel %d\n", chan);
+ return -EBUSY;
+ }
+
+ /* Initialize the remaining fields in the state structure and return
+ * success.
+ */
+
+ freerun->chan = chan;
+ freerun->running = false;
+ freerun->overflow = 0;
+
+ /* Set up to receive the callback when the counter overflow occurs */
+
+ (void)sam_tc_attach(freerun->tch, sam_freerun_handler,
+ freerun, TC_INTFLAG_OVF);
+
+ /* Start the counter */
+
+ sam_tc_start(freerun->tch);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_freerun_counter
+ *
+ * Description:
+ * Read the counter register of the free-running timer.
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize();
+ * ts The location in which to return the time from the free-running
+ * timer.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts)
+{
+ uint64_t usec;
+ uint32_t counter;
+ uint32_t verify;
+ uint8_t sr;
+ uint32_t overflow;
+ uint32_t sec;
+ irqstate_t flags;
+
+ DEBUGASSERT(freerun && freerun->tch && ts);
+
+ /* Temporarily disable the overflow counter.
+ * NOTE that we have to be here because sam_tc_getpending()
+ * will reset the pending interrupt status.
+ * If we do not handle the overflow here then, it will be lost.
+ */
+
+ flags = enter_critical_section();
+ overflow = freerun->overflow;
+ counter = sam_tc_getcounter(freerun->tch);
+ sr = sam_tc_getpending(freerun->tch);
+ verify = sam_tc_getcounter(freerun->tch);
+
+ /* If an interrupt was pending before we re-enabled interrupts,
+ * then the overflow needs to be incremented.
+ */
+
+ if ((sr & TC_INTFLAG_OVF) != 0)
+ {
+ /* Increment the overflow count and use the value of the
+ * guaranteed to be AFTER the overflow occurred.
+ */
+
+ overflow++;
+ counter = verify;
+
+ /* Update freerun overflow counter. */
+
+ freerun->overflow = overflow;
+ }
+
+ leave_critical_section(flags);
+
+ tmrinfo("counter=%u (%u) overflow=%u, sr=0x%x\n",
+ counter, verify, overflow, sr);
+
+ /* Convert the whole thing to units of microseconds.
+ *
+ * frequency = ticks / second
+ * seconds = ticks * frequency
+ * usecs = (ticks * USEC_PER_SEC) / frequency;
+ */
+
+ usec = ((((uint64_t)overflow << 32) + (uint64_t)counter) * USEC_PER_SEC) /
+ sam_tc_divfreq(freerun->tch);
+
+ /* And return the value of the timer */
+
+ sec = (uint32_t)(usec / USEC_PER_SEC);
+ ts->tv_sec = sec;
+ ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+
+ tmrinfo("usec=%llu ts=(%lu, %lu)\n",
+ usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_freerun_uninitialize
+ *
+ * Description:
+ * Stop the free-running timer and release all resources that it uses.
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize();
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_uninitialize(struct sam_freerun_s *freerun)
+{
+ DEBUGASSERT(freerun && freerun->tch);
+
+ /* Now we can disable the timer interrupt and disable the timer. */
+
+ sam_tc_attach(freerun->tch, NULL, NULL, 0);
+ sam_tc_stop(freerun->tch);
+
+ /* Free the timer */
+
+ sam_tc_free(freerun->tch);
+ freerun->tch = NULL;
+ return OK;
+}
+
+#endif /* CONFIG_SAMD5E5_FREERUN */
diff --git a/arch/arm/src/samd5e5/sam_freerun.h b/arch/arm/src/samd5e5/sam_freerun.h
new file mode 100644
index 0000000..0a66d06
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_freerun.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_freerun.h
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMD5E5_SAM_FREERUN_H
+#define __ARCH_ARM_SRC_SAMD5E5_SAM_FREERUN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "sam_tc.h"
+
+#ifdef CONFIG_SAMD5E5_FREERUN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define FREERUN_INITIALIZED(s) (((s)->tch) != NULL)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The freerun client must allocate an instance of this structure and called
+ * sam_freerun_initialize() before using the freerun facilities. The client
+ * should not access the contents of this structure directly since the
+ * contents are subject to change.
+ */
+
+struct sam_freerun_s
+{
+ uint8_t chan; /* The timer/counter in use */
+ bool running; /* True: the timer is running */
+ uint32_t overflow; /* Timer counter overflow */
+ TC_HANDLE tch; /* Handle returned by sam_tc_initialize() */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_freerun_initialize
+ *
+ * Description:
+ * Initialize the freerun timer wrapper
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure
+ * chan Timer counter channel to be used. See the TC_CHAN*
+ * definitions in arch/arm/src/sama5/sam_tc.h.
+ * resolution The required resolution of the timer in units of
+ * microseconds. NOTE that the range is restricted to the
+ * range of uint16_t (excluding zero).
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_initialize(struct sam_freerun_s *freerun, int chan,
+ uint16_t resolution);
+
+/****************************************************************************
+ * Name: sam_freerun_counter
+ *
+ * Description:
+ * Read the counter register of the free-running timer.
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize();
+ * ts The location in which to return the time remaining on the
+ * oneshot timer.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_counter(struct sam_freerun_s *freerun, struct timespec *ts);
+
+/****************************************************************************
+ * Name: sam_freerun_uninitialize
+ *
+ * Description:
+ * Stop the free-running timer and release all resources that it uses.
+ *
+ * Input Parameters:
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize();
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_freerun_uninitialize(struct sam_freerun_s *freerun);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_SAMD5E5_FREERUN */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_SAM_FREERUN_H */
diff --git a/arch/arm/src/samd5e5/sam_oneshot.c b/arch/arm/src/samd5e5/sam_oneshot.c
new file mode 100644
index 0000000..6c0f946
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_oneshot.c
@@ -0,0 +1,459 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_oneshot.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+
+#include "sam_oneshot.h"
+#include "sam_freerun.h"
+
+#ifdef CONFIG_SAMD5E5_ONESHOT
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_oneshot_handler
+ *
+ * Description:
+ * Timer interrupt callback. When the oneshot timer interrupt expires,
+ * this function will be called. It will forward the call to the next
+ * level up.
+ *
+ * Input Parameters:
+ * tch - The handle that represents the timer state
+ * arg - An opaque argument provided when the interrupt was registered
+ * sr - The value of the timer interrupt status register at the time
+ * that the interrupt occurred.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sam_oneshot_handler(TC_HANDLE tch, void *arg, uint32_t sr)
+{
+ struct sam_oneshot_s *oneshot = (struct sam_oneshot_s *)arg;
+ oneshot_handler_t oneshot_handler;
+ void *oneshot_arg;
+
+ tmrinfo("Expired...\n");
+ DEBUGASSERT(oneshot && oneshot->handler);
+
+ /* The clock was stopped, but not disabled when the RC match occurred.
+ * Disable the TC now and disable any further interrupts.
+ */
+
+ sam_tc_attach(oneshot->tch, NULL, NULL, 0);
+ sam_tc_stop(oneshot->tch);
+
+ /* The timer is no longer running */
+
+ oneshot->running = false;
+
+ /* Forward the event, clearing out any vestiges */
+
+ oneshot_handler = (oneshot_handler_t)oneshot->handler;
+ oneshot->handler = NULL;
+ oneshot_arg = (void *)oneshot->arg;
+ oneshot->arg = NULL;
+#ifdef CONFIG_SAMD5E5_FREERUN
+ oneshot->start_count = 0;
+#endif
+
+ oneshot_handler(oneshot_arg);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_oneshot_initialize
+ *
+ * Description:
+ * Initialize the oneshot timer wrapper
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure
+ * chan Timer counter channel to be used. See the TC_CHAN*
+ * definitions in arch/arm/src/samd5e5/sam_tc.h.
+ * resolution The required resolution of the timer in units of
+ * microseconds. NOTE that the range is restricted to the
+ * range of uint16_t (excluding zero).
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan,
+ uint16_t resolution)
+{
+ uint32_t frequency;
+
+ tmrinfo("chan=%d resolution=%d usec\n", chan, resolution);
+ DEBUGASSERT(oneshot && resolution > 0);
+
+ /* Get the TC frequency the corresponds to the requested resolution */
+
+ frequency = USEC_PER_SEC / (uint32_t)resolution;
+
+ oneshot->tch = sam_tc_allocate(chan, frequency);
+ if (!oneshot->tch)
+ {
+ tmrerr("ERROR: Failed to allocate timer channel %d\n", chan);
+ return -EBUSY;
+ }
+
+ /* Initialize the remaining fields in the state structure and return
+ * success.
+ */
+
+ oneshot->chan = chan;
+ oneshot->running = false;
+ oneshot->handler = NULL;
+ oneshot->arg = NULL;
+#ifdef CONFIG_SAMD5E5_FREERUN
+ oneshot->start_count = 0;
+#endif
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_oneshot_max_delay
+ *
+ * Description:
+ * Return the maximum delay supported by the one shot timer (in
+ * microseconds).
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * usec The location in which to return the maximum delay.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec)
+{
+ DEBUGASSERT(oneshot != NULL && usec != NULL);
+ *usec = (0xffffull * USEC_PER_SEC) /
+ (uint64_t)sam_tc_divfreq(oneshot->tch);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_oneshot_start
+ *
+ * Description:
+ * Start the oneshot timer
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * handler The function to call when when the oneshot timer expires.
+ * arg An opaque argument that will accompany the callback.
+ * ts Provides the duration of the one shot timer.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_start(struct sam_oneshot_s *oneshot,
+ struct sam_freerun_s *freerun,
+ oneshot_handler_t handler, void *arg,
+ const struct timespec *ts)
+{
+ uint64_t usec;
+ uint64_t regval;
+ irqstate_t flags;
+
+ tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
+ handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+ DEBUGASSERT(oneshot && handler && ts);
+
+ /* Was the oneshot already running? */
+
+ flags = enter_critical_section();
+ if (oneshot->running)
+ {
+ /* Yes.. then cancel it */
+
+ tmrinfo("Already running... cancelling\n");
+ (void)sam_oneshot_cancel(oneshot, freerun, NULL);
+ }
+
+ /* Save the new handler and its argument */
+
+ oneshot->handler = handler;
+ oneshot->arg = arg;
+
+ /* Express the delay in microseconds */
+
+ usec = (uint64_t)ts->tv_sec * USEC_PER_SEC + (uint64_t)(ts->tv_nsec /
+ NSEC_PER_USEC);
+
+ /* Get the timer counter frequency and determine
+ * the number of counts need to achieve the requested delay.
+ *
+ * frequency = ticks / second
+ * ticks = seconds * frequency
+ * = (usecs * frequency) / USEC_PER_SEC;
+ */
+
+ regval = (usec * (uint64_t)sam_tc_divfreq(oneshot->tch)) / USEC_PER_SEC;
+
+ tmrinfo("usec=%llu * %lu / %lu -> regval=0x%08llx\n", usec,
+ sam_tc_divfreq(oneshot->tch), USEC_PER_SEC, regval);
+ DEBUGASSERT(regval <= UINT32_MAX);
+
+ /* Set up to receive the callback when the interrupt occurs */
+
+ (void)sam_tc_attach(oneshot->tch, sam_oneshot_handler,
+ oneshot, TC_INTFLAG_MC0);
+
+ /* Set CC0 so that an event will be triggered when COUNT register
+ * counts up to CC0.
+ */
+
+ sam_tc_setregister(oneshot->tch, TC_REGCC0, (uint32_t)regval);
+ sam_tc_setregister(oneshot->tch, TC_REGCC1, (uint32_t)0xffffffff);
+
+ /* Start the counter */
+
+ sam_tc_start(oneshot->tch);
+
+#ifdef CONFIG_SAMD5E5_FREERUN
+ /* The function sam_tc_start() starts the timer/counter by setting the
+ * bits TC_CCR_CLKEN and TC_CCR_SWTRG in the channel control register.
+ * The first one enables the timer/counter the latter performs an
+ * software trigger, which starts the clock and sets the counter
+ * register to zero. This reset is performed with the next valid edge
+ * of the selected clock. Thus it can take up USEC_PER_TICK microseconds
+ * until the counter register becomes zero.
+ *
+ * If the timer is canceled within this period the counter register holds
+ * the counter value for the last timer/counter run. To circumvent this
+ * the counter value of the freerun timer/counter is stored at each start
+ * of the oneshot timer/counter.
+ *
+ * The function up_timer_gettime() could also be used for this but it takes
+ * too long. If up_timer_gettime() is called within this function the
+ * problem vanishes at least if compiled with no optimisation.
+ */
+
+ if (freerun != NULL)
+ {
+ oneshot->start_count = sam_tc_getcounter(freerun->tch);
+ }
+#endif
+
+ /* Enable interrupts. We should get the callback when the interrupt
+ * occurs.
+ */
+
+ oneshot->running = true;
+ leave_critical_section(flags);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_oneshot_cancel
+ *
+ * Description:
+ * Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ * NOTE: This function may execute at a high rate with no timer running (as
+ * when pre-emption is enabled and disabled).
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * ts The location in which to return the time remaining on the
+ * oneshot timer. A time of zero is returned if the timer is
+ * not running. ts may be zero in which case the time remaining
+ * is not returned.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A call to up_timer_cancel() when
+ * the timer is not active should also return success; a negated errno
+ * value is returned on any failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_cancel(struct sam_oneshot_s *oneshot,
+ struct sam_freerun_s *freerun, struct timespec *ts)
+{
+ irqstate_t flags;
+ uint64_t usec;
+ uint64_t sec;
+ uint64_t nsec;
+ uint32_t count;
+ uint32_t rc;
+
+ /* Was the timer running? */
+
+ flags = enter_critical_section();
+ if (!oneshot->running)
+ {
+ /* No.. Just return zero timer remaining and successful cancellation.
+ * This function may execute at a high rate with no timer running
+ * (as when pre-emption is enabled and disabled).
+ */
+
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ leave_critical_section(flags);
+ return OK;
+ }
+
+ /* Yes.. Get the timer counter and rc registers and stop the counter. If
+ * the counter expires while we are doing this, the counter clock will be
+ * stopped, but the clock will not be disabled.
+ *
+ * The expected behavior is that the counter register will freezes at
+ * a value equal to the RC register when the timer expires. The counter
+ * should have values between 0 and RC in all other cased.
+ *
+ * REVISIT: This does not appear to be the case.
+ */
+
+ tmrinfo("Cancelling...\n");
+
+ count = sam_tc_getcounter(oneshot->tch);
+ rc = sam_tc_getregister(oneshot->tch, TC_REGCC0);
+
+#ifdef CONFIG_SAMD5E5_FREERUN
+ /* In the case the timer/counter was canceled very short after its start,
+ * the counter register can hold the wrong value (the value of the last
+ * run). To prevent this the counter value is set to zero if not at
+ * least on tick passed since the start of the timer/counter.
+ */
+
+ if (count > 0 && freerun != NULL &&
+ sam_tc_getcounter(freerun->tch) == oneshot->start_count)
+ {
+ count = 0;
+ }
+#endif
+
+ /* Now we can disable the interrupt and stop the timer. */
+
+ sam_tc_attach(oneshot->tch, NULL, NULL, 0);
+ sam_tc_stop(oneshot->tch);
+
+ oneshot->running = false;
+ oneshot->handler = NULL;
+ oneshot->arg = NULL;
+ leave_critical_section(flags);
+
+ /* Did the caller provide us with a location to return the time
+ * remaining?
+ */
+
+ if (ts)
+ {
+ /* Yes.. then calculate and return the time remaining on the
+ * oneshot timer.
+ */
+
+ tmrinfo("rc=%lu count=%lu usec=%lu\n",
+ (unsigned long)rc, (unsigned long)count, (unsigned long)usec);
+
+ /* REVISIT: I am not certain why the timer counter value sometimes
+ * exceeds RC. Might be a bug, or perhaps the counter does not stop
+ * in all cases.
+ */
+
+ if (count >= rc)
+ {
+ /* No time remaining (?) */
+
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ }
+ else
+ {
+ /* The total time remaining is the difference. Convert the that
+ * to units of microseconds.
+ *
+ * frequency = ticks / second
+ * seconds = ticks * frequency
+ * usecs = (ticks * USEC_PER_SEC) / frequency;
+ */
+
+ usec = (((uint64_t)(rc - count)) * USEC_PER_SEC) /
+ sam_tc_divfreq(oneshot->tch);
+
+ /* Each time the timer/counter is canceled the time calculated from
+ * the two registers (counter and REGC) is accurate up to an error
+ * between 0 and USEC_PER_TICK microseconds. To correct this error
+ * one tick which means USEC_PER_TICK microseconds are subtracted.
+ */
+
+ usec = usec > USEC_PER_TICK ? usec - USEC_PER_TICK : 0;
+
+ /* Return the time remaining in the correct form */
+
+ sec = usec / USEC_PER_SEC;
+ nsec = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+
+ ts->tv_sec = (time_t)sec;
+ ts->tv_nsec = (unsigned long)nsec;
+ }
+
+ tmrinfo("remaining (%lu, %lu)\n",
+ (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_SAMD5E5_ONESHOT */
diff --git a/arch/arm/src/samd5e5/sam_oneshot.h b/arch/arm/src/samd5e5/sam_oneshot.h
new file mode 100644
index 0000000..6be2145
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_oneshot.h
@@ -0,0 +1,212 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_oneshot.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMD5E5_SAM_ONESHOT_H
+#define __ARCH_ARM_SRC_SAMD5E5_SAM_ONESHOT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "sam_tc.h"
+
+#ifdef CONFIG_SAMD5E5_ONESHOT
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ONESHOT_INITIALIZED(s) (((s)->tch) != NULL)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This describes the callback function that will be invoked when the oneshot
+ * timer expires. The oneshot fires, the client will receive:
+ *
+ * arg - The opaque argument provided when the interrupt was registered
+ */
+
+typedef void (*oneshot_handler_t)(void *arg);
+
+/* The oneshot client must allocate an instance of this structure and called
+ * sam_oneshot_initialize() before using the oneshot facilities. The client
+ * should not access the contents of this structure directly since the
+ * contents are subject to change.
+ */
+
+struct sam_oneshot_s
+{
+ uint8_t chan; /* The timer/counter in use */
+ volatile bool running; /* True: the timer is running */
+ TC_HANDLE tch; /* Handle returned by
+ * sam_tc_initialize() */
+ volatile oneshot_handler_t handler; /* Oneshot expiration callback */
+ volatile void *arg; /* The argument that will accompany
+ * the callback */
+#ifdef CONFIG_SAMD5E5_FREERUN
+ volatile uint32_t start_count; /* Stores the value of the freerun counter,
+ * at each start of the onshot timer. Is neccesary
+ * to find out if the onshot counter was updated
+ * correctly at the time of the call to
+ * sam_oneshot_cancel or not. */
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_oneshot_initialize
+ *
+ * Description:
+ * Initialize the oneshot timer wrapper
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure
+ * chan Timer counter channel to be used. See the TC_CHAN*
+ * definitions in arch/arm/src/samd5e5/sam_tc.h.
+ * resolution The required resolution of the timer in units of
+ * microseconds. NOTE that the range is restricted to the
+ * range of uint16_t (excluding zero).
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan,
+ uint16_t resolution);
+
+/****************************************************************************
+ * Name: sam_oneshot_max_delay
+ *
+ * Description:
+ * Return the maximum delay supported by the one shot timer (in
+ * microseconds).
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * usec The location in which to return the maximum delay.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec);
+
+/****************************************************************************
+ * Name: sam_oneshot_start
+ *
+ * Description:
+ * Start the oneshot timer
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize(). May be NULL if there is no matching
+ * free-running timer.
+ * handler The function to call when when the oneshot timer expires.
+ * arg An opaque argument that will accompany the callback.
+ * ts Provides the duration of the one shot timer.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+struct sam_freerun_s;
+int sam_oneshot_start(struct sam_oneshot_s *oneshot,
+ struct sam_freerun_s *freerun,
+ oneshot_handler_t handler, void *arg,
+ const struct timespec *ts);
+
+/****************************************************************************
+ * Name: sam_oneshot_cancel
+ *
+ * Description:
+ * Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ * NOTE: This function may execute at a high rate with no timer running (as
+ * when pre-emption is enabled and disabled).
+ *
+ * Input Parameters:
+ * oneshot Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_oneshot_initialize();
+ * freerun Caller allocated instance of the freerun state structure. This
+ * structure must have been previously initialized via a call to
+ * sam_freerun_initialize(). May be NULL if there is no matching
+ * free-running timer.
+ * ts The location in which to return the time remaining on the
+ * oneshot timer. A time of zero is returned if the timer is
+ * not running.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A call to up_timer_cancel() when
+ * the timer is not active should also return success; a negated errno
+ * value is returned on any failure.
+ *
+ ****************************************************************************/
+
+struct sam_freerun_s;
+int sam_oneshot_cancel(struct sam_oneshot_s *oneshot,
+ struct sam_freerun_s *freerun, struct timespec *ts);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_SAMD5E5_ONESHOT */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_SAM_ONESHOT_H */
diff --git a/arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c b/arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c
new file mode 100644
index 0000000..b1bda1b
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c
@@ -0,0 +1,336 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/timers/oneshot.h>
+
+#include "sam_oneshot.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes the state of oneshot timer lower-half driver */
+
+struct sam_oneshot_lowerhalf_s
+{
+ /* This is the part of the lower half driver that is visible to the upper-
+ * half client of the driver. This must be the first thing in this
+ * structure so that pointers to struct oneshot_lowerhalf_s are cast
+ * compatible to struct sam_oneshot_lowerhalf_s and vice versa.
+ */
+
+ struct oneshot_lowerhalf_s lh; /* Common lower-half driver fields */
+
+ /* Private lower half data follows */
+
+ struct sam_oneshot_s oneshot; /* SAM-specific oneshot state */
+ oneshot_callback_t callback; /* internal handler that receives callback */
+ FAR void *arg; /* Argument that is passed to the handler */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void sam_oneshot_handler(void *arg);
+
+static int sam_max_delay(FAR struct oneshot_lowerhalf_s *lower,
+ FAR struct timespec *ts);
+static int sam_start(FAR struct oneshot_lowerhalf_s *lower,
+ oneshot_callback_t callback, FAR void *arg,
+ FAR const struct timespec *ts);
+static int sam_cancel(FAR struct oneshot_lowerhalf_s *lower,
+ FAR struct timespec *ts);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Lower half operations */
+
+static const struct oneshot_operations_s g_oneshot_ops =
+{
+ .max_delay = sam_max_delay,
+ .start = sam_start,
+ .cancel = sam_cancel,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_oneshot_handler
+ *
+ * Description:
+ * Timer expiration handler
+ *
+ * Input Parameters:
+ * arg - Should be the same argument provided when sam_oneshot_start()
+ * was called.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sam_oneshot_handler(void *arg)
+{
+ FAR struct sam_oneshot_lowerhalf_s *priv =
+ (FAR struct sam_oneshot_lowerhalf_s *)arg;
+ oneshot_callback_t callback;
+ FAR void *cbarg;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Perhaps the callback was nullified in a race condition with
+ * sam_cancel?
+ */
+
+ if (priv->callback)
+ {
+ /* Sample and nullify BEFORE executing callback (in case the callback
+ * restarts the oneshot).
+ */
+
+ callback = priv->callback;
+ cbarg = priv->arg;
+ priv->callback = NULL;
+ priv->arg = NULL;
+
+ /* Then perform the callback */
+
+ callback(&priv->lh, cbarg);
+ }
+}
+
+/****************************************************************************
+ * Name: sam_max_delay
+ *
+ * Description:
+ * Determine the maximum delay of the one-shot timer (in microseconds)
+ *
+ * Input Parameters:
+ * lower An instance of the lower-half oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * oneshot_initialize();
+ * ts The location in which to return the maxumum delay.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+static int sam_max_delay(FAR struct oneshot_lowerhalf_s *lower,
+ FAR struct timespec *ts)
+{
+ FAR struct sam_oneshot_lowerhalf_s *priv =
+ (FAR struct sam_oneshot_lowerhalf_s *)lower;
+ uint64_t usecs;
+ int ret;
+
+ DEBUGASSERT(priv != NULL && ts != NULL);
+ ret = sam_oneshot_max_delay(&priv->oneshot, &usecs);
+ if (ret >= 0)
+ {
+ uint64_t sec = usecs / 1000000;
+ usecs -= 1000000 * sec;
+
+ ts->tv_sec = (time_t)sec;
+ ts->tv_nsec = (long)(usecs * 1000);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: sam_start
+ *
+ * Description:
+ * Start the oneshot timer
+ *
+ * Input Parameters:
+ * lower An instance of the lower-half oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * oneshot_initialize();
+ * handler The function to call when when the oneshot timer expires.
+ * arg An opaque argument that will accompany the callback.
+ * ts Provides the duration of the one shot timer.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned
+ * on failure.
+ *
+ ****************************************************************************/
+
+static int sam_start(FAR struct oneshot_lowerhalf_s *lower,
+ oneshot_callback_t callback, FAR void *arg,
+ FAR const struct timespec *ts)
+{
+ FAR struct sam_oneshot_lowerhalf_s *priv =
+ (FAR struct sam_oneshot_lowerhalf_s *)lower;
+ irqstate_t flags;
+ int ret;
+
+ DEBUGASSERT(priv != NULL && callback != NULL && ts != NULL);
+
+ /* Save the callback information and start the timer */
+
+ flags = enter_critical_section();
+ priv->callback = callback;
+ priv->arg = arg;
+ ret = sam_oneshot_start(&priv->oneshot, NULL,
+ sam_oneshot_handler, priv, ts);
+ leave_critical_section(flags);
+
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_oneshot_start failed: %d\n", flags);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: sam_cancel
+ *
+ * Description:
+ * Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ * NOTE: This function may execute at a high rate with no timer running (as
+ * when pre-emption is enabled and disabled).
+ *
+ * Input Parameters:
+ * lower Caller allocated instance of the oneshot state structure. This
+ * structure must have been previously initialized via a call to
+ * oneshot_initialize();
+ * ts The location in which to return the time remaining on the
+ * oneshot timer. A time of zero is returned if the timer is
+ * not running.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A call to up_timer_cancel() when
+ * the timer is not active should also return success; a negated errno
+ * value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static int sam_cancel(FAR struct oneshot_lowerhalf_s *lower,
+ FAR struct timespec *ts)
+{
+ FAR struct sam_oneshot_lowerhalf_s *priv =
+ (FAR struct sam_oneshot_lowerhalf_s *)lower;
+ irqstate_t flags;
+ int ret;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Cancel the timer */
+
+ flags = enter_critical_section();
+ ret = sam_oneshot_cancel(&priv->oneshot, NULL, ts);
+ priv->callback = NULL;
+ priv->arg = NULL;
+ leave_critical_section(flags);
+
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_oneshot_cancel failed: %d\n", flags);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: oneshot_initialize
+ *
+ * Description:
+ * Initialize the oneshot timer and return a oneshot lower half driver
+ * instance.
+ *
+ * Input Parameters:
+ * chan Timer counter channel to be used.
+ * resolution The required resolution of the timer in units of
+ * microseconds. NOTE that the range is restricted to the
+ * range of uint16_t (excluding zero).
+ *
+ * Returned Value:
+ * On success, a non-NULL instance of the oneshot lower-half driver is
+ * returned. NULL is return on any failure.
+ *
+ ****************************************************************************/
+
+FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan,
+ uint16_t resolution)
+{
+ FAR struct sam_oneshot_lowerhalf_s *priv;
+ int ret;
+
+ /* Allocate an instance of the lower half driver */
+
+ priv = (FAR struct sam_oneshot_lowerhalf_s *)
+ kmm_zalloc(sizeof(struct sam_oneshot_lowerhalf_s));
+
+ if (priv == NULL)
+ {
+ tmrerr("ERROR: Failed to initialized state structure\n");
+ return NULL;
+ }
+
+ /* Initialize the lower-half driver structure */
+
+ priv->lh.ops = &g_oneshot_ops;
+
+ /* Initialize the contained SAM oneshot timer */
+
+ ret = sam_oneshot_initialize(&priv->oneshot, chan, resolution);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_oneshot_initialize failed: %d\n", ret);
+ kmm_free(priv);
+ return NULL;
+ }
+
+ return &priv->lh;
+}
diff --git a/arch/arm/src/samd5e5/sam_port.h b/arch/arm/src/samd5e5/sam_port.h
index 89af653..6a34ecf 100644
--- a/arch/arm/src/samd5e5/sam_port.h
+++ b/arch/arm/src/samd5e5/sam_port.h
@@ -57,9 +57,9 @@
/* Bit-encoded input to sam_portconfig() */
-/* 24-bit Encoding. This could be compacted into 16-bits by making the bit usage
- * mode specific. However, by giving each bit field a unique position, we handle
- * bad combinations of properties safely.
+/* 24-bit Encoding. This could be compacted into 16-bits by making the bit
+ * usage mode specific. However, by giving each bit field a unique position,
+ * we handle bad combinations of properties safely.
*
* MODE BITFIELDS
* ------------ -----------------------------
@@ -85,12 +85,13 @@
* Peripheral: MM.. .... .... .... .... ....
*/
-#define PORT_MODE_SHIFT (22) /* Bits 22-23: PORT mode */
+#define PORT_MODE_SHIFT (22) /* Bits 22-23: PORT mode */
#define PORT_MODE_MASK (3 << PORT_MODE_SHIFT)
# define PORT_INPUT (0 << PORT_MODE_SHIFT) /* PORT Input */
# define PORT_OUTPUT (1 << PORT_MODE_SHIFT) /* PORT Output */
# define PORT_PERIPHERAL (2 << PORT_MODE_SHIFT) /* Controlled by peripheral */
# define PORT_INTERRUPT (3 << PORT_MODE_SHIFT) /* Interrupting input */
+#define PORT_MODE(n) ((uint8_t)(n) << PORT_MODE_SHIFT)
/* Pull-up/down resistor control for inputs
*
@@ -217,8 +218,8 @@
# define PORT_OUTREADBACK_DISABLE (0 << PORT_OUTREADBACK_SHIFT)
# define PORT_OUTREADBACK_ENABLE (1 << PORT_OUTREADBACK_SHIFT)
-/* If the pin is a PORT output, then this identifies the initial output value:
- *
+/* If the pin is a PORT output, then this
+ * identifies the initial output value:
* MODE BITFIELDS
* ------------ -----------------------------
* 2222 1111 1111 1100 0000 0000
@@ -251,6 +252,8 @@
# define PORT_INT_CHANGE (0 << PORT_INT_SHIFT) /* Pin change */
# define PORT_INT_RISING (1 << PORT_INT_SHIFT) /* Rising edge */
# define PORT_INT_FALLING (2 << PORT_INT_SHIFT) /* Falling edge */
+# define PORT_INT_BOTH (3 << PORT_INT_SHIFT) /* Both edge */
+# define PORT_INT_HIGH (4 << PORT_INT_SHIFT) /* High edge */
/* This identifies the PORT port:
*
diff --git a/arch/arm/src/samd5e5/sam_tc.c b/arch/arm/src/samd5e5/sam_tc.c
new file mode 100644
index 0000000..bbd0edc
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_tc.c
@@ -0,0 +1,1143 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_tc.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/wdog.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+
+#include "arm_internal.h"
+#include "arm_arch.h"
+
+#include "sam_gclk.h"
+#include "sam_periphclks.h"
+#include "sam_port.h"
+#include "sam_tc.h"
+
+#include "hardware/sam_pac.h"
+
+#include <arch/board/board.h>
+
+#ifdef CONFIG_SAMD5E5_TC
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Invariant attributes of an TC */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMD5E5_TC0
+static const struct tc_attr_s g_tc0attr =
+{
+ .tc = 0,
+ .irq = SAM_IRQ_TC0,
+ .coregen = BOARD_TC0_GCLKGEN,
+ .cc0 = BOARD_TC0_PINMAP_CC0,
+ .cc1 = BOARD_TC0_PINMAP_CC1,
+ .srcfreq = BOARD_TC0_FREQUENCY,
+ .base = SAM_TC0_BASE,
+};
+static struct sam_tc_dev_s g_tc0 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+#ifdef CONFIG_SAMD5E5_TC1
+static const struct tc_attr_s g_tc1attr =
+{
+ .tc = 1,
+ .irq = SAM_IRQ_TC1,
+ .coregen = BOARD_TC1_GCLKGEN,
+ .cc0 = BOARD_TC1_PINMAP_CC0,
+ .cc1 = BOARD_TC1_PINMAP_CC1,
+ .srcfreq = BOARD_TC1_FREQUENCY,
+ .base = SAM_TC1_BASE,
+};
+static struct sam_tc_dev_s g_tc1 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+#ifdef CONFIG_SAMD5E5_TC2
+static const struct tc_attr_s g_tc2attr =
+{
+ .tc = 2,
+ .irq = SAM_IRQ_TC2,
+ .coregen = BOARD_TC2_GCLKGEN,
+ .cc0 = BOARD_TC2_PINMAP_CC0,
+ .cc1 = BOARD_TC2_PINMAP_CC1,
+ .srcfreq = BOARD_TC2_FREQUENCY,
+ .base = SAM_TC2_BASE,
+};
+static struct sam_tc_dev_s g_tc2 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+#ifdef CONFIG_SAMD5E5_TC3
+static const struct tc_attr_s g_tc3attr =
+{
+ .tc = 3,
+ .irq = SAM_IRQ_TC3,
+ .coregen = BOARD_TC3_GCLKGEN,
+ .cc0 = BOARD_TC3_PINMAP_CC0,
+ .cc1 = BOARD_TC3_PINMAP_CC1,
+ .srcfreq = BOARD_TC3_FREQUENCY,
+ .base = SAM_TC3_BASE,
+};
+static struct sam_tc_dev_s g_tc3 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+#ifdef CONFIG_SAMD5E5_TC4
+static const struct tc_attr_s g_tc4attr =
+{
+ .tc = 4,
+ .irq = SAM_IRQ_TC4,
+ .coregen = BOARD_TC4_GCLKGEN,
+ .cc0 = BOARD_TC4_PINMAP_CC0,
+ .cc1 = BOARD_TC4_PINMAP_CC1,
+ .srcfreq = BOARD_TC4_FREQUENCY,
+ .base = SAM_TC4_BASE,
+};
+static struct sam_tc_dev_s g_tc4 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+#ifdef CONFIG_SAMD5E5_TC5
+static const struct tc_attr_s g_tc5attr =
+{
+ .tc = 5,
+ .irq = SAM_IRQ_TC5,
+ .coregen = BOARD_TC5_GCLKGEN,
+ .cc0 = BOARD_TC5_PINMAP_CC0,
+ .cc1 = BOARD_TC5_PINMAP_CC1,
+ .srcfreq = BOARD_TC5_FREQUENCY,
+ .base = SAM_TC5_BASE,
+};
+static struct sam_tc_dev_s g_tc5 =
+{
+ .initialized = false,
+ .inuse = false,
+};
+#endif
+
+static const uint8_t g_corclk_channel[SAMD5E5_NTC] =
+{
+ GCLK_CHAN_TC0
+ #if SAMD5E5_NTC > 1
+ , GCLK_CHAN_TC1
+ #endif
+ #if SAMD5E5_NTC > 2
+ , GCLK_CHAN_TC2
+ #endif
+ #if SAMD5E5_NTC > 3
+ , GCLK_CHAN_TC3
+ #endif
+ #if SAMD5E5_NTC > 4
+ , GCLK_CHAN_TC4
+ #endif
+ #if SAMD5E5_NTC > 5
+ , GCLK_CHAN_TC5
+ #endif
+};
+
+/* TC frequency data.
+ * This table provides the frequency for each selection of TCCLK
+ */
+
+#define TC_NDIVIDERS 8
+
+/* This is the list of divider values: divider = (1 << value) */
+
+static const uint8_t g_log2divider[TC_NDIVIDERS] =
+{
+ 0, /* TIMER_CLOCK -> div1 */
+ 1, /* TIMER_CLOCK -> div2 */
+ 2, /* TIMER_CLOCK -> div4 */
+ 3, /* TIMER_CLOCK -> div8 */
+ 4, /* TIMER_CLOCK -> div16 */
+ 6, /* TIMER_CLOCK -> div64 */
+ 8, /* TIMER_CLOCK -> div256 */
+ 10 /* TIMER_CLOCK -> div1024 */
+};
+
+/* TC register lookup used by sam_tc_setregister */
+
+#define TC_NREGISTERS 2
+
+static const uint8_t g_regoffset[TC_NREGISTERS] =
+{
+ SAM_TC_COUNT32_CC0_OFFSET, /* Channel 0 */
+ SAM_TC_COUNT32_CC1_OFFSET, /* Channel 1 */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Initialization */
+
+static void tc_takesem(struct sam_tc_dev_s *priv);
+#define tc_givesem(priv) (nxsem_post(&priv->exclsem))
+void tc_bridge_enable(int tc);
+void sam_tc_dumpregs(struct sam_tc_dev_s *priv);
+void sam_tc_setperiod(struct sam_tc_dev_s *priv);
+
+static uint32_t sam_tc_divfreq_lookup(uint32_t ftcin, int ndx);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tc_takesem
+ *
+ * Description:
+ * Take the wait semaphore (handling false alarm wake-ups due to
+ * the receipt of signals).
+ *
+ * Input Parameters:
+ * dev - Instance of the SDIO device driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void tc_takesem(struct sam_tc_dev_s *priv)
+{
+ int ret;
+
+ do
+ {
+ /* Take the semaphore (perhaps waiting) */
+
+ ret = nxsem_wait(&priv->exclsem);
+
+ /* The only case that an error should occur here is if the wait was
+ * awakened by a signal.
+ */
+
+ /* DEBUGASSERT(ret == OK || ret == -EINTR); */
+ }
+
+ while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Name: tc_enable
+ *
+ * Description:
+ * Enable the Main Clock for Tc. (MCLK_APBxMASK)
+ *
+ ****************************************************************************/
+
+void tc_bridge_enable(int tc)
+{
+ DEBUGASSERT((unsigned)tc < SAMD5E5_NTC);
+
+ switch (tc)
+ {
+ case 0:
+ sam_apb_tc0_enableperiph();
+ break;
+
+ case 1:
+ sam_apb_tc1_enableperiph();
+ break;
+
+ case 2:
+ sam_apb_tc2_enableperiph();
+ break;
+
+ case 3:
+ sam_apb_tc3_enableperiph();
+ break;
+
+ case 4:
+ sam_apb_tc4_enableperiph();
+ break;
+
+ case 5:
+ sam_apb_tc5_enableperiph();
+ break;
+
+ default:
+ break;
+ }
+}
+
+/****************************************************************************
+ * Name: tc_wait_synchronization
+ *
+ * Description:
+ * Wait until the TC reports that it is synchronized.
+ *
+ ****************************************************************************/
+
+static void tc_wait_synchronization(struct sam_tc_dev_s *priv)
+{
+ while ((getreg32(priv->attr->base + SAM_TC_SYNCBUSY_OFFSET) & 0x7) != 0);
+}
+
+/****************************************************************************
+ * Name: tc_coreclk_configure
+ *
+ * Description:
+ * Configure the TC source clock. PCHCTRL[id]
+ *
+ * One generic clock is used by the TC: GCLK_TCx.
+ *
+ ****************************************************************************/
+
+void tc_coreclk_configure(int tc, int coregen, bool wrlock)
+{
+ uint8_t corechan;
+
+ DEBUGASSERT((unsigned)tc < SAMD5E5_NTC);
+
+ /* Set up the TCn_GCLK_ID_CORE clock */
+
+ corechan = g_corclk_channel[tc];
+ sam_gclk_chan_enable(corechan, coregen, wrlock);
+}
+
+/****************************************************************************
+ * Name: tc_interrupt
+ *
+ * Description:
+ * Common timer channel interrupt handling.
+ *
+ * Input Parameters:
+ * tc Timer status instance
+ *
+ * Returned Value:
+ * A pointer to the initialized timer channel structure associated with tc
+ * and channel. NULL is returned on any failure.
+ *
+ * On successful return, the caller holds the tc exclusive access semaphore.
+ *
+ ****************************************************************************/
+
+static int tc_interrupt(int irq, void *context, FAR void *arg)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)arg;
+ uint8_t flags;
+
+ /* Get the interrupt status for this channel */
+
+ flags = getreg8(priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+ if (flags & TC_INTFLAG_OVF)
+ {
+ tmrinfo("Overflow Interrupt Flag\n");
+ putreg8(TC_INTFLAG_OVF, priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+ }
+
+ if (flags & TC_INTFLAG_ERR)
+ {
+ tmrinfo("Error Interrupt Flag\n");
+ putreg8(TC_INTFLAG_ERR, priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+ }
+
+ if (flags & TC_INTFLAG_MC0)
+ {
+ tmrinfo("MC0 Interrupt Flag\n");
+ putreg8(TC_INTFLAG_MC0, priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+ }
+
+ if (flags & TC_INTFLAG_MC1)
+ {
+ tmrinfo("MC1 Interrupt Flag\n");
+ putreg8(TC_INTFLAG_MC1, priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+ }
+
+ if (priv->handler)
+ {
+ /* Execute the callback */
+
+ priv->handler(priv, priv->arg, flags);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: sam_tc_freqdiv_lookup
+ *
+ * Description:
+ * Given the TC input frequency (Ftcin) and a divider index, return the
+ * value of the Ftcin divider.
+ *
+ * Input Parameters:
+ * ftcin - TC input frequency
+ * ndx - Divider index
+ *
+ * Returned Value:
+ * The Ftcin input divider value
+ *
+ ****************************************************************************/
+
+static int sam_tc_freqdiv_lookup(uint32_t ftcin, int ndx)
+{
+ /* The final option is to use the SLOW clock */
+
+ if (ndx >= TC_NDIVIDERS)
+ {
+ /* Not really a divider. In this case, the board is actually driven
+ * by the 32.768KHz slow clock. This returns a value that looks like
+ * correct divider if MCK were the input.
+ */
+
+ return ftcin / BOARD_OSC32K_FREQUENCY;
+ }
+ else
+ {
+ return 1 << g_log2divider[ndx];
+ }
+}
+
+/****************************************************************************
+ * Name: sam_tc_divfreq_lookup
+ *
+ * Description:
+ * Given the TC input frequency (Ftcin) and a divider index, return the
+ * value of the divided frequency
+ *
+ * Input Parameters:
+ * ftcin - TC input frequency
+ * ndx - Divider index
+ *
+ * Returned Value:
+ * The divided frequency value
+ *
+ ****************************************************************************/
+
+static uint32_t sam_tc_divfreq_lookup(uint32_t ftcin, int ndx)
+{
+ /* The final option is to use the SLOW clock */
+
+ if (ndx >= TC_NDIVIDERS)
+ {
+ return BOARD_OSC32K_FREQUENCY;
+ }
+ else
+ {
+ return ftcin >> g_log2divider[ndx];
+ }
+}
+
+/****************************************************************************
+ * Name: sam_tc_initialize
+ *
+ * Description:
+ * There is no global, one-time initialization of timer/counter data
+ * structures. Rather, this function is called each time that a channel
+ * is allocated and, if the channel has not been initialized, it will be
+ * initialized then.
+ *
+ * Input Parameters:
+ * channel TC channel number (see TC_CHANx definitions)
+ *
+ * Returned Value:
+ * A pointer to the initialized timer channel structure associated with tc
+ * and channel. NULL is returned on any failure.
+ *
+ * On successful return, the caller holds the tc exclusive access semaphore.
+ *
+ ****************************************************************************/
+
+static inline struct sam_tc_dev_s *sam_tc_initialize(int tc)
+{
+ struct sam_tc_dev_s *priv;
+
+ /* Select the timer/counter and get the index associated with the TC. */
+
+#ifdef CONFIG_SAMD5E5_TC0
+ if (tc == 0)
+ {
+ /* Select up TC0 and setup invariant attributes */
+
+ priv = &g_tc0;
+ priv->attr = &g_tc0attr;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMD5E5_TC1
+ if (tc == 1)
+ {
+ /* Select up TC1 and setup invariant attributes */
+
+ priv = &g_tc1;
+ priv->attr = &g_tc1attr;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMD5E5_TC2
+ if (tc == 2)
+ {
+ /* Select up TC2 and setup invariant attributes */
+
+ priv = &g_tc2;
+ priv->attr = &g_tc2attr;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMD5E5_TC3
+ if (tc == 3)
+ {
+ /* Select up TC3 and setup invariant attributes */
+
+ priv = &g_tc3;
+ priv->attr = &g_tc3attr;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMD5E5_TC4
+ if (tc == 4)
+ {
+ /* Select up TC4 and setup invariant attributes */
+
+ priv = &g_tc4;
+ priv->attr = &g_tc4attr;
+ }
+ else
+#endif
+#ifdef CONFIG_SAMD5E5_TC5
+ if (tc == 5)
+ {
+ /* Select up TC5 and setup invariant attributes */
+
+ priv = &g_tc5;
+ priv->attr = &g_tc5attr;
+ }
+ else
+#endif
+ {
+ tmrerr("ERROR: Unsupported TC%d\n", tc);
+ return NULL;
+ }
+
+ return priv;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_tc_allocate
+ *
+ * Description:
+ * Configures a Timer Counter to operate in the given mode. The timer is
+ * stopped after configuration and must be restarted with sam_tc_start().
+ * All the interrupts of the timer are also disabled.
+ *
+ * Input Parameters:
+ * channel TC channel number
+ * mode Operating mode (TC_CMR value).
+ *
+ * Returned Value:
+ * On success, a non-NULL handle value is returned. This handle may be
+ * used with subsequent timer/counter interfaces to manage the timer. A
+ * NULL handle value is returned on a failure.
+ *
+ ****************************************************************************/
+
+TC_HANDLE sam_tc_allocate(int tc, int frequency)
+{
+ struct sam_tc_dev_s *priv;
+ int ret;
+ uint32_t divisor;
+ uint32_t ctrla;
+ uint32_t regval;
+ irqstate_t flags;
+
+ /* Initialize the timer/counter data (if necessary) and get exclusive
+ * access to the requested tc.
+ */
+
+ tmrinfo("tc=%d frequency=%d\n", tc, frequency);
+
+ priv = sam_tc_initialize(tc);
+ if (priv)
+ {
+ /* The pre-calculate values to use when we start the timer */
+
+ ret = sam_tc_divisor(priv, frequency, &divisor, &ctrla);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_tc_divisor failed: %d\n", ret);
+ return NULL;
+ }
+
+ tmrinfo("frequency=%lu, divisor=%lu, ctrla=0x%08lx\n",
+ (unsigned long)frequency, (unsigned long)divisor,
+ (unsigned long)ctrla);
+
+ /* Perform one-time TC initialization */
+
+ flags = enter_critical_section();
+
+ /* Attach Interrupt Handler */
+
+ ret = irq_attach(priv->attr->irq, tc_interrupt, priv);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: TC%d failed to attach irq %d\n",
+ tc, priv->attr->irq);
+ leave_critical_section(flags);
+ return NULL;
+ }
+
+ tmrinfo("TC%d attached irq %d\n", tc, priv->attr->irq);
+
+ /* Initialize the TC driver structure */
+
+ priv->flags = 0;
+ (void)nxsem_init(&priv->exclsem, 0, 1);
+
+ /* Enable clocking to the TC module in PCHCTRL */
+
+ tc_bridge_enable(priv->attr->tc);
+ tc_bridge_enable(priv->attr->tc +1); /* Slave TC in 32 bits mode */
+
+ /* Configure the GCLKs for the TC module */
+
+ tc_coreclk_configure(priv->attr->tc, priv->attr->coregen, false);
+
+ /* Check if module is enabled */
+
+ regval = getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ if (regval & TC_CTRLA_ENABLE)
+ {
+ tmrerr("ERROR: Cannot initialize TC! It's already initialized!\n");
+ leave_critical_section(flags);
+ return NULL;
+ }
+
+ /* Check if reset is in progress */
+
+ regval = getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ if (regval & TC_CTRLA_SWRST)
+ {
+ tmrerr("ERROR: Module is in RESET process!\n");
+ leave_critical_section(flags);
+ return NULL;
+ }
+
+ /* see 48.7.1 | TC_CTRLA_PRESCSYNC_PRESC */
+
+ putreg32(ctrla | TC_CTRLA_MODE_COUNT32,
+ priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ tc_wait_synchronization(priv);
+
+ /* Enable TC interrupts at the NVIC */
+
+ up_enable_irq(priv->attr->irq);
+ tmrinfo("enable TC%d irq=%d\n", tc, priv->attr->irq);
+
+ /* Get exclusive access to the timer/count data structure */
+
+ tc_takesem(priv);
+
+ /* Is it available? */
+
+ if (priv->inuse)
+ {
+ /* No.. return a failure */
+
+ tmrerr("ERROR: TC%d is in-use\n", priv->attr->tc);
+ tc_givesem(priv);
+ leave_critical_section(flags);
+ return NULL;
+ }
+
+ /* Mark the TC "inuse" */
+
+ priv->inuse = true;
+
+ /* Now the channel is initialized */
+
+ priv->initialized = true;
+
+ leave_critical_section(flags);
+ tc_givesem(priv);
+ }
+
+ /* Return an opaque reference to the tc */
+
+ tmrinfo("Returning 0x%p\n", priv);
+ return (TC_HANDLE)priv;
+}
+
+/****************************************************************************
+ * Name: sam_tc_free
+ *
+ * Description:
+ * Release the handle previously allocated by sam_tc_allocate().
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_free(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+
+ tmrinfo("Freeing %p inuse=%d\n", priv, priv->inuse);
+ DEBUGASSERT(priv && priv->inuse);
+
+ /* Make sure that interrupts are detached and disabled and that the channel
+ * is stopped and disabled.
+ */
+
+ sam_tc_attach(handle, NULL, NULL, 0);
+ sam_tc_stop(handle);
+
+ /* Mark the channel as available */
+
+ priv->inuse = false;
+}
+
+/****************************************************************************
+ * Name: sam_tc_start
+ *
+ * Description:
+ * Reset and Start the TC Channel. Enables the timer clock and performs a
+ * software reset to start the counting.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void sam_tc_start(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+ uint32_t regval;
+
+ tmrinfo("Starting TC%d inuse=%d COUNT=%d\n",
+ priv->attr->tc, priv->inuse, sam_tc_getcounter(priv));
+ DEBUGASSERT(priv && priv->inuse);
+
+ putreg32(0, priv->attr->base + SAM_TC_COUNT_OFFSET);
+
+ /* Clear any pending interrupts on this channel */
+
+ putreg8(TC_INTFLAG_ALL, priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+
+ /* Then enable the timer */
+
+ regval = getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ regval |= TC_CTRLA_ENABLE;
+ putreg32(regval, priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ tc_wait_synchronization(priv);
+}
+
+/****************************************************************************
+ * Name: sam_tc_stop
+ *
+ * Description:
+ * Stop TC Channel. Disables the timer clock, stopping the counting.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void sam_tc_stop(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+ uint32_t regval;
+
+ tmrinfo("Stopping TC%d inuse=%d\n", priv->attr->tc, priv->inuse);
+ DEBUGASSERT(priv && priv->inuse);
+
+ regval = getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ regval &= ~TC_CTRLA_ENABLE;
+ putreg32(regval, priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ tc_wait_synchronization(priv);
+}
+
+/****************************************************************************
+ * Name: sam_tc_attach
+ *
+ * Description:
+ * Attach or detach an interrupt handler to the timer interrupt. The
+ * interrupt is detached if the handler argument is NULL.
+ *
+ * Input Parameters:
+ * handle The handle that represents the timer state
+ * handler The interrupt handler that will be invoked when the interrupt
+ * condition occurs
+ * arg An opaque argument that will be provided when the interrupt
+ * handler callback is executed.
+ * mask The value of the timer interrupt mask register that defines
+ * which interrupts should be disabled.
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+tc_handler_t sam_tc_attach(TC_HANDLE handle, tc_handler_t handler,
+ void *arg, uint32_t mask)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+ tc_handler_t oldhandler;
+ irqstate_t flags;
+
+ DEBUGASSERT(priv);
+
+ /* Remember the old interrupt handler and set the new handler */
+
+ flags = enter_critical_section();
+ oldhandler = priv->handler;
+ priv->handler = handler;
+
+ /* Don't enable interrupt if we are detaching no matter what the caller
+ * says.
+ */
+
+ if (!handler)
+ {
+ arg = NULL;
+ mask = 0;
+ }
+
+ priv->arg = arg;
+
+ /* Now enable interrupt as requested */
+
+ putreg8(TC_INTFLAG_ALL, priv->attr->base + SAM_TC_INTENCLR_OFFSET);
+ putreg8(mask, priv->attr->base + SAM_TC_INTENSET_OFFSET);
+ if (mask & TC_INTFLAG_MC0)
+ putreg8(TC_CTRLBSET_ONESHOT, priv->attr->base + SAM_TC_CTRLBSET_OFFSET);
+
+ leave_critical_section(flags);
+
+ return oldhandler;
+}
+
+/****************************************************************************
+ * Name: sam_tc_getpending
+ *
+ * Description:
+ * Return the current contents of the interrupt status register, clearing
+ * all pending interrupts.
+ *
+ * Input Parameters:
+ * handle The handle that represents the timer state
+ *
+ * Returned Value:
+ * The value of the channel interrupt status register.
+ *
+ ****************************************************************************/
+
+uint8_t sam_tc_getpending(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+ DEBUGASSERT(priv);
+ return getreg8(priv->attr->base + SAM_TC_INTFLAG_OFFSET);
+}
+
+/****************************************************************************
+ * Name: sam_tc_setregister
+ *
+ * Description:
+ * Set TC_REGA, TC_REGB, or TC_REGC register.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ * regid One of {TC_REGA, TC_REGB, or TC_REGC}
+ * regval Then value to set in the register
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_setregister(TC_HANDLE handle, int regid, uint32_t regval)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+
+ DEBUGASSERT(priv && regid < TC_NREGISTERS);
+
+ tmrinfo("TC%d: Set register CC%d to 0x%08lx\n",
+ priv->attr->tc, regid, (unsigned long)regval);
+
+ putreg32(regval, priv->attr->base + g_regoffset[regid]);
+}
+
+/****************************************************************************
+ * Name: sam_tc_getregister
+ *
+ * Description:
+ * Get the current value of the channel register.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ * regid One of {TC_REGA, TC_REGB, or TC_REGC}
+ *
+ * Returned Value:
+ * The value of the specified register.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_getregister(TC_HANDLE handle, int regid)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+
+ DEBUGASSERT(priv && regid < TC_NREGISTERS);
+ return getreg32(priv->attr->base + g_regoffset[regid]);
+}
+
+/****************************************************************************
+ * Name: sam_tc_getcounter
+ *
+ * Description:
+ * Return the current value of the timer counter register
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * The current value of the timer counter register for this channel.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_getcounter(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+
+ DEBUGASSERT(priv);
+ putreg8(TC_CTRLBSET_CMD_READSYNC,
+ priv->attr->base + SAM_TC_CTRLBSET_OFFSET);
+ return getreg32(priv->attr->base + SAM_TC_COUNT_OFFSET);
+}
+
+/****************************************************************************
+ * Name: sam_tc_infreq
+ *
+ * Description:
+ * Return the timer input frequency (Ftcin), that is, the MCK frequency
+ * divided down so that the timer/counter is driven within its maximum
+ * frequency.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The timer input frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_infreq(void)
+{
+ return BOARD_GCLK3_FREQUENCY;
+}
+
+/****************************************************************************
+ * Name: sam_tc_divfreq
+ *
+ * Description:
+ * Return the divided timer input frequency that is currently driving the
+ * the timer counter.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * The timer counter frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_divfreq(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+ uint32_t ftcin = priv->attr->srcfreq;
+ uint32_t regval;
+ int tcclks;
+
+ DEBUGASSERT(priv);
+
+ /* Get the SAM_TC_CTRLA_OFFSET register contents for this channel
+ * and extract the PRESCALER index.
+ */
+
+ regval = getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+ tcclks = (regval & TC_CTRLA_PRESCALER_MASK) >> TC_CTRLA_PRESCALER_SHIFT;
+
+ /* And use the TCCLKS index to calculate the timer counter frequency */
+
+ return sam_tc_divfreq_lookup(ftcin, tcclks);
+}
+
+/****************************************************************************
+ * Name: sam_tc_divisor
+ *
+ * Description:
+ * Finds the best MCK divisor given the timer frequency and MCK. The
+ * result is guaranteed to satisfy the following equation:
+ *
+ * (Ftcin / (div * 65536)) <= freq <= (Ftcin / dev)
+ *
+ * where:
+ * freq - the desired frequency
+ * Ftcin - The timer/counter input frequency
+ * div - With DIV being the highest possible value.
+ *
+ * Input Parameters:
+ * frequency Desired timer frequency.
+ * div Divisor value.
+ * tcclks TCCLKS field value for divisor.
+ *
+ * Returned Value:
+ * Zero (OK) if a proper divisor has been found, otherwise a negated
+ * errno value indicating the nature of the failure.
+ *
+ ****************************************************************************/
+
+int sam_tc_divisor(struct sam_tc_dev_s *tc, uint32_t frequency,
+ uint32_t *div, uint32_t *tcclks)
+{
+ uint32_t ftcin = tc->attr->srcfreq;
+ int ndx = 0;
+
+ tmrinfo("frequency=%d\n", frequency);
+
+ /* Satisfy lower bound. That is, the value of the divider such that:
+ *
+ * frequency >= (tc_input_frequency * 65536) / divider.
+ */
+
+ while (frequency < (sam_tc_divfreq_lookup(ftcin, ndx) >> 16))
+ {
+ if (++ndx > TC_NDIVIDERS)
+ {
+ /* If no divisor can be found, return -ERANGE */
+
+ tmrerr("ERROR: Lower bound search failed\n");
+ return -ERANGE;
+ }
+ }
+
+ /* Try to maximize DIV while still satisfying upper bound.
+ * That the value of the divider such that:
+ *
+ * frequency < tc_input_frequency / divider.
+ */
+
+ for (; ndx < (TC_NDIVIDERS - 1); ndx++)
+ {
+ if (frequency > sam_tc_divfreq_lookup(ftcin, ndx + 1))
+ {
+ break;
+ }
+ }
+
+ /* Return the divider value */
+
+ if (div)
+ {
+ uint32_t value = sam_tc_freqdiv_lookup(ftcin, ndx);
+ tmrinfo("return div=%lu\n", (unsigned long)value);
+ *div = value;
+ }
+
+ /* Return the PRESCALER selection */
+
+ if (tcclks)
+ {
+ tmrinfo("return tcclks=0x%08lx\n",
+ (unsigned long)TC_CTRLA_PRESCALER(ndx));
+ *tcclks = TC_CTRLA_PRESCALER(ndx);
+ }
+
+ return OK;
+}
+
+uint32_t sam_tc_getctrla(TC_HANDLE handle)
+{
+ struct sam_tc_dev_s *priv = (struct sam_tc_dev_s *)handle;
+
+ DEBUGASSERT(priv);
+ return getreg32(priv->attr->base + SAM_TC_CTRLA_OFFSET);
+}
+
+#endif /* CONFIG_SAMD5E5_TC */
diff --git a/arch/arm/src/samd5e5/sam_tc.h b/arch/arm/src/samd5e5/sam_tc.h
new file mode 100644
index 0000000..88a61f1
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_tc.h
@@ -0,0 +1,367 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_tc.h
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_SAMD5E5_SAM_TC_H
+#define __ARCH_ARM_SRC_SAMD5E5_SAM_TC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "sam_config.h"
+#include "sam_port.h"
+#include "sam_periphclks.h"
+#include "hardware/sam_tc.h"
+#include "hardware/sam_pinmap.h"
+#include "semaphore.h"
+
+#ifdef CONFIG_SAMD5E5_TC
+
+/* Register identifier used with sam_tc_setregister */
+
+#define TC_REGCC0 0
+#define TC_REGCC1 1
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* An opaque handle used to represent a timer channel */
+
+typedef void *TC_HANDLE;
+
+/* Timer interrupt callback. When a timer interrupt expires, the client will
+ * receive:
+ *
+ * tch - The handle that represents the timer state
+ * arg - An opaque argument provided when the interrupt was registered
+ * sr - The value of the timer interrupt status register at the time
+ * that the interrupt occurred.
+ */
+
+typedef void (*tc_handler_t)(TC_HANDLE tch, void *arg, uint32_t sr);
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+struct tc_attr_s
+{
+ uint8_t tc; /* Identifies the TC peripheral */
+ uint8_t irq; /* Tc IRQ number */
+ uint8_t coregen; /* Source GCLK generator */
+ port_pinset_t cc0; /* Pin configuration CC0 - Compare/Capture Channel */
+ port_pinset_t cc1; /* Pin configuration CC1 - Compare/Capture Channel */
+ uint32_t srcfreq; /* Source clock frequency */
+ uintptr_t base; /* Base address of Tc registers */
+};
+
+/* Setup TC -> Add the timer register settings here. */
+
+struct sam_tc_dev_s
+{
+ const struct tc_attr_s *attr; /* Invariant attributes of TC device */
+ uint32_t mode; /* TC mode */
+ uint32_t prescaler; /* TC prescaler */
+ uint32_t prescsync; /* TC prescsync */
+ uint8_t wave; /* TC wave mode */
+ uint16_t flags; /* Transfer flags */
+ uint32_t freq; /* TC freq */
+ uint32_t duty; /* TC duty cycle */
+
+ sem_t exclsem; /* Only one thread can access at a time */
+ sem_t waitsem; /* Wait for TC */
+
+ bool initialized; /* True: Timer data has been initialized */
+ bool inuse; /* True: channel is in use */
+ tc_handler_t handler; /* Attached interrupt handler */
+ void *arg; /* Interrupt handler argument */
+};
+
+/****************************************************************************
+ * Name: sam_tc_configure
+ *
+ * Description:
+ * Configure the interrupt edge sensitivity in CONFIGn register of the
+ * tc. The interrupt will be enabled at the tc (but not at the NVIC).
+ *
+ * Input Parameters:
+ * eirq - Pin to be configured (0..15)
+ * pinset - Configuration of the pin
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+int sam_tc_configure(uint8_t tcrq, port_pinset_t pinset);
+
+/****************************************************************************
+ * Name: sam_tc_allocate
+ *
+ * Description:
+ * Configures a Timer Counter to operate in the given mode. The timer is
+ * stopped after configuration and must be restarted with sam_tc_start().
+ * All the interrupts of the timer are also disabled.
+ *
+ * Input Parameters:
+ * channel TC channel number (see TC_CHANx definitions)
+ * mode Operating mode (TC_CMR value).
+ *
+ * Returned Value:
+ * On success, a non-NULL handle value is returned. This handle may be
+ * used with subsequent timer/counter interfaces to manage the timer. A
+ * NULL handle value is returned on a failure.
+ *
+ ****************************************************************************/
+
+TC_HANDLE sam_tc_allocate(int channel, int frequency);
+
+/****************************************************************************
+ * Name: sam_tc_free
+ *
+ * Description:
+ * Release the handle previously allocated by sam_tc_allocate().
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_free(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_start
+ *
+ * Description:
+ * Reset and Start the TC Channel. Enables the timer clock and performs a
+ * software reset to start the counting.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void sam_tc_start(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_stop
+ *
+ * Description:
+ * Stop TC Channel. Disables the timer clock, stopping the counting.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+void sam_tc_stop(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_attach/sam_tc_detach
+ *
+ * Description:
+ * Attach or detach an interrupt handler to the timer interrupt. The
+ * interrupt is detached if the handler argument is NULL.
+ *
+ * Input Parameters:
+ * handle The handle that represents the timer state
+ * handler The interrupt handler that will be invoked when the interrupt
+ * condition occurs
+ * arg An opaque argument that will be provided when the interrupt
+ * handler callback is executed. Ignored if handler is NULL.
+ * mask The value of the timer interrupt mask register that defines
+ * which interrupts should be disabled. Ignored if handler is
+ * NULL.
+ *
+ * Returned Value:
+ * The address of the previous handler, if any.
+ *
+ ****************************************************************************/
+
+tc_handler_t sam_tc_attach(TC_HANDLE handle, tc_handler_t handler,
+ void *arg, uint32_t mask);
+
+#define sam_tc_detach(h) sam_tc_attach(h, NULL, NULL, 0)
+
+/****************************************************************************
+ * Name: sam_tc_getpending
+ *
+ * Description:
+ * Return the current contents of the interrutp status register, clearing
+ * all pending interrupts.
+ *
+ * Input Parameters:
+ * handle The handle that represents the timer state
+ *
+ * Returned Value:
+ * The value of the channel interrupt status register.
+ *
+ ****************************************************************************/
+
+uint8_t sam_tc_getpending(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_setregister
+ *
+ * Description:
+ * Set TC_REGA, TC_REGB, or TC_REGC register.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ * regid One of {TC_REGA, TC_REGB, or TC_REGC}
+ * regval Then value to set in the register
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void sam_tc_setregister(TC_HANDLE handle, int regid, uint32_t regval);
+
+/****************************************************************************
+ * Name: sam_tc_getregister
+ *
+ * Description:
+ * Get the current value of the TC_REGA, TC_REGB, or TC_REGC register.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ * regid One of {TC_REGA, TC_REGB, or TC_REGC}
+ *
+ * Returned Value:
+ * The value of the specified register.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_getregister(TC_HANDLE handle, int regid);
+
+/****************************************************************************
+ * Name: sam_tc_getcounter
+ *
+ * Description:
+ * Return the current value of the timer counter register
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * The current value of the timer counter register for this channel.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_getcounter(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_infreq
+ *
+ * Description:
+ * Return the timer input frequency, that is, the MCK frequency divided
+ * down so that the timer/counter is driven within its maximum frequency.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The timer input frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_infreq(void);
+
+/****************************************************************************
+ * Name: sam_tc_divfreq
+ *
+ * Description:
+ * Return the divided timer input frequency that is currently driving the
+ * the timer counter.
+ *
+ * Input Parameters:
+ * handle Channel handle previously allocated by sam_tc_allocate()
+ *
+ * Returned Value:
+ * The timer counter frequency.
+ *
+ ****************************************************************************/
+
+uint32_t sam_tc_divfreq(TC_HANDLE handle);
+
+/****************************************************************************
+ * Name: sam_tc_divisor
+ *
+ * Description:
+ * Finds the best MCK divisor given the timer frequency and MCK. The
+ * result is guaranteed to satisfy the following equation:
+ *
+ * (Ftcin / (div * 65536)) <= freq <= (Ftcin / div)
+ *
+ * where:
+ * freq - the desired frequency
+ * Ftcin - The timer/counter input frequency
+ * div - With DIV being the highest possible value.
+ *
+ * Input Parameters:
+ * frequency Desired timer frequency.
+ * div Divisor value.
+ * tcclks TCCLKS field value for divisor.
+ *
+ * Returned Value:
+ * Zero (OK) if a proper divisor has been found, otherwise a negated errno
+ * value indicating the nature of the failure.
+ *
+ ****************************************************************************/
+
+int sam_tc_divisor(struct sam_tc_dev_s *tc, uint32_t frequency,
+ uint32_t *div, uint32_t *tcclks);
+
+uint32_t sam_tc_getctrla(TC_HANDLE handle);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+#endif /* CONFIG_SAMD5E5_TC */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_SAM_TC_H */
\ No newline at end of file
diff --git a/arch/arm/src/samd5e5/sam_tickless.c b/arch/arm/src/samd5e5/sam_tickless.c
new file mode 100644
index 0000000..ed4c2aa
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_tickless.c
@@ -0,0 +1,409 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_tickless.c
+ *
+ * Copyright 2020 Falker Automacao Agricola LTDA.
+ * Author: Leomar Mateus Radke <le...@falker.com.br>
+ * Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Tickless OS Support.
+ *
+ * When CONFIG_SCHED_TICKLESS is enabled, all support for timer interrupts
+ * is suppressed and the platform specific code is expected to provide the
+ * following custom functions.
+ *
+ * void arm_timer_initialize(void): Initializes the timer facilities.
+ * Calledearly in the initialization sequence (by up_intialize()).
+ * int up_timer_gettime(FAR struct timespec *ts): Returns the current
+ * time from the platform specific time source.
+ * int up_timer_cancel(void): Cancels the interval timer.
+ * int up_timer_start(FAR const struct timespec *ts): Start (or re-starts)
+ * the interval timer.
+ *
+ * The RTOS will provide the following interfaces for use by the platform-
+ * specific interval timer implementation:
+ *
+ * void nxsched_timer_expiration(void): Called by the platform-specific
+ * logic when the interval timer expires.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * SAMD5E5 Timer Usage
+ *
+ * This current implementation uses two timers: A one-shot timer to provide
+ * the timed events and a free running timer to provide the current time.
+ * Since timers are a limited resource, that could be an issue on some
+ * systems.
+ *
+ * We could do the job with a single timer if we were to keep the single
+ * timer in a free-running at all times. The SAMD5E5 timer/counters have
+ * 32-bit counters with the capability to generate a compare interrupt when
+ * the timer matches a compare value but also to continue counting without
+ * stopping (giving another, different interrupt when the timer rolls over
+ * from 0xffffffff to zero). So we could potentially just set the compare
+ * at the number of ticks you want PLUS the current value of timer. Then
+ * you could have both with a single timer: An interval timer and a free-
+ * running counter with the same timer!
+ *
+ * Patches are welcome!
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "arm_arch.h"
+
+#include <nuttx/arch.h>
+
+#include "sam_oneshot.h"
+#include "sam_freerun.h"
+
+#ifdef CONFIG_SCHED_TICKLESS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_SAMD5E5_HAVE_TC
+# error Timer/counters must be selected for the Tickless OS option
+#endif
+
+#ifndef CONFIG_SAMD5E5_ONESHOT
+# error CONFIG_SAMD5E5_ONESHOT must be selected for the Tickless OS option
+#endif
+
+#ifndef CONFIG_SAMD5E5_FREERUN
+# error CONFIG_SAMD5E5_FREERUN must be selected for the Tickless OS option
+#endif
+
+#ifndef CONFIG_SAMD5E5_TICKLESS_FREERUN
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN must be selected for the Tickless OS option
+#endif
+
+#ifndef CONFIG_SAMD5E5_TICKLESS_ONESHOT
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT must be selected for the Tickless OS option
+#endif
+
+#if CONFIG_SAMD5E5_TICKLESS_ONESHOT == 0 && !defined(CONFIG_SAMD5E5_TC0)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 0 && CONFIG_SAMD5E5_TC0 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 1 && !defined(CONFIG_SAMD5E5_TC1)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 1 && CONFIG_SAMD5E5_TC1 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 2 && !defined(CONFIG_SAMD5E5_TC2)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 2 && CONFIG_SAMD5E5_TC2 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 3 && !defined(CONFIG_SAMD5E5_TC3)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 3 && CONFIG_SAMD5E5_TC3 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 4 && !defined(CONFIG_SAMD5E5_TC4)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 4 && CONFIG_SAMD5E5_TC4 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 5 && !defined(CONFIG_SAMD5E5_TC5)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 5 && CONFIG_SAMD5E5_TC5 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 6 && !defined(CONFIG_SAMD5E5_TC6)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 6 && CONFIG_SAMD5E5_TC6 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_ONESHOT == 7 && !defined(CONFIG_SAMD5E5_TC7)
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT == 7 && CONFIG_SAMD5E5_TC7 not selected
+#endif
+
+#if CONFIG_SAMD5E5_TICKLESS_ONESHOT < 0 || CONFIG_SAMD5E5_TICKLESS_ONESHOT > 7
+# error CONFIG_SAMD5E5_TICKLESS_ONESHOT is not valid
+#endif
+
+#if CONFIG_SAMD5E5_TICKLESS_FREERUN == 0 && !defined(CONFIG_SAMD5E5_TC0)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 0 && CONFIG_SAMD5E5_TC0 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 1 && !defined(CONFIG_SAMD5E5_TC1)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 1 && CONFIG_SAMD5E5_TC1 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 2 && !defined(CONFIG_SAMD5E5_TC2)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 2 && CONFIG_SAMD5E5_TC2 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 3 && !defined(CONFIG_SAMD5E5_TC3)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 3 && CONFIG_SAMD5E5_TC3 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 4 && !defined(CONFIG_SAMD5E5_TC4)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 4 && CONFIG_SAMD5E5_TC4 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 5 && !defined(CONFIG_SAMD5E5_TC5)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 5 && CONFIG_SAMD5E5_TC5 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 6 && !defined(CONFIG_SAMD5E5_TC6)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 6 && CONFIG_SAMD5E5_TC6 not selected
+#elif CONFIG_SAMD5E5_TICKLESS_FREERUN == 7 && !defined(CONFIG_SAMD5E5_TC7)
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN == 7 && CONFIG_SAMD5E5_TC7 not selected
+#endif
+
+#if CONFIG_SAMD5E5_TICKLESS_FREERUN < 0 || CONFIG_SAMD5E5_TICKLESS_FREERUN > 7
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN is not valid
+#endif
+
+#if CONFIG_SAMD5E5_TICKLESS_FREERUN == CONFIG_SAMD5E5_TICKLESS_ONESHOT
+# error CONFIG_SAMD5E5_TICKLESS_FREERUN is the same as CONFIG_SAMD5E5_TICKLESS_ONESHOT
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct sam_tickless_s
+{
+ struct sam_oneshot_s oneshot;
+ struct sam_freerun_s freerun;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct sam_tickless_s g_tickless;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_oneshot_handler
+ *
+ * Description:
+ * Called when the one shot timer expires
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called early in the initialization sequence before any special
+ * concurrency protections are required.
+ *
+ ****************************************************************************/
+
+static void sam_oneshot_handler(void *arg)
+{
+ tmrinfo("Expired...\n");
+ nxsched_timer_expiration();
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_timer_initialize
+ *
+ * Description:
+ * Initializes all platform-specific timer facilities. This function is
+ * called early in the initialization sequence by up_intialize().
+ * On return, the current up-time should be available from
+ * up_timer_gettime() and the interval timer is ready for use (but not
+ * actively timing.
+ *
+ * Provided by platform-specific code and called from the architecture-
+ * specific logic.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called early in the initialization sequence before any special
+ * concurrency protections are required.
+ *
+ ****************************************************************************/
+
+void up_timer_initialize(void)
+{
+#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
+ uint64_t max_delay;
+#endif
+ int ret;
+
+ /* Initialize the one-shot timer */
+
+ ret = sam_oneshot_initialize(&g_tickless.oneshot,
+ CONFIG_SAMD5E5_TICKLESS_ONESHOT,
+ CONFIG_USEC_PER_TICK);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_oneshot_initialize failed\n");
+ DEBUGPANIC();
+ }
+
+ DEBUGASSERT(ONESHOT_INITIALIZED(&g_tickless.oneshot));
+
+#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
+ /* Get the maximum delay of the one-shot timer in microseconds */
+
+ ret = sam_oneshot_max_delay(&g_tickless.oneshot, &max_delay);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_oneshot_max_delay failed\n");
+ DEBUGPANIC();
+ }
+
+ /* Convert this to configured clock ticks for use by the OS timer logic */
+
+ max_delay /= CONFIG_USEC_PER_TICK;
+ if (max_delay > (uint64_t)UINT32_MAX)
+ {
+ g_oneshot_maxticks = UINT32_MAX;
+ }
+ else
+ {
+ g_oneshot_maxticks = (uint32_t)max_delay;
+ }
+#endif
+
+ /* Initialize the free-running timer */
+
+ ret = sam_freerun_initialize(&g_tickless.freerun,
+ CONFIG_SAMD5E5_TICKLESS_FREERUN,
+ CONFIG_USEC_PER_TICK);
+ if (ret < 0)
+ {
+ tmrerr("ERROR: sam_freerun_initialize failed\n");
+ DEBUGPANIC();
+ }
+
+ DEBUGASSERT(FREERUN_INITIALIZED(&g_tickless.freerun));
+}
+
+/****************************************************************************
+ * Name: up_timer_gettime
+ *
+ * Description:
+ * Return the elapsed time since power-up (or, more correctly, since
+ * arm_timer_initialize() was called). This function is functionally
+ * equivalent to:
+ *
+ * int clock_gettime(clockid_t clockid, FAR struct timespec *ts);
+ *
+ * when clockid is CLOCK_MONOTONIC.
+ *
+ * This function provides the basis for reporting the current time and
+ * also is used to eliminate error build-up from small errors in interval
+ * time calculations.
+ *
+ * Provided by platform-specific code and called from the RTOS base code.
+ *
+ * Input Parameters:
+ * ts - Provides the location in which to return the up-time.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned on
+ * any failure.
+ *
+ * Assumptions:
+ * Called from the normal tasking context. The implementation must
+ * provide whatever mutual exclusion is necessary for correct operation.
+ * This can include disabling interrupts in order to assure atomic register
+ * operations.
+ *
+ ****************************************************************************/
+
+int up_timer_gettime(FAR struct timespec *ts)
+{
+ return FREERUN_INITIALIZED(&g_tickless.freerun) ?
+ sam_freerun_counter(&g_tickless.freerun, ts) :
+ -EAGAIN;
+}
+
+/****************************************************************************
+ * Name: up_timer_cancel
+ *
+ * Description:
+ * Cancel the interval timer and return the time remaining on the timer.
+ * These two steps need to be as nearly atomic as possible.
+ * nxsched_timer_expiration() will not be called unless the timer is
+ * restarted with up_timer_start().
+ *
+ * If, as a race condition, the timer has already expired when this
+ * function is called, then that pending interrupt must be cleared so
+ * that up_timer_start() and the remaining time of zero should be
+ * returned.
+ *
+ * NOTE: This function may execute at a high rate with no timer running (as
+ * when pre-emption is enabled and disabled).
+ *
+ * Provided by platform-specific code and called from the RTOS base code.
+ *
+ * Input Parameters:
+ * ts - Location to return the remaining time. Zero should be returned
+ * if the timer is not active. ts may be zero in which case the
+ * time remaining is not returned.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success. A call to up_timer_cancel() when
+ * the timer is not active should also return success; a negated errno
+ * value is returned on any failure.
+ *
+ * Assumptions:
+ * May be called from interrupt level handling or from the normal tasking
+ * level. Interrupts may need to be disabled internally to assure
+ * non-reentrancy.
+ *
+ ****************************************************************************/
+
+int up_timer_cancel(FAR struct timespec *ts)
+{
+ return ONESHOT_INITIALIZED(&g_tickless.oneshot) &&
+ FREERUN_INITIALIZED(&g_tickless.freerun) ?
+ sam_oneshot_cancel(&g_tickless.oneshot, &g_tickless.freerun, ts) :
+ -EAGAIN;
+}
+
+/****************************************************************************
+ * Name: up_timer_start
+ *
+ * Description:
+ * Start the interval timer. nxsched_timer_expiration() will be
+ * called at the completion of the timeout (unless up_timer_cancel
+ * is called to stop the timing.
+ *
+ * Provided by platform-specific code and called from the RTOS base code.
+ *
+ * Input Parameters:
+ * ts - Provides the time interval until nxsched_timer_expiration() is
+ * called.
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned on
+ * any failure.
+ *
+ * Assumptions:
+ * May be called from interrupt level handling or from the normal tasking
+ * level. Interrupts may need to be disabled internally to assure
+ * non-reentrancy.
+ *
+ ****************************************************************************/
+
+int up_timer_start(FAR const struct timespec *ts)
+{
+ tmrinfo("ts=(%lu, %lu)\n", (unsigned long)ts->tv_sec,
+ (unsigned long)ts->tv_nsec);
+ return ONESHOT_INITIALIZED(&g_tickless.oneshot) ?
+ sam_oneshot_start(&g_tickless.oneshot, &g_tickless.freerun,
+ sam_oneshot_handler, NULL, ts) :
+ -EAGAIN;
+}
+#endif /* CONFIG_SCHED_TICKLESS */
diff --git a/arch/arm/src/samd5e5/sam_timerisr.c b/arch/arm/src/samd5e5/sam_timerisr.c
index 51413d7..2bd4cf3 100644
--- a/arch/arm/src/samd5e5/sam_timerisr.c
+++ b/arch/arm/src/samd5e5/sam_timerisr.c
@@ -103,7 +103,7 @@ static int sam_timerisr(int irq, uint32_t *regs, void *arg)
****************************************************************************/
/****************************************************************************
- * Function: up_timer_initialize
+ * Function: arm_timer_initialize
*
* Description:
* This function is called during start-up to initialize the timer
@@ -129,7 +129,7 @@ void up_timer_initialize(void)
/* Attach the timer interrupt vector */
- irq_attach(SAM_IRQ_SYSTICK, (xcpt_t)sam_timerisr, NULL);
+ (void)irq_attach(SAM_IRQ_SYSTICK, (xcpt_t)sam_timerisr, NULL);
/* Enable SysTick interrupts using the processor clock source. */
diff --git a/boards/arm/samd5e5/metro-m4/include/board.h b/boards/arm/samd5e5/metro-m4/include/board.h
index 7bde7d1..0b9eec7 100644
--- a/boards/arm/samd5e5/metro-m4/include/board.h
+++ b/boards/arm/samd5e5/metro-m4/include/board.h
@@ -480,6 +480,21 @@
#define BOARD_SERCOM5_SLOW_GCLKGEN 3
#define BOARD_SERCOM5_FREQUENCY BOARD_GCLK1_FREQUENCY
+/* Tickless */
+
+#define BOARD_TC0_PINMAP_CC0 0 /* CC0: (not used) */
+#define BOARD_TC0_PINMAP_CC1 0 /* CC1: (not used) */
+#define BOARD_TC0_GCLKGEN 3
+#define BOARD_TC0_FREQUENCY BOARD_GCLK3_FREQUENCY
+#define BOARD_TC2_PINMAP_CC0 0 /* CC0: (not used) */
+#define BOARD_TC2_PINMAP_CC1 0 /* CC1: (not used) */
+#define BOARD_TC2_GCLKGEN 3
+#define BOARD_TC2_FREQUENCY BOARD_GCLK3_FREQUENCY
+#define BOARD_TC4_PINMAP_CC0 0 /* CC0: (not used) */
+#define BOARD_TC4_PINMAP_CC1 0 /* CC1: (not used) */
+#define BOARD_TC4_GCLKGEN 3
+#define BOARD_TC4_FREQUENCY BOARD_GCLK3_FREQUENCY
+
/* USB */
#define BOARD_USB_GCLKGEN 1 /* GCLK1, 48MHz */