This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 3c05605079e kinetis/pit: Update Kconfig, implement oneshot PIT
3c05605079e is described below
commit 3c05605079e9bacb38106bb996d8bde8933ca43e
Author: Jiri Vlasak <[email protected]>
AuthorDate: Tue Mar 3 10:56:36 2026 +0100
kinetis/pit: Update Kconfig, implement oneshot PIT
Implementation of the Kinetis' Periodic Interrupt Timer (PIT). The lower
half driver is oneshot.
Signed-off-by: Jiri Vlasak <[email protected]>
---
arch/arm/src/kinetis/CMakeLists.txt | 4 +
arch/arm/src/kinetis/Kconfig | 51 +++-
arch/arm/src/kinetis/Make.defs | 4 +
arch/arm/src/kinetis/kinetis_oneshot_pit.c | 404 +++++++++++++++++++++++++++++
include/nuttx/timers/oneshot.h | 14 +
5 files changed, 471 insertions(+), 6 deletions(-)
diff --git a/arch/arm/src/kinetis/CMakeLists.txt
b/arch/arm/src/kinetis/CMakeLists.txt
index cd8795e9875..ed8723af56f 100644
--- a/arch/arm/src/kinetis/CMakeLists.txt
+++ b/arch/arm/src/kinetis/CMakeLists.txt
@@ -131,4 +131,8 @@ if(CONFIG_ANALOG)
endif()
endif()
+if(CONFIG_KINETIS_PIT)
+ list(APPEND SRCS kinetis_oneshot_pit.c)
+endif()
+
target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/arm/src/kinetis/Kconfig b/arch/arm/src/kinetis/Kconfig
index 6dbf32c615e..5af694bcb6f 100644
--- a/arch/arm/src/kinetis/Kconfig
+++ b/arch/arm/src/kinetis/Kconfig
@@ -687,6 +687,51 @@ config KINETIS_TPM2
---help---
Support TPM module 2
+
+config KINETIS_PIT
+ bool "Periodic Interrupt Timer (PIT)"
+ default n
+ select ONESHOT
+ select ONESHOT_COUNT
+ ---help---
+ Support for Periodic Interrupt Timer (PIT).
+
+ From the Reference Manual:
+
+ The PIT module is an array of timers that can be
+ used to raise interrupts and trigger DMA channels.
+
+ Currently, PIT is used for oneshot lower half driver.
+
+config KINETIS_PIT_CH0
+ bool "Channel 0"
+ default n
+ depends on KINETIS_PIT
+ ---help---
+ Enable Channel 0 of the Periodic Interrupt Timer (PIT).
+
+config KINETIS_PIT_CH1
+ bool "Channel 1"
+ default n
+ depends on KINETIS_PIT
+ ---help---
+ Enable Channel 1 of the Periodic Interrupt Timer (PIT).
+
+config KINETIS_PIT_CH2
+ bool "Channel 2"
+ default n
+ depends on KINETIS_PIT
+ ---help---
+ Enable Channel 2 of the Periodic Interrupt Timer (PIT).
+
+config KINETIS_PIT_CH3
+ bool "Channel 3"
+ default n
+ depends on KINETIS_PIT
+ ---help---
+ Enable Channel 3 of the Periodic Interrupt Timer (PIT).
+
+
config KINETIS_LPTMR0
bool "Low power timer 0 (LPTMR0)"
default n
@@ -783,12 +828,6 @@ config KINETIS_PDB
---help---
Support the Programmable Delay Block
-config KINETIS_PIT
- bool "Programmable interval timer (PIT)"
- default n
- ---help---
- Support Programmable Interval Timers
-
endmenu
menu "Kinetis FTM PWM Configuration"
diff --git a/arch/arm/src/kinetis/Make.defs b/arch/arm/src/kinetis/Make.defs
index 66461d889fa..22344ae10ad 100644
--- a/arch/arm/src/kinetis/Make.defs
+++ b/arch/arm/src/kinetis/Make.defs
@@ -39,6 +39,10 @@ ifneq ($(CONFIG_SCHED_TICKLESS),y)
CHIP_CSRCS += kinetis_timerisr.c
endif
+ifeq ($(CONFIG_KINETIS_PIT),y)
+CHIP_CSRCS += kinetis_oneshot_pit.c
+endif
+
ifeq ($(CONFIG_BUILD_PROTECTED),y)
CHIP_CSRCS += kinetis_userspace.c
endif
diff --git a/arch/arm/src/kinetis/kinetis_oneshot_pit.c
b/arch/arm/src/kinetis/kinetis_oneshot_pit.c
new file mode 100644
index 00000000000..46f8c3d6f53
--- /dev/null
+++ b/arch/arm/src/kinetis/kinetis_oneshot_pit.c
@@ -0,0 +1,404 @@
+/****************************************************************************
+ * arch/arm/src/kinetis/kinetis_oneshot_pit.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Periodic Interrupt Timer (PIT)
+ *
+ * From the Reference manual:
+ *
+ * The PIT module is an array of timers that can be used to raise interrupts
+ * and trigger DMA channels.
+ *
+ * This file provides oneshot timer driver that uses Kinetis' PIT.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/irq.h> /* Enter and leave critical sections. */
+#include <nuttx/timers/oneshot.h> /* oneshot_lowerhalf_s, oneshot_... */
+
+#include "hardware/kinetis_sim.h" /* KINETIS_SIM_... */
+#include "hardware/kinetis_pit.h" /* KINETIS_PIT_... */
+
+#include "kinetis.h"
+
+#if defined(CONFIG_KINETIS_PIT)
+
+#if !defined(CONFIG_ONESHOT) || !defined(CONFIG_ONESHOT_COUNT)
+# error "CONFIG_ONESHOT and CONFIG_ONESHOT_COUNT must be defined"
+#endif
+
+/****************************************************************************
+ * Private Types
+ *
+ * kinetis_oneshot_lowerhalf_s
+ * Private data structure to keep oneshot_lowerhalf_s structure and private
+ * information of the Kinetis implementation.
+ *
+ ****************************************************************************/
+
+struct kinetis_oneshot_lowerhalf_s
+{
+ struct oneshot_lowerhalf_s lh;
+
+ int channel;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ *
+ * See doc of the oneshot_operations_s in include/nuttx/timers/oneshot.h
+ *
+ * kinetis_oneshot_isr
+ * Interrupt service routine that calls oneshot_process_callback when timer
+ * finishes.
+ *
+ ****************************************************************************/
+
+static clkcnt_t kinetis_oneshot_current(struct oneshot_lowerhalf_s *lower);
+static void kinetis_oneshot_start(struct oneshot_lowerhalf_s *lower,
+ clkcnt_t delay_count);
+static void kinetis_oneshot_start_absolute(
+ struct oneshot_lowerhalf_s *lower, clkcnt_t at_count);
+static void kinetis_oneshot_cancel(struct oneshot_lowerhalf_s *lower);
+static clkcnt_t kinetis_oneshot_maxdelay(struct oneshot_lowerhalf_s *lower);
+
+static int kinetis_oneshot_isr(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct oneshot_operations_s const g_oneshot_ops =
+{
+ .current = kinetis_oneshot_current,
+ .start = kinetis_oneshot_start,
+ .start_absolute = kinetis_oneshot_start_absolute,
+ .cancel = kinetis_oneshot_cancel,
+ .max_delay = kinetis_oneshot_maxdelay,
+};
+
+#if defined(CONFIG_KINETIS_PIT_CH0)
+static struct kinetis_oneshot_lowerhalf_s g_pit_ch0 =
+{
+ .lh =
+ {
+ .ops = &g_oneshot_ops,
+ },
+ .channel = 0,
+};
+#endif /* CONFIG_KINETIS_PIT_CH0 */
+
+#if defined(CONFIG_KINETIS_PIT_CH1)
+static struct kinetis_oneshot_lowerhalf_s g_pit_ch1 =
+{
+ .lh =
+ {
+ .ops = &g_oneshot_ops,
+ },
+ .channel = 1,
+};
+#endif /* CONFIG_KINETIS_PIT_CH1 */
+
+#if defined(CONFIG_KINETIS_PIT_CH2)
+static struct kinetis_oneshot_lowerhalf_s g_pit_ch2 =
+{
+ .lh =
+ {
+ .ops = &g_oneshot_ops,
+ },
+ .channel = 2,
+};
+#endif /* CONFIG_KINETIS_PIT_CH2 */
+
+#if defined(CONFIG_KINETIS_PIT_CH3)
+static struct kinetis_oneshot_lowerhalf_s g_pit_ch3 =
+{
+ .lh =
+ {
+ .ops = &g_oneshot_ops,
+ },
+ .channel = 3,
+};
+#endif /* CONFIG_KINETIS_PIT_CH3 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static clkcnt_t
+kinetis_oneshot_current(struct oneshot_lowerhalf_s *lower)
+{
+ struct kinetis_oneshot_lowerhalf_s *priv =
+ (struct kinetis_oneshot_lowerhalf_s *)lower;
+
+ DEBUGASSERT(NULL != priv);
+
+ switch (priv->channel)
+ {
+ case 0:
+ return getreg32(KINETIS_PIT_CVAL0);
+ break;
+ case 1:
+ return getreg32(KINETIS_PIT_CVAL1);
+ break;
+ case 2:
+ return getreg32(KINETIS_PIT_CVAL2);
+ break;
+ case 3:
+ return getreg32(KINETIS_PIT_CVAL3);
+ break;
+ default:
+ tmrerr("ERROR: Bad channel %d", priv->channel);
+ return 0;
+ }
+}
+
+static void
+kinetis_oneshot_start(struct oneshot_lowerhalf_s *lower,
+ clkcnt_t delay_count)
+{
+ struct kinetis_oneshot_lowerhalf_s *priv =
+ (struct kinetis_oneshot_lowerhalf_s *)lower;
+ irqstate_t flags;
+
+ DEBUGASSERT(NULL != priv);
+
+ flags = enter_critical_section();
+ switch (priv->channel)
+ {
+ case 0:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL0);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG0);
+ putreg32((uint32_t)delay_count, KINETIS_PIT_LDVAL0);
+ putreg32(PIT_TCTRL_TEN | PIT_TCTRL_TIE, KINETIS_PIT_TCTRL0);
+ irq_attach(KINETIS_IRQ_PITCH0, kinetis_oneshot_isr, NULL);
+ up_enable_irq(KINETIS_IRQ_PITCH0);
+ break;
+ case 1:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL1);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG1);
+ putreg32((uint32_t)delay_count, KINETIS_PIT_LDVAL1);
+ putreg32(PIT_TCTRL_TEN | PIT_TCTRL_TIE, KINETIS_PIT_TCTRL1);
+ irq_attach(KINETIS_IRQ_PITCH1, kinetis_oneshot_isr, NULL);
+ up_enable_irq(KINETIS_IRQ_PITCH1);
+ break;
+ case 2:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL2);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG2);
+ putreg32((uint32_t)delay_count, KINETIS_PIT_LDVAL2);
+ putreg32(PIT_TCTRL_TEN | PIT_TCTRL_TIE, KINETIS_PIT_TCTRL2);
+ irq_attach(KINETIS_IRQ_PITCH2, kinetis_oneshot_isr, NULL);
+ up_enable_irq(KINETIS_IRQ_PITCH2);
+ break;
+ case 3:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL3);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG3);
+ putreg32((uint32_t)delay_count, KINETIS_PIT_LDVAL3);
+ putreg32(PIT_TCTRL_TEN | PIT_TCTRL_TIE, KINETIS_PIT_TCTRL3);
+ irq_attach(KINETIS_IRQ_PITCH3, kinetis_oneshot_isr, NULL);
+ up_enable_irq(KINETIS_IRQ_PITCH3);
+ break;
+ default:
+ tmrerr("ERROR: Bad channel 0 <= %d <= 3", priv->channel);
+ }
+
+ leave_critical_section(flags);
+}
+
+static void
+kinetis_oneshot_start_absolute(struct oneshot_lowerhalf_s *lower,
+ clkcnt_t at_count)
+{
+ /* Copied from the esp_oneshot.c file. */
+
+ uint32_t alarm = (uint32_t)at_count;
+ uint32_t counter = (uint32_t)kinetis_oneshot_current(lower);
+
+ counter = alarm - counter >= alarm ? 0 : alarm - counter;
+ kinetis_oneshot_start(lower, counter);
+}
+
+static void
+kinetis_oneshot_cancel(struct oneshot_lowerhalf_s *lower)
+{
+ struct kinetis_oneshot_lowerhalf_s *priv =
+ (struct kinetis_oneshot_lowerhalf_s *)lower;
+ irqstate_t flags;
+
+ DEBUGASSERT(NULL != priv);
+
+ /* Reset PIT_TCTRLn and KINETIS_PIT_TFLGn. */
+
+ flags = enter_critical_section();
+ switch (priv->channel)
+ {
+ case 0:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL0);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG0);
+ up_disable_irq(KINETIS_IRQ_PITCH0);
+ irq_detach(KINETIS_IRQ_PITCH0);
+ break;
+ case 1:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL1);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG1);
+ up_disable_irq(KINETIS_IRQ_PITCH1);
+ irq_detach(KINETIS_IRQ_PITCH1);
+ break;
+ case 2:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL2);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG2);
+ up_disable_irq(KINETIS_IRQ_PITCH2);
+ irq_detach(KINETIS_IRQ_PITCH2);
+ break;
+ case 3:
+ putreg32(0x00000000, KINETIS_PIT_TCTRL3);
+ putreg32(PIT_TFLG_TIF, KINETIS_PIT_TFLG3);
+ up_disable_irq(KINETIS_IRQ_PITCH3);
+ irq_detach(KINETIS_IRQ_PITCH3);
+ break;
+ default:
+ tmrerr("ERROR: Bad channel 0 <= %d <= 3", priv->channel);
+ }
+
+ leave_critical_section(flags);
+}
+
+static clkcnt_t
+kinetis_oneshot_maxdelay(struct oneshot_lowerhalf_s *lower)
+{
+ /* PIT is 32-bit wide register, we cannot put in more. */
+
+ return 0xffffffff;
+}
+
+static int
+kinetis_oneshot_isr(int irq, void *context, void *arg)
+{
+ UNUSED(context);
+ UNUSED(arg);
+
+ switch (irq)
+ {
+#if defined(CONFIG_KINETIS_PIT_CH0)
+ case KINETIS_IRQ_PITCH0:
+ kinetis_oneshot_cancel(&g_pit_ch0.lh);
+ oneshot_process_callback(&g_pit_ch0.lh);
+ break;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH1)
+ case KINETIS_IRQ_PITCH1:
+ kinetis_oneshot_cancel(&g_pit_ch1.lh);
+ oneshot_process_callback(&g_pit_ch1.lh);
+ break;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH2)
+ case KINETIS_IRQ_PITCH2:
+ kinetis_oneshot_cancel(&g_pit_ch2.lh);
+ oneshot_process_callback(&g_pit_ch2.lh);
+ break;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH3)
+ case KINETIS_IRQ_PITCH3:
+ kinetis_oneshot_cancel(&g_pit_ch3.lh);
+ oneshot_process_callback(&g_pit_ch3.lh);
+ break;
+#endif
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+struct oneshot_lowerhalf_s *oneshot_initialize(int chan, uint16_t resolution)
+{
+ DEBUGASSERT(0 <= chan);
+ DEBUGASSERT(chan <= 3);
+
+ /* We do not use resolution. Frequency of PIT for Kinetis is given by the
+ * Peripheral bus clock.
+ */
+
+ UNUSED(resolution);
+
+ uint32_t reg;
+
+ /* Enable PIT in SIM. */
+
+ reg = getreg32(KINETIS_SIM_SCGC6);
+ reg |= SIM_SCGC6_PIT;
+ putreg32(reg, KINETIS_SIM_SCGC6);
+
+ /* Enable PIT in PIT_MCR. */
+
+ reg = getreg32(KINETIS_PIT_MCR);
+ reg &= ~PIT_MCR_MDIS;
+ putreg32(reg, KINETIS_PIT_MCR);
+
+ switch (chan)
+ {
+#if defined(CONFIG_KINETIS_PIT_CH0)
+ case 0:
+ oneshot_count_init(&g_pit_ch0.lh, (uint32_t)BOARD_BUS_FREQ);
+ return &g_pit_ch0.lh;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH1)
+ case 1:
+ oneshot_count_init(&g_pit_ch1.lh, (uint32_t)BOARD_BUS_FREQ);
+ return &g_pit_ch1.lh;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH2)
+ case 2:
+ oneshot_count_init(&g_pit_ch2.lh, (uint32_t)BOARD_BUS_FREQ);
+ return &g_pit_ch2.lh;
+#endif
+#if defined(CONFIG_KINETIS_PIT_CH3)
+ case 3:
+ oneshot_count_init(&g_pit_ch3.lh, (uint32_t)BOARD_BUS_FREQ);
+ return &g_pit_ch3.lh;
+#endif
+ default:
+ if (0 <= chan && chan <= 3)
+ {
+ tmrwarn("CONFIG_KINETIS_PIT_CH%d must be defined", chan);
+ }
+ else
+ {
+ tmrwarn("Bad channel specified, must be 0 <= %d <= 3", chan);
+ }
+ }
+
+ return NULL;
+}
+
+#endif /* CONFIG_KINETIS_PIT */
diff --git a/include/nuttx/timers/oneshot.h b/include/nuttx/timers/oneshot.h
index 74ed607c96f..99d2090d638 100644
--- a/include/nuttx/timers/oneshot.h
+++ b/include/nuttx/timers/oneshot.h
@@ -203,12 +203,26 @@ struct oneshot_operations_s
* conversion, and the theoretical optimal timing accuracy.
*/
+ /* Get the current timer count. */
+
CODE clkcnt_t (*current)(FAR struct oneshot_lowerhalf_s *lower);
+
+ /* Start a relative timer. */
+
CODE void (*start)(FAR struct oneshot_lowerhalf_s *lower,
clkcnt_t delay);
+
+ /* Start an absolute timer. */
+
CODE void (*start_absolute)(FAR struct oneshot_lowerhalf_s *lower,
clkcnt_t cnt);
+
+ /* Cancel the timer event. */
+
CODE void (*cancel)(FAR struct oneshot_lowerhalf_s *lower);
+
+ /* Get the timer's maximum delay. */
+
CODE clkcnt_t (*max_delay)(FAR struct oneshot_lowerhalf_s *lower);
#else
/* Deprecated interfaces, just for compatiable-usage. */