当前文档版本为v0.3.0,您可以访问 开发中 的文档以获取最近可能的更新。

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连续计数模式

  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);
    }
    
  2. 获取设备并配置定时时间

    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值*/
    
  3. 启动COUNTER。

    err = counter_start(dev);
    if (err != 0) {
        LOG_INF("Counter failed to start\n");
    }
    
  4. 设置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. 观测打印信息,查看获取的比较值与期望值是否符合,打印信息如下:

    continues_run

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);