Driver: Counter¶
1 功能概述¶
该sample演示了外设模块COUNTER的连续计数功能,间隔20ms触发一次中断。
2 环境要求¶
PAN1080 EVB一块
Micro USB线一条(用于供电和查看串口打印Log)
硬件接线:
使用USB线,将PC USB与EVB MicroUSB(USB->UART)相连
使用杜邦线将EVB上的:
UART1 TX与P06相连
UART1 RX与P07相连
PC软件: 串口调试助手(UartAssist)或终端工具(SecureCRT),波特率921600
3 编译和烧录¶
例程位置:zephyr\samples_panchip\drivers\counter
目前可使用ZAL工具或quick build脚本进行编译和下载。
脚本位置:quick_build_samples\drivers\counter.bat
打开脚本后默认会编译项目,编译完成时,可输入字符进行后续下载等操作:
Input the keyword to continue:
'b' build 编译项目
'r' make clean and rebuild 重新编译项目
'f' flash download 下载
'e' erase chip 擦除芯片
'o' open project by VS Code 打开 `VS Code`,可查看源码,执行编译下载等
others exit 退出
wait input:
4 演示说明¶
4.1连续计数模式¶
设置回调函数
static void top_handler(const struct device *dev, void *user_data) { uint32_t cnt; counter_get_value(dev, &cnt); /*获取中断产生时的计数器值*/ if (last_cnt > cnt) { cnt = cnt + 0xffffff - last_cnt; } LOG_INF("isr,expect counter is 320000, meas count is %d", cnt - last_cnt); last_cnt = cnt; /*保存上一次中断计数器值*/ if (user_data != exp_user_data) { LOG_INF("Unexpected callback\n"); } if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { top_cnt++; return; } k_sem_give(&top_cnt_sem); }
获取设备并配置定时时间
dev = device_get_binding(DT_LABEL(DT_INST(0, panchip_pan_timer))); if (!dev) { LOG_INF("Cannot get timer0 device\n"); } else { /* if more counter drivers exist other than RTC, * the test value set to 20000 by default */ counter_period_us = 20000; /*20ms*/ } top_cfg.ticks = counter_us_to_ticks(dev, counter_period_us); /*转换为tick值*/
启动COUNTER。
err = counter_start(dev); if (err != 0) { LOG_INF("Counter failed to start\n"); }
设置COUNTER比较值。
err = counter_set_top_value(dev, &top_cfg); if (err != 0) { LOG_INF("Counter failed to set top value (err: %d)\n", err); }
观测打印信息,查看获取的比较值与期望值是否符合,打印信息如下:
5开发说明¶
5.1 启用COUNTER模块¶
在prj.conf文件中添加“CONFIG_COUNTER=y”启用COUNTER模块。
CONFIG_COUNTER=y
CONFIG_COUNTER_PANCHIP_TIMER0=y
5.2 COUNTER数据结构及参数含义¶
计数器配置
/** @brief Top value configuration structure.
*
* @param ticks Top value.
* @param callback Callback function. Can be NULL.
* @param user_data User data passed to callback function. Not valid if
* callback is NULL.
* @param flags Flags. See @ref COUNTER_TOP_FLAGS.
*/
struct counter_top_cfg {
uint32_t ticks;
counter_top_callback_t callback;
void *user_data;
uint32_t flags;
};
到点警报配置
/** @brief Alarm callback structure.
*
* @param callback Callback called on alarm (cannot be NULL).
* @param ticks Number of ticks that triggers the alarm. It can be relative (to
* now) or absolute value (see @ref COUNTER_ALARM_CFG_ABSOLUTE).
* Absolute alarm cannot be set further in future than top_value
* decremented by the guard period. Relative alarm ticks cannot
* exceed current top value (see @ref counter_get_top_value).
* If counter is clock driven then ticks can be converted to
* microseconds (see @ref counter_ticks_to_us). Alternatively,
* counter implementation may count asynchronous events.
* @param user_data User data returned in callback.
* @param flags Alarm flags. See @ref COUNTER_ALARM_FLAGS.
*/
struct counter_alarm_cfg {
counter_alarm_callback_t callback;
uint32_t ticks;
void *user_data;
uint32_t flags;
};
5.3 COUNTER API接口¶
接口总览
__subsystem struct counter_driver_api {
counter_api_start start;
counter_api_stop stop;
counter_api_get_value get_value;
counter_api_set_alarm set_alarm;
counter_api_cancel_alarm cancel_alarm;
counter_api_set_top_value set_top_value;
counter_api_get_pending_int get_pending_int;
counter_api_get_top_value get_top_value;
counter_api_get_guard_period get_guard_period; /*暂不支持*/
counter_api_set_guard_period set_guard_period; /*暂不支持*/
};
启动counter,开始计数
/**
* @brief Start counter device in free running mode.
*
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 0 If successful.
* @retval Negative errno code if failure.
*/
__syscall int counter_start(const struct device *dev);
停止counter,暂停计数
/**
* @brief Stop counter device.
*
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 0 If successful.
* @retval -ENOTSUP if the device doesn't support stopping the
* counter.
*/
__syscall int counter_stop(const struct device *dev);
获取counter计数器值
/**
* @brief Get current counter value.
* @param dev Pointer to the device structure for the driver instance.
* @param ticks Pointer to where to store the current counter value
*
* @retval 0 If successful.
* @retval Negative error code on failure getting the counter value
*/
__syscall int counter_get_value(const struct device *dev, uint32_t *ticks);
设置到点警报
/**
* @brief Set a single shot alarm on a channel.
*
* After expiration alarm can be set again, disabling is not needed. When alarm
* expiration handler is called, channel is considered available and can be
* set again in that context.
*
* @note API is not thread safe.
*
* @param dev Pointer to the device structure for the driver instance.
* @param chan_id Channel ID.
* @param alarm_cfg Alarm configuration.
*
* @retval 0 If successful.
* @retval -ENOTSUP if request is not supported (device does not support
* interrupts or requested channel).
* @retval -EINVAL if alarm settings are invalid.
* @retval -ETIME if absolute alarm was set too late.
*/
__syscall int counter_set_channel_alarm(const struct device *dev,
uint8_t chan_id,
const struct counter_alarm_cfg *alarm_cfg);
取消到点警报
/**
* @brief Cancel an alarm on a channel.
*
* @note API is not thread safe.
*
* @param dev Pointer to the device structure for the driver instance.
* @param chan_id Channel ID.
*
* @retval 0 If successful.
* @retval -ENOTSUP if request is not supported or the counter was not started
* yet.
*/
__syscall int counter_cancel_channel_alarm(const struct device *dev,
uint8_t chan_id);
设置比较值
/**
* @brief Set counter top value.
*
* Function sets top value and optionally resets the counter to 0 or top value
* depending on counter direction. On turnaround, counter can be reset and
* optional callback is periodically called. Top value can only be changed when
* there is no active channel alarm.
*
* @ref COUNTER_TOP_CFG_DONT_RESET prevents counter reset. When counter is
* running while top value is updated, it is possible that counter progresses
* outside the new top value. In that case, error is returned and optionally
* driver can reset the counter (see @ref COUNTER_TOP_CFG_RESET_WHEN_LATE).
*
* @param dev Pointer to the device structure for the driver instance.
* @param cfg Configuration. Cannot be NULL.
*
* @retval 0 If successful.
* @retval -ENOTSUP if request is not supported (e.g. top value cannot be
* changed or counter cannot/must be reset during top value
update).
* @retval -EBUSY if any alarm is active.
* @retval -ETIME if @ref COUNTER_TOP_CFG_DONT_RESET was set and new top value
* is smaller than current counter value (counter counting up).
*/
__syscall int counter_set_top_value(const struct device *dev,
const struct counter_top_cfg *cfg);
获取中断标志
/**
* @brief Function to get pending interrupts
*
* The purpose of this function is to return the interrupt
* status register for the device.
* This is especially useful when waking up from
* low power states to check the wake up source.
*
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 1 if any counter interrupt is pending.
* @retval 0 if no counter interrupt is pending.
*/
__syscall int counter_get_pending_int(const struct device *dev);
获取设置的比较值
/**
* @brief Function to retrieve current top value.
*
* @param[in] dev Pointer to the device structure for the driver instance.
*
* @return Top value.
*/
__syscall uint32_t counter_get_top_value(const struct device *dev);
获取设置的比较值
/**
* @brief Function to retrieve current top value.
*
* @param[in] dev Pointer to the device structure for the driver instance.
*
* @return Top value.
*/
__syscall uint32_t counter_get_top_value(const struct device *dev);