瀏覽代碼

Merge pull request #5297 from chenyingchun0312/fea_nrf5x_hwtimer

[bsp/nrf5x] add hwtimer driver
Bernard Xiong 3 年之前
父節點
當前提交
3bc5ffb495

二進制
bsp/nrf5x/docs/images/nrf52832.png


+ 3 - 0
bsp/nrf5x/libraries/drivers/SConscript

@@ -39,6 +39,9 @@ if GetDepend(['BSP_USING_WDT']):
 
 if GetDepend(['BSP_USING_ONCHIP_RTC']):
     src += ['drv_rtc.c']
+    
+if GetDepend(['BSP_USING_TIM']):
+    src += ['drv_hwtimer.c']
 
 path =  [cwd]
 

+ 321 - 0
bsp/nrf5x/libraries/drivers/drv_hwtimer.c

@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-11-21     chenyingchun first version
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <board.h>
+#include <nrfx_timer.h>
+
+#ifdef SOFTDEVICE_PRESENT
+#ifdef BSP_USING_TIM0
+#error "TIMER0 cannot be used when SOFTDEVICE has been used."
+#endif
+#endif
+
+#ifdef BSP_USING_TIM
+
+#define LOG_TAG             "drv.hwtimer"
+#define DBG_LVL              DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_HWTIMER
+
+#ifndef TIM_DEV_INFO_CONFIG
+// maxfreq and minfreq unit is HZ
+#define TIM_DEV_INFO_CONFIG                     \
+    {                                           \
+        .maxfreq = 16000000,                    \
+        .minfreq = 31250,                       \
+        .maxcnt  = 0xFFFFFFFF,                  \
+        .cntmode = HWTIMER_CNTMODE_UP,          \
+    }
+#endif
+
+typedef struct
+{
+    nrfx_timer_t            timer_inst;
+    nrfx_timer_config_t     timer_cfg;
+    nrf_timer_cc_channel_t  cc_channel;
+}nrf5x_timer_info_t;
+
+struct nrf5x_hwtimer
+{
+    rt_hwtimer_t            timer_device;
+    nrf5x_timer_info_t      timer_info;
+    char                    *name;
+};
+
+static struct nrf5x_hwtimer nrf5x_hwtimer_obj[] =
+{
+#ifdef BSP_USING_TIM0
+    {
+       .timer_info.timer_inst = NRFX_TIMER_INSTANCE(0),
+       .timer_info.timer_cfg  = NRFX_TIMER_DEFAULT_CONFIG,
+       .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL0,
+       .name                  = "timer0",
+    },
+#endif
+
+#ifdef BSP_USING_TIM1
+    {
+       .timer_info.timer_inst = NRFX_TIMER_INSTANCE(1),
+       .timer_info.timer_cfg  = NRFX_TIMER_DEFAULT_CONFIG,
+       .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL1,
+       .name                  = "timer1",
+    },
+#endif
+
+#ifdef BSP_USING_TIM2
+     {
+        .timer_info.timer_inst = NRFX_TIMER_INSTANCE(2),
+        .timer_info.timer_cfg  = NRFX_TIMER_DEFAULT_CONFIG,
+        .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL2,
+        .name                  = "timer2",
+     },
+#endif
+
+#ifdef BSP_USING_TIM3
+     {
+        .timer_info.timer_inst = NRFX_TIMER_INSTANCE(3),
+        .timer_info.timer_cfg  = NRFX_TIMER_DEFAULT_CONFIG,
+        .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL3,
+        .name                  = "timer3",
+     },
+#endif
+
+#ifdef BSP_USING_TIM4
+     {
+        .timer_info.timer_inst = NRFX_TIMER_INSTANCE(4),
+        .timer_info.timer_cfg  = NRFX_TIMER_DEFAULT_CONFIG,
+        .timer_info.cc_channel = NRF_TIMER_CC_CHANNEL4,
+        .name                  = "timer4",
+     }
+#endif
+};
+
+static void timer_callback(nrf_timer_event_t event_type, void* p_context)
+{
+    rt_hwtimer_t       *timer_device = (struct rt_hwtimer_device *)p_context;
+
+    // no matter what event_type is(NRF_TIMER_EVENT_COMPARE0 or others), call same function "rt_device_hwtimer_isr"
+    LOG_D("timer_callback event_type = %d, inst_id = %d, cc conunt = %d\r\n",
+           event_type, timer_info->timer_inst.instance_id, timer_info->timer_inst.cc_channel_count);
+    rt_device_hwtimer_isr(timer_device);
+}
+
+static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
+{
+    nrf5x_timer_info_t *timer_info   = RT_NULL;
+    nrfx_timer_config_t *timer_cfg   = RT_NULL;
+
+    RT_ASSERT(timer != RT_NULL);
+    if (state)
+    {
+        timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
+        timer_cfg  = &(timer_info->timer_cfg);
+        timer_cfg->bit_width = NRF_TIMER_BIT_WIDTH_32;
+        timer_cfg->p_context = timer;
+
+        nrfx_timer_init(&(timer_info->timer_inst), timer_cfg, timer_callback);
+    }
+}
+
+static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
+{
+    nrf5x_timer_info_t *timer_info   = RT_NULL;
+    nrf_timer_short_mask_t mask = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK;
+
+    RT_ASSERT(timer != RT_NULL);
+
+    timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
+
+    if (opmode == HWTIMER_MODE_ONESHOT)
+    {
+        // means TIMER_SHORTS_COMPARE0_STOP_Msk or TIMER_SHORTS_COMPARE1_STOP_Msk ..., according to cc_channel.
+        mask = (nrf_timer_short_mask_t)(1 << (timer_info->cc_channel + 8));
+    }
+    else
+    {
+        // means TIMER_SHORTS_COMPARE0_CLEAR_Msk or TIMER_SHORTS_COMPARE1_CLEAR_Msk ..., according to cc_channel.
+        mask = (nrf_timer_short_mask_t)(1 << timer_info->cc_channel);
+    }
+
+    nrfx_timer_extended_compare(&(timer_info->timer_inst), timer_info->cc_channel, t, mask, true);
+    nrfx_timer_enable(&(timer_info->timer_inst));
+    return RT_EOK;
+}
+
+static void timer_stop(rt_hwtimer_t *timer)
+{
+    nrf5x_timer_info_t *timer_info = RT_NULL;
+
+    RT_ASSERT(timer != RT_NULL);
+
+    timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
+
+    nrfx_timer_disable(&(timer_info->timer_inst));
+
+    /* set time count register to zero*/
+    nrfx_timer_clear(&(timer_info->timer_inst));
+}
+
+static nrf_timer_frequency_t frequency_convert(rt_uint32_t freq)
+{
+    nrf_timer_frequency_t frequency = NRF_TIMER_FREQ_1MHz;
+    switch (freq)
+    {
+        case 16000000:
+        {
+            frequency = NRF_TIMER_FREQ_16MHz;
+            break;
+        }
+
+        case 8000000:
+        {
+            frequency = NRF_TIMER_FREQ_8MHz;
+            break;
+        }
+
+        case 2000000:
+        {
+            frequency = NRF_TIMER_FREQ_2MHz;
+            break;
+        }
+
+        case 1000000:
+        {
+            frequency = NRF_TIMER_FREQ_1MHz;
+            break;
+        }
+
+        case 500000:
+        {
+            frequency = NRF_TIMER_FREQ_500kHz;
+            break;
+        }
+
+        case 250000:
+        {
+            frequency = NRF_TIMER_FREQ_250kHz;
+            break;
+        }
+
+        case 125000:
+        {
+            frequency = NRF_TIMER_FREQ_125kHz;
+            break;
+        }
+
+         case 62500:
+        {
+            frequency = NRF_TIMER_FREQ_62500Hz;
+            break;
+        }
+
+        case 31250:
+        {
+            frequency = NRF_TIMER_FREQ_31250Hz;
+            break;
+        }
+
+        default:
+        {
+            break;
+        }
+    }
+
+    return frequency;
+}
+
+static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
+{
+    rt_err_t result = RT_EOK;
+    nrf5x_timer_info_t *timer_info = RT_NULL;
+    nrfx_timer_t *timer_inst = RT_NULL;
+
+    RT_ASSERT(timer != RT_NULL);
+    RT_ASSERT(arg != RT_NULL);
+
+    timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
+    timer_inst = &(timer_info->timer_inst);
+
+    switch (cmd)
+    {
+        case HWTIMER_CTRL_FREQ_SET:
+        {
+            rt_uint32_t freq;
+            /* set timer frequence */
+            freq = *((rt_uint32_t *)arg);
+
+            nrf_timer_frequency_set(timer_inst->p_reg, frequency_convert(freq));
+            break;
+        }
+        default:
+        {
+            result = -RT_ENOSYS;
+            break;
+        }
+
+    }
+
+    return result;
+}
+
+static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
+{
+    rt_uint32_t count = 0;
+    nrf5x_timer_info_t *timer_info = RT_NULL;
+
+    RT_ASSERT(timer != RT_NULL);
+
+    timer_info = (nrf5x_timer_info_t *)timer->parent.user_data;
+
+    // capture method will copy the current counter register to the specified cc channel (here is NRF_TIMER_CC_CHANNEL5).
+    // the specified cc channel cannot be same with the already used cc channels
+    count = nrfx_timer_capture(&(timer_info->timer_inst), NRF_TIMER_CC_CHANNEL5);
+    return count;
+}
+
+static const struct rt_hwtimer_info _info = TIM_DEV_INFO_CONFIG;
+static const struct rt_hwtimer_ops _ops =
+{
+    .init = timer_init,
+    .start = timer_start,
+    .stop = timer_stop,
+    .count_get = timer_counter_get,
+    .control = timer_ctrl,
+};
+
+static int nrf5x_hwtimer_init(void)
+{
+    int i = 0;
+    int result = RT_EOK;
+
+    for (i = 0; i < sizeof(nrf5x_hwtimer_obj) / sizeof(nrf5x_hwtimer_obj[0]); i++)
+    {
+        nrf5x_hwtimer_obj[i].timer_device.info = &_info;
+        nrf5x_hwtimer_obj[i].timer_device.ops  = &_ops;
+        if (rt_device_hwtimer_register(&nrf5x_hwtimer_obj[i].timer_device, nrf5x_hwtimer_obj[i].name, &nrf5x_hwtimer_obj[i].timer_info) == RT_EOK)
+        {
+            LOG_D("%s register success", nrf5x_hwtimer_obj[i].name);
+        }
+        else
+        {
+            LOG_E("%s register failed", nrf5x_hwtimer_obj[i].name);
+            result = -RT_ERROR;
+        }
+    }
+
+    return result;
+}
+INIT_BOARD_EXPORT(nrf5x_hwtimer_init);
+
+#endif /* RT_USING_HWTIMER */
+#endif /* BSP_USING_TIM */
+

