Merge pull request #5297 from chenyingchun0312/fea_nrf5x_hwtimer
[bsp/nrf5x] add hwtimer driver
This commit is contained in:
commit
3bc5ffb495
Binary file not shown.
After Width: | Height: | Size: 730 KiB |
|
@ -40,6 +40,9 @@ if GetDepend(['BSP_USING_WDT']):
|
||||||
if GetDepend(['BSP_USING_ONCHIP_RTC']):
|
if GetDepend(['BSP_USING_ONCHIP_RTC']):
|
||||||
src += ['drv_rtc.c']
|
src += ['drv_rtc.c']
|
||||||
|
|
||||||
|
if GetDepend(['BSP_USING_TIM']):
|
||||||
|
src += ['drv_hwtimer.c']
|
||||||
|
|
||||||
path = [cwd]
|
path = [cwd]
|
||||||
|
|
||||||
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)
|
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -14,7 +14,7 @@ PCA10040-nRF52832是Nordic 官方的开发板,搭载nRF52832 芯片,基于AR
|
||||||
|
|
||||||
开发板外观如下图所示
|
开发板外观如下图所示
|
||||||
|
|
||||||
![](../docs/images/nrf52832.jpg)
|
![](../docs/images/nrf52832.png)
|
||||||
|
|
||||||
PCA10040-nrf52832开发板常用 **板载资源** 如下:
|
PCA10040-nrf52832开发板常用 **板载资源** 如下:
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ PCA10040-nrf52832开发板常用 **板载资源** 如下:
|
||||||
本 BSP 目前对外设的支持情况如下:
|
本 BSP 目前对外设的支持情况如下:
|
||||||
|
|
||||||
| **片上外设** | **支持情况** | **备注** |
|
| **片上外设** | **支持情况** | **备注** |
|
||||||
| :----------- | :----------: | :------: |
|
| :----------- | :----------: | :-----------: |
|
||||||
| GPIO | 支持 | GPION |
|
| GPIO | 支持 | GPION |
|
||||||
| UART | 支持 | UART0 |
|
| UART | 支持 | UART0 |
|
||||||
| PWM | 支持 | 支持 |
|
| PWM | 支持 | 支持 |
|
||||||
| SPI | 支持 | 支持 |
|
| SPI | 支持 | 支持 |
|
||||||
| RTC | 支持 | |
|
| RTC | 支持 | |
|
||||||
| ADC | 支持 | |
|
| ADC | 支持 | |
|
||||||
| | | |
|
| TIMER | 支持 | TIMER0~TIMER4 |
|
||||||
| | | |
|
| | | |
|
||||||
| | | |
|
| | | |
|
||||||
|
|
||||||
|
|
|
@ -419,6 +419,57 @@ menu "On-chip Peripheral Drivers"
|
||||||
range 0 2
|
range 0 2
|
||||||
default 2
|
default 2
|
||||||
endif
|
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
|
endmenu
|
||||||
|
|
||||||
choice
|
choice
|
||||||
|
|
Loading…
Reference in New Issue