You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/09/30 22:26:17 UTC
[1/2] incubator-mynewt-core git commit: MYNEWT-401: HAL Timer
Repository: incubator-mynewt-core
Updated Branches:
refs/heads/develop e8704def7 -> cb45cd451
MYNEWT-401: HAL Timer
HAL timer implementation for nrf52. Note that this cut does not contain any of
the RTC timers. They will be added in a future commit.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/cb45cd45
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/cb45cd45
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/cb45cd45
Branch: refs/heads/develop
Commit: cb45cd4514d3e308f175e8be44d310c680ea4df1
Parents: 92c6dab
Author: William San Filippo <wi...@runtime.io>
Authored: Fri Sep 30 15:20:01 2016 -0700
Committer: William San Filippo <wi...@runtime.io>
Committed: Fri Sep 30 15:26:05 2016 -0700
----------------------------------------------------------------------
apps/timtest/pkg.yml | 38 ++
apps/timtest/src/main.c | 196 ++++++++
hw/bsp/nrf52dk/include/bsp/bsp.h | 1 +
hw/bsp/nrf52dk/pkg.yml | 17 +
hw/mcu/nordic/nrf52xxx/src/hal_timer.c | 679 ++++++++++++++++++++++++++++
5 files changed, 931 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/cb45cd45/apps/timtest/pkg.yml
----------------------------------------------------------------------
diff --git a/apps/timtest/pkg.yml b/apps/timtest/pkg.yml
new file mode 100644
index 0000000..66d03e6
--- /dev/null
+++ b/apps/timtest/pkg.yml
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+pkg.name: apps/timtest
+pkg.type: app
+pkg.description: board test code for hal timer.
+pkg.author: "Apache Mynewt <de...@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - sys/console/full
+ - kernel/os
+ - sys/shell
+ - sys/config
+ - sys/log
+ - sys/stats
+
+pkg.syscfg_vals:
+ SHELL_TASK: 0
+ TIMER_1: 1
+ TIMER_2: 1
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/cb45cd45/apps/timtest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/timtest/src/main.c b/apps/timtest/src/main.c
new file mode 100755
index 0000000..c13c835
--- /dev/null
+++ b/apps/timtest/src/main.c
@@ -0,0 +1,196 @@
+/**
+ * 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.
+ */
+#include "os/os.h"
+#include "bsp/bsp.h"
+#include "hal/hal_gpio.h"
+#include "hal/hal_timer.h"
+#include "stats/stats.h"
+#include "config/config.h"
+#include <os/os_dev.h>
+#include <assert.h>
+#include <string.h>
+#include "app_util_platform.h"
+#include "app_error.h"
+
+/* Init all tasks */
+volatile int tasks_initialized;
+int init_tasks(void);
+
+/* Task 1 */
+#define TASK1_PRIO (1)
+#define TASK1_STACK_SIZE OS_STACK_ALIGN(64)
+struct os_task task1;
+os_stack_t stack1[TASK1_STACK_SIZE];
+
+#define TASK1_TIMER_NUM (1)
+#define TASK1_TIMER_FREQ (1000000)
+
+/* Task 2 */
+#define TASK2_PRIO (2)
+#define TASK2_STACK_SIZE OS_STACK_ALIGN(64)
+struct os_task task2;
+os_stack_t stack2[TASK2_STACK_SIZE];
+
+#define TASK2_TIMER_NUM (2)
+#define TASK2_TIMER_FREQ (250000)
+
+/* For LED toggling */
+int g_led1_pin;
+int g_led2_pin;
+struct os_sem g_test_sem;
+
+struct hal_timer g_task1_timer;
+uint32_t task1_timer_arg = 0xdeadc0de;
+
+void
+task1_timer_cb(void *arg)
+{
+ uint32_t timer_arg_val;
+
+ timer_arg_val = *(uint32_t *)arg;
+ assert(timer_arg_val == 0xdeadc0de);
+
+ os_sem_release(&g_test_sem);
+}
+
+void
+task1_handler(void *arg)
+{
+ int rc;
+ int cntr;
+ uint32_t timer_cntr;
+
+ /* Task 1 toggles LED 1 (LED_BLINK_PIN) */
+ g_led1_pin = LED_BLINK_PIN;
+ hal_gpio_init_out(g_led1_pin, 1);
+
+ hal_timer_set_cb(TASK1_TIMER_NUM, &g_task1_timer, task1_timer_cb,
+ &task1_timer_arg);
+
+ cntr = 0;
+ rc = hal_timer_start(&g_task1_timer, TASK1_TIMER_FREQ);
+ assert(rc == 0);
+
+ while (1) {
+ /* Wait for semaphore from ISR */
+ os_sem_pend(&g_test_sem, OS_TIMEOUT_NEVER);
+
+ /* Toggle the LED */
+ hal_gpio_toggle(g_led1_pin);
+
+ ++cntr;
+ if (cntr & 1) {
+ timer_cntr = hal_timer_read(TASK1_TIMER_NUM);
+ hal_timer_start_at(&g_task1_timer, timer_cntr + TASK1_TIMER_FREQ);
+ if ((cntr % 10) == 0) {
+ hal_timer_stop(&g_task1_timer);
+ os_sem_release(&g_test_sem);
+ }
+ } else {
+ hal_timer_start(&g_task1_timer, TASK1_TIMER_FREQ);
+ if ((cntr % 10) == 0) {
+ hal_timer_stop(&g_task1_timer);
+ os_sem_release(&g_test_sem);
+ }
+ }
+ }
+}
+
+void
+task2_handler(void *arg)
+{
+ int32_t delta;
+ uint32_t tval1;
+ uint32_t tval2;
+
+ g_led2_pin = LED_2;
+ hal_gpio_init_out(g_led2_pin, 1);
+
+ while (1) {
+ /* Read timer, block for 500 msecs, make sure timer counter counts! */
+ tval1 = hal_timer_read(TASK2_TIMER_NUM);
+ hal_timer_delay(TASK2_TIMER_NUM, TASK2_TIMER_FREQ / 2);
+ tval2 = hal_timer_read(TASK2_TIMER_NUM);
+ delta = (int32_t)(tval2 - tval1);
+ assert(delta > (int)(TASK2_TIMER_FREQ / 2));
+
+ /* Toggle LED2 */
+ hal_gpio_toggle(g_led2_pin);
+ }
+}
+
+/**
+ * init_tasks
+ *
+ * Called by main.c after os_init(). This function performs initializations
+ * that are required before tasks are running.
+ *
+ * @return int 0 success; error otherwise.
+ */
+int
+init_tasks(void)
+{
+ uint32_t res;
+
+ /* Initialize global test semaphore */
+ os_sem_init(&g_test_sem, 0);
+
+ /* Initialize timer 0 to count at 1 MHz */
+ hal_timer_init(TASK1_TIMER_NUM, TASK1_TIMER_FREQ);
+ res = hal_timer_get_resolution(TASK1_TIMER_NUM);
+ assert(res == 1000);
+
+ /* Initialize timer 1 to count at 250 kHz */
+ hal_timer_init(TASK2_TIMER_NUM, TASK2_TIMER_FREQ);
+ res = hal_timer_get_resolution(TASK2_TIMER_NUM);
+ assert(res == 4000);
+
+ os_task_init(&task1, "task1", task1_handler, NULL,
+ TASK1_PRIO, OS_WAIT_FOREVER, stack1, TASK1_STACK_SIZE);
+
+ os_task_init(&task2, "task2", task2_handler, NULL,
+ TASK2_PRIO, OS_WAIT_FOREVER, stack2, TASK2_STACK_SIZE);
+
+ tasks_initialized = 1;
+ return 0;
+}
+
+/**
+ * main
+ *
+ * The main function for the project. This function initializes the os, calls
+ * init_tasks to initialize tasks (and possibly other objects), then starts the
+ * OS. We should not return from os start.
+ *
+ * @return int NOTE: this function should never return!
+ */
+int
+main(int argc, char **argv)
+{
+ int rc;
+
+ os_init();
+ rc = init_tasks();
+ os_start();
+
+ assert(0);
+
+ return rc;
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/cb45cd45/hw/bsp/nrf52dk/include/bsp/bsp.h
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf52dk/include/bsp/bsp.h b/hw/bsp/nrf52dk/include/bsp/bsp.h
index 08ebe93..f009898 100644
--- a/hw/bsp/nrf52dk/include/bsp/bsp.h
+++ b/hw/bsp/nrf52dk/include/bsp/bsp.h
@@ -39,6 +39,7 @@ extern uint8_t _ram_start;
/* LED pins */
#define LED_BLINK_PIN (17)
+#define LED_2 (18)
/* SPI SS */
#define SPI_SS_PIN (22)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/cb45cd45/hw/bsp/nrf52dk/pkg.yml
----------------------------------------------------------------------
diff --git a/hw/bsp/nrf52dk/pkg.yml b/hw/bsp/nrf52dk/pkg.yml
index ee9095b..ac2cd78 100644
--- a/hw/bsp/nrf52dk/pkg.yml
+++ b/hw/bsp/nrf52dk/pkg.yml
@@ -105,3 +105,20 @@ pkg.syscfg_defs:
SPI_SLAVE:
description: 'TBD'
value: 0
+
+ TIMER_0:
+ description: 'NRF52 Timer 0'
+ value: 0
+ TIMER_1:
+ description: 'NRF52 Timer 1'
+ value: 0
+ TIMER_2:
+ description: 'NRF52 Timer 2'
+ value: 0
+ TIMER_3:
+ description: 'NRF52 Timer 3'
+ value: 0
+ TIMER_4:
+ description: 'NRF52 Timer 4'
+ value: 0
+
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/cb45cd45/hw/mcu/nordic/nrf52xxx/src/hal_timer.c
----------------------------------------------------------------------
diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_timer.c b/hw/mcu/nordic/nrf52xxx/src/hal_timer.c
new file mode 100644
index 0000000..b89f664
--- /dev/null
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_timer.c
@@ -0,0 +1,679 @@
+/**
+ * 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.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+#include "syscfg/syscfg.h"
+#include "bsp/cmsis_nvic.h"
+#include "hal/hal_timer.h"
+#include "nrf52.h"
+#include "nrf52_bitfields.h"
+#include "mcu/nrf52_hal.h"
+
+/* IRQ prototype */
+typedef void (*hal_timer_irq_handler_t)(void);
+
+/* User CC 2 for reading counter, CC 3 for timer isr */
+#define NRF_TIMER_CC_READ (2)
+#define NRF_TIMER_CC_INT (3)
+
+/* XXX: what about RTC timers? How are they instantiated? How do we
+ relate timer numbers to them? */
+#define NRF52_HAL_TIMER_MAX (5)
+
+/* Maximum timer frequency */
+#define NRF52_MAX_TIMER_FREQ (16000000)
+
+struct nrf52_hal_timer {
+ uint8_t tmr_enabled;
+ uint8_t tmr_irq_num;
+ uint8_t tmr_pad[2];
+ uint32_t timer_isrs;
+ uint32_t tmr_freq;
+ NRF_TIMER_Type *tmr_reg;
+ TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q;
+};
+
+#if MYNEWT_VAL(TIMER_0)
+struct nrf52_hal_timer nrf52_hal_timer0;
+#endif
+#if MYNEWT_VAL(TIMER_1)
+struct nrf52_hal_timer nrf52_hal_timer1;
+#endif
+#if MYNEWT_VAL(TIMER_2)
+struct nrf52_hal_timer nrf52_hal_timer2;
+#endif
+#if MYNEWT_VAL(TIMER_3)
+struct nrf52_hal_timer nrf52_hal_timer3;
+#endif
+#if MYNEWT_VAL(TIMER_4)
+struct nrf52_hal_timer nrf52_hal_timer4;
+#endif
+
+struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = {
+#if MYNEWT_VAL(TIMER_0)
+ &nrf52_hal_timer0,
+#else
+ NULL,
+#endif
+#if MYNEWT_VAL(TIMER_1)
+ &nrf52_hal_timer1,
+#else
+ NULL,
+#endif
+#if MYNEWT_VAL(TIMER_2)
+ &nrf52_hal_timer2,
+#else
+ NULL,
+#endif
+#if MYNEWT_VAL(TIMER_3)
+ &nrf52_hal_timer3,
+#else
+ NULL,
+#endif
+#if MYNEWT_VAL(TIMER_4)
+ &nrf52_hal_timer4
+#else
+ NULL
+#endif
+};
+
+/* Resolve timer number into timer structure */
+#define NRF52_HAL_TIMER_RESOLVE(__n, __v) \
+ if ((__n) >= NRF52_HAL_TIMER_MAX) { \
+ rc = EINVAL; \
+ goto err; \
+ } \
+ (__v) = nrf52_hal_timers[(__n)]; \
+ if ((__v) == NULL) { \
+ rc = EINVAL; \
+ goto err; \
+ }
+
+/* Interrupt mask for interrupt enable/clear */
+#define NRF_TIMER_INT_MASK(x) ((1 << (uint32_t)(x)) << 16)
+
+static uint32_t
+nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer)
+{
+ uint32_t tcntr;
+
+ /* Force a capture of the timer into 'cntr' capture channel; read it */
+ hwtimer->TASKS_CAPTURE[NRF_TIMER_CC_READ] = 1;
+ tcntr = hwtimer->CC[NRF_TIMER_CC_READ];
+
+ return tcntr;
+}
+
+/**
+ * nrf timer set ocmp
+ *
+ * Set the OCMP used by the timer to the desired expiration tick
+ *
+ * NOTE: Must be called with interrupts disabled.
+ *
+ * @param timer Pointer to timer.
+ */
+static void
+nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry)
+{
+ NRF_TIMER_Type *hwtimer;
+
+ hwtimer = bsptimer->tmr_reg;
+
+ /* Disable ocmp interrupt and set new value */
+ hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
+
+ /* Set output compare register to timer expiration */
+ hwtimer->CC[NRF_TIMER_CC_INT] = expiry;
+
+ /* Clear interrupt flag */
+ hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
+
+ /* Enable the output compare interrupt */
+ hwtimer->INTENSET = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
+
+ /* Force interrupt to occur as we may have missed it */
+ if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) {
+ NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
+ }
+}
+
+/* Disable output compare used for timer */
+static void
+nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer)
+{
+ hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
+}
+
+/**
+ * hal timer chk queue
+ *
+ *
+ * @param bsptimer
+ */
+static void
+hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer)
+{
+ uint32_t tcntr;
+ uint32_t ctx;
+ struct hal_timer *timer;
+
+ /* disable interrupts */
+ __HAL_DISABLE_INTERRUPTS(ctx);
+ while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) {
+ tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
+ if ((int32_t)(tcntr - timer->expiry) >= 0) {
+ TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
+ timer->link.tqe_prev = NULL;
+ timer->cb_func(timer->cb_arg);
+ } else {
+ break;
+ }
+ }
+
+ /* Any timers left on queue? If so, we need to set OCMP */
+ timer = TAILQ_FIRST(&bsptimer->hal_timer_q);
+ if (timer) {
+ nrf_timer_set_ocmp(bsptimer, timer->expiry);
+ } else {
+ nrf_timer_disable_ocmp(bsptimer->tmr_reg);
+ }
+ __HAL_ENABLE_INTERRUPTS(ctx);
+}
+
+/**
+ * hal timer irq handler
+ *
+ * Generic HAL timer irq handler.
+ *
+ * @param tmr
+ */
+/**
+ * hal timer irq handler
+ *
+ * This is the global timer interrupt routine.
+ *
+ */
+#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \
+ MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4))
+
+static void
+hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer)
+{
+ uint32_t compare;
+ NRF_TIMER_Type *hwtimer;
+
+ /* Check interrupt source. If set, clear them */
+ hwtimer = bsptimer->tmr_reg;
+ compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
+ if (compare) {
+ hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
+ }
+
+ /* XXX: make these stats? */
+ /* Count # of timer isrs */
+ ++bsptimer->timer_isrs;
+
+ /*
+ * NOTE: we dont check the 'compare' variable here due to how the timer
+ * is implemented on this chip. There is no way to force an output
+ * compare, so if we are late setting the output compare (i.e. the timer
+ * counter is already passed the output compare value), we use the NVIC
+ * to set a pending interrupt. This means that there will be no compare
+ * flag set, so all we do is check to see if the compare interrupt is
+ * enabled.
+ */
+ if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) {
+ hal_timer_chk_queue(bsptimer);
+ /* XXX: Recommended by nordic to make sure interrupts are cleared */
+ compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
+ }
+}
+#endif
+
+#if MYNEWT_VAL(TIMER_0)
+void
+nrf52_timer0_irq_handler(void)
+{
+ hal_timer_irq_handler(&nrf52_hal_timer0);
+}
+#endif
+
+#if MYNEWT_VAL(TIMER_1)
+void
+nrf52_timer1_irq_handler(void)
+{
+ hal_timer_irq_handler(&nrf52_hal_timer1);
+}
+#endif
+
+#if MYNEWT_VAL(TIMER_2)
+void
+nrf52_timer2_irq_handler(void)
+{
+ hal_timer_irq_handler(&nrf52_hal_timer2);
+}
+#endif
+
+#if MYNEWT_VAL(TIMER_3)
+void
+nrf52_timer3_irq_handler(void)
+{
+ hal_timer_irq_handler(&nrf52_hal_timer3);
+}
+#endif
+
+#if MYNEWT_VAL(TIMER_4)
+void
+nrf52_timer4_irq_handler(void)
+{
+ hal_timer_irq_handler(&nrf52_hal_timer4);
+}
+#endif
+
+/**
+ * hal timer init
+ *
+ * Initialize (and start) a timer to run at the desired frequency.
+ *
+ * @param timer_num
+ * @param freq_hz
+ *
+ * @return int
+ */
+int
+hal_timer_init(int timer_num, uint32_t freq_hz)
+{
+ int rc;
+ uint8_t prescaler;
+ uint8_t irq_num;
+ uint32_t ctx;
+ uint32_t div;
+ uint32_t min_delta;
+ uint32_t max_delta;
+ struct nrf52_hal_timer *bsptimer;
+ NRF_TIMER_Type *hwtimer;
+ hal_timer_irq_handler_t irq_isr;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ /* Set timer to desired frequency */
+ div = NRF52_MAX_TIMER_FREQ / freq_hz;
+
+ /* Largest prescaler is 2^9 and must make sure frequency not too high */
+ if (bsptimer->tmr_enabled || (div == 0) || (div > 512)) {
+ rc = EINVAL;
+ goto err;
+ }
+
+ if (div == 1) {
+ prescaler = 0;
+ } else {
+ /* Find closest prescaler */
+ for (prescaler = 1; prescaler < 10; ++prescaler) {
+ if (div <= (1 << prescaler)) {
+ min_delta = div - (1 << (prescaler - 1));
+ max_delta = (1 << prescaler) - div;
+ if (min_delta < max_delta) {
+ prescaler -= 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Now set the actual frequency */
+ bsptimer->tmr_freq = NRF52_MAX_TIMER_FREQ / (1 << prescaler);
+
+ switch (timer_num) {
+#if MYNEWT_VAL(TIMER_0)
+ case 0:
+ irq_num = TIMER0_IRQn;
+ hwtimer = NRF_TIMER0;
+ irq_isr = nrf52_timer0_irq_handler;
+ break;
+#endif
+#if MYNEWT_VAL(TIMER_1)
+ case 1:
+ irq_num = TIMER1_IRQn;
+ hwtimer = NRF_TIMER1;
+ irq_isr = nrf52_timer1_irq_handler;
+ break;
+#endif
+#if MYNEWT_VAL(TIMER_2)
+ case 2:
+ irq_num = TIMER2_IRQn;
+ hwtimer = NRF_TIMER2;
+ irq_isr = nrf52_timer2_irq_handler;
+ break;
+#endif
+#if MYNEWT_VAL(TIMER_3)
+ case 3:
+ irq_num = TIMER3_IRQn;
+ hwtimer = NRF_TIMER3;
+ irq_isr = nrf52_timer3_irq_handler;
+ break;
+#endif
+#if MYNEWT_VAL(TIMER_4)
+ case 4:
+ irq_num = TIMER4_IRQn;
+ hwtimer = NRF_TIMER4;
+ irq_isr = nrf52_timer4_irq_handler;
+ break;
+#endif
+ default:
+ hwtimer = NULL;
+ break;
+ }
+
+ if (hwtimer == NULL) {
+ rc = EINVAL;
+ goto err;
+ }
+
+ bsptimer->tmr_reg = hwtimer;
+ bsptimer->tmr_irq_num = irq_num;
+ bsptimer->tmr_enabled = 1;
+
+ /* disable interrupts */
+ __HAL_DISABLE_INTERRUPTS(ctx);
+
+ /* Stop the timer first */
+ hwtimer->TASKS_STOP = 1;
+
+ /* Put the timer in timer mode using 32 bits. */
+ hwtimer->MODE = TIMER_MODE_MODE_Timer;
+ hwtimer->BITMODE = TIMER_BITMODE_BITMODE_32Bit;
+
+ /* Set the pre-scalar */
+ hwtimer->PRESCALER = prescaler;
+
+ /* Start the timer */
+ hwtimer->TASKS_START = 1;
+
+ /* Set isr in vector table and enable interrupt */
+ NVIC_SetVector(irq_num, (uint32_t)irq_isr);
+ NVIC_EnableIRQ(irq_num);
+
+ __HAL_ENABLE_INTERRUPTS(ctx);
+
+ hwtimer->PRESCALER = prescaler;
+
+ return 0;
+
+err:
+ return rc;
+}
+
+/**
+ * hal timer deinit
+ *
+ * De-initialize a HW timer.
+ *
+ * @param timer_num
+ *
+ * @return int
+ */
+int
+hal_timer_deinit(int timer_num)
+{
+ int rc;
+ uint32_t ctx;
+ struct nrf52_hal_timer *bsptimer;
+ NRF_TIMER_Type *hwtimer;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ __HAL_DISABLE_INTERRUPTS(ctx);
+ hwtimer = bsptimer->tmr_reg;
+ hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
+ hwtimer->TASKS_STOP = 1;
+ __HAL_ENABLE_INTERRUPTS(ctx);
+
+ bsptimer->tmr_enabled = 0;
+
+err:
+ return rc;
+}
+
+/**
+ * hal timer get resolution
+ *
+ * Get the resolution of the timer. This is the timer period, in nanoseconds
+ *
+ * @param timer_num
+ *
+ * @return uint32_t The
+ */
+uint32_t
+hal_timer_get_resolution(int timer_num)
+{
+ int rc;
+ uint32_t resolution;
+ struct nrf52_hal_timer *bsptimer;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ resolution = 1000000000 / bsptimer->tmr_freq;
+ return resolution;
+
+err:
+ rc = 0;
+ return rc;
+}
+
+/**
+ * hal timer read
+ *
+ * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only
+ * the lower 16 bits are valid. If the timer is a 64-bit timer, only the
+ * low 32-bits are returned.
+ *
+ * @return uint32_t The timer counter register.
+ */
+uint32_t
+hal_timer_read(int timer_num)
+{
+ int rc;
+ uint32_t tcntr;
+ struct nrf52_hal_timer *bsptimer;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ /* Force a capture of the timer into 'cntr' capture channel; read it */
+ tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
+
+ return tcntr;
+
+ /* Assert here since there is no invalid return code */
+err:
+ assert(0);
+ rc = 0;
+ return rc;
+}
+
+/**
+ * hal timer delay
+ *
+ * Blocking delay for n ticks
+ *
+ * @param timer_num
+ * @param ticks
+ *
+ * @return int 0 on success; error code otherwise.
+ */
+int
+hal_timer_delay(int timer_num, uint32_t ticks)
+{
+ int rc;
+ uint32_t until;
+ NRF_TIMER_Type *hwtimer;
+ struct nrf52_hal_timer *bsptimer;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ hwtimer = bsptimer->tmr_reg;
+ until = nrf_read_timer_cntr(hwtimer) + ticks;
+ while ((int32_t)(nrf_read_timer_cntr(hwtimer) - until) <= 0) {
+ /* Loop here till finished */
+ }
+ rc = 0;
+
+err:
+ return rc;
+}
+
+/**
+ *
+ * Initialize the HAL timer structure with the callback and the callback
+ * argument. Also initializes the HW specific timer pointer.
+ *
+ * @param cb_func
+ *
+ * @return int
+ */
+int
+hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func,
+ void *arg)
+{
+ int rc;
+ struct nrf52_hal_timer *bsptimer;
+
+ NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
+
+ timer->cb_func = cb_func;
+ timer->cb_arg = arg;
+ timer->link.tqe_prev = NULL;
+ timer->bsp_timer = bsptimer;
+
+ rc = 0;
+
+err:
+ return rc;
+}
+
+int
+hal_timer_start(struct hal_timer *timer, uint32_t ticks)
+{
+ int rc;
+ uint32_t tick;
+ struct nrf52_hal_timer *bsptimer;
+
+ /* Set the tick value at which the timer should expire */
+ if (ticks) {
+ bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
+ tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks;
+ rc = hal_timer_start_at(timer, tick);
+ } else {
+ rc = EINVAL;
+ }
+ return rc;
+}
+
+int
+hal_timer_start_at(struct hal_timer *timer, uint32_t tick)
+{
+ uint32_t ctx;
+ struct hal_timer *entry;
+ struct nrf52_hal_timer *bsptimer;
+
+ if ((timer == NULL) || (timer->link.tqe_prev != NULL) ||
+ (timer->cb_func == NULL)) {
+ return EINVAL;
+ }
+ bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
+ timer->expiry = tick;
+
+ __HAL_DISABLE_INTERRUPTS(ctx);
+
+ if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) {
+ TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link);
+ } else {
+ TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) {
+ if ((int32_t)(timer->expiry - entry->expiry) < 0) {
+ TAILQ_INSERT_BEFORE(entry, timer, link);
+ break;
+ }
+ }
+ if (!entry) {
+ TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link);
+ }
+ }
+
+ /* If this is the head, we need to set new OCMP */
+ if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
+ nrf_timer_set_ocmp(bsptimer, timer->expiry);
+ }
+
+ __HAL_ENABLE_INTERRUPTS(ctx);
+
+ return 0;
+}
+
+/**
+ * hal timer stop
+ *
+ * Stop a timer.
+ *
+ * @param timer
+ *
+ * @return int
+ */
+int
+hal_timer_stop(struct hal_timer *timer)
+{
+ uint32_t ctx;
+ int reset_ocmp;
+ struct hal_timer *entry;
+ struct nrf52_hal_timer *bsptimer;
+
+ if (timer == NULL) {
+ return EINVAL;
+ }
+
+ bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
+
+ __HAL_DISABLE_INTERRUPTS(ctx);
+
+ if (timer->link.tqe_prev != NULL) {
+ reset_ocmp = 0;
+ if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
+ /* If first on queue, we will need to reset OCMP */
+ entry = TAILQ_NEXT(timer, link);
+ reset_ocmp = 1;
+ }
+ TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
+ timer->link.tqe_prev = NULL;
+ if (reset_ocmp) {
+ if (entry) {
+ nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer,
+ entry->expiry);
+ } else {
+ nrf_timer_disable_ocmp(bsptimer->tmr_reg);
+ }
+ }
+ }
+
+ __HAL_ENABLE_INTERRUPTS(ctx);
+
+ return 0;
+}
[2/2] incubator-mynewt-core git commit: MYNEWT-401: HAL Timer
Posted by we...@apache.org.
MYNEWT-401: HAL Timer
This is the initial commit of the HAL Timer API.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/92c6dabd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/92c6dabd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/92c6dabd
Branch: refs/heads/develop
Commit: 92c6dabd1197742da7dace459c1d7b760113fb1d
Parents: e8704de
Author: William San Filippo <wi...@runtime.io>
Authored: Fri Sep 30 15:17:56 2016 -0700
Committer: William San Filippo <wi...@runtime.io>
Committed: Fri Sep 30 15:26:05 2016 -0700
----------------------------------------------------------------------
hw/hal/include/hal/hal_timer.h | 97 +++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/92c6dabd/hw/hal/include/hal/hal_timer.h
----------------------------------------------------------------------
diff --git a/hw/hal/include/hal/hal_timer.h b/hw/hal/include/hal/hal_timer.h
new file mode 100644
index 0000000..1ca48bf
--- /dev/null
+++ b/hw/hal/include/hal/hal_timer.h
@@ -0,0 +1,97 @@
+/**
+ * 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 H_HAL_TIMER_
+#define H_HAL_TIMER_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "os/queue.h"
+
+/* HAL timer struct */
+typedef void (*hal_timer_cb)(void *arg);
+
+/**
+ * The HAL timer structure. The user can declare as many of these structures
+ * as desired. They are enqueued on a particular HW timer queue when the user
+ * calls the hal_timer_start or hal_timer_start_at API. The user must have
+ * called hal_timer_set_cb before starting a timer.
+ *
+ * NOTE: the user should not have to modify/examine the contents of this
+ * structure; the hal timer API should be used.
+ */
+struct hal_timer
+{
+ void *bsp_timer; /* Internal platform specific pointer */
+ hal_timer_cb cb_func; /* Callback function */
+ void *cb_arg; /* Callback argument */
+ uint32_t expiry; /* Tick at which timer should expire */
+ TAILQ_ENTRY(hal_timer) link; /* Queue linked list structure */
+};
+
+/*
+ * Initialize a HW timer at the given frequency and start it. If the exact
+ * frequency is not obtainable the closest obtainable frequency is set.
+ */
+int hal_timer_init(int timer_num, uint32_t freq_hz);
+
+/* Un-initialize a HW timer. */
+int hal_timer_deinit(int timer_num);
+
+/*
+ * Returns the resolution of the HW timer. NOTE: the frequency may not be
+ * obtainable so the caller can use this to determine the resolution.
+ * Returns resolution in nanoseconds. A return value of 0 indicates an invalid
+ * timer was used.
+ */
+uint32_t hal_timer_get_resolution(int timer_num);
+
+/* Returns the HW timer current tick value */
+uint32_t hal_timer_read(int timer_num);
+
+/* Perform a blocking delay for a number of ticks. */
+int hal_timer_delay(int timer_num, uint32_t ticks);
+
+/*
+ * Set the timer structure prior to use. Should not be called if the timer
+ * is running. Must be called at least once prior to using timer.
+ */
+int hal_timer_set_cb(int timer_num, struct hal_timer *tmr, hal_timer_cb cb_func,
+ void *arg);
+
+/* Start a timer that will expire in 'ticks' ticks. Ticks cannot be 0 */
+int hal_timer_start(struct hal_timer *, uint32_t ticks);
+
+/*
+ * Start a timer that will expire when the timer reaches 'tick'. If tick
+ * has already passed the timer callback will be called "immediately" (at
+ * interrupt context).
+ */
+int hal_timer_start_at(struct hal_timer *, uint32_t tick);
+
+/* Stop a currently running timer; associated callback will NOT be called */
+int hal_timer_stop(struct hal_timer *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_HAL_TIMER_ */