+ 12 - 12
bsp/nrf5x/nrf52832/README.md

@@ -14,7 +14,7 @@ PCA10040-nRF52832是Nordic 官方的开发板,搭载nRF52832 芯片,基于AR
 
 开发板外观如下图所示
 
-![](../docs/images/nrf52832.jpg)
+![](../docs/images/nrf52832.png)
 
 PCA10040-nrf52832开发板常用 **板载资源** 如下:
 
@@ -34,17 +34,17 @@ PCA10040-nrf52832开发板常用 **板载资源** 如下:
 
 本 BSP 目前对外设的支持情况如下:
 
-| **片上外设** | **支持情况** | **备注** |
-| :----------- | :----------: | :------: |
-| GPIO         |     支持     |  GPION   |
-| UART         |     支持     |  UART0   |
-| PWM          |     支持     |   支持   |
-| SPI          |     支持     |   支持   |
-| RTC          |     支持     |          |
-| ADC          |     支持     |          |
-|              |              |          |
-|              |              |          |
-|              |              |          |
+| **片上外设** | **支持情况** |   **备注**    |
+| :----------- | :----------: | :-----------: |
+| GPIO         |     支持     |     GPION     |
+| UART         |     支持     |     UART0     |
+| PWM          |     支持     |     支持      |
+| SPI          |     支持     |     支持      |
+| RTC          |     支持     |               |
+| ADC          |     支持     |               |
+| TIMER        |     支持     | TIMER0~TIMER4 |
+|              |              |               |
+|              |              |               |
 
 
 

