You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2021/04/09 12:28:54 UTC

[GitHub] [incubator-nuttx] davids5 commented on a change in pull request #3488: stm32h7: Adds tickless support.

davids5 commented on a change in pull request #3488:
URL: https://github.com/apache/incubator-nuttx/pull/3488#discussion_r610572321



##########
File path: arch/arm/src/stm32h7/stm32_tickless.c
##########
@@ -0,0 +1,1059 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_tickless.c
+ *
+ * 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 up_timer_initialize(void): Initializes the timer facilities.
+ *     Called early in the initialization sequence (by up_initialize()).
+ *   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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * STM32 Timer Usage
+ *
+ * This implementation uses one timer:  A free running timer to provide
+ * the current time and a capture/compare channel for timed-events.
+ *
+ * BASIC timers that are found on some STM32 chips (timers 6 and 7) are
+ * incompatible with this implementation because they don't have capture/
+ * compare channels.  There are two interrupts generated from our timer,
+ * the overflow interrupt which drives the timing handler and the capture/
+ * compare interrupt which drives the interval handler.  There are some low
+ * level timer control functions implemented here because the API of
+ * stm32_tim.c does not provide adequate control over capture/compare
+ * interrupts.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/arch_timer.h>
+#include <debug.h>
+#include <arch/board/board.h>
+
+#include "arm_arch.h"
+
+#include "stm32_tim.h"
+#include "stm32_dbgmcu.h"
+
+#include "systick.h"
+
+#ifdef CONFIG_SCHED_TICKLESS
+
+/* Only TIM2 and TIM5 timers may be 32-bits in width */
+
+#undef HAVE_32BIT_TICKLESS
+
+#if (CONFIG_STM32H7_TICKLESS_TIMER == 2) || \
+    (CONFIG_STM32H7_TICKLESS_TIMER == 5)
+ #define HAVE_32BIT_TICKLESS 1
+#endif
+
+#if CONFIG_STM32H7_TICKLESS_CHANNEL == 1
+#define DIER_CAPT_IE          ATIM_DIER_CC1IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 2
+#define DIER_CAPT_IE          ATIM_DIER_CC2IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 3
+#define DIER_CAPT_IE          ATIM_DIER_CC3IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 4
+#define DIER_CAPT_IE          ATIM_DIER_CC4IE
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_tickless_s
+{
+  uint8_t timer;                   /* The timer/counter in use */
+  uint8_t channel;                 /* The timer channel to use for intervals */
+  FAR struct stm32_tim_dev_s *tch; /* Handle returned by stm32_tim_init() */
+  uint32_t frequency;
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+  uint64_t counter_mask;
+#else
+  uint32_t overflow;               /* Timer counter overflow */
+#endif
+  volatile bool pending;           /* True: pending task */
+  uint32_t period;                 /* Interval period */
+  uint32_t base;
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  uint64_t last_alrm;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct stm32_tickless_s g_tickless;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_getreg16
+ *
+ * Description:
+ *   Get a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint16_t stm32_getreg16(uint8_t offset)
+{
+  return getreg16(g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Put a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_putreg16(uint8_t offset, uint16_t value)
+{
+  putreg16(value, g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_modifyreg16
+ *
+ * Description:
+ *   Modify a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits,
+                                     uint16_t setbits)
+{
+  modifyreg16(g_tickless.base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_enableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_enableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 0, 1 << channel);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_disableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_disableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 1 << channel, 0);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_ackint
+ ****************************************************************************/
+
+static inline void stm32_tickless_ackint(int channel)
+{
+  stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel));
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_getint
+ ****************************************************************************/
+
+static inline uint16_t stm32_tickless_getint(void)
+{
+  return stm32_getreg16(STM32_BTIM_SR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_setchannel
+ ****************************************************************************/
+
+static int stm32_tickless_setchannel(uint8_t channel)
+{
+  uint16_t ccmr_orig   = 0;
+  uint16_t ccmr_val    = 0;
+  uint16_t ccmr_mask   = 0xff;
+  uint16_t ccer_val    = stm32_getreg16(STM32_GTIM_CCER_OFFSET);
+  uint8_t  ccmr_offset = STM32_GTIM_CCMR1_OFFSET;
+
+  /* Further we use range as 0..3; if channel=0 it will also overflow here */
+
+  if (--channel > 4)
+    {
+      return -EINVAL;
+    }
+
+  /* Assume that channel is disabled and polarity is active high */
+
+  ccer_val &= ~(3 << (channel << 2));
+
+  /* This function is not supported on basic timers. To enable or
+   * disable it, simply set its clock to valid frequency or zero.
+   */
+
+  if (g_tickless.base == STM32_TIM6_BASE ||
+      g_tickless.base == STM32_TIM7_BASE)
+    {
+      return -EINVAL;
+    }
+
+  /* Frozen mode because we don't want to change the GPIO, preload register
+   * disabled.
+   */
+
+  ccmr_val = (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
+
+  /* Set polarity */
+
+  ccer_val |= ATIM_CCER_CC1P << (channel << 2);
+
+  /* Define its position (shift) and get register offset */
+
+  if ((channel & 1) != 0)
+    {
+      ccmr_val  <<= 8;
+      ccmr_mask <<= 8;
+    }
+
+  if (channel > 1)
+    {
+      ccmr_offset = STM32_GTIM_CCMR2_OFFSET;
+    }
+
+  ccmr_orig  = stm32_getreg16(ccmr_offset);
+  ccmr_orig &= ~ccmr_mask;
+  ccmr_orig |= ccmr_val;
+  stm32_putreg16(ccmr_offset, ccmr_orig);
+  stm32_putreg16(STM32_GTIM_CCER_OFFSET, ccer_val);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_interval_handler
+ *
+ * Description:
+ *   Called when the timer counter matches the compare register
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called early in the initialization sequence before any special
+ *   concurrency protections are required.
+ *
+ ****************************************************************************/
+
+static void stm32_interval_handler(void)
+{
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  struct timespec tv;
+#endif
+  tmrinfo("Expired...\n");
+
+  /* Disable the compare interrupt now. */
+
+  stm32_tickless_disableint(g_tickless.channel);
+  stm32_tickless_ackint(g_tickless.channel);
+
+  g_tickless.pending = false;
+
+#ifndef CONFIG_SCHED_TICKLESS_ALARM
+  nxsched_timer_expiration();
+#else
+  up_timer_gettime(&tv);
+  nxsched_alarm_expiration(&tv);
+#endif
+}
+
+/****************************************************************************
+ * Name: stm32_timing_handler
+ *
+ * Description:
+ *   Timer interrupt callback.  When the freerun timer counter overflows,
+ *   this interrupt will occur.  We will just increment an overflow count.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static void stm32_timing_handler(void)
+{
+  g_tickless.overflow++;
+
+  STM32_TIM_ACKINT(g_tickless.tch, 0);
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Name: stm32_tickless_handler
+ *
+ * Description:
+ *   Generic interrupt handler for this timer.  It checks the source of the
+ *   interrupt and fires the appropriate handler.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int stm32_tickless_handler(int irq, void *context, void *arg)
+{
+  int interrupt_flags = stm32_tickless_getint();
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+  if (interrupt_flags & ATIM_SR_UIF)
+    {
+      stm32_timing_handler();
+    }
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+  if (interrupt_flags & (1 << g_tickless.channel))
+    {
+      stm32_interval_handler();
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_get_counter
+ *
+ ****************************************************************************/
+
+static uint64_t stm32_get_counter(void)
+{
+  return ((uint64_t)g_tickless.overflow << 32) |
+         STM32_TIM_GETCOUNTER(g_tickless.tch);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_timer_initialize
+ *
+ * Description:
+ *   Initializes all platform-specific timer facilities.  This function is
+ *   called early in the initialization sequence by up_initialize().
+ *   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)
+{
+  switch (CONFIG_STM32H7_TICKLESS_TIMER)
+    {
+#ifdef CONFIG_STM32H7_TIM1
+      case 1:
+        g_tickless.base = STM32_TIM1_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM1STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM2
+      case 2:
+        g_tickless.base = STM32_TIM2_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM2STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM3
+      case 3:
+        g_tickless.base = STM32_TIM3_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM3STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM4
+      case 4:
+        g_tickless.base = STM32_TIM4_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM4STOP);
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM5
+      case 5:
+        g_tickless.base = STM32_TIM5_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM5STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM6

Review comment:
       Would a compile time error would be better?

##########
File path: arch/arm/src/stm32h7/stm32_tickless.c
##########
@@ -0,0 +1,1059 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_tickless.c
+ *
+ * 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 up_timer_initialize(void): Initializes the timer facilities.
+ *     Called early in the initialization sequence (by up_initialize()).
+ *   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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * STM32 Timer Usage
+ *
+ * This implementation uses one timer:  A free running timer to provide
+ * the current time and a capture/compare channel for timed-events.
+ *
+ * BASIC timers that are found on some STM32 chips (timers 6 and 7) are
+ * incompatible with this implementation because they don't have capture/
+ * compare channels.  There are two interrupts generated from our timer,
+ * the overflow interrupt which drives the timing handler and the capture/
+ * compare interrupt which drives the interval handler.  There are some low
+ * level timer control functions implemented here because the API of
+ * stm32_tim.c does not provide adequate control over capture/compare
+ * interrupts.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/arch_timer.h>
+#include <debug.h>
+#include <arch/board/board.h>
+
+#include "arm_arch.h"
+
+#include "stm32_tim.h"
+#include "stm32_dbgmcu.h"
+
+#include "systick.h"
+
+#ifdef CONFIG_SCHED_TICKLESS
+
+/* Only TIM2 and TIM5 timers may be 32-bits in width */
+
+#undef HAVE_32BIT_TICKLESS
+
+#if (CONFIG_STM32H7_TICKLESS_TIMER == 2) || \
+    (CONFIG_STM32H7_TICKLESS_TIMER == 5)
+ #define HAVE_32BIT_TICKLESS 1
+#endif
+
+#if CONFIG_STM32H7_TICKLESS_CHANNEL == 1
+#define DIER_CAPT_IE          ATIM_DIER_CC1IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 2
+#define DIER_CAPT_IE          ATIM_DIER_CC2IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 3
+#define DIER_CAPT_IE          ATIM_DIER_CC3IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 4
+#define DIER_CAPT_IE          ATIM_DIER_CC4IE
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_tickless_s
+{
+  uint8_t timer;                   /* The timer/counter in use */
+  uint8_t channel;                 /* The timer channel to use for intervals */
+  FAR struct stm32_tim_dev_s *tch; /* Handle returned by stm32_tim_init() */
+  uint32_t frequency;
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+  uint64_t counter_mask;
+#else
+  uint32_t overflow;               /* Timer counter overflow */
+#endif
+  volatile bool pending;           /* True: pending task */
+  uint32_t period;                 /* Interval period */
+  uint32_t base;
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  uint64_t last_alrm;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct stm32_tickless_s g_tickless;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_getreg16
+ *
+ * Description:
+ *   Get a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint16_t stm32_getreg16(uint8_t offset)
+{
+  return getreg16(g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Put a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_putreg16(uint8_t offset, uint16_t value)
+{
+  putreg16(value, g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_modifyreg16
+ *
+ * Description:
+ *   Modify a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits,
+                                     uint16_t setbits)
+{
+  modifyreg16(g_tickless.base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_enableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_enableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 0, 1 << channel);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_disableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_disableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 1 << channel, 0);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_ackint
+ ****************************************************************************/
+
+static inline void stm32_tickless_ackint(int channel)
+{
+  stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel));
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_getint
+ ****************************************************************************/
+
+static inline uint16_t stm32_tickless_getint(void)
+{
+  return stm32_getreg16(STM32_BTIM_SR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_setchannel
+ ****************************************************************************/
+
+static int stm32_tickless_setchannel(uint8_t channel)
+{
+  uint16_t ccmr_orig   = 0;
+  uint16_t ccmr_val    = 0;
+  uint16_t ccmr_mask   = 0xff;
+  uint16_t ccer_val    = stm32_getreg16(STM32_GTIM_CCER_OFFSET);
+  uint8_t  ccmr_offset = STM32_GTIM_CCMR1_OFFSET;
+
+  /* Further we use range as 0..3; if channel=0 it will also overflow here */
+
+  if (--channel > 4)
+    {
+      return -EINVAL;
+    }
+
+  /* Assume that channel is disabled and polarity is active high */
+
+  ccer_val &= ~(3 << (channel << 2));

Review comment:
       Can you tie this back to bit names and shifts from the resister definitions?
   I.E. Use something like (sadly use cap N)
   #define xxx__CC1En STM32_CCER_CC1E_MASK
   #define xxx_CC1Pn STM32_CCER_CC1P_MASK
   #define xxx_CC1NPn  STM32_CCER_CC1N1P_MASK
   #define xxx_CCN_SHIFT (STM32_CCER_CC2E_SHIFT-STM32_CCER_CC1E_SHIFT))
   
   then the code says what it is doing
   
   `ccer_val &= ~( (xxx_CC1NPn | xxx_CC1Pn)   << (channel << CCN_SHIFT));`
   

##########
File path: arch/arm/src/stm32h7/stm32_tickless.c
##########
@@ -0,0 +1,1059 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_tickless.c
+ *
+ * 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 up_timer_initialize(void): Initializes the timer facilities.
+ *     Called early in the initialization sequence (by up_initialize()).
+ *   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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * STM32 Timer Usage
+ *
+ * This implementation uses one timer:  A free running timer to provide
+ * the current time and a capture/compare channel for timed-events.
+ *
+ * BASIC timers that are found on some STM32 chips (timers 6 and 7) are
+ * incompatible with this implementation because they don't have capture/
+ * compare channels.  There are two interrupts generated from our timer,
+ * the overflow interrupt which drives the timing handler and the capture/
+ * compare interrupt which drives the interval handler.  There are some low
+ * level timer control functions implemented here because the API of
+ * stm32_tim.c does not provide adequate control over capture/compare
+ * interrupts.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/arch_timer.h>
+#include <debug.h>
+#include <arch/board/board.h>
+
+#include "arm_arch.h"
+
+#include "stm32_tim.h"
+#include "stm32_dbgmcu.h"
+
+#include "systick.h"
+
+#ifdef CONFIG_SCHED_TICKLESS
+
+/* Only TIM2 and TIM5 timers may be 32-bits in width */
+
+#undef HAVE_32BIT_TICKLESS
+
+#if (CONFIG_STM32H7_TICKLESS_TIMER == 2) || \
+    (CONFIG_STM32H7_TICKLESS_TIMER == 5)
+ #define HAVE_32BIT_TICKLESS 1
+#endif
+
+#if CONFIG_STM32H7_TICKLESS_CHANNEL == 1
+#define DIER_CAPT_IE          ATIM_DIER_CC1IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 2
+#define DIER_CAPT_IE          ATIM_DIER_CC2IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 3
+#define DIER_CAPT_IE          ATIM_DIER_CC3IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 4
+#define DIER_CAPT_IE          ATIM_DIER_CC4IE
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_tickless_s
+{
+  uint8_t timer;                   /* The timer/counter in use */
+  uint8_t channel;                 /* The timer channel to use for intervals */
+  FAR struct stm32_tim_dev_s *tch; /* Handle returned by stm32_tim_init() */
+  uint32_t frequency;
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+  uint64_t counter_mask;
+#else
+  uint32_t overflow;               /* Timer counter overflow */
+#endif
+  volatile bool pending;           /* True: pending task */
+  uint32_t period;                 /* Interval period */
+  uint32_t base;
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  uint64_t last_alrm;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct stm32_tickless_s g_tickless;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_getreg16
+ *
+ * Description:
+ *   Get a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint16_t stm32_getreg16(uint8_t offset)
+{
+  return getreg16(g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Put a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_putreg16(uint8_t offset, uint16_t value)
+{
+  putreg16(value, g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_modifyreg16
+ *
+ * Description:
+ *   Modify a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits,
+                                     uint16_t setbits)
+{
+  modifyreg16(g_tickless.base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_enableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_enableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 0, 1 << channel);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_disableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_disableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 1 << channel, 0);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_ackint
+ ****************************************************************************/
+
+static inline void stm32_tickless_ackint(int channel)
+{
+  stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel));
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_getint
+ ****************************************************************************/
+
+static inline uint16_t stm32_tickless_getint(void)
+{
+  return stm32_getreg16(STM32_BTIM_SR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_setchannel
+ ****************************************************************************/
+
+static int stm32_tickless_setchannel(uint8_t channel)
+{
+  uint16_t ccmr_orig   = 0;
+  uint16_t ccmr_val    = 0;
+  uint16_t ccmr_mask   = 0xff;
+  uint16_t ccer_val    = stm32_getreg16(STM32_GTIM_CCER_OFFSET);
+  uint8_t  ccmr_offset = STM32_GTIM_CCMR1_OFFSET;
+
+  /* Further we use range as 0..3; if channel=0 it will also overflow here */
+
+  if (--channel > 4)
+    {
+      return -EINVAL;
+    }
+
+  /* Assume that channel is disabled and polarity is active high */
+
+  ccer_val &= ~(3 << (channel << 2));
+
+  /* This function is not supported on basic timers. To enable or
+   * disable it, simply set its clock to valid frequency or zero.
+   */
+
+  if (g_tickless.base == STM32_TIM6_BASE ||
+      g_tickless.base == STM32_TIM7_BASE)
+    {
+      return -EINVAL;
+    }
+
+  /* Frozen mode because we don't want to change the GPIO, preload register
+   * disabled.
+   */
+
+  ccmr_val = (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
+
+  /* Set polarity */
+
+  ccer_val |= ATIM_CCER_CC1P << (channel << 2);
+
+  /* Define its position (shift) and get register offset */
+
+  if ((channel & 1) != 0)
+    {
+      ccmr_val  <<= 8;
+      ccmr_mask <<= 8;
+    }
+
+  if (channel > 1)
+    {
+      ccmr_offset = STM32_GTIM_CCMR2_OFFSET;
+    }
+
+  ccmr_orig  = stm32_getreg16(ccmr_offset);
+  ccmr_orig &= ~ccmr_mask;
+  ccmr_orig |= ccmr_val;
+  stm32_putreg16(ccmr_offset, ccmr_orig);
+  stm32_putreg16(STM32_GTIM_CCER_OFFSET, ccer_val);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_interval_handler
+ *
+ * Description:
+ *   Called when the timer counter matches the compare register
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called early in the initialization sequence before any special
+ *   concurrency protections are required.
+ *
+ ****************************************************************************/
+
+static void stm32_interval_handler(void)
+{
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  struct timespec tv;
+#endif
+  tmrinfo("Expired...\n");
+
+  /* Disable the compare interrupt now. */
+
+  stm32_tickless_disableint(g_tickless.channel);
+  stm32_tickless_ackint(g_tickless.channel);
+
+  g_tickless.pending = false;
+
+#ifndef CONFIG_SCHED_TICKLESS_ALARM
+  nxsched_timer_expiration();
+#else
+  up_timer_gettime(&tv);
+  nxsched_alarm_expiration(&tv);
+#endif
+}
+
+/****************************************************************************
+ * Name: stm32_timing_handler
+ *
+ * Description:
+ *   Timer interrupt callback.  When the freerun timer counter overflows,
+ *   this interrupt will occur.  We will just increment an overflow count.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static void stm32_timing_handler(void)
+{
+  g_tickless.overflow++;
+
+  STM32_TIM_ACKINT(g_tickless.tch, 0);
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Name: stm32_tickless_handler
+ *
+ * Description:
+ *   Generic interrupt handler for this timer.  It checks the source of the
+ *   interrupt and fires the appropriate handler.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int stm32_tickless_handler(int irq, void *context, void *arg)
+{
+  int interrupt_flags = stm32_tickless_getint();
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+  if (interrupt_flags & ATIM_SR_UIF)
+    {
+      stm32_timing_handler();
+    }
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+  if (interrupt_flags & (1 << g_tickless.channel))
+    {
+      stm32_interval_handler();
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_get_counter
+ *
+ ****************************************************************************/
+
+static uint64_t stm32_get_counter(void)
+{
+  return ((uint64_t)g_tickless.overflow << 32) |
+         STM32_TIM_GETCOUNTER(g_tickless.tch);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_timer_initialize
+ *
+ * Description:
+ *   Initializes all platform-specific timer facilities.  This function is
+ *   called early in the initialization sequence by up_initialize().
+ *   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)
+{
+  switch (CONFIG_STM32H7_TICKLESS_TIMER)
+    {
+#ifdef CONFIG_STM32H7_TIM1
+      case 1:
+        g_tickless.base = STM32_TIM1_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM1STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM2
+      case 2:
+        g_tickless.base = STM32_TIM2_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM2STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM3
+      case 3:
+        g_tickless.base = STM32_TIM3_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM3STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM4
+      case 4:
+        g_tickless.base = STM32_TIM4_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM4STOP);
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM5
+      case 5:
+        g_tickless.base = STM32_TIM5_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM5STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM6
+      case 6:
+
+        /* Basic timers not supported by this implementation */
+
+        DEBUGASSERT(0);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM7
+      case 7:
+
+        /* Basic timers not supported by this implementation */
+
+        DEBUGASSERT(0);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM8
+      case 8:
+        g_tickless.base = STM32_TIM8_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM8STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM9
+      case 9:
+        g_tickless.base = STM32_TIM9_BASE;
+
+        /* A freeze bit for TIM9 doesn't seem to exist */
+
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM10
+      case 10:
+        g_tickless.base = STM32_TIM10_BASE;
+
+        /* A freeze bit for TIM10 doesn't seem to exist */
+
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM11
+      case 11:
+        g_tickless.base = STM32_TIM11_BASE;
+
+        /* A freeze bit for TIM11 doesn't seem to exist */
+
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM12
+      case 12:
+        g_tickless.base = STM32_TIM12_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM12STOP);
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM13
+      case 13:
+        g_tickless.base = STM32_TIM13_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM13STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM14
+      case 14:
+        g_tickless.base = STM32_TIM14_BASE;
+        modifyreg32(STM32_DBGMCU_APB1LFZ1, 0, DBGMCU_APB1L_TIM14STOP);
+        break;
+#endif
+#ifdef CONFIG_STM32H7_TIM15
+      case 15:
+        g_tickless.base = STM32_TIM15_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM15STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM16
+      case 16:
+        g_tickless.base = STM32_TIM16_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM16STOP);
+        break;
+#endif
+
+#ifdef CONFIG_STM32H7_TIM17
+      case 17:
+        g_tickless.base = STM32_TIM17_BASE;
+        modifyreg32(STM32_DBGMCU_APB2FZ1, 0, DBGMCU_APB2Z1_TIM17STOP);
+        break;
+#endif
+
+      default:
+        DEBUGASSERT(0);
+    }
+
+  /* Get the TC frequency that corresponds to the requested resolution */
+
+  g_tickless.frequency = USEC_PER_SEC / (uint32_t)CONFIG_USEC_PER_TICK;
+  g_tickless.timer     = CONFIG_STM32H7_TICKLESS_TIMER;
+  g_tickless.channel   = CONFIG_STM32H7_TICKLESS_CHANNEL;
+  g_tickless.pending   = false;
+  g_tickless.period    = 0;
+
+  tmrinfo("timer=%d channel=%d frequency=%d Hz\n",
+           g_tickless.timer, g_tickless.channel, g_tickless.frequency);
+
+  g_tickless.tch = stm32_tim_init(g_tickless.timer);
+  if (!g_tickless.tch)
+    {
+      tmrerr("ERROR: Failed to allocate TIM%d\n", g_tickless.timer);
+      DEBUGASSERT(0);
+    }
+
+  STM32_TIM_SETCLOCK(g_tickless.tch, g_tickless.frequency);
+
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+
+  /* Should this be changed to 0xffff because we use 16 bit timers? */
+
+  g_tickless.counter_mask = 0xffffffffull;

Review comment:
       how is up_timer_getmask  used?

##########
File path: arch/arm/src/stm32h7/stm32_tickless.c
##########
@@ -0,0 +1,1059 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_tickless.c
+ *
+ * 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 up_timer_initialize(void): Initializes the timer facilities.
+ *     Called early in the initialization sequence (by up_initialize()).
+ *   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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * STM32 Timer Usage
+ *
+ * This implementation uses one timer:  A free running timer to provide
+ * the current time and a capture/compare channel for timed-events.
+ *
+ * BASIC timers that are found on some STM32 chips (timers 6 and 7) are
+ * incompatible with this implementation because they don't have capture/
+ * compare channels.  There are two interrupts generated from our timer,
+ * the overflow interrupt which drives the timing handler and the capture/
+ * compare interrupt which drives the interval handler.  There are some low
+ * level timer control functions implemented here because the API of
+ * stm32_tim.c does not provide adequate control over capture/compare
+ * interrupts.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/arch_timer.h>
+#include <debug.h>
+#include <arch/board/board.h>
+
+#include "arm_arch.h"
+
+#include "stm32_tim.h"
+#include "stm32_dbgmcu.h"
+
+#include "systick.h"
+
+#ifdef CONFIG_SCHED_TICKLESS
+
+/* Only TIM2 and TIM5 timers may be 32-bits in width */
+
+#undef HAVE_32BIT_TICKLESS
+
+#if (CONFIG_STM32H7_TICKLESS_TIMER == 2) || \
+    (CONFIG_STM32H7_TICKLESS_TIMER == 5)
+ #define HAVE_32BIT_TICKLESS 1
+#endif
+
+#if CONFIG_STM32H7_TICKLESS_CHANNEL == 1
+#define DIER_CAPT_IE          ATIM_DIER_CC1IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 2
+#define DIER_CAPT_IE          ATIM_DIER_CC2IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 3
+#define DIER_CAPT_IE          ATIM_DIER_CC3IE
+#elif CONFIG_STM32H7_TICKLESS_CHANNEL == 4
+#define DIER_CAPT_IE          ATIM_DIER_CC4IE
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_tickless_s
+{
+  uint8_t timer;                   /* The timer/counter in use */
+  uint8_t channel;                 /* The timer channel to use for intervals */
+  FAR struct stm32_tim_dev_s *tch; /* Handle returned by stm32_tim_init() */
+  uint32_t frequency;
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+  uint64_t counter_mask;
+#else
+  uint32_t overflow;               /* Timer counter overflow */
+#endif
+  volatile bool pending;           /* True: pending task */
+  uint32_t period;                 /* Interval period */
+  uint32_t base;
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  uint64_t last_alrm;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct stm32_tickless_s g_tickless;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_getreg16
+ *
+ * Description:
+ *   Get a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint16_t stm32_getreg16(uint8_t offset)
+{
+  return getreg16(g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Put a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_putreg16(uint8_t offset, uint16_t value)
+{
+  putreg16(value, g_tickless.base + offset);
+}
+
+/****************************************************************************
+ * Name: stm32_modifyreg16
+ *
+ * Description:
+ *   Modify a 16-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits,
+                                     uint16_t setbits)
+{
+  modifyreg16(g_tickless.base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_enableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_enableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 0, 1 << channel);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_disableint
+ ****************************************************************************/
+
+static inline void stm32_tickless_disableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 1 << channel, 0);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_ackint
+ ****************************************************************************/
+
+static inline void stm32_tickless_ackint(int channel)
+{
+  stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel));
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_getint
+ ****************************************************************************/
+
+static inline uint16_t stm32_tickless_getint(void)
+{
+  return stm32_getreg16(STM32_BTIM_SR_OFFSET);
+}
+
+/****************************************************************************
+ * Name: stm32_tickless_setchannel
+ ****************************************************************************/
+
+static int stm32_tickless_setchannel(uint8_t channel)
+{
+  uint16_t ccmr_orig   = 0;
+  uint16_t ccmr_val    = 0;
+  uint16_t ccmr_mask   = 0xff;
+  uint16_t ccer_val    = stm32_getreg16(STM32_GTIM_CCER_OFFSET);
+  uint8_t  ccmr_offset = STM32_GTIM_CCMR1_OFFSET;
+
+  /* Further we use range as 0..3; if channel=0 it will also overflow here */
+
+  if (--channel > 4)
+    {
+      return -EINVAL;
+    }
+
+  /* Assume that channel is disabled and polarity is active high */
+
+  ccer_val &= ~(3 << (channel << 2));
+
+  /* This function is not supported on basic timers. To enable or
+   * disable it, simply set its clock to valid frequency or zero.
+   */
+
+  if (g_tickless.base == STM32_TIM6_BASE ||
+      g_tickless.base == STM32_TIM7_BASE)
+    {
+      return -EINVAL;
+    }
+
+  /* Frozen mode because we don't want to change the GPIO, preload register
+   * disabled.
+   */
+
+  ccmr_val = (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
+
+  /* Set polarity */
+
+  ccer_val |= ATIM_CCER_CC1P << (channel << 2);
+
+  /* Define its position (shift) and get register offset */
+
+  if ((channel & 1) != 0)
+    {
+      ccmr_val  <<= 8;
+      ccmr_mask <<= 8;
+    }
+
+  if (channel > 1)
+    {
+      ccmr_offset = STM32_GTIM_CCMR2_OFFSET;
+    }
+
+  ccmr_orig  = stm32_getreg16(ccmr_offset);
+  ccmr_orig &= ~ccmr_mask;
+  ccmr_orig |= ccmr_val;
+  stm32_putreg16(ccmr_offset, ccmr_orig);
+  stm32_putreg16(STM32_GTIM_CCER_OFFSET, ccer_val);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_interval_handler
+ *
+ * Description:
+ *   Called when the timer counter matches the compare register
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called early in the initialization sequence before any special
+ *   concurrency protections are required.
+ *
+ ****************************************************************************/
+
+static void stm32_interval_handler(void)
+{
+#ifdef CONFIG_SCHED_TICKLESS_ALARM
+  struct timespec tv;
+#endif
+  tmrinfo("Expired...\n");
+
+  /* Disable the compare interrupt now. */
+
+  stm32_tickless_disableint(g_tickless.channel);
+  stm32_tickless_ackint(g_tickless.channel);
+
+  g_tickless.pending = false;
+
+#ifndef CONFIG_SCHED_TICKLESS_ALARM
+  nxsched_timer_expiration();
+#else
+  up_timer_gettime(&tv);
+  nxsched_alarm_expiration(&tv);
+#endif
+}
+
+/****************************************************************************
+ * Name: stm32_timing_handler
+ *
+ * Description:
+ *   Timer interrupt callback.  When the freerun timer counter overflows,
+ *   this interrupt will occur.  We will just increment an overflow count.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static void stm32_timing_handler(void)
+{
+  g_tickless.overflow++;
+
+  STM32_TIM_ACKINT(g_tickless.tch, 0);
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Name: stm32_tickless_handler
+ *
+ * Description:
+ *   Generic interrupt handler for this timer.  It checks the source of the
+ *   interrupt and fires the appropriate handler.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int stm32_tickless_handler(int irq, void *context, void *arg)
+{
+  int interrupt_flags = stm32_tickless_getint();
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+  if (interrupt_flags & ATIM_SR_UIF)
+    {
+      stm32_timing_handler();
+    }
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+  if (interrupt_flags & (1 << g_tickless.channel))
+    {
+      stm32_interval_handler();
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_get_counter
+ *
+ ****************************************************************************/
+
+static uint64_t stm32_get_counter(void)
+{
+  return ((uint64_t)g_tickless.overflow << 32) |
+         STM32_TIM_GETCOUNTER(g_tickless.tch);
+}

Review comment:
       How does this work with 16 bit and 32 bit counter registers?
   the data 
   `0x 0000 0001 0000 ffff-> 0x0000 0002 0000 0000 < dt is not 1>`
   
   vs a linear 32 bit 
   
   `0x 0000 0001 ffff ffff-> 0x0000 0002 0000 0000 < dt =1 >`




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org