From 882b0fc2c8b4859119540cd98c5d3d5c320406da Mon Sep 17 00:00:00 2001 From: MacRsh Date: Fri, 17 Nov 2023 01:35:43 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E5=AE=9A=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=88=E9=9B=86=E6=88=90=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E3=80=81PWM=EF=BC=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dev/timer.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ dev/timer.h | 107 +++++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 dev/timer.c create mode 100644 dev/timer.h diff --git a/dev/timer.c b/dev/timer.c new file mode 100644 index 0000000..033d222 --- /dev/null +++ b/dev/timer.c @@ -0,0 +1,169 @@ +/* + * @copyright (c) 2023, MR Development Team + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2023-11-15 MacRsh First version + */ + +#include "timer.h" + +#ifdef MR_USING_TIMER + +static int mr_timer_open(struct mr_dev *dev) +{ + struct mr_timer *timer = (struct mr_timer *)dev; + struct mr_timer_ops *ops = (struct mr_timer_ops *)dev->drv->ops; + + return ops->configure(timer, MR_ENABLE); +} + +static int mr_timer_close(struct mr_dev *dev) +{ + struct mr_timer *timer = (struct mr_timer *)dev; + struct mr_timer_ops *ops = (struct mr_timer_ops *)dev->drv->ops; + + return ops->configure(timer, MR_DISABLE); +} + +static ssize_t mr_timer_write(struct mr_dev *dev, int off, const void *buf, size_t size, int sync_or_async) +{ + struct mr_timer *timer = (struct mr_timer *)dev; + struct mr_timer_ops *ops = (struct mr_timer_ops *)dev->drv->ops; + uint32_t *wr_buf = (uint32_t *)buf; + uint32_t data = 0; + ssize_t wr_size = 0; + + if (timer->config.mode == MR_TIMER_MODE_TIMING) + { + uint32_t timeout = 0; + + /* Only the last valid data will be written */ + mr_bits_clr(size, sizeof(*wr_buf) - 1); + for (wr_size = 0; wr_size < size; wr_size += sizeof(*wr_buf)) + { + timeout = *wr_buf; + wr_buf++; + } + + /* Stop timer */ + ops->stop(timer); + + /* Calculate reload value */ + timer->reload = (uint32_t)(((float)timeout / 1000000.0f) * (float)timer->config.freq + 0.5f); + + ops->start(timer, timer->prescaler, timer->reload); + } + + return wr_size; +} + +static int mr_timer_ioctl(struct mr_dev *dev, int off, int cmd, void *args) +{ + struct mr_timer *timer = (struct mr_timer *)dev; + struct mr_timer_ops *ops = (struct mr_timer_ops *)dev->drv->ops; + + switch (cmd) + { + case MR_CTRL_SET_CONFIG: + { + if (args != MR_NULL) + { + struct mr_timer_config *config = (struct mr_timer_config *)args; + uint32_t count = 0, prescaler = 0; + int error_min = INT32_MAX; + + /* Too large frequency */ + if (config->freq > timer->info.clk || config->freq == 0) + { + return MR_EINVAL; + } + + /* Stop timer */ + ops->stop(timer); + + /* Calculate period and prescaler */ + if (timer->config.freq != config->freq) + { + count = timer->info.clk / config->freq; + for (prescaler = (count / timer->info.period_max) + 1; prescaler < timer->info.prescaler_max; + prescaler++) + { + uint32_t period = 0; + int error = 0; + + period = count / prescaler; + error = (int)(count - (prescaler * period)); + + /* Allowable error <= 1 */ + if (error <= 1) + { + timer->period = period; + break; + } + + /* Update error */ + if (error < error_min) + { + error_min = error; + timer->period = period; + } + } + timer->prescaler = count / timer->period; + } + timer->config = *config; + + /* Start timer if mode is PWM */ + if (timer->config.mode == MR_TIMER_MODE_PWM) + { + ops->start(timer, timer->prescaler, timer->period); + } + return MR_EOK; + } + return MR_EINVAL; + } + + case MR_CTRL_TIMER_SET_CHANNEL_STATE: + { + if (args != MR_NULL) + { + int mode = *((int *)args); + + + } + return MR_EINVAL; + } + + default: + { + return MR_ENOTSUP; + } + } +} + +int mr_timer_register(struct mr_timer *timer, const char *name, struct mr_drv *drv, struct mr_timer_info *info) +{ + static struct mr_dev_ops ops = + { + mr_timer_open, + mr_timer_close, + MR_NULL, + mr_timer_write, + mr_timer_ioctl + }; + struct mr_timer_config default_config = MR_TIMER_CONFIG_DEFAULT; + + mr_assert(timer != MR_NULL); + mr_assert(name != MR_NULL); + mr_assert(drv != MR_NULL); + mr_assert(drv->ops != MR_NULL); + mr_assert(info != MR_NULL); + + /* Initialize the fields */ + timer->info = *info; + timer->config = default_config; + + return mr_dev_register(&timer->dev, name, Mr_Dev_Type_Timer, MR_SFLAG_RDWR, &ops, drv); +} + +#endif /* MR_USING_TIMER */ diff --git a/dev/timer.h b/dev/timer.h new file mode 100644 index 0000000..4352b83 --- /dev/null +++ b/dev/timer.h @@ -0,0 +1,107 @@ +/* + * @copyright (c) 2023, MR Development Team + * + * @license SPDX-License-Identifier: Apache-2.0 + * + * @date 2023-11-15 MacRsh First version + */ + +#ifndef _PWM_H_ +#define _PWM_H_ + +#include "mr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef MR_USING_TIMER + +/** +* @brief Timer channel mode. +*/ +#define MR_TIMER_MODE_NONE (0) +#define MR_TIMER_MODE_TIMING (1) +#define MR_TIMER_MODE_PWM (2) + +#define MR_TIMER_TRIGGER_MODE_PERIODIC (0) +#define MR_TIMER_TRIGGER_MODE_ONESHOT (1) + +/** +* @brief Timer default configuration. +*/ +#define MR_TIMER_CONFIG_DEFAULT \ +{ \ + 1000, \ +} + +/** + * @brief Timer configuration structure. + */ +struct mr_timer_config +{ + uint32_t freq; /* Frequency */ + uint32_t mode: 2; /* Mode */ + uint32_t trigger_mode: 1; +}; + +/** + * @brief Timer channel mode command. + */ +#define MR_CTRL_TIMER_SET_CHANNEL_STATE ((0x01|0x80) << 16) /**< Set channel mode */ +#define MR_CTRL_TIMER_GET_CHANNEL_STATE ((0x01|0x00) << 16) /**< Get channel mode */ + +#define MR_CTRL_TIMER_SET_TIMING ((0x02|0x80) << 16) /**< Set timing */ + +struct mr_timer_info +{ + uint32_t clk; /* Clock */ + uint32_t prescaler_max; + uint32_t period_max; +}; + +/** + * @brief Timer data type. + */ +typedef uint8_t mr_timer_data_t; /**< Timer read/write data type */ + +/** + * @brief Timer structure. + */ +struct mr_timer +{ + struct mr_dev dev; /* Device */ + + struct mr_timer_info info; /* Information */ + struct mr_timer_config config; /* Config */ + uint32_t channel; /* Channel */ + uint32_t prescaler; /* Prescaler */ + uint32_t period; /* Period */ + uint32_t reload; +}; + +/** + * @brief Timer operations structure. + */ +struct mr_timer_ops +{ + int (*configure)(struct mr_timer *timer, int state); + int (*channel_configure)(struct mr_timer *timer, int channel, int mode); + void (*start)(struct mr_timer *timer, uint32_t prescaler, uint32_t period); + void (*stop)(struct mr_timer *timer); +}; + +/** + * @addtogroup Timer. + * @{ + */ +int mr_timer_register(struct mr_timer *timer, const char *name, struct mr_drv *drv, struct mr_timer_info *info); +/** @} */ + +#endif /* MR_USING_TIMER */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _PWM_H_ */