From f5912b5cbad3b7a731231d778ccc101da6f3c353 Mon Sep 17 00:00:00 2001 From: leomarradke Date: Fri, 14 Aug 2020 15:23:40 -0300 Subject: [PATCH] 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 --- 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(-) create mode 100644 arch/arm/src/samd5e5/hardware/sam_tc.h create mode 100644 arch/arm/src/samd5e5/sam_freerun.c create mode 100644 arch/arm/src/samd5e5/sam_freerun.h create mode 100644 arch/arm/src/samd5e5/sam_oneshot.c create mode 100644 arch/arm/src/samd5e5/sam_oneshot.h create mode 100644 arch/arm/src/samd5e5/sam_oneshot_lowerhalf.c create mode 100644 arch/arm/src/samd5e5/sam_tc.c create mode 100644 arch/arm/src/samd5e5/sam_tc.h create mode 100644 arch/arm/src/samd5e5/sam_tickless.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index b55e225e95..cb53dd7abc 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 85ae19b63e..f2c45b18ba 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 52fcbda0c4..026293dcb7 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 0000000000..46121e25d7 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#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 c7955270c9..a27a61f89c 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 bdd0049d4a..3a2d177fcc 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 @@ -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 6b32abd40b..be64b7e5f1 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 0000000000..91d68e96ce --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 0000000000..0a66d06f87 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include + +#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 0000000000..6c0f946a7c --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 0000000000..6be2145598 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include + +#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 0000000000..b1bda1b312 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 89af653813..6a34ecfcf7 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 0000000000..bbd0edcb63 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 + +#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 0000000000..88a61f15aa --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include + +#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 0000000000..ed4c2aad55 --- /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 + * Author: Ricardo Wartchow + * + * 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 + +#include +#include +#include + +#include "arm_arch.h" + +#include + +#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 51413d7a96..2bd4cf3a53 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 7bde7d1af2..0b9eec7484 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 */