+ 51 - 0
bsp/nrf5x/nrf52832/board/Kconfig

@@ -419,6 +419,57 @@ menu "On-chip Peripheral Drivers"
             range 0 2
             default 2
     endif
+
+    config BSP_USING_TIM
+        bool "Enable TIMER"
+        select RT_USING_HWTIMER
+        default n
+        if BSP_USING_TIM
+            config NRFX_TIMER_ENABLED
+            int 
+            default 1
+            config BSP_USING_TIM0
+                bool "Enable TIMER0"
+                default n
+            if BSP_USING_TIM0
+                config NRFX_TIMER0_ENABLED
+                int 
+                default 1
+            endif
+            config BSP_USING_TIM1
+                bool "Enable TIMER1"
+                default n
+            if BSP_USING_TIM1
+                config NRFX_TIMER1_ENABLED
+                int 
+                default 1
+            endif
+            config BSP_USING_TIM2
+                bool "Enable TIMER2"
+                default n
+            if BSP_USING_TIM2
+                config NRFX_TIMER2_ENABLED
+                int 
+                default 1
+            endif
+            config BSP_USING_TIM3
+                bool "Enable TIMER3"
+                default n
+            if BSP_USING_TIM3
+                config NRFX_TIMER3_ENABLED
+                int 
+                default 1
+            endif
+
+            config BSP_USING_TIM4
+                bool "Enable TIMER4"
+                default n
+            if BSP_USING_TIM4
+                config NRFX_TIMER4_ENABLED
+                int 
+                default 1
+            endif
+        endif
 endmenu
 
 choice