feat(device): 设备版本更新v1.0.0

This commit is contained in:
MacRsh
2024-06-10 18:45:26 +08:00
parent 0969cd963e
commit f7f3f87a91
18 changed files with 1781 additions and 904 deletions

View File

@@ -16,13 +16,6 @@ menu "Device configure"
help
This option sets the max number of descriptors.
# AIO
config MR_USE_AIO_EXT
bool "Use extended AIO"
default n
help
This option uses extended asynchronous I/O.
comment "--- Device ---"
# ADC
@@ -31,7 +24,16 @@ menu "Device configure"
# PIN
source "device/pin/Kconfig"
# PWM
source "device/pwm/Kconfig"
# Serial
source "device/serial/Kconfig"
# SPI
source "device/spi/Kconfig"
# Timer
source "device/timer/Kconfig"
endmenu

View File

@@ -6,19 +6,27 @@
* @date 2023-11-06 MacRsh First version
*/
#include "../mr-library/include/device/mr_adc.h"
#include <include/device/mr_adc.h>
#ifdef MR_USE_ADC
#define _ADC_CHANNEL_IS_VALID(_adc, _channel) \
#define _ADC_CHANNEL_IS_VALID(_adc, _channel) \
(((_channel) >= 0) && ((_channel) < (sizeof((_adc)->channels) * 8)))
#define _ADC_CHANNEL_IS_EXISTED(_data, _channel) \
(((_data)->channels & (1 << (_channel))) != 0)
#define _ADC_CHANNEL_IS_ENABLED(_adc, _channel) \
(MR_BIT_IS_SET((_adc)->channels, (1 << (_channel))))
#define _ADC_CHANNEL_IS_EXISTED(_data, _channel) \
(((_data)->channels & (0x1 << (_channel))) != 0)
#define _ADC_CHANNEL_STATE_GET(_adc, _channel) \
(MR_BIT_IS_SET((_adc)->channels, (0x1 << (_channel))))
#define _ADC_CHANNEL_STATE_SET(_adc, _channel, _state) \
do \
{ \
MR_BIT_CLR(adc->channels, (0x1 << channel)); \
MR_BIT_SET(adc->channels, ((_state) << channel)); \
} while (0);
#define _ADC_CHANNEL_IS_ENABLED(_adc, _channel) \
(_ADC_CHANNEL_STATE_GET((_adc), (_channel)) != MR_ADC_CHANNEL_STATE_DISABLE)
MR_INLINE int _adc_channel_configure_set(struct mr_adc *adc, int channel,
const struct mr_adc_config *config)
static int _adc_channel_configure_set(struct mr_adc *adc, int channel,
const struct mr_adc_config *config)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)adc);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
@@ -49,19 +57,13 @@ MR_INLINE int _adc_channel_configure_set(struct mr_adc *adc, int channel,
return ret;
}
/* Enable or disable the channel */
if (config->channel_state == true)
{
MR_BIT_SET(adc->channels, (1 << channel));
} else
{
MR_BIT_CLR(adc->channels, (1 << channel));
}
/* Set the channel state */
_ADC_CHANNEL_STATE_SET(adc, channel, config->channel_state);
return MR_EOK;
}
MR_INLINE int _adc_channel_configure_get(const struct mr_adc *adc, int channel,
struct mr_adc_config *config)
static int _adc_channel_configure_get(const struct mr_adc *adc, int channel,
struct mr_adc_config *config)
{
/* Check if the channel is valid */
if (_ADC_CHANNEL_IS_VALID(adc, channel) == false)
@@ -69,8 +71,8 @@ MR_INLINE int _adc_channel_configure_get(const struct mr_adc *adc, int channel,
return MR_EINVAL;
}
/* Get the channel configure */
config->channel_state = _ADC_CHANNEL_IS_ENABLED(adc, channel);
/* Get the channel state */
config->channel_state = _ADC_CHANNEL_STATE_GET(adc, channel);
return MR_EOK;
}
@@ -104,8 +106,8 @@ static int adc_close(struct mr_device *device)
{
if (_ADC_CHANNEL_IS_ENABLED(adc, i) == true)
{
/* Just close the channel, without clearing the channel mask, and
* the channel will be restored when opened */
/* Just close the channel, without clearing the channel mask, and the channel will be
* restored when opened */
ops->channel_configure(driver, i, false);
}
}
@@ -114,8 +116,7 @@ static int adc_close(struct mr_device *device)
return ops->configure(driver, false);
}
static ssize_t adc_read(struct mr_device *device, int pos, void *buf,
size_t count)
static ssize_t adc_read(struct mr_device *device, int pos, void *buf, size_t count)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_adc_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
@@ -126,18 +127,16 @@ static ssize_t adc_read(struct mr_device *device, int pos, void *buf,
struct mr_adc *adc = (struct mr_adc *)device;
/* Check if the channel is enabled */
if ((_ADC_CHANNEL_IS_VALID(adc, pos) == false) ||
(_ADC_CHANNEL_IS_ENABLED(adc, pos) == false))
if ((_ADC_CHANNEL_IS_VALID(adc, pos) == false) || (_ADC_CHANNEL_IS_ENABLED(adc, pos) == false))
{
return MR_EINVAL;
}
#endif /* MR_USE_ADC_CHECK */
/* Read data */
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, sizeof(*rbuf));
rcount += sizeof(*rbuf))
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, sizeof(*rbuf)); rcount += sizeof(*rbuf))
{
int ret = ops->read(driver, pos, rbuf);
int ret = ops->get(driver, pos, rbuf);
if (ret < 0)
{
/* If no data is read, return the error code */
@@ -156,7 +155,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
switch (cmd)
{
case MR_CMD_ADC_CHANNEL_STATE:
case MR_CMD_ADC_CONFIG:
{
struct mr_adc_config *config = (struct mr_adc_config *)args;
@@ -165,7 +164,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
return MR_EINVAL;
}
/* Set the channel configure */
/* Set the adc channel configure */
int ret = _adc_channel_configure_set(adc, pos, config);
if (ret < 0)
{
@@ -173,7 +172,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
}
return sizeof(*config);
}
case (-MR_CMD_ADC_CHANNEL_STATE):
case (-MR_CMD_ADC_CONFIG):
{
struct mr_adc_config *config = (struct mr_adc_config *)args;
@@ -182,7 +181,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
return MR_EINVAL;
}
/* Get the channel configure */
/* Get the adc channel configure */
int ret = _adc_channel_configure_get(adc, pos, config);
if (ret < 0)
{
@@ -204,7 +203,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
/* Driver does not provide the corresponding information */
if (data == NULL)
{
return MR_EPERM;
return MR_EIO;
}
/* Get the resolution */
@@ -227,8 +226,7 @@ static int adc_ioctl(struct mr_device *device, int pos, int cmd, void *args)
*
* @return The error code.
*/
int mr_adc_register(struct mr_adc *adc, const char *path,
const struct mr_driver *driver)
int mr_adc_register(struct mr_adc *adc, const char *path, const struct mr_driver *driver)
{
MR_ASSERT(adc != NULL);
MR_ASSERT(path != NULL);
@@ -243,8 +241,7 @@ int mr_adc_register(struct mr_adc *adc, const char *path,
adc->channels = 0;
/* Register the adc device */
return mr_device_register((struct mr_device *)adc, path, MR_DEVICE_TYPE_ADC,
&ops, driver);
return mr_device_register((struct mr_device *)adc, path, MR_DEVICE_TYPE_ADC, &ops, driver);
}
#endif /* MR_USE_ADC */

View File

@@ -6,33 +6,30 @@
* @date 2023-11-08 MacRsh First version
*/
#include "../mr-library/include/device/mr_pin.h"
#include <include/device/mr_pin.h>
#ifdef MR_USE_PIN
#define _PIN_IS_VALID(_pin, _number) \
#define _PIN_IS_VALID(_pin, _number) \
(((_number) >= 0) && ((_number) < (sizeof((_pin)->pins) * 4)))
#define _PIN_IS_RDONLY(_data, _number) \
#define _PIN_IS_RDONLY(_data, _number) \
(((_data)->pins[(_number) / 16] & (0x1 << (_number))) != 0)
#define _PIN_IS_WRONLY(_data, _number) \
#define _PIN_IS_WRONLY(_data, _number) \
(((_data)->pins[(_number) / 16] & (0x2 << (_number))) != 0)
#define _PIN_IS_EXISTED(_data, _number) \
#define _PIN_IS_EXISTED(_data, _number) \
(((_data)->pins[(_number) / 16] & (0x3 << (_number))) != 0)
#define _PIN_MODE_SET(_pin, _number, _mode) \
do \
{ \
MR_BIT_CLR((_pin)->pins[(_number) / 16], \
(0x3 << (((_number) % 16) * 2))); \
MR_BIT_SET((_pin)->pins[(_number) / 16], \
((_mode) << (((_number) % 16) * 2))); \
} while (0)
#define _PIN_MODE_GET(_pin, _number) \
#define _PIN_MODE_GET(_pin, _number) \
((uint32_t)((_pin)->pins[(_number) / 16] & (0x3 << (((_number) % 16) * 2))))
#define _PIN_IS_ENABLED(_pin, _number) \
#define _PIN_MODE_SET(_pin, _number, _mode) \
do \
{ \
MR_BIT_CLR((_pin)->pins[(_number) / 16], (0x3 << (((_number) % 16) * 2))); \
MR_BIT_SET((_pin)->pins[(_number) / 16], ((_mode) << (((_number) % 16) * 2))); \
} while (0)
#define _PIN_IS_ENABLED(_pin, _number) \
(_PIN_MODE_GET((_pin), _number) != MR_PIN_MODE_NONE)
MR_INLINE int _pin_configure_set(struct mr_pin *pin, int number,
const struct mr_pin_config *config)
static int _pin_configure_set(struct mr_pin *pin, int number, const struct mr_pin_config *config)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)pin);
struct mr_pin_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
@@ -68,8 +65,7 @@ MR_INLINE int _pin_configure_set(struct mr_pin *pin, int number,
return MR_EOK;
}
MR_INLINE int _pin_configure_get(const struct mr_pin *pin, int number,
struct mr_pin_config *config)
static int _pin_configure_get(const struct mr_pin *pin, int number, struct mr_pin_config *config)
{
/* Check if the pin is valid */
if (_PIN_IS_VALID(pin, number) == false)
@@ -122,23 +118,18 @@ static int pin_close(struct mr_device *device)
return MR_EOK;
}
static ssize_t pin_read(struct mr_device *device, int pos, void *buf,
size_t count)
static ssize_t pin_read(struct mr_device *device, int pos, void *buf, size_t count)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pin_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint8_t *rbuf = (uint8_t *)buf;
ssize_t rcount;
/* Release the read operator lock */
_MR_DEVICE_OPERATOR_RD_CLR(device);
#ifdef MR_USE_PIN_CHECK
struct mr_pin *pin = (struct mr_pin *)device;
/* Check if the pin is enabled */
if ((_PIN_IS_VALID(pin, pos) == false) ||
(_PIN_IS_ENABLED(pin, pos) == false))
if ((_PIN_IS_VALID(pin, pos) == false) || (_PIN_IS_ENABLED(pin, pos) == false))
{
return MR_EINVAL;
}
@@ -147,7 +138,7 @@ static ssize_t pin_read(struct mr_device *device, int pos, void *buf,
/* Read data */
for (rcount = 0; rcount < count; rcount += sizeof(*rbuf))
{
int ret = ops->read(driver, (uint32_t)pos, rbuf);
int ret = ops->get(driver, (uint32_t)pos, rbuf);
if (ret < 0)
{
/* If no data is read, return the error code */
@@ -160,23 +151,18 @@ static ssize_t pin_read(struct mr_device *device, int pos, void *buf,
return rcount;
}
static ssize_t pin_write(struct mr_device *device, int pos, const void *buf,
size_t count)
static ssize_t pin_write(struct mr_device *device, int pos, const void *buf, size_t count)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pin_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
const uint8_t *wbuf = (const uint8_t *)buf;
ssize_t wcount;
/* Release the write operator lock */
_MR_DEVICE_OPERATOR_WR_CLR(device);
#ifdef MR_USE_PIN_CHECK
struct mr_pin *pin = (struct mr_pin *)device;
/* Check if the pin is enabled */
if ((_PIN_IS_VALID(pin, pos) == false) ||
(_PIN_IS_ENABLED(pin, pos) == false))
if ((_PIN_IS_VALID(pin, pos) == false) || (_PIN_IS_ENABLED(pin, pos) == false))
{
return MR_EINVAL;
}
@@ -185,7 +171,7 @@ static ssize_t pin_write(struct mr_device *device, int pos, const void *buf,
/* Write data */
for (wcount = 0; wcount < count; wcount += sizeof(*wbuf))
{
int ret = ops->write(driver, pos, *wbuf);
int ret = ops->set(driver, pos, *wbuf);
if (ret < 0)
{
/* If no data is written, return the error code */
@@ -204,7 +190,7 @@ static int pin_ioctl(struct mr_device *device, int pos, int cmd, void *args)
switch (cmd)
{
case MR_CMD_PIN_MODE:
case MR_CMD_PIN_CONFIG:
{
struct mr_pin_config *config = (struct mr_pin_config *)args;
@@ -221,7 +207,7 @@ static int pin_ioctl(struct mr_device *device, int pos, int cmd, void *args)
}
return sizeof(*config);
}
case (-MR_CMD_PIN_MODE):
case (-MR_CMD_PIN_CONFIG):
{
struct mr_pin_config *config = (struct mr_pin_config *)args;
@@ -256,8 +242,7 @@ static int pin_isr(struct mr_device *device, uint32_t event, void *args)
int *number = (int *)args;
/* Check if the pin is enabled */
if ((_PIN_IS_VALID(pin, *number) == false) ||
(_PIN_IS_ENABLED(pin, *number) == false))
if ((_PIN_IS_VALID(pin, *number) == false) || (_PIN_IS_ENABLED(pin, *number) == false))
{
/* This EXTI will be ignored */
return MR_EINVAL;
@@ -282,9 +267,12 @@ static int pin_isr(struct mr_device *device, uint32_t event, void *args)
*
* @return The error code.
*/
int mr_pin_register(struct mr_pin *pin, const char *path,
const struct mr_driver *driver)
int mr_pin_register(struct mr_pin *pin, const char *path, const struct mr_driver *driver)
{
MR_ASSERT(pin != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL));
static struct mr_device_ops ops = {.open = pin_open,
.close = pin_close,
.read = pin_read,
@@ -292,14 +280,9 @@ int mr_pin_register(struct mr_pin *pin, const char *path,
.ioctl = pin_ioctl,
.isr = pin_isr};
MR_ASSERT(pin != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL));
/* Register the pin */
return mr_device_register((struct mr_device *)pin, path,
MR_DEVICE_TYPE_PIN | MR_DEVICE_TYPE_FDX, &ops,
driver);
MR_DEVICE_TYPE_PIN | MR_DEVICE_TYPE_FDX, &ops, driver);
}
#endif /* MR_USE_PIN */

16
device/pwm/Kconfig Normal file
View File

@@ -0,0 +1,16 @@
menu "PWM configure"
# PWM
config MR_USE_PWM
bool "Use PWM"
default n
help
Use this option allows for the use of PWM.
config MR_USE_PWM_CHECK
bool "Use PWM check"
default y
help
This option allows for the use of PWM check.
endmenu

402
device/pwm/mr_pwm.c Normal file
View File

@@ -0,0 +1,402 @@
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-12-10 MacRsh First version
*/
#include <include/device/mr_pwm.h>
#ifdef MR_USE_PWM
#define _PWM_CHANNEL_IS_VALID(_pwm, _channel) \
(((_channel) >= 0) && ((_channel) < (sizeof((_pwm)->channels) * 4)))
#define _PWM_CHANNEL_IS_EXISTED(_data, _channel) \
(((_data)->channels & (0x1 << (_channel))) != 0)
#define _PWM_CHANNEL_STATE_GET(_pwm, _channel) \
(MR_BIT_IS_SET((_pwm)->channels, (0x1 << ((_channel) * 2))))
#define _PWM_CHANNEL_STATE_SET(_pwm, _channel, _state) \
do \
{ \
MR_BIT_CLR(pwm->channels, (0x1 << ((_channel) * 2))); \
MR_BIT_SET(pwm->channels, ((_state) << ((_channel) * 2))); \
} while (0)
#define _PWM_CHANNEL_POLARITY_GET(_pwm, _channel) \
(MR_BIT_IS_SET((_pwm)->channels, (0x2 << ((_channel) * 2))))
#define _PWM_CHANNEL_POLARITY_SET(_pwm, _channel, _polarity) \
do \
{ \
MR_BIT_CLR(pwm->channels, (0x2 << ((_channel) * 2 + 1))); \
MR_BIT_SET(pwm->channels, ((_polarity) << ((_channel) * 2 + 1))); \
} while (0)
#define _PWM_CHANNEL_IS_ENABLED(_pwm, _channel) \
(_PWM_CHANNEL_STATE_GET((_pwm), (_channel)) != MR_PWM_CHANNEL_STATE_DISABLE)
static int _pwm_channel_configure_set(struct mr_pwm *pwm, int channel,
const struct mr_pwm_config *config)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)pwm);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
struct mr_pwm_driver_data *data = _MR_DRIVER_DATA_GET(driver);
/* Check if the channel is valid */
if (_PWM_CHANNEL_IS_VALID(pwm, channel) == false)
{
return MR_EINVAL;
}
/* Check if the channel is existed */
if ((data != NULL) && (_PWM_CHANNEL_IS_EXISTED(data, channel) == false))
{
return MR_EINVAL;
}
/* Check if the channel is already configured */
if (config->channel_state == _PWM_CHANNEL_IS_ENABLED(pwm, channel))
{
return MR_EOK;
}
/* Configure the channel */
int ret = ops->channel_configure(driver, channel, config->channel_state, config->polarity);
if (ret < 0)
{
return ret;
}
/* Set the channel state and polarity */
_PWM_CHANNEL_STATE_SET(pwm, channel, config->channel_state);
_PWM_CHANNEL_POLARITY_SET(pwm, channel, config->polarity);
return MR_EOK;
}
static int _pwm_channel_configure_get(const struct mr_pwm *pwm, int channel,
struct mr_pwm_config *config)
{
/* Check if the channel is valid */
if (_PWM_CHANNEL_IS_VALID(pwm, channel) == false)
{
return MR_EINVAL;
}
/* Get the channel state and polarity */
config->channel_state = _PWM_CHANNEL_STATE_GET(pwm, channel);
config->polarity = _PWM_CHANNEL_POLARITY_GET(pwm, channel);
return MR_EOK;
}
static int _pwm_freq_calculate(struct mr_pwm *pwm, uint32_t freq)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)pwm);
struct mr_pwm_driver_data *data = _MR_DRIVER_DATA_GET(driver);
uint32_t clk = data->clk, psc_max = data->prescaler_max, per_max = data->period_max;
uint32_t psc_best = 1, per_best = 1;
/* Check driver clock is valid */
if (clk == 0)
{
return MR_EIO;
}
/* Check frequency is valid */
if (freq == 0)
{
return MR_EINVAL;
}
/* Calculate the prescaler and period product */
uint32_t product = clk / freq;
/* If the product is within the maximum period, set it as the period */
if (product <= per_max)
{
psc_best = 1;
per_best = MR_BOUND(product, 1, per_max);
} else
{
int error_min = INT32_MAX;
/* Calculate the least error prescaler and period */
for (uint32_t psc = MR_BOUND(product / per_max, 1, psc_max); psc < psc_max; psc++)
{
uint32_t per = MR_BOUND(product / psc, 1, per_max);
int error = (clk / psc / per) - freq;
/* Found a valid and optimal solution */
if (error == 0)
{
psc_best = psc;
per_best = per;
break;
}
/* Found a valid and optimal solution */
if (error < error_min)
{
error_min = error;
psc_best = psc;
per_best = per;
}
}
}
/* Set pwm parameters */
pwm->prescaler = psc_best;
pwm->period = per_best;
pwm->freq = clk / psc_best / per_best;
return MR_EOK;
}
static int pwm_open(struct mr_device *device)
{
struct mr_pwm *pwm = (struct mr_pwm *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Recover all enabled channels */
for (uint32_t i = 0; i < (sizeof(pwm->channels) * 4); i++)
{
if (_PWM_CHANNEL_IS_ENABLED(pwm, i) == true)
{
ops->channel_configure(driver, i, true, _PWM_CHANNEL_POLARITY_GET(pwm, i));
}
}
/* Enable pwm */
return ops->configure(driver, true);
}
static int pwm_close(struct mr_device *device)
{
struct mr_pwm *pwm = (struct mr_pwm *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Disable all enabled channels */
for (uint32_t i = 0; i < (sizeof(pwm->channels) * 4); i++)
{
if (_PWM_CHANNEL_IS_ENABLED(pwm, i) == true)
{
/* Just close the channel, without clearing the channel mask, and the channel will be
* restored when opened */
ops->channel_configure(driver, i, false, MR_PWM_POLARITY_NORMAL);
}
}
/* Disable pwm */
return ops->configure(driver, false);
}
static ssize_t pwm_read(struct mr_device *device, int pos, void *buf, size_t count)
{
struct mr_pwm *pwm = (struct mr_pwm *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t *rbuf = (uint32_t *)buf;
ssize_t rcount;
#ifdef MR_USE_PWM_CHECK
/* Check if the channel is enabled */
if ((_PWM_CHANNEL_IS_VALID(pwm, pos) == false) || (_PWM_CHANNEL_IS_ENABLED(pwm, pos) == false))
{
return MR_EINVAL;
}
#endif /* MR_USE_PWM_CHECK */
/* Read data */
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, sizeof(*rbuf)); rcount += sizeof(*rbuf))
{
uint32_t pwm_compare;
/* Get the pwm compare */
int ret = ops->get(driver, pos, &pwm_compare);
if (ret < 0)
{
/* If no data is read, return the error code */
return (rcount == 0) ? ret : rcount;
}
/* Calculate the fequency */
*rbuf = ((float)pwm_compare / (float)pwm->period) * 1000000.0f;
rbuf++;
}
/* Return the number of bytes read */
return rcount;
}
static ssize_t pwm_write(struct mr_device *device, int pos, const void *buf, size_t count)
{
struct mr_pwm *pwm = (struct mr_pwm *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t *wbuf = (uint32_t *)buf;
ssize_t wcount;
#ifdef MR_USE_PWM_CHECK
/* Check if the channel is enabled */
if ((_PWM_CHANNEL_IS_VALID(pwm, pos) == false) || (_PWM_CHANNEL_IS_ENABLED(pwm, pos) == false))
{
return MR_EINVAL;
}
#endif /* MR_USE_PWM_CHECK */
/* Write data */
for (wcount = 0; wcount < MR_ALIGN_DOWN(count, sizeof(*wbuf)); wcount += sizeof(*wbuf))
{
/* Calculate the compare value */
uint32_t compare_value =
MR_BOUND(((float)*wbuf / 1000000.0f) * (float)(pwm->period), 0, pwm->period);
int ret = ops->set(driver, pos, compare_value);
if (ret < 0)
{
/* If no data is written, return the error code */
return (wcount == 0) ? ret : wcount;
}
wbuf++;
}
/* Return the number of bytes written */
return wcount;
}
static int pwm_ioctl(struct mr_device *device, int pos, int cmd, void *args)
{
struct mr_pwm *pwm = (struct mr_pwm *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_pwm_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
switch(cmd)
{
case MR_CMD_PWM_CONFIG:
{
struct mr_pwm_config *config = (struct mr_pwm_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Set the pwm channel configure */
int ret = _pwm_channel_configure_set(pwm, pos, config);
if (ret < 0)
{
return ret;
}
return sizeof(*config);
}
case (-MR_CMD_PWM_CONFIG):
{
struct mr_pwm_config *config = (struct mr_pwm_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Get the pwm channel configure */
int ret = _pwm_channel_configure_get(pwm, pos, config);
if (ret < 0)
{
return ret;
}
return sizeof(*config);
}
case MR_CMD_PWM_FREQ:
{
uint32_t *freq = (uint32_t *)args;
uint32_t old_period = pwm->period;
if (freq == NULL)
{
return MR_EINVAL;
}
/* Calculate the frequency prescaler and period */
int ret = _pwm_freq_calculate(pwm, *freq);
if (ret < 0)
{
return ret;
}
/* Start the pwm */
ret = ops->start(driver, pwm->prescaler, pwm->period);
if (ret < 0)
{
return ret;
}
/* Refresh all channels compare value */
for (uint32_t i = 0; i < (sizeof(pwm->channels) * 4); i++)
{
if (_PWM_CHANNEL_IS_ENABLED(pwm, i) == true)
{
uint32_t pwm_compare;
/* Get the old compare value */
ret = ops->get(driver, i, &pwm_compare);
if (ret < 0)
{
continue;
}
/* Calculate the new compare value */
pwm_compare = ((float)pwm_compare / (float)old_period) * (float)(pwm->period);
ops->set(driver, i, pwm_compare);
}
}
return sizeof(*freq);
}
case (-MR_CMD_PWM_FREQ):
{
uint32_t *freq = (uint32_t *)args;
if (freq == NULL)
{
return MR_EINVAL;
}
/* Get the current pwm frequency */
*freq = pwm->freq;
return sizeof(*freq);
}
default:
{
return MR_EPERM;
}
}
}
/**
* @brief This function registers a pwm.
*
* @param pwm The pwm.
* @param path The path of the pwm.
* @param driver The driver of the pwm.
*
* @return The error code.
*/
int mr_pwm_register(struct mr_pwm *pwm, const char *path, const struct mr_driver *driver)
{
MR_ASSERT(pwm != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL) && (driver->data != NULL));
static struct mr_device_ops ops = {.open = pwm_open,
.close = pwm_close,
.read = pwm_read,
.write = pwm_write,
.ioctl = pwm_ioctl};
/* Initialize the pwm */
pwm->freq = 0;
pwm->prescaler = 0;
pwm->period = 0;
pwm->channels = 0;
/* Register the pwm */
return mr_device_register((struct mr_device *)pwm, path, MR_DEVICE_TYPE_PWM, &ops, driver);
}
#endif /* MR_USE_PWM */

View File

@@ -9,7 +9,7 @@ menu "Serial configure"
config MR_CFG_SERIAL_RD_FIFO_SIZE
depends on MR_USE_SERIAL
int "Serial read fifo size"
int "Serial read FIFO size"
range 0 2147483647
default 128
help
@@ -17,7 +17,7 @@ menu "Serial configure"
config MR_CFG_SERIAL_WR_FIFO_SIZE
depends on MR_USE_SERIAL
int "Serial write fifo size"
int "Serial write FIFO size"
range 0 2147483647
default 0
help
@@ -26,14 +26,14 @@ menu "Serial configure"
# DMA
config MR_USE_SERIAL_DMA
depends on MR_USE_SERIAL
bool "Use serial dma"
bool "Use serial DMA"
default n
help
Use this option allows for the use of serial DMA.
config MR_CFG_SERIAL_RD_DMA_FIFO_SIZE
depends on MR_USE_SERIAL_DMA
int "Serial read dma fifo size"
int "Serial read DMA FIFO size"
range 0 2147483647
default 128
help
@@ -41,18 +41,10 @@ menu "Serial configure"
config MR_CFG_SERIAL_WR_DMA_FIFO_SIZE
depends on MR_USE_SERIAL_DMA
int "Serial write dma fifo size"
int "Serial write DMA FIFO size"
range 0 2147483647
default 128
help
This option sets the size of the write DMA FIFO.
# AIO
config MR_USE_SERIAL_AIO_EXT
depends on MR_USE_SERIAL and MR_USE_AIO_EXT
bool "Use serial extended AIO"
default n
help
This option uses extended asynchronous I/O
endmenu

26
device/spi/Kconfig Normal file
View File

@@ -0,0 +1,26 @@
menu "SPI configure"
# SPI
config MR_USE_SPI
bool "Use SPI"
default n
help
Use this option allows for the use of SPI.
config MR_CFG_SPI_RD_FIFO_SIZE
depends on MR_USE_SPI
int "SPI read FIFO size"
range 0 2147483647
default 128
help
This option sets the size of the read FIFO.
config MR_CFG_SPI_WR_FIFO_SIZE
depends on MR_USE_SPI
int "SPI write FIFO size"
range 0 2147483647
default 0
help
This option sets the size of the write FIFO.
endmenu

View File

@@ -6,105 +6,16 @@
* @date 2023-11-01 MacRsh First version
*/
#include "../mr-library/include/device/mr_spi.h"
#include <include/device/mr_spi.h>
#ifdef MR_USE_SPI
static int spi_isr(struct mr_device *device, uint32_t event, void *args)
{
struct mr_spi_bus *spi_bus = (struct mr_spi_bus *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
#define _STATE_SEND_INT (0x01 << 8) /**< Send interrupt */
switch (event)
{
case MR_EVENT_SPI_RD_COMPLETE_INT:
{
struct mr_spi_device *spi_device =
(struct mr_spi_device *)spi_bus->owner;
if (spi_device == NULL)
{
return MR_EINVAL;
}
/* The master does not support this operation */
if (spi_device->config.role == MR_SPI_ROLE_MASTER)
{
return MR_EPERM;
}
/* Check the chip select */
if (spi_device->cs_active != MR_SPI_CS_ACTIVE_NONE)
{
uint8_t level;
if (ops->cs_get != NULL)
{
int ret = ops->cs_get(driver, spi_device->cs_pin, &level);
if (ret < 0)
{
return ret;
}
}
#ifdef MR_USE_PIN
else if (spi_bus->pin_descriptor >= 0)
{
int ret = (int)mr_device_read(spi_bus->pin_descriptor,
&level, sizeof(level));
if (ret < 0)
{
return ret;
}
}
#endif /* MR_USE_PIN */
else
{
return MR_EIO;
}
/* If the chip select is not active, abandon the transfer */
if (level != spi_device->cs_active)
{
uint32_t data;
/* Discard the received data */
ops->transfer(driver, &data);
return MR_EOK;
}
}
/* If FIFO is empty, the transfer operation is abandoned */
if ((mr_fifo_size_get(&spi_device->rfifo) == 0) &&
mr_fifo_size_get(&spi_device->wfifo) == 0)
{
return MR_EOK;
}
uint32_t data_sizeof = spi_device->config.data_bits / 8;
uint32_t data = 0;
/* Read data that needs to be sent from the FIFO */
mr_fifo_read(&spi_device->wfifo, &data, data_sizeof);
/* Send the data that needs to be sent
* and get the data that is received */
int ret = ops->transfer(driver, &data);
if (ret < 0)
{
return ret;
}
/* Force write data to FIFO */
mr_fifo_write_force(&spi_device->rfifo, &data, data_sizeof);
return MR_EOK;
}
default:
{
return MR_EPERM;
}
}
}
#define _SPI_CS_MODE_NONE (0) /**< None */
#define _SPI_CS_MODE_OUTPUT (1) /**< Output push-pull mode */
#define _SPI_CS_MODE_INPUT_UP (4) /**< Input pull-up mode */
#define _SPI_CS_MODE_INPUT_DOWN (5) /**< Input pull-down mode */
static int spi_bus_attach(struct mr_device *device, struct mr_device *source)
{
@@ -119,22 +30,25 @@ static int spi_bus_attach(struct mr_device *device, struct mr_device *source)
}
/* In the first attaching, if the driver does not support chip selection
* configuration or level operation, try using a pin device */
if ((mr_list_is_empty(&device->clist) == true) &&
((ops->cs_configure == NULL) || (ops->cs_set == NULL) ||
(ops->cs_get == NULL)))
* configuration or level operation, will try using a pin device */
if ((_MR_DEVICE_REF_COUNT_GET(device) == 0) &&
((ops->cs_configure == NULL) || (ops->cs_set == NULL)))
{
#ifdef MR_USE_PIN
#ifndef MR_CFG_SPI_PIN_NAME
#define MR_CFG_SPI_PIN_NAME ("pin")
#define MR_CFG_SPI_PIN_NAME ("pin")
#endif /* MR_CFG_SPI_PIN_NAME */
spi_bus->pin_descriptor =
mr_device_open(MR_CFG_SPI_PIN_NAME, MR_FLAG_RDWR);
if (spi_bus->pin_descriptor < 0)
/* Open the pin device */
int ret = mr_device_open(MR_CFG_SPI_PIN_NAME, MR_FLAG_RDWR);
if (ret < 0)
{
return spi_bus->pin_descriptor;
return ret;
}
/* Store the pin descriptor */
spi_bus->pin_descriptor = ret;
#else
/* Driver cannot control chip select */
return MR_EIO;
#endif /* MR_USE_PIN */
}
@@ -149,10 +63,9 @@ static int spi_bus_detach(struct mr_device *device, struct mr_device *source)
struct mr_spi_bus *spi_bus = (struct mr_spi_bus *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
struct mr_spi_config null_config = {0};
/* In the last detaching, try to release the resource */
if (mr_list_is_empty(&device->clist) == true)
if (_MR_DEVICE_REF_COUNT_GET(device) == 1)
{
#ifdef MR_USE_PIN
/* Close the pin device if it is open */
@@ -171,11 +84,14 @@ static int spi_bus_detach(struct mr_device *device, struct mr_device *source)
/* Reset the SPI bus */
_MR_DEVICE_OPERATOR_CLR((struct mr_device *)spi_bus);
spi_bus->config = null_config;
spi_bus->owner = NULL;
/* Configure the driver as disabled */
return ops->configure(driver, false, &spi_bus->config);
int ret = ops->configure(driver, false, NULL);
if (ret < 0)
{
return ret;
}
}
/* Allow detaching */
@@ -183,6 +99,118 @@ static int spi_bus_detach(struct mr_device *device, struct mr_device *source)
return MR_EOK;
}
static int spi_isr(struct mr_device *device, uint32_t event, void *args)
{
struct mr_spi_bus *spi_bus = (struct mr_spi_bus *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
struct mr_spi_device *spi_device = (struct mr_spi_device *)spi_bus->owner;
/* Check whether the SPI bus is not in use */
if ((_MR_DEVICE_OPERATOR_GET((struct mr_device *)spi_bus) == -1))
{
return MR_ENOENT;
}
switch (event)
{
case MR_EVENT_SPI_RD_DATA_INT:
{
uint8_t data_sizeof = spi_device->config.data_bits / 8;
size_t count = 1;
/* Hardware FIFO is considered to be used */
if (args != NULL)
{
count = *((size_t *)args);
}
/* The master does not support this operation */
if (spi_device->config.role == MR_SPI_ROLE_MASTER)
{
return MR_EPERM;
}
/* If FIFO is empty, the read operation is abandoned */
if (mr_fifo_size_get(&spi_device->rfifo) == 0)
{
return 0;
}
/* Read all data from hardware FIFO */
for (size_t rcount = 0; rcount < count; rcount += data_sizeof)
{
uint32_t data = 0;
/* Read data from SPI bus */
int ret = ops->receive(driver, &data);
if (ret < 0)
{
return ret;
}
/* Force write data to FIFO */
mr_fifo_write_force(&spi_device->rfifo, &data, data_sizeof);
}
/* Returns the number of data in the read FIFO */
return mr_fifo_used_get(&spi_device->rfifo);
}
case MR_EVENT_SPI_WR_DATA_INT:
{
uint8_t data_sizeof = spi_device->config.data_bits / 8;
size_t count = 1;
/* Hardware FIFO is considered to be used */
if (args != NULL)
{
count = *((size_t *)args);
}
/* Write all data from hardware FIFO */
for (size_t wcount = 0; wcount < count; wcount += data_sizeof)
{
uint32_t data = 0;
/* If FIFO is empty, stop sending */
if (mr_fifo_peek(&spi_device->wfifo, &data, data_sizeof) == 0)
{
/* Stop sending */
int ret = ops->send_int_configure(driver, false);
if (ret < 0)
{
/* If the stop is failed, nothing can do */
return ret;
}
/* Clear the sending state */
MR_BIT_CLR(spi_bus->state, _STATE_SEND_INT);
/* Returns the number of data in the write FIFO */
return mr_fifo_used_get(&spi_device->wfifo);
}
/* Write data to serial */
int ret = ops->send(driver, data);
if (ret < 0)
{
return ret;
}
/* Discard sent data */
mr_fifo_discard(&spi_device->wfifo, data_sizeof);
}
/* Returns the number of data in the write FIFO */
return mr_fifo_used_get(&spi_device->wfifo);
}
default:
{
return MR_EPERM;
}
}
}
/**
* @brief This function register a SPI bus.
*
@@ -192,37 +220,33 @@ static int spi_bus_detach(struct mr_device *device, struct mr_device *source)
*
* @return The error code.
*/
int mr_spi_bus_register(struct mr_spi_bus *spi_bus, const char *path,
struct mr_driver *driver)
int mr_spi_bus_register(struct mr_spi_bus *spi_bus, const char *path, struct mr_driver *driver)
{
MR_ASSERT(spi_bus != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL));
static struct mr_device_ops ops = {.isr = spi_isr,
.attach = spi_bus_attach,
.detach = spi_bus_detach};
static struct mr_device_ops ops = {.attach = spi_bus_attach,
.detach = spi_bus_detach,
.isr = spi_isr};
struct mr_spi_config null_config = {0};
/* Initialize the SPI bus */
spi_bus->config = null_config;
spi_bus->owner = NULL;
spi_bus->state = 0;
#ifdef MR_USE_PIN
spi_bus->pin_descriptor = -1;
#endif /* MR_USE_PIN */
/* Register the SPI bus */
return mr_device_register((struct mr_device *)spi_bus, path,
MR_DEVICE_TYPE_SPI, &ops, driver);
return mr_device_register((struct mr_device *)spi_bus, path, MR_DEVICE_TYPE_SPI, &ops, driver);
}
static int _spi_device_cs_configure(struct mr_spi_device *spi_device,
bool enable)
static int _spi_device_cs_configure(struct mr_spi_device *spi_device, bool enable)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver =
_MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint8_t level = !spi_device->cs_active;
uint32_t mode;
@@ -239,17 +263,17 @@ static int _spi_device_cs_configure(struct mr_spi_device *spi_device,
/* Configure the chip to select the pin mode according to the role */
if (spi_device->config.role == MR_SPI_ROLE_MASTER)
{
mode = MR_SPI_CS_MODE_OUTPUT;
mode = _SPI_CS_MODE_OUTPUT;
} else if (spi_device->cs_active == MR_SPI_CS_ACTIVE_LOW)
{
mode = MR_SPI_CS_MODE_INPUT_UP;
mode = _SPI_CS_MODE_INPUT_UP;
} else
{
mode = MR_SPI_CS_MODE_INPUT_DOWN;
mode = _SPI_CS_MODE_INPUT_DOWN;
}
} else
{
mode = MR_SPI_CS_MODE_NONE;
mode = _SPI_CS_MODE_NONE;
}
/* Configure the chip select pin */
@@ -263,7 +287,7 @@ static int _spi_device_cs_configure(struct mr_spi_device *spi_device,
}
/* If the mode is not output, there is no need to set the level */
if (mode != MR_SPI_CS_MODE_OUTPUT)
if (mode != _SPI_CS_MODE_OUTPUT)
{
return MR_EOK;
}
@@ -272,27 +296,24 @@ static int _spi_device_cs_configure(struct mr_spi_device *spi_device,
return ops->cs_set(driver, spi_device->cs_pin, level);
}
#ifdef MR_USE_PIN
else if (spi_bus->pin_descriptor >= 0)
if (spi_bus->pin_descriptor >= 0)
{
/* Configure mode */
mr_device_ioctl(spi_bus->pin_descriptor, MR_CTRL_SET(MR_CMD_POS),
&spi_device->cs_pin);
ret = mr_device_ioctl(spi_bus->pin_descriptor,
MR_CTRL_SET(MR_CMD_CONFIG), &mode);
mr_device_ioctl(spi_bus->pin_descriptor, MR_CMD_POS, &spi_device->cs_pin);
ret = mr_device_ioctl(spi_bus->pin_descriptor, MR_CMD_CONFIG, &mode);
if (ret < 0)
{
return ret;
}
/* If the mode is not output, there is no need to set the level */
if (mode == MR_SPI_CS_MODE_OUTPUT)
if (mode != _SPI_CS_MODE_OUTPUT)
{
return MR_EOK;
}
/* Set the inactive level */
return (int)mr_device_write(spi_bus->pin_descriptor, &level,
sizeof(level));
return (int)mr_device_write(spi_bus->pin_descriptor, &level, sizeof(level));
}
#endif /* MR_USE_PIN */
return MR_EIO;
@@ -300,10 +321,8 @@ static int _spi_device_cs_configure(struct mr_spi_device *spi_device,
static int _spi_device_cs_set(struct mr_spi_device *spi_device, bool enable)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver =
_MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint8_t level = spi_device->cs_active;
int ret;
@@ -336,8 +355,7 @@ static int _spi_device_cs_set(struct mr_spi_device *spi_device, bool enable)
#ifdef MR_USE_PIN
else
{
ret = (int)mr_device_write(spi_bus->pin_descriptor, &level,
sizeof(level));
ret = (int)mr_device_write(spi_bus->pin_descriptor, &level, sizeof(level));
if (ret < 0)
{
return ret;
@@ -358,21 +376,18 @@ static int _spi_device_cs_set(struct mr_spi_device *spi_device, bool enable)
return MR_EOK;
}
MR_INLINE int _spi_device_take_bus(struct mr_spi_device *spi_device)
static int _spi_device_take_bus(struct mr_spi_device *spi_device)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver =
_MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
int spi_bus_operator, spi_device_operator;
/* Critical section enter */
mr_critical_enter();
/* Check whether the SPI bus is already in use */
spi_bus_operator = _MR_DEVICE_OPERATOR_GET((struct mr_device *)spi_bus);
if ((spi_bus_operator != -1) && (spi_device != spi_bus->owner))
if ((_MR_DEVICE_OPERATOR_GET((struct mr_device *)spi_bus) != -1) &&
(spi_device != spi_bus->owner))
{
/* Critical section exit */
mr_critical_exit();
@@ -380,9 +395,8 @@ MR_INLINE int _spi_device_take_bus(struct mr_spi_device *spi_device)
}
/* Set the SPI device operator as the SPI bus operator */
spi_device_operator =
_MR_DEVICE_OPERATOR_GET((struct mr_device *)spi_device);
_MR_DEVICE_OPERATOR_SET((struct mr_device *)spi_bus, spi_device_operator);
_MR_DEVICE_OPERATOR_SET((struct mr_device *)spi_bus,
_MR_DEVICE_OPERATOR_GET((struct mr_device *)spi_device));
/* Critical section exit */
mr_critical_exit();
@@ -405,7 +419,7 @@ MR_INLINE int _spi_device_take_bus(struct mr_spi_device *spi_device)
return ret;
}
/* Update the spi-bus configuration */
/* Update the SPI bus configuration */
spi_bus->config = spi_device->config;
spi_bus->owner = spi_device;
}
@@ -415,48 +429,57 @@ MR_INLINE int _spi_device_take_bus(struct mr_spi_device *spi_device)
/* Switch to the SPI bus owner's chip select pin */
if (spi_bus->pin_descriptor >= 0)
{
mr_device_ioctl(spi_bus->pin_descriptor, MR_CTRL_SET(MR_CMD_POS),
&spi_device->cs_pin);
mr_device_ioctl(spi_bus->pin_descriptor, MR_CMD_POS, &spi_device->cs_pin);
}
#endif /* MR_USE_PIN */
return MR_EOK;
}
MR_INLINE int _spi_device_release_bus(struct mr_spi_device *spi_device)
static int _spi_device_release_bus(struct mr_spi_device *spi_device)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
/* Release the SPI bus if its role is not slave */
if (spi_bus->config.role != MR_SPI_ROLE_SLAVE)
{
_MR_DEVICE_OPERATOR_SET((struct mr_device *)spi_bus, -1);
_MR_DEVICE_OPERATOR_CLR((struct mr_device *)spi_bus);
}
return MR_EOK;
}
MR_INLINE ssize_t _spi_device_master_read(struct mr_spi_device *spi_device,
int pos, uint8_t *buf, size_t count)
static int _spi_device_transfer(struct mr_spi_device *spi_device, uint32_t *data)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver =
_MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t data_sizeof = spi_device->config.data_bits / 8;
/* Send the data */
int ret = ops->send(driver, *data);
if (ret < 0)
{
return ret;
}
/* Receive the data */
return ops->receive(driver, data);
}
static ssize_t _spi_device_master_read(struct mr_spi_device *spi_device, int pos, uint8_t *buf,
size_t count)
{
uint8_t data_sizeof = spi_device->config.data_bits / 8;
ssize_t rcount;
/* Send the address of the register that needs to be read */
if (spi_device->config.addr_bits > 0)
if (spi_device->config.reg_bits > 0)
{
for (size_t addr_count = 0;
addr_count < (spi_device->config.addr_bits / 8);
addr_count += data_sizeof)
for (size_t reg_count = 0; reg_count < (spi_device->config.reg_bits / 8);
reg_count += data_sizeof)
{
uint32_t data;
memcpy(&data, ((uint8_t *)&pos) + addr_count, data_sizeof);
int ret = ops->transfer(driver, &data);
memcpy(&data, ((uint8_t *)&pos) + reg_count, data_sizeof);
int ret = _spi_device_transfer(spi_device, &data);
if (ret < 0)
{
/* Return the error code */
@@ -465,12 +488,12 @@ MR_INLINE ssize_t _spi_device_master_read(struct mr_spi_device *spi_device,
}
}
/* Receive data */
for (rcount = 0; rcount < count; rcount += data_sizeof)
/* Read data */
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, data_sizeof); rcount += data_sizeof)
{
uint32_t data;
uint32_t data = 0;
int ret = ops->transfer(driver, &data);
int ret = _spi_device_transfer(spi_device, &data);
if (ret < 0)
{
/* If no data received, return the error code */
@@ -485,36 +508,28 @@ MR_INLINE ssize_t _spi_device_master_read(struct mr_spi_device *spi_device,
return rcount;
}
MR_INLINE ssize_t _spi_device_slave_read(struct mr_spi_device *spi_device,
int pos, uint8_t *buf, size_t count)
static ssize_t _spi_device_slave_read(struct mr_spi_device *spi_device, uint8_t *buf, size_t count)
{
/* Read data from the FIFO which master will write */
/* Read data from the FIFO */
return (ssize_t)mr_fifo_read(&spi_device->rfifo, buf, count);
}
MR_INLINE ssize_t _spi_device_master_write(struct mr_spi_device *spi_device,
int pos, const uint8_t *buf,
size_t count)
static ssize_t _spi_device_master_write(struct mr_spi_device *spi_device, int pos,
const uint8_t *buf, size_t count)
{
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver =
_MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t data_sizeof = spi_device->config.data_bits / 8;
uint8_t data_sizeof = spi_device->config.data_bits / 8;
ssize_t wcount;
/* Send the address of the register that needs to be written */
if (spi_device->config.addr_bits > 0)
if (spi_device->config.reg_bits > 0)
{
for (size_t addr_count = 0;
addr_count < (spi_device->config.addr_bits / 8);
addr_count += data_sizeof)
for (size_t reg_count = 0; reg_count < (spi_device->config.reg_bits / 8);
reg_count += data_sizeof)
{
uint32_t data;
memcpy(&data, ((uint8_t *)&pos) + addr_count, data_sizeof);
int ret = ops->transfer(driver, &data);
memcpy(&data, ((uint8_t *)&pos) + reg_count, data_sizeof);
int ret = _spi_device_transfer(spi_device, &data);
if (ret < 0)
{
/* Return the error code */
@@ -523,13 +538,13 @@ MR_INLINE ssize_t _spi_device_master_write(struct mr_spi_device *spi_device,
}
}
/* Send data */
for (wcount = 0; wcount < count; wcount += data_sizeof)
/* Write data */
for (wcount = 0; wcount < MR_ALIGN_DOWN(count, data_sizeof); wcount += data_sizeof)
{
uint32_t data;
memcpy(&data, buf, data_sizeof);
int ret = ops->transfer(driver, &data);
int ret = _spi_device_transfer(spi_device, &data);
if (ret < 0)
{
/* If no data sent, return the error code */
@@ -542,15 +557,99 @@ MR_INLINE ssize_t _spi_device_master_write(struct mr_spi_device *spi_device,
return wcount;
}
MR_INLINE ssize_t _spi_device_slave_write(struct mr_spi_device *spi_device,
int pos, const uint8_t *buf,
size_t count)
static ssize_t _spi_device_slave_write(struct mr_spi_device *spi_device, const uint8_t *buf,
size_t count)
{
/* Write data to the FIFO which master will read */
return (ssize_t)mr_fifo_write(&spi_device->wfifo, buf, count);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Write data to the FIFO */
ssize_t wcount = (ssize_t)mr_fifo_write(&spi_device->wfifo, buf, count);
if (wcount == 0)
{
return wcount;
}
/* Driver does not support this function */
if (ops->send_int_configure == NULL)
{
return MR_EIO;
}
/* If the SPI bus is not sending, enable it */
if (MR_BIT_IS_SET(spi_bus->state, _STATE_SEND_INT) == false)
{
MR_BIT_SET(spi_bus->state, _STATE_SEND_INT);
int ret = ops->send_int_configure(driver, true);
if (ret < 0)
{
/* Data has been written to the FIFO, if the boot sent fails, wait
* for the next retry startup */
MR_BIT_CLR(spi_bus->state, _STATE_SEND_INT);
return wcount;
}
}
/* Return the number of bytes sent */
return wcount;
}
MR_INLINE int _spi_device_fifo_allocate(struct mr_fifo *fifo, size_t *size)
static ssize_t _spi_device_master_transfer(struct mr_spi_device *spi_device,
struct mr_spi_transfer *transfer)
{
uint8_t data_sizeof = spi_device->config.data_bits / 8;
const uint8_t *wbuf = (const uint8_t *)transfer->wbuf;
uint8_t *rbuf = (uint8_t *)transfer->rbuf;
ssize_t tcount;
/* Transfer data */
for (tcount = 0; tcount < MR_ALIGN_DOWN(transfer->count, data_sizeof); tcount += data_sizeof)
{
uint32_t data;
memcpy(&data, wbuf, data_sizeof);
int ret = _spi_device_transfer(spi_device, &data);
if (ret < 0)
{
/* If no data transferred, return the error code */
return (tcount == 0) ? ret : tcount;
}
memcpy(rbuf, &data, data_sizeof);
wbuf += data_sizeof;
rbuf += data_sizeof;
}
/* Return the number of bytes transferred */
return tcount;
}
static ssize_t _spi_device_slave_transfer(struct mr_spi_device *spi_device,
struct mr_spi_transfer *transfer)
{
size_t rcount = mr_fifo_used_get(&spi_device->rfifo);
size_t wcount = mr_fifo_free_get(&spi_device->wfifo);
ssize_t tcount = MR_MIN(rcount, wcount, size_t);
/* Check whether the transfer count is larger than the FIFO size */
if (tcount > transfer->count)
{
tcount = transfer->count;
}
/* Write data to FIFO */
tcount = _spi_device_slave_write(spi_device, transfer->wbuf, tcount);
if (tcount < 0)
{
return tcount;
}
/* Read data from FIFO */
return _spi_device_slave_read(spi_device, transfer->rbuf, tcount);
}
static int _spi_device_fifo_allocate(struct mr_fifo *fifo, size_t *size)
{
/* Allocate new buffer for FIFO */
int ret = mr_fifo_allocate(fifo, *size);
@@ -566,10 +665,9 @@ MR_INLINE int _spi_device_fifo_allocate(struct mr_fifo *fifo, size_t *size)
static int spi_device_open(struct mr_device *device)
{
struct mr_spi_device *spi_device = (struct mr_spi_device *)device;
int ret;
/* Enable the spi-device chip select pin */
ret = _spi_device_cs_configure(spi_device, true);
/* Enable the SPI device chip select pin */
int ret = _spi_device_cs_configure(spi_device, true);
if (ret < 0)
{
return ret;
@@ -585,8 +683,12 @@ static int spi_device_close(struct mr_device *device)
{
struct mr_spi_device *spi_device = (struct mr_spi_device *)device;
/* Disable the spi-device chip select pin */
_spi_device_cs_configure(spi_device, false);
/* Disable the SPI device chip select pin */
int ret = _spi_device_cs_configure(spi_device, false);
if (ret < 0)
{
return ret;
}
/* Free FIFO */
mr_fifo_free(&spi_device->rfifo);
@@ -594,8 +696,7 @@ static int spi_device_close(struct mr_device *device)
return MR_EOK;
}
static ssize_t spi_device_read(struct mr_device *device, int pos, void *buf,
size_t count)
static ssize_t spi_device_read(struct mr_device *device, int pos, void *buf, size_t count)
{
struct mr_spi_device *spi_device = (struct mr_spi_device *)device;
@@ -619,7 +720,7 @@ static ssize_t spi_device_read(struct mr_device *device, int pos, void *buf,
} else
{
/* Polling SPI bus as a slave */
ret = _spi_device_slave_read(spi_device, pos, buf, count);
ret = _spi_device_slave_read(spi_device, buf, count);
}
/* Release the SPI bus */
@@ -629,8 +730,7 @@ static ssize_t spi_device_read(struct mr_device *device, int pos, void *buf,
return ret;
}
static ssize_t spi_device_write(struct mr_device *device, int pos,
const void *buf, size_t count)
static ssize_t spi_device_write(struct mr_device *device, int pos, const void *buf, size_t count)
{
struct mr_spi_device *spi_device = (struct mr_spi_device *)device;
@@ -654,7 +754,7 @@ static ssize_t spi_device_write(struct mr_device *device, int pos,
} else
{
/* Polling SPI bus as a slave */
ret = _spi_device_slave_write(spi_device, pos, buf, count);
ret = _spi_device_slave_write(spi_device, buf, count);
}
/* Release the SPI bus */
@@ -664,20 +764,19 @@ static ssize_t spi_device_write(struct mr_device *device, int pos,
return ret;
}
static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
void *args)
static int spi_device_ioctl(struct mr_device *device, int pos, int cmd, void *args)
{
struct mr_spi_device *spi_device = (struct mr_spi_device *)device;
struct mr_spi_bus *spi_bus =
_MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_spi_bus *spi_bus = _MR_DEVICE_PARENT_GET((struct mr_device *)spi_device);
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)spi_bus);
struct mr_spi_bus_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
switch (cmd)
{
case MR_CTRL_SET(MR_CMD_SPI_CONFIG):
case MR_CMD_SPI_CONFIG:
{
struct mr_spi_config old_config = spi_device->config;
struct mr_spi_config *config = (struct mr_spi_config *)args;
int ret;
if (config == NULL)
{
@@ -685,18 +784,23 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
}
/* Validate the configuration */
if ((config->addr_bits > config->data_bits) ||
(config->data_bits == 0) || ((config->data_bits % 8) != 0) ||
(config->data_bits > 32) || ((config->addr_bits % 8) != 0))
if ((config->data_bits == 0) || (config->data_bits > 32) ||
((config->data_bits % 8) != 0) || ((config->reg_bits % 8) != 0))
{
return MR_EINVAL;
}
/* Driver does not support this function */
if ((config->role == MR_SPI_ROLE_SLAVE) && (ops->send_int_configure == NULL))
{
return MR_EIO;
}
/* Reconfigure CS if SPI device role is changed */
if (config->role != spi_device->config.role)
{
spi_device->config = *config;
ret = _spi_device_cs_configure(spi_device, true);
int ret = _spi_device_cs_configure(spi_device, true);
if (ret < 0)
{
spi_device->config = old_config;
@@ -707,7 +811,7 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
/* If holding the bus, release it */
if (spi_device == spi_bus->owner)
{
_MR_DEVICE_OPERATOR_SET((struct mr_device *)spi_bus, -1);
_MR_DEVICE_OPERATOR_CLR((struct mr_device *)spi_bus);
spi_bus->owner = NULL;
}
@@ -715,9 +819,10 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
if (config->role == MR_SPI_ROLE_SLAVE)
{
spi_device->config = *config;
ret = _spi_device_take_bus(spi_device);
int ret = _spi_device_take_bus(spi_device);
if (ret < 0)
{
spi_device->config = old_config;
return ret;
}
}
@@ -726,32 +831,7 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
spi_device->config = *config;
return sizeof(*config);
}
case MR_CTRL_SET(MR_CMD_SPI_RD_FIFO_SIZE):
{
size_t *fifo_size = (size_t *)args;
if (fifo_size == NULL)
{
return MR_EINVAL;
}
/* Update FIFO size */
spi_device->rfifo_size = *fifo_size;
int ret = _spi_device_fifo_allocate(&spi_device->rfifo,
&spi_device->rfifo_size);
if (ret < 0)
{
return ret;
}
return sizeof(*fifo_size);
}
case MR_CTRL_CLR(MR_CMD_SPI_RD_FIFO_DATA):
{
/* Reset FIFO */
mr_fifo_reset(&spi_device->rfifo);
return MR_EOK;
}
case MR_CTRL_GET(MR_CMD_SPI_CONFIG):
case (-MR_CMD_SPI_CONFIG):
{
struct mr_spi_config *config = (struct mr_spi_config *)args;
@@ -764,7 +844,25 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
*config = spi_device->config;
return sizeof(*config);
}
case MR_CTRL_GET(MR_CMD_SPI_RD_FIFO_SIZE):
case MR_CMD_SPI_RD_FIFO_SIZE:
{
size_t *fifo_size = (size_t *)args;
if (fifo_size == NULL)
{
return MR_EINVAL;
}
/* Update FIFO size */
spi_device->rfifo_size = *fifo_size;
int ret = _spi_device_fifo_allocate(&spi_device->rfifo, &spi_device->rfifo_size);
if (ret < 0)
{
return ret;
}
return sizeof(*fifo_size);
}
case (-MR_CMD_SPI_RD_FIFO_SIZE):
{
size_t *fifo_size = (size_t *)args;
@@ -777,7 +875,13 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
*fifo_size = spi_device->rfifo_size;
return sizeof(*fifo_size);
}
case MR_CTRL_GET(MR_CMD_SPI_RD_FIFO_DATA):
case MR_CMD_SPI_RD_FIFO_DATA:
{
/* Reset FIFO */
mr_fifo_reset(&spi_device->rfifo);
return MR_EOK;
}
case (-MR_CMD_SPI_RD_FIFO_DATA):
{
size_t *data_size = (size_t *)args;
@@ -790,6 +894,34 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
*data_size = mr_fifo_used_get(&spi_device->rfifo);
return sizeof(*data_size);
}
case MR_CMD_SPI_TRANSFER:
{
struct mr_spi_transfer *transfer = (struct mr_spi_transfer *)args;
if (transfer == NULL)
{
return MR_EINVAL;
}
/* Take the SPI bus */
int ret = _spi_device_take_bus(spi_device);
if (ret < 0)
{
return ret;
}
if (spi_device->config.role == MR_SPI_ROLE_MASTER)
{
ret = _spi_device_master_transfer(spi_device, transfer);
} else
{
ret = _spi_device_slave_transfer(spi_device, transfer);
}
/* Release the SPI bus */
_spi_device_release_bus(spi_device);
return ret;
}
default:
{
return MR_EPERM;
@@ -808,13 +940,12 @@ static int spi_device_ioctl(struct mr_device *device, int pos, int cmd,
*
* @return The error code.
*/
int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path,
int cs_pin, int cs_active, const char *spi_bus_name)
int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path, int cs_pin,
int cs_active, const char *spi_bus_name)
{
MR_ASSERT(spi_device != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((cs_active >= MR_SPI_CS_ACTIVE_LOW) &&
(cs_active <= MR_SPI_CS_ACTIVE_NONE));
MR_ASSERT((cs_active >= MR_SPI_CS_ACTIVE_LOW) && (cs_active <= MR_SPI_CS_ACTIVE_NONE));
static struct mr_device_ops ops = {.open = spi_device_open,
.close = spi_device_close,
@@ -828,10 +959,10 @@ int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path,
mr_fifo_init(&spi_device->rfifo, NULL, 0);
mr_fifo_init(&spi_device->wfifo, NULL, 0);
#ifndef MR_CFG_SPI_RD_FIFO_SIZE
#define MR_CFG_SPI_RD_FIFO_SIZE (32)
#define MR_CFG_SPI_RD_FIFO_SIZE (128)
#endif /* MR_CFG_SPI_RD_FIFO_SIZE */
#ifndef MR_CFG_SPI_WR_FIFO_SIZE
#define MR_CFG_SPI_WR_FIFO_SIZE (32)
#define MR_CFG_SPI_WR_FIFO_SIZE (0)
#endif /* MR_CFG_SPI_WR_FIFO_SIZE */
spi_device->rfifo_size = MR_CFG_SPI_RD_FIFO_SIZE;
spi_device->wfifo_size = MR_CFG_SPI_WR_FIFO_SIZE;
@@ -839,8 +970,8 @@ int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path,
spi_device->cs_active = (cs_pin >= 0) ? cs_active : MR_SPI_CS_ACTIVE_NONE;
/* Register the SPI device to the SPI bus */
return mr_device_register_to((struct mr_device *)spi_device, path,
MR_DEVICE_TYPE_SPI, &ops, NULL, spi_bus_name);
return mr_device_register_to((struct mr_device *)spi_device, path, MR_DEVICE_TYPE_SPI, &ops,
NULL, spi_bus_name);
}
/**

10
device/timer/Kconfig Normal file
View File

@@ -0,0 +1,10 @@
menu "Timer configure"
# Timer
config MR_USE_TIMER
bool "Use timer"
default n
help
Use this option allows for the use of timer.
endmenu

324
device/timer/mr_timer.c Normal file
View File

@@ -0,0 +1,324 @@
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-11-15 MacRsh First version
*/
#include <include/device/mr_timer.h>
#ifdef MR_USE_TIMER
static int _timer_timeout_calculate(struct mr_timer *timer, uint32_t timeout)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET((struct mr_device *)timer);
struct mr_timer_driver_data *data = _MR_DRIVER_DATA_GET(driver);
uint32_t clk = data->clk, psc_max = data->prescaler_max, per_max = data->period_max;
uint32_t psc_best = 1, per_best = 1, reload_best = 1;
uint32_t product = timeout;
/* Check driver clock is valid */
if (clk == 0)
{
return MR_EIO;
}
/* Check timeout is valid */
if (timeout == 0)
{
return MR_EINVAL;
}
/* If the product is within the maximum period, set it as the period */
if (product <= per_max)
{
psc_best = clk / 1000000;
per_best = MR_BOUND(product, 1, per_max);
} else
{
int error_min = INT32_MAX;
/* Calculate the least error prescaler and period */
for (uint32_t psc = MR_BOUND((product / per_max), 1, product); psc < UINT32_MAX; psc++)
{
uint32_t per = MR_BOUND(product / psc, 1, per_max);
int error = (int)(timeout - (per * psc));
/* Allowable error is less than or equal to 1us */
if (error <= 1)
{
psc_best = psc;
per_best = per;
break;
}
/* Found a valid and optimal solution */
if (error < error_min)
{
error_min = error;
psc_best = psc;
per_best = per;
}
}
/* Calculate the reload and prescaler product */
product = psc_best * (clk / 1000000);
error_min = INT32_MAX;
/* Calculate the least error reload and prescaler */
for (uint32_t reload = MR_BOUND(product / psc_max, 1, product); reload < product; reload++)
{
uint32_t psc = MR_BOUND(product / reload, 1, psc_max);
int error = (int)product - (int)(reload * psc);
/* Allowable error is less than or equal to 1us */
if (error <= 1)
{
reload_best = reload;
psc_best = psc;
break;
}
/* Found a valid and optimal solution */
if (error < error_min)
{
error_min = error;
reload_best = reload;
psc_best = psc;
}
}
/* If period can take reload value, lower interrupts by loading reload to period */
if (per_best <= (per_max / reload_best))
{
per_best *= reload_best;
reload_best = 1;
/* If the reload is less than the prescaler, swap them */
} else if ((reload_best > per_best) && (reload_best < per_max))
{
MR_SWAP(reload_best, per_best, uint32_t);
}
}
/* Set timer parameters */
timer->prescaler = psc_best;
timer->period = per_best;
timer->reload = reload_best;
timer->count = timer->reload;
timer->timeout = timeout / timer->reload;
return MR_EOK;
}
static int timer_open(struct mr_device *device)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_timer_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Enable timer */
return ops->configure(driver, true);
}
static int timer_close(struct mr_device *device)
{
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_timer_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
/* Disable timer */
return ops->configure(driver, false);
}
static ssize_t timer_read(struct mr_device *device, int pos, void *buf, size_t count)
{
struct mr_timer *timer = (struct mr_timer *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_timer_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t *rbuf = (uint32_t *)buf;
ssize_t rcount;
/* Read data */
for (rcount = 0; rcount < MR_ALIGN_DOWN(count, sizeof(*rbuf)); rcount += sizeof(*rbuf))
{
uint32_t timer_count;
/* Get the timer count */
int ret = ops->get(driver, &timer_count);
if (ret < 0)
{
/* If no data is read, return the error code */
return (rcount == 0) ? ret : rcount;
}
/* Calculate the time */
*rbuf = (timer->reload - timer->count) * timer->timeout + (
((float)timer_count / (float)timer->period) * (float)timer->timeout);
rbuf++;
}
/* Return the number of bytes read */
return rcount;
}
static ssize_t timer_write(struct mr_device *device, int pos, const void *buf, size_t count)
{
struct mr_timer *timer = (struct mr_timer *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_timer_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
uint32_t *wbuf = (uint32_t *)buf;
uint32_t timeout = 0;
ssize_t wcount;
/* Only the last value can be written */
for (wcount = 0; wcount < MR_ALIGN_DOWN(count, sizeof(*wbuf)); wcount += sizeof(*wbuf))
{
timeout = *wbuf;
wbuf++;
}
/* No data is written */
if (wcount == 0)
{
return wcount;
}
/* Stop the timer */
int ret = ops->stop(driver);
if (ret < 0)
{
return ret;
}
/* Calculate the timeout prescaler and period */
ret = _timer_timeout_calculate(timer, timeout);
if (ret < 0)
{
return ret;
}
/* Start the timer */
ret = ops->start(driver, timer->prescaler, timer->period);
if (ret < 0)
{
return ret;
}
/* Return the number of bytes written */
return wcount;
}
static int timer_ioctl(struct mr_device *device, int pos, int cmd, void *args)
{
struct mr_timer *timer = (struct mr_timer *)device;
switch (cmd)
{
case MR_CMD_TIMER_CONFIG:
{
struct mr_timer_config *config = (struct mr_timer_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Set the timer configure */
timer->config = *config;
return sizeof(*config);
}
case (-MR_CMD_TIMER_CONFIG):
{
struct mr_timer_config *config = (struct mr_timer_config *)args;
if (config == NULL)
{
return MR_EINVAL;
}
/* Get the timer configure */
*config = timer->config;
return sizeof(*config);
}
default:
{
return MR_EPERM;
}
}
}
static int timer_isr(struct mr_device *device, uint32_t event, void *args)
{
struct mr_timer *timer = (struct mr_timer *)device;
struct mr_driver *driver = _MR_DEVICE_DRIVER_GET(device);
struct mr_timer_driver_ops *ops = _MR_DRIVER_OPS_GET(driver);
switch (event)
{
case MR_EVENT_TIMER_TIMEOUT_INT:
{
/* Decrement the timer count */
timer->count--;
/* If the timer count does not reach 0, continue running */
if (timer->count > 0)
{
return MR_EBUSY;
}
/* Reset the timer count */
timer->count = timer->reload;
/* If the timer is in oneshot mode, stop the timer */
if (timer->config.mode == MR_TIMER_MODE_ONESHOT)
{
int ret = ops->stop(driver);
if (ret < 0)
{
return ret;
}
}
return MR_EOK;
}
default:
{
return MR_EPERM;
}
}
}
/**
* @brief This function registers a timer.
*
* @param timer The timer.
* @param path The path of the timer.
* @param driver The driver of the timer.
*
* @return The error code.
*/
int mr_timer_register(struct mr_timer *timer, const char *path, const struct mr_driver *driver)
{
MR_ASSERT(timer != NULL);
MR_ASSERT(path != NULL);
MR_ASSERT((driver != NULL) && (driver->ops != NULL) && (driver->data != NULL));
static struct mr_device_ops ops = {.open = timer_open,
.close = timer_close,
.read = timer_read,
.write = timer_write,
.ioctl = timer_ioctl,
.isr = timer_isr};
struct mr_timer_config default_config = MR_TIMER_CONFIG_DEFAULT;
/* Initialize the timer */
timer->config = default_config;
timer->reload = 0;
timer->count = 0;
timer->timeout = 0;
timer->prescaler = 0;
timer->period = 0;
/* Register the timer */
return mr_device_register((struct mr_device *)timer, path, MR_DEVICE_TYPE_TIMER, &ops, driver);
}
#endif /* MR_USE_TIMER */

View File

@@ -1,4 +1,4 @@
/*
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
@@ -9,7 +9,7 @@
#ifndef _MR_ADC_H_
#define _MR_ADC_H_
#include "../mr-library/include/mr_api.h"
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
@@ -22,21 +22,21 @@ extern "C" {
* @{
*/
#define MR_ADC_CHANNEL_STATE_ENABLE true /**< Channel enable */
#define MR_ADC_CHANNEL_STATE_DISABLE false /**< Channel disable */
#define MR_ADC_CHANNEL_STATE_DISABLE (false) /**< Channel disable */
#define MR_ADC_CHANNEL_STATE_ENABLE (true) /**< Channel enable */
#define MR_CMD_ADC_CHANNEL MR_CMD_POS /**< ADC channel command */
#define MR_CMD_ADC_CHANNEL_STATE MR_CMD_CONFIG /**< ADC channel state command */
#define MR_CMD_ADC_RESOLUTION (0x01) /**< ADC resolution command */
#define MR_CMD_ADC_CHANNEL MR_CMD_POS /**< Channel command */
#define MR_CMD_ADC_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_ADC_RESOLUTION (0x01) /**< Resolution command */
typedef uint32_t mr_adc_data_t; /**< ADC read data type */
typedef uint32_t mr_adc_data_t; /**< ADC read data type */
/**
* @brief ADC configuration structure.
*/
struct mr_adc_config
{
uint32_t channel_state; /**< Channel state */
uint32_t channel_state; /**< Channel state */
};
/**
@@ -44,9 +44,9 @@ struct mr_adc_config
*/
struct mr_adc
{
struct mr_device device; /**< Device */
struct mr_device device; /**< Device */
uint32_t channels; /**< Channels state mask */
uint32_t channels; /**< Channels state mask */
};
/**
@@ -55,9 +55,8 @@ struct mr_adc
struct mr_adc_driver_ops
{
int (*configure)(struct mr_driver *driver, bool enable);
int (*channel_configure)(struct mr_driver *driver, uint32_t channel,
bool enable);
int (*read)(struct mr_driver *driver, uint32_t channel, uint32_t *data);
int (*channel_configure)(struct mr_driver *driver, uint32_t channel, bool enable);
int (*get)(struct mr_driver *driver, uint32_t channel, uint32_t *data);
};
/**
@@ -65,12 +64,11 @@ struct mr_adc_driver_ops
*/
struct mr_adc_driver_data
{
uint32_t channels; /**< Channels exists mask */
uint32_t resolution; /**< Resolution */
uint32_t channels; /**< Channels exists mask */
uint32_t resolution; /**< Resolution */
};
int mr_adc_register(struct mr_adc *adc, const char *path,
const struct mr_driver *driver);
int mr_adc_register(struct mr_adc *adc, const char *path, const struct mr_driver *driver);
/** @} */

View File

@@ -1,4 +1,4 @@
/*
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
@@ -9,7 +9,7 @@
#ifndef _MR_PIN_H_
#define _MR_PIN_H_
#include "../mr-library/include/mr_api.h"
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
@@ -22,42 +22,42 @@ extern "C" {
* @{
*/
#define MR_PIN_MODE_NONE (0) /**< No mode */
#define MR_PIN_MODE_OUTPUT (1) /**< Output push-pull mode */
#define MR_PIN_MODE_OUTPUT_OD (2) /**< Output open-drain mode */
#define MR_PIN_MODE_INPUT (3) /**< Input mode */
#define MR_PIN_MODE_INPUT_UP (4) /**< Input pull-up mode */
#define MR_PIN_MODE_INPUT_DOWN (5) /**< Input pull-down mode */
#define MR_PIN_MODE_IRQ_RISING (6) /**< Interrupt rising edge mode */
#define MR_PIN_MODE_IRQ_FALLING (7) /**< Interrupt falling edge mode */
#define MR_PIN_MODE_IRQ_EDGE (8) /**< Interrupt edge mode */
#define MR_PIN_MODE_IRQ_LOW (9) /**< Interrupt low level mode */
#define MR_PIN_MODE_IRQ_HIGH (10) /**< Interrupt high level mode */
#define MR_PIN_MODE_NONE (0) /**< No mode */
#define MR_PIN_MODE_OUTPUT (1) /**< Output push-pull mode */
#define MR_PIN_MODE_OUTPUT_OD (2) /**< Output open-drain mode */
#define MR_PIN_MODE_INPUT (3) /**< Input mode */
#define MR_PIN_MODE_INPUT_UP (4) /**< Input pull-up mode */
#define MR_PIN_MODE_INPUT_DOWN (5) /**< Input pull-down mode */
#define MR_PIN_MODE_IRQ_RISING (6) /**< Interrupt rising edge mode */
#define MR_PIN_MODE_IRQ_FALLING (7) /**< Interrupt falling edge mode */
#define MR_PIN_MODE_IRQ_EDGE (8) /**< Interrupt edge mode */
#define MR_PIN_MODE_IRQ_LOW (9) /**< Interrupt low level mode */
#define MR_PIN_MODE_IRQ_HIGH (10) /**< Interrupt high level mode */
#define MR_CMD_PIN_NUMBER MR_CMD_POS /**< PIN number command */
#define MR_CMD_PIN_MODE MR_CMD_CONFIG /**< PIN mode command */
#define MR_CMD_PIN_NUMBER MR_CMD_POS /**< Number command */
#define MR_CMD_PIN_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_EVENT_PIN_EXTI_INT \
(MR_EVENT_RD | MR_EVENT_DATA | (0x01)) /**< Interrupt on EXTI event */
#define MR_EVENT_PIN_EXTI_INT \
(MR_EVENT_RD | MR_EVENT_DATA | (0x01)) /**< Interrupt on EXTI event */
typedef uint8_t mr_pin_data_t; /**< PIN read/write data type */
/**
* @brief PIN configuration structure.
*/
struct mr_pin_config
{
uint32_t mode; /**< Mode */
uint32_t mode; /**< Mode */
};
typedef uint8_t mr_pin_data_t; /**< PIN read/write data type */
/**
* @brief PIN structure.
*/
struct mr_pin
{
struct mr_device device; /**< Device */
struct mr_device device; /**< Device */
uint32_t pins[16]; /**< Pins mode mask */
uint32_t pins[16]; /**< Pins mode mask */
};
/**
@@ -66,8 +66,8 @@ struct mr_pin
struct mr_pin_driver_ops
{
int (*configure)(struct mr_driver *driver, uint32_t number, uint32_t mode);
int (*read)(struct mr_driver *driver, uint32_t number, uint8_t *value);
int (*write)(struct mr_driver *driver, uint32_t number, uint8_t value);
int (*get)(struct mr_driver *driver, uint32_t number, uint8_t *value);
int (*set)(struct mr_driver *driver, uint32_t number, uint8_t value);
};
/**
@@ -75,11 +75,10 @@ struct mr_pin_driver_ops
*/
struct mr_pin_driver_data
{
uint32_t pins[16]; /**< Pins exists mask */
uint32_t pins[16]; /**< Pins exists mask */
};
int mr_pin_register(struct mr_pin *pin, const char *path,
const struct mr_driver *driver);
int mr_pin_register(struct mr_pin *pin, const char *path, const struct mr_driver *driver);
/** @} */

92
include/device/mr_pwm.h Normal file
View File

@@ -0,0 +1,92 @@
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-12-10 MacRsh First version
*/
#ifndef _MR_PWM_H_
#define _MR_PWM_H_
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef MR_USE_PWM
/**
* @addtogroup Timer
* @{
*/
#define MR_PWM_CHANNEL_STATE_DISABLE (false) /**< Channel disable */
#define MR_PWM_CHANNEL_STATE_ENABLE (true) /**< Channel enable */
#define MR_PWM_POLARITY_NORMAL (0) /**< Normal polarity */
#define MR_PWM_POLARITY_INVERTED (1) /**< Inverted polarity */
#define MR_CMD_PWM_CHANNEL MR_CMD_POS /**< Channel command */
#define MR_CMD_PWM_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_PWM_FREQ (0x01) /**< Frequency command */
typedef uint32_t mr_pwm_data_t; /**< PWM read/write data type */
typedef uint32_t mr_pwm_freq_t; /**< PWM frequency type */
/**
* @brief PWM configuration structure.
*/
struct mr_pwm_config
{
uint32_t channel_state; /**< Channel state */
uint32_t polarity; /**< Polarity */
};
/**
* @brief PWM structure.
*/
struct mr_pwm
{
struct mr_device device; /**< Device */
uint32_t freq; /**< Frequency */
uint32_t prescaler; /**< Prescaler */
uint32_t period; /**< Period */
uint32_t channels; /**< Channels state mask */
};
/**
* @brief PWM driver operations structure.
*/
struct mr_pwm_driver_ops
{
int (*configure)(struct mr_driver *driver, bool enable);
int (*start)(struct mr_driver *driver, uint32_t prescaler, uint32_t period);
int (*channel_configure)(struct mr_driver *driver, uint32_t channel, bool enable,
uint32_t polarity);
int (*get)(struct mr_driver *driver, uint32_t channel, uint32_t *compare_value);
int (*set)(struct mr_driver *driver, uint32_t channel, uint32_t compare_value);
};
/**
* @brief PWM driver data structure.
*/
struct mr_pwm_driver_data
{
uint32_t clk; /**< Clock(Hz) */
uint32_t prescaler_max; /**< Prescaler max */
uint32_t period_max; /**< Period max */
uint32_t channels; /**< Channels exists mask */
};
/** @} */
#endif /* MR_USE_PWM */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _MR_PWM_H_ */

View File

@@ -1,4 +1,4 @@
/*
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
@@ -10,7 +10,7 @@
#ifndef _MR_SERIAL_H_
#define _MR_SERIAL_H_
#include "../mr-library/include/mr_api.h"
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
@@ -23,67 +23,67 @@ extern "C" {
* @{
*/
#define MR_SERIAL_DATA_BITS_5 (5) /**< 5 bits data */
#define MR_SERIAL_DATA_BITS_6 (6) /**< 6 bits data */
#define MR_SERIAL_DATA_BITS_7 (7) /**< 7 bits data */
#define MR_SERIAL_DATA_BITS_8 (8) /**< 8 bits data */
#define MR_SERIAL_DATA_BITS_5 (5) /**< 5 bits data */
#define MR_SERIAL_DATA_BITS_6 (6) /**< 6 bits data */
#define MR_SERIAL_DATA_BITS_7 (7) /**< 7 bits data */
#define MR_SERIAL_DATA_BITS_8 (8) /**< 8 bits data */
#define MR_SERIAL_STOP_BITS_1 (1) /**< 1 bit stop */
#define MR_SERIAL_STOP_BITS_2 (2) /**< 2 bit stop */
#define MR_SERIAL_STOP_BITS_3 (3) /**< 3 bit stop */
#define MR_SERIAL_STOP_BITS_4 (4) /**< 4 bit stop */
#define MR_SERIAL_STOP_BITS_1 (1) /**< 1 bit stop */
#define MR_SERIAL_STOP_BITS_2 (2) /**< 2 bit stop */
#define MR_SERIAL_STOP_BITS_3 (3) /**< 3 bit stop */
#define MR_SERIAL_STOP_BITS_4 (4) /**< 4 bit stop */
#define MR_SERIAL_PARITY_NONE (0) /**< No parity */
#define MR_SERIAL_PARITY_EVEN (1) /**< Even parity */
#define MR_SERIAL_PARITY_ODD (2) /**< Odd parity */
#define MR_SERIAL_PARITY_NONE (0) /**< No parity */
#define MR_SERIAL_PARITY_EVEN (1) /**< Even parity */
#define MR_SERIAL_PARITY_ODD (2) /**< Odd parity */
#define MR_SERIAL_BITS_ORDER_LSB (0) /**< LSB first */
#define MR_SERIAL_BITS_ORDER_MSB (1) /**< MSB first */
#define MR_SERIAL_BITS_ORDER_LSB (0) /**< LSB first */
#define MR_SERIAL_BITS_ORDER_MSB (1) /**< MSB first */
#define MR_SERIAL_POLARITY_NORMAL (0) /**< Normal polarity */
#define MR_SERIAL_POLARITY_INVERTED (1) /**< Inverted polarity */
#define MR_SERIAL_POLARITY_NORMAL (0) /**< Normal polarity */
#define MR_SERIAL_POLARITY_INVERTED (1) /**< Inverted polarity */
#define MR_CMD_SERIAL_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_SERIAL_RD_FIFO_SIZE (0x01) /**< Read FIFO size command */
#define MR_CMD_SERIAL_WR_FIFO_SIZE (0x02) /**< Write FIFO size command */
#define MR_CMD_SERIAL_RD_FIFO_DATA (0x03) /**< Read FIFO data command */
#define MR_CMD_SERIAL_WR_FIFO_DATA (0x04) /**< Write FIFO data command */
#define MR_EVENT_SERIAL_RD_DATA_INT \
(MR_EVENT_RD | MR_EVENT_DATA | (0x01)) /**< Interrupt on read completion event */
#define MR_EVENT_SERIAL_WR_DATA_INT \
(MR_EVENT_WR | MR_EVENT_DATA | (0x01)) /**< Interrupt on write completion event */
#define MR_EVENT_SERIAL_RD_DATA_DMA \
(MR_EVENT_RD | MR_EVENT_DATA | (0x02)) /**< Interrupt on read DMA completion event */
#define MR_EVENT_SERIAL_WR_DATA_DMA \
(MR_EVENT_WR | MR_EVENT_DATA | (0x02)) /**< Interrupt on write DMA completion event */
typedef uint8_t mr_serial_data_t; /**< Serial read/write data type */
/**
* @brief Serial default configuration.
*/
#define MR_SERIAL_CONFIG_DEFAULT \
{ \
.baud_rate = 115200, \
.data_bits = MR_SERIAL_DATA_BITS_8, \
.stop_bits = MR_SERIAL_STOP_BITS_1, \
.parity = MR_SERIAL_PARITY_NONE, \
.bits_order = MR_SERIAL_BITS_ORDER_LSB, \
.polarity = MR_SERIAL_POLARITY_NORMAL, \
#define MR_SERIAL_CONFIG_DEFAULT \
{ \
.baud_rate = 115200, \
.data_bits = MR_SERIAL_DATA_BITS_8, \
.stop_bits = MR_SERIAL_STOP_BITS_1, \
.parity = MR_SERIAL_PARITY_NONE, \
.bits_order = MR_SERIAL_BITS_ORDER_LSB, \
.polarity = MR_SERIAL_POLARITY_NORMAL, \
}
#define MR_CMD_SERIAL_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_SERIAL_RD_FIFO_SIZE (0x01) /**< Read FIFO size command */
#define MR_CMD_SERIAL_WR_FIFO_SIZE (0x02) /**< Write FIFO size command */
#define MR_CMD_SERIAL_RD_FIFO_DATA (0x03) /**< Read FIFO data command */
#define MR_CMD_SERIAL_WR_FIFO_DATA (0x04) /**< Write FIFO data command */
#define MR_EVENT_SERIAL_RD_DATA_INT \
(MR_EVENT_RD | MR_EVENT_DATA | (0x01)) /**< Interrupt on read completion event */
#define MR_EVENT_SERIAL_WR_DATA_INT \
(MR_EVENT_WR | MR_EVENT_DATA | (0x01)) /**< Interrupt on write completion event */
#define MR_EVENT_SERIAL_RD_DATA_DMA \
(MR_EVENT_RD | MR_EVENT_DATA | (0x02)) /**< Interrupt on read DMA completion event */
#define MR_EVENT_SERIAL_WR_DATA_DMA \
(MR_EVENT_WR | MR_EVENT_DATA | (0x02)) /**< Interrupt on write DMA completion event */
typedef uint8_t mr_serial_data_t; /**< Serial read/write data type */
/**
* @brief Serial configuration structure.
*/
struct mr_serial_config
{
uint32_t baud_rate; /**< Baud rate */
uint32_t data_bits; /**< Data bits */
uint32_t stop_bits; /**< Stop bits */
uint32_t parity; /**< Parity */
uint32_t bits_order; /**< Bits order */
uint32_t polarity; /**< Polarity */
uint32_t baud_rate; /**< Baud rate */
uint32_t data_bits; /**< Data bits */
uint32_t stop_bits; /**< Stop bits */
uint32_t parity; /**< Parity */
uint32_t bits_order; /**< Bits order */
uint32_t polarity; /**< Polarity */
};
/**
@@ -91,14 +91,14 @@ struct mr_serial_config
*/
struct mr_serial
{
struct mr_device device; /**< Device */
struct mr_device device; /**< Device */
struct mr_serial_config config; /**< Configuration */
struct mr_fifo rfifo; /**< Read FIFO */
struct mr_fifo wfifo; /**< Write FIFO */
size_t rfifo_size; /**< Read buffer size */
size_t wfifo_size; /**< Write buffer size */
uint32_t state; /**< Transmission state */
struct mr_serial_config config; /**< Configuration */
struct mr_fifo rfifo; /**< Read FIFO */
struct mr_fifo wfifo; /**< Write FIFO */
size_t rfifo_size; /**< Read buffer size */
size_t wfifo_size; /**< Write buffer size */
uint32_t state; /**< Transmission state */
#ifdef MR_USE_SERIAL_DMA
#ifndef MR_CFG_SERIAL_RD_DMA_FIFO_SIZE
#define MR_CFG_SERIAL_RD_DMA_FIFO_SIZE (128)
@@ -106,15 +106,9 @@ struct mr_serial
#ifndef MR_CFG_SERIAL_WR_DMA_FIFO_SIZE
#define MR_CFG_SERIAL_WR_DMA_FIFO_SIZE (128)
#endif /* MR_CFG_SERIAL_WR_DMA_FIFO_SIZE */
uint8_t rdma[MR_CFG_SERIAL_RD_DMA_FIFO_SIZE]; /**< Read DMA buffer */
uint8_t wdma[MR_CFG_SERIAL_WR_DMA_FIFO_SIZE]; /**< Write DMA buffer */
uint8_t rdma[MR_CFG_SERIAL_RD_DMA_FIFO_SIZE]; /**< Read DMA buffer */
uint8_t wdma[MR_CFG_SERIAL_WR_DMA_FIFO_SIZE]; /**< Write DMA buffer */
#endif /* MR_USE_SERIAL_DMA */
#ifdef MR_USE_SERIAL_AIO_EXT
uint8_t *rabuf; /**< Read async buffer */
size_t racount; /**< Read async count */
const uint8_t *wabuf; /**< Write async buffer */
size_t wacount; /**< Write async count */
#endif /* MR_USE_SERIAL_AIO_EXT */
};
/**
@@ -122,21 +116,17 @@ struct mr_serial
*/
struct mr_serial_driver_ops
{
int (*configure)(struct mr_driver *driver, bool enable,
struct mr_serial_config *config);
int (*configure)(struct mr_driver *driver, bool enable, struct mr_serial_config *config);
int (*receive)(struct mr_driver *driver, uint8_t *data);
int (*send)(struct mr_driver *driver, uint8_t data);
/* Optional operations */
int (*send_int_configure)(struct mr_driver *driver, bool enable);
int (*receive_dma)(struct mr_driver *driver, bool enable, void *buf,
size_t count);
int (*send_dma)(struct mr_driver *driver, bool enable, const void *buf,
size_t count);
int (*receive_dma)(struct mr_driver *driver, bool enable, void *buf, size_t count);
int (*send_dma)(struct mr_driver *driver, bool enable, const void *buf, size_t count);
};
int mr_serial_register(struct mr_serial *serial, const char *path,
const struct mr_driver *driver);
int mr_serial_register(struct mr_serial *serial, const char *path, const struct mr_driver *driver);
/** @} */

View File

@@ -9,7 +9,7 @@
#ifndef _MR_SPI_H_
#define _MR_SPI_H_
#include "../mr-library/include/mr_api.h"
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
@@ -22,69 +22,71 @@ extern "C" {
* @{
*/
#define MR_SPI_ROLE_MASTER (0) /**< SPI master */
#define MR_SPI_ROLE_SLAVE (1) /**< SPI slave */
#define MR_SPI_ROLE_MASTER (0) /**< SPI master */
#define MR_SPI_ROLE_SLAVE (1) /**< SPI slave */
#define MR_SPI_MODE_0 (0) /**< CPOL = 0, CPHA = 0 */
#define MR_SPI_MODE_1 (1) /**< CPOL = 0, CPHA = 1 */
#define MR_SPI_MODE_2 (2) /**< CPOL = 1, CPHA = 0 */
#define MR_SPI_MODE_3 (3) /**< CPOL = 1, CPHA = 1 */
#define MR_SPI_MODE_0 (0) /**< CPOL = 0, CPHA = 0 */
#define MR_SPI_MODE_1 (1) /**< CPOL = 0, CPHA = 1 */
#define MR_SPI_MODE_2 (2) /**< CPOL = 1, CPHA = 0 */
#define MR_SPI_MODE_3 (3) /**< CPOL = 1, CPHA = 1 */
#define MR_SPI_BIT_ORDER_MSB (0) /**< MSB first */
#define MR_SPI_BIT_ORDER_LSB (1) /**< LSB first */
#define MR_SPI_BIT_ORDER_MSB (0) /**< MSB first */
#define MR_SPI_BIT_ORDER_LSB (1) /**< LSB first */
#define MR_SPI_DATA_BITS_8 (8) /**< 8 bits data */
#define MR_SPI_DATA_BITS_16 (16) /**< 16 bits data */
#define MR_SPI_DATA_BITS_32 (32) /**< 32 bits data */
#define MR_SPI_DATA_BITS_8 (8) /**< 8 bits data */
#define MR_SPI_DATA_BITS_16 (16) /**< 16 bits data */
#define MR_SPI_DATA_BITS_32 (32) /**< 32 bits data */
#define MR_SPI_ADDR_BITS_0 (0) /**< Disable address */
#define MR_SPI_ADDR_BITS_8 (8) /**< 8 bits address */
#define MR_SPI_ADDR_BITS_16 (16) /**< 16 bits address */
#define MR_SPI_ADDR_BITS_32 (32) /**< 32 bits address */
#define MR_SPI_REG_BITS_0 (0) /**< Disable register */
#define MR_SPI_REG_BITS_8 (8) /**< 8 bits register */
#define MR_SPI_REG_BITS_16 (16) /**< 16 bits register */
#define MR_SPI_REG_BITS_32 (32) /**< 32 bits register */
#define MR_CMD_SPI_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_SPI_REG MR_CMD_POS /**< Register command */
#define MR_CMD_SPI_RD_FIFO_SIZE (0x01) /**< Read FIFO size command */
#define MR_CMD_SPI_WR_FIFO_SIZE (0x02) /**< Write FIFO size command */
#define MR_CMD_SPI_RD_FIFO_DATA (0x03) /**< Read FIFO data command */
#define MR_CMD_SPI_WR_FIFO_DATA (0x04) /**< Write FIFO data command */
#define MR_CMD_SPI_TRANSFER (0x05) /**< Transfer command */
#define MR_EVENT_SPI_RD_DATA_INT \
(MR_EVENT_RD | MR_EVENT_DATA | (0x01)) /**< Interrupt on read completion event */
#define MR_EVENT_SPI_WR_DATA_INT \
(MR_EVENT_WR | MR_EVENT_DATA | (0x01)) /**< Interrupt on write completion event */
#define MR_SPI_CS_ACTIVE_LOW (0) /**< CS active low */
#define MR_SPI_CS_ACTIVE_HIGH (1) /**< CS active high */
#define MR_SPI_CS_ACTIVE_NONE (2) /**< CS active none */
typedef uint8_t mr_spi_data_t; /**< SPI read/write data type */
/**
* @brief SPI default configuration.
*/
#define MR_SPI_CONFIG_DEFAULT \
{ \
.baud_rate = 3000000, \
.role = MR_SPI_ROLE_MASTER, \
.mode = MR_SPI_MODE_0, \
.bit_order = MR_SPI_BIT_ORDER_MSB, \
.data_bits = MR_SPI_DATA_BITS_8, \
.addr_bits = MR_SPI_ADDR_BITS_0, \
.cs_delay = 0, \
#define MR_SPI_CONFIG_DEFAULT \
{ \
.baud_rate = 3000000, \
.role = MR_SPI_ROLE_MASTER, \
.mode = MR_SPI_MODE_0, \
.bit_order = MR_SPI_BIT_ORDER_MSB, \
.data_bits = MR_SPI_DATA_BITS_8, \
.reg_bits = MR_SPI_REG_BITS_0, \
.cs_delay = 0, \
}
#define MR_CMD_SPI_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_CMD_SPI_ADDR MR_CMD_POS /**< Address command */
#define MR_CMD_SPI_RD_FIFO_SIZE (0x01) /**< Read FIFO size command */
#define MR_CMD_SPI_WR_FIFO_SIZE (0x02) /**< Write FIFO size command */
#define MR_CMD_SPI_RD_FIFO_DATA (0x03) /**< Read FIFO data command */
#define MR_CMD_SPI_WR_FIFO_DATA (0x04) /**< Write FIFO data command */
#define MR_CMD_SPI_TRANSFER (0x05) /**< Transfer command */
#define MR_EVENT_SPI_RD_COMPLETE_INT \
MR_EVENT_RD_COMPLETE /**< Interrupt on read completion event */
#define MR_EVENT_SPI_WR_COMPLETE_INT \
MR_EVENT_WR_COMPLETE /**< Interrupt on write completion event */
#define MR_SPI_CS_ACTIVE_LOW (0) /**< CS active low */
#define MR_SPI_CS_ACTIVE_HIGH (1) /**< CS active high */
#define MR_SPI_CS_ACTIVE_NONE (2) /**< CS active none */
/**
* @brief SPI configuration structure.
*/
struct mr_spi_config
{
uint32_t baud_rate; /**< Baud rate */
uint32_t role; /**< Role(master/slave) */
uint32_t mode; /**< Mode */
uint32_t bit_order; /**< Bit order */
uint32_t data_bits; /**< Data bits */
uint32_t addr_bits; /**< Address bits */
uint32_t cs_delay; /**< CS delay */
uint32_t baud_rate; /**< Baud rate */
uint32_t role; /**< Role(master/slave) */
uint32_t mode; /**< Mode */
uint32_t bit_order; /**< Bit order */
uint32_t data_bits; /**< Data bits */
uint32_t reg_bits; /**< Register bits */
uint32_t cs_delay; /**< CS delay */
};
/**
@@ -92,48 +94,39 @@ struct mr_spi_config
*/
struct mr_spi_transfer
{
void *rbuf; /**< Read buffer */
const void *wbuf; /**< Write buffer */
size_t count; /**< Transfer size */
void *rbuf; /**< Read buffer */
const void *wbuf; /**< Write buffer */
size_t count; /**< Transfer size */
};
/**
* @brief SPI data type.
*/
typedef uint8_t mr_spi_data_t; /**< SPI read/write data type */
/**
* @brief SPI bus structure.
*/
struct mr_spi_bus
{
struct mr_device device; /**< Device */
struct mr_device device; /**< Device */
struct mr_spi_config config; /**< Configuration */
volatile void *owner; /**< Owner */
struct mr_spi_config config; /**< Configuration */
volatile void *owner; /**< Owner */
uint32_t state; /**< State */
#ifdef MR_USE_PIN
int pin_descriptor; /**< Pin device descriptor */
int pin_descriptor; /**< Pin device descriptor */
#endif /* MR_USE_PIN */
};
#define MR_SPI_CS_MODE_NONE (0) /**< None */
#define MR_SPI_CS_MODE_OUTPUT (1) /**< Output push-pull mode */
#define MR_SPI_CS_MODE_INPUT_UP (4) /**< Input pull-up mode */
#define MR_SPI_CS_MODE_INPUT_DOWN (5) /**< Input pull-down mode */
/**
* @brief SPI bus driver operations structure.
*/
struct mr_spi_bus_driver_ops
{
int (*configure)(struct mr_driver *driver, bool enable,
struct mr_spi_config *config);
int (*transfer)(struct mr_driver *driver, uint32_t *data);
int (*configure)(struct mr_driver *driver, bool enable, struct mr_spi_config *config);
int (*receive)(struct mr_driver *driver, uint32_t *data);
int (*send)(struct mr_driver *driver, uint32_t data);
/* Optional operations */
int (*send_int_configure)(struct mr_driver *driver, bool enable);
int (*cs_configure)(struct mr_driver *driver, uint32_t pin, uint32_t mode);
int (*cs_set)(struct mr_driver *driver, uint32_t pin, uint8_t level);
int (*cs_get)(struct mr_driver *driver, uint32_t pin, uint8_t *level);
};
/**
@@ -141,21 +134,20 @@ struct mr_spi_bus_driver_ops
*/
struct mr_spi_device
{
struct mr_device device; /**< Device */
struct mr_device device; /**< Device */
struct mr_spi_config config; /**< Configuration */
struct mr_fifo rfifo; /**< Read FIFO */
struct mr_fifo wfifo; /**< Write FIFO */
size_t rfifo_size; /**< Read buffer size */
size_t wfifo_size; /**< Write buffer size */
int cs_pin; /**< CS pin */
int cs_active; /**< CS active level */
struct mr_spi_config config; /**< Configuration */
struct mr_fifo rfifo; /**< Read FIFO */
struct mr_fifo wfifo; /**< Write FIFO */
size_t rfifo_size; /**< Read buffer size */
size_t wfifo_size; /**< Write buffer size */
uint32_t cs_pin; /**< CS pin */
uint32_t cs_active; /**< CS active level */
};
int mr_spi_bus_register(struct mr_spi_bus *spi_bus, const char *path,
struct mr_driver *driver);
int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path,
int cs_pin, int cs_active, const char *spi_bus_name);
int mr_spi_bus_register(struct mr_spi_bus *spi_bus, const char *path, struct mr_driver *driver);
int mr_spi_device_register(struct mr_spi_device *spi_device, const char *path, int cs_pin,
int cs_active, const char *spi_bus_name);
int mr_spi_device_unregister(struct mr_spi_device *spi_device);
/** @} */

97
include/device/mr_timer.h Normal file
View File

@@ -0,0 +1,97 @@
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-11-15 MacRsh First version
*/
#ifndef _MR_TIMER_H_
#define _MR_TIMER_H_
#include <include/mr_api.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef MR_USE_TIMER
/**
* @addtogroup Timer
* @{
*/
#define MR_TIMER_MODE_PERIOD (0) /**< Periodic mode */
#define MR_TIMER_MODE_ONESHOT (1) /**< One shot mode */
#define MR_CMD_TIMER_CONFIG MR_CMD_CONFIG /**< Configuration command */
#define MR_EVENT_TIMER_TIMEOUT_INT \
(MR_EVENT_WR | MR_EVENT_DATA | (0x01)) /**< Interrupt on timeout event */
typedef uint32_t mr_timer_data_t; /**< Timer read/write data type */
/**
* @brief Timer default configuration.
*/
#define MR_TIMER_CONFIG_DEFAULT \
{ \
MR_TIMER_MODE_PERIOD, \
}
/**
* @brief Timer configuration structure.
*/
struct mr_timer_config
{
uint32_t mode; /**< Mode */
};
/**
* @brief Timer structure.
*/
struct mr_timer
{
struct mr_device device; /**< Device */
struct mr_timer_config config; /**< Configuration */
uint32_t reload; /**< Reload value */
uint32_t count; /**< Current count */
uint32_t timeout; /**< Timeout */
uint32_t prescaler; /**< Prescaler */
uint32_t period; /**< Period */
};
/**
* @brief Timer driver operations structure.
*/
struct mr_timer_driver_ops
{
int (*configure)(struct mr_driver *driver, bool enable);
int (*start)(struct mr_driver *driver, uint32_t prescaler, uint32_t period);
int (*stop)(struct mr_driver *driver);
int (*get)(struct mr_driver *driver, uint32_t *count_value);
};
/**
* @brief Timer driver data structure.
*/
struct mr_timer_driver_data
{
uint32_t clk; /**< Clock(Hz) */
uint32_t prescaler_max; /**< Prescaler max */
uint32_t period_max; /**< Period max */
};
int mr_timer_register(struct mr_timer *timer, const char *path, const struct mr_driver *driver);
/** @} */
#endif /* MR_USE_TIMER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _MR_TIMER_H_ */

View File

@@ -1,4 +1,4 @@
/*
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
@@ -10,10 +10,12 @@
#ifndef _MR_DEF_H_
#define _MR_DEF_H_
#include "../mr-library/include/mr_config.h"
#include <include/mr_config.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
@@ -26,12 +28,7 @@ extern "C" {
* @{
*/
#define MR_VERSION_MAJOR (1) /**< Major version (X.y.z) */
#define MR_VERSION_MINOR (0) /**< Minor version (x.Y.z) */
#define MR_VERSION_PATCH (0) /**< Patch version (x.y.Z) */
/** Version (X.Y.Z) */
#define MR_VERSION \
(MR_VERSION_MAJOR << 16 | MR_VERSION_MINOR << 8 | MR_VERSION_PATCH)
#define MR_VERSION ("1.0.0") /** Version (X.Y.Z) */
/** @} */
@@ -69,20 +66,14 @@ extern "C" {
* @{
*/
/** Auto-initialization functions */
typedef void (*mr_init_fn_t)(void);
/** Exports an initialization function by level */
#define MR_INIT_EXPORT(_fn, _level) \
MR_USED MR_SECTION("mr_auto_init." _level) \
const mr_init_fn_t _mr_auto_init_##_fn = _fn
/** Exports a Board initialization function */
#define MR_INIT_BOARD_EXPORT(_fn) MR_INIT_EXPORT(_fn, "1")
/** Exports a Driver initialization function */
#define MR_INIT_DRIVER_EXPORT(_fn) MR_INIT_EXPORT(_fn, "2")
/** Exports a Device initialization function */
#define MR_INIT_DEVICE_EXPORT(_fn) MR_INIT_EXPORT(_fn, "3")
/** Exports an App initialization function */
#define MR_INIT_APP_EXPORT(_fn) MR_INIT_EXPORT(_fn, "4")
typedef void (*mr_init_fn_t)(void); /**< Auto-initialization functions */
#define MR_INIT_EXPORT(_fn, _level) \
MR_USED MR_SECTION("mr_auto_init." _level) \
const mr_init_fn_t _mr_auto_init_##_fn = _fn /**< Exports an initialization function by level */
#define MR_INIT_BOARD_EXPORT(_fn) MR_INIT_EXPORT(_fn, "1") /** Exports a Board initialization function */
#define MR_INIT_DRIVER_EXPORT(_fn) MR_INIT_EXPORT(_fn, "2") /** Exports a Driver initialization function */
#define MR_INIT_DEVICE_EXPORT(_fn) MR_INIT_EXPORT(_fn, "3") /** Exports a Device initialization function */
#define MR_INIT_APP_EXPORT(_fn) MR_INIT_EXPORT(_fn, "4") /** Exports an App initialization function */
/** @} */
@@ -91,16 +82,16 @@ typedef void (*mr_init_fn_t)(void);
* @{
*/
#define MR_EOK (0) /** No error */
#define MR_EPERM (-1) /** Operation not permitted */
#define MR_ENOENT (-2) /** No such file or directory */
#define MR_EIO (-3) /** I/O error */
#define MR_ENOMEM (-4) /**< Out of memory */
#define MR_EACCES (-5) /**< Permission denied */
#define MR_EBUSY (-6) /**< Resource busy */
#define MR_EEXIST (-7) /**< Resource exists */
#define MR_EINVAL (-8) /**< Invalid argument */
#define MR_ETIMEOUT (-9) /**< Operation timed */
#define MR_EOK (0) /** No error */
#define MR_EPERM (-1) /** Operation not permitted */
#define MR_ENOENT (-2) /** No such file or directory */
#define MR_EIO (-3) /** I/O error */
#define MR_ENOMEM (-4) /**< Out of memory */
#define MR_EACCES (-5) /**< Permission denied */
#define MR_EBUSY (-6) /**< Resource busy */
#define MR_EEXIST (-7) /**< Resource exists */
#define MR_EINVAL (-8) /**< Invalid argument */
#define MR_ETIMEOUT (-9) /**< Operation timed */
/** @} */
@@ -114,9 +105,9 @@ typedef void (*mr_init_fn_t)(void);
*/
struct mr_heap_block
{
struct mr_heap_block *next; /**< Point to next block */
uint32_t size: 31; /**< Size of this block */
uint32_t allocated: 1; /**< Allocated flag */
struct mr_heap_block *next; /**< Point to next block */
uint32_t size: 31; /**< Size of this block */
uint32_t allocated: 1; /**< Allocated flag */
};
/** @} */
@@ -131,8 +122,8 @@ struct mr_heap_block
*/
struct mr_list
{
struct mr_list *next; /**< Point to next node */
struct mr_list *prev; /**< Point to prev node */
struct mr_list *next; /**< Point to next node */
struct mr_list *prev; /**< Point to prev node */
};
/** @} */
@@ -147,11 +138,11 @@ struct mr_list
*/
struct mr_fifo
{
uint32_t in; /**< Input index */
uint32_t out; /**< Output index */
uint8_t *buf; /**< Data buffer */
uint32_t size: 31; /**< Buffer size */
uint32_t dynamic: 1; /**< Dynamic mode */
uint32_t in; /**< Input index */
uint32_t out; /**< Output index */
uint8_t *buf; /**< Data buffer */
uint32_t size: 31; /**< Buffer size */
uint32_t dynamic: 1; /**< Dynamic mode */
};
/** @} */
@@ -161,38 +152,38 @@ struct mr_fifo
* @{
*/
#define MR_FLAG_RDONLY (0x01 << 24) /**< Read only flag */
#define MR_FLAG_WRONLY (0x02 << 24) /**< Write only flag */
#define MR_FLAG_RDWR (0x03 << 24) /**< Read/write flag */
#define MR_FLAG_RDONLY (0x01 << 24) /**< Read only flag */
#define MR_FLAG_WRONLY (0x02 << 24) /**< Write only flag */
#define MR_FLAG_RDWR (0x03 << 24) /**< Read/write flag */
#define MR_CMD_POS (0x01 << 24) /**< Position command */
#define MR_CMD_EVENT (0x02 << 24) /**< Event command */
#define MR_CMD_CONFIG (0x03 << 24) /**< Configuration command */
#define MR_CMD_POS (0x01 << 24) /**< Position command */
#define MR_CMD_EVENT (0x02 << 24) /**< Event command */
#define MR_CMD_CONFIG (0x03 << 24) /**< Configuration command */
#define MR_EVENT_DATA (0x01 << 24) /**< Data event */
#define MR_EVENT_RD (0x10 << 24) /**< Read event */
#define MR_EVENT_WR (0x20 << 24) /**< Write event */
#define _MR_EVENT_MASK (0xff << 24) /**< Event mask */
#define MR_EVENT_DATA (0x01 << 24) /**< Data event */
#define MR_EVENT_RD (0x10 << 24) /**< Read event */
#define MR_EVENT_WR (0x20 << 24) /**< Write event */
#define _MR_EVENT_MASK (0xff << 24) /**< Event mask */
#define _MR_OPERATE_MASK_RD (0xffff0000) /**< Read lock mask */
#define _MR_OPERATE_MASK_WR (0x0000ffff) /**< Write lock mask */
#define _MR_OPERATE_MASK_ALL (0xffffffff) /**< Read/write lock mask */
#define _MR_OPERATE_MASK_RD (0xffff0000) /**< Read lock mask */
#define _MR_OPERATE_MASK_WR (0x0000ffff) /**< Write lock mask */
#define _MR_OPERATE_MASK_ALL (0xffffffff) /**< Read/write lock mask */
/**
* @brief Device types.
*/
enum mr_device_type
{
MR_DEVICE_TYPE_ADC, /**< ADC device */
MR_DEVICE_TYPE_CAN, /**< CAN device */
MR_DEVICE_TYPE_DAC, /**< DAC device */
MR_DEVICE_TYPE_I2C, /**< I2C device */
MR_DEVICE_TYPE_PIN, /**< PIN device */
MR_DEVICE_TYPE_SERIAL, /**< Serial device */
MR_DEVICE_TYPE_SPI, /**< SPI device */
MR_DEVICE_TYPE_TIMER, /**< Timer device */
MR_DEVICE_TYPE_PWM, /**< PWM device */
MR_DEVICE_TYPE_FDX = 0x80000000, /**< Full duplex device */
MR_DEVICE_TYPE_ADC, /**< ADC device */
MR_DEVICE_TYPE_CAN, /**< CAN device */
MR_DEVICE_TYPE_DAC, /**< DAC device */
MR_DEVICE_TYPE_I2C, /**< I2C device */
MR_DEVICE_TYPE_PIN, /**< PIN device */
MR_DEVICE_TYPE_SERIAL, /**< Serial device */
MR_DEVICE_TYPE_SPI, /**< SPI device */
MR_DEVICE_TYPE_TIMER, /**< Timer device */
MR_DEVICE_TYPE_PWM, /**< PWM device */
MR_DEVICE_TYPE_FDX = 0x80000000, /**< Full duplex device */
};
struct mr_device;
@@ -207,16 +198,9 @@ struct mr_device_ops
int (*open)(struct mr_device *device);
int (*close)(struct mr_device *device);
ssize_t (*read)(struct mr_device *device, int pos, void *buf, size_t count);
ssize_t (*write)(struct mr_device *device, int pos, const void *buf,
size_t count);
ssize_t (*write)(struct mr_device *device, int pos, const void *buf, size_t count);
int (*ioctl)(struct mr_device *device, int pos, int cmd, void *args);
int (*isr)(struct mr_device *device, uint32_t event, void *args);
#ifdef MR_USE_AIO_EXT
ssize_t (*aread)(struct mr_device *device, int pos, void *buf,
size_t count);
ssize_t (*awrite)(struct mr_device *device, int pos, const void *buf,
size_t count);
#endif /* MR_USE_AIO_EXT */
};
/**
@@ -224,24 +208,24 @@ struct mr_device_ops
*/
struct mr_device
{
uint32_t magic; /**< Magic number */
uint32_t magic; /**< Magic number */
#ifndef MR_CFG_DEVICE_NAME_MAX
#define MR_CFG_DEVICE_NAME_MAX (12)
#endif /* MR_CFG_DEVICE_NAME_MAX */
char name[MR_CFG_DEVICE_NAME_MAX]; /**< Name */
struct mr_list list; /**< Same level list */
struct mr_list clist; /**< Children list */
void *parent; /**< Parent device */
char name[MR_CFG_DEVICE_NAME_MAX]; /**< Name */
struct mr_list list; /**< Same level list */
struct mr_list clist; /**< Children list */
void *parent; /**< Parent device */
uint32_t type: 31; /**< Type */
uint32_t fdx: 1; /**< Full duplex */
uint32_t flags; /**< Flags */
size_t ref_count; /**< Reference count */
volatile uint32_t lock; /**< Operation lock */
const struct mr_device_ops *ops; /**< Operations */
struct mr_list elist; /**< Event list */
uint32_t type: 31; /**< Type */
uint32_t fdx: 1; /**< Full duplex */
uint32_t flags; /**< Flags */
size_t ref_count; /**< Reference count */
volatile uint32_t lock; /**< Operation lock */
const struct mr_device_ops *ops; /**< Operations */
struct mr_list elist; /**< Event list */
const void *driver; /**< Driver */
const void *driver; /**< Driver */
};
/**
@@ -249,9 +233,9 @@ struct mr_device
*/
struct mr_descriptor
{
struct mr_device *device; /**< Device */
uint32_t flags; /**< Open flags */
int pos; /**< Current position */
struct mr_device *device; /**< Device */
uint32_t flags; /**< Open flags */
int pos; /**< Current position */
};
/**
@@ -259,11 +243,11 @@ struct mr_descriptor
*/
struct mr_event
{
uint32_t event: 31; /**< Event */
uint32_t self: 1; /**< Self-defined event */
void (*callback)(int descriptor, uint32_t event,
void *args, void *op_data); /**< Callback function */
void *op_data; /**< Operator data */
uint32_t event: 31; /**< Event */
uint32_t self: 1; /**< Self-defined event */
void (*callback)(int descriptor, uint32_t event, void *args,
void *op_data); /**< Callback function */
void *op_data; /**< Operator data */
};
/** @} */
@@ -278,8 +262,8 @@ struct mr_event
*/
struct mr_driver
{
const void *ops; /**< Operations */
void *data; /**< Data */
const void *ops; /**< Operations */
void *data; /**< Data */
};
/** @} */

View File

@@ -1,53 +1,67 @@
/*
/**
* @copyright (c) 2023-2024, MR Development Team
*
* @license SPDX-License-Identifier: Apache-2.0
*
* @date 2023-10-20 MacRsh First version
* @date 2024-04-07 MacRsh Add async operation support
* @date 2024-05-08 MacRsh Add attach/detach operation
*/
#include "../mr-library/include/mr_api.h"
#include <string.h>
#include <include/mr_api.h>
#ifdef MR_USE_DEVICE_LOG
#undef MR_LOG_TAG
#define MR_LOG_TAG ("device")
#endif /* MR_USE_DEVICE_LOG */
#define _MAGIC_NUMBER (0xdeadbeef) /**< Magic number */
#define _MAGIC_NUMBER (0xdeadbeef) /**< Magic number */
/**
* @brief Device event complete structure.
*/
struct _event
{
struct mr_list list; /**< Event list */
uint32_t descriptor: 30; /**< Descriptor */
uint32_t hold: 1; /**< Hold flag */
uint32_t free: 1; /**< Free flag */
uint32_t event: 31; /**< Event */
uint32_t self: 1; /**< Self-defined flag */
void (*callback)(int descriptor, uint32_t event,
void *args, void *op_data); /**< Callback function */
void *op_data; /**< Operator data */
struct mr_list list; /**< Event list */
uint32_t descriptor: 30; /**< Descriptor */
uint32_t hold: 1; /**< Hold flag */
uint32_t free: 1; /**< Free flag */
uint32_t event: 31; /**< Event */
uint32_t self: 1; /**< Self-defined flag */
void (*callback)(int descriptor, uint32_t event, void *args,
void *op_data); /**< Callback function */
void *op_data; /**< Operator data */
};
static struct mr_device _root_device = {
.magic = _MAGIC_NUMBER,
.name = "/",
.list = MR_LIST_INIT(&_root_device.list),
.clist = MR_LIST_INIT(&_root_device.clist),
.parent = NULL};
/** Root device */
static struct mr_device _root_device = {.magic = _MAGIC_NUMBER,
.name = "/",
.list = MR_LIST_INIT(&_root_device.list),
.clist = MR_LIST_INIT(&_root_device.clist),
.parent = NULL};
/** Device descriptor table */
#ifndef MR_CFG_DESCRIPTOR_MAX
#define MR_CFG_DESCRIPTOR_MAX (128)
#endif /* MR_CFG_DESCRIPTOR_MAX */
static struct mr_descriptor _descriptor_map[MR_CFG_DESCRIPTOR_MAX] = {0};
static struct mr_descriptor _descriptor_table[MR_CFG_DESCRIPTOR_MAX] = {0};
MR_INLINE struct mr_device *_device_find_from(const char *name,
struct mr_device *parent)
static bool _device_flags_is_valid(const struct mr_device *device, uint32_t flags)
{
return (device->flags & flags) == flags;
}
static bool _descriptor_flags_is_valid(int descriptor, uint32_t flags)
{
return (_descriptor_table[descriptor].flags & flags) == flags;
}
static bool _descriptor_is_valid(int descriptor)
{
return (descriptor >= 0) && (descriptor < MR_ARRAY_NUM(_descriptor_table)) &&
(_descriptor_table[descriptor].device != NULL);
}
static struct mr_device *_device_find_from(const char *name, struct mr_device *parent)
{
/* Deal with special names */
if (strcmp(name, "..") == 0)
@@ -60,8 +74,7 @@ MR_INLINE struct mr_device *_device_find_from(const char *name,
}
/* Find the device with the specified name */
for (struct mr_list *list = parent->clist.next; list != &parent->clist;
list = list->next)
for (struct mr_list *list = parent->clist.next; list != &parent->clist; list = list->next)
{
struct mr_device *iter = MR_CONTAINER_OF(list, struct mr_device, list);
if (strcmp(name, iter->name) == 0)
@@ -72,8 +85,7 @@ MR_INLINE struct mr_device *_device_find_from(const char *name,
return NULL;
}
MR_INLINE struct mr_device *_device_next_find(const char **path,
struct mr_device *parent)
static struct mr_device *_device_next_find(const char **path, struct mr_device *parent)
{
/* Skip the leading '/' */
if ((*path)[0] == '/')
@@ -135,8 +147,7 @@ static int _device_register_iter(struct mr_device *device, const char *path,
return MR_EOK;
}
static struct mr_device *_device_find_iter(const char *path,
struct mr_device *parent)
static struct mr_device *_device_find_iter(const char *path, struct mr_device *parent)
{
struct mr_device *next_parent = _device_next_find(&path, parent);
if (next_parent != NULL)
@@ -149,24 +160,7 @@ static struct mr_device *_device_find_iter(const char *path,
return _device_find_from(path, parent);
}
MR_INLINE bool _device_flags_is_valid(const struct mr_device *device,
uint32_t flags)
{
return MR_BIT_IS_SET(device->flags, flags);
}
MR_INLINE bool _descriptor_is_valid(int descriptor)
{
return (descriptor >= 0) && (descriptor < MR_ARRAY_NUM(_descriptor_map)) &&
(_descriptor_map[descriptor].device != NULL);
}
MR_INLINE bool _descriptor_flags_is_valid(int descriptor, uint32_t flags)
{
return MR_BIT_IS_SET(_descriptor_map[descriptor].flags, flags);
}
MR_INLINE struct mr_device *_device_find(const char *path)
static struct mr_device *_device_find(const char *path)
{
/* Critical section enter */
mr_critical_enter();
@@ -179,8 +173,7 @@ MR_INLINE struct mr_device *_device_find(const char *path)
return device;
}
MR_INLINE int _device_take(struct mr_device *device, int descriptor,
uint32_t mask)
static int _device_take(struct mr_device *device, int descriptor, uint32_t mask)
{
int ret;
@@ -211,7 +204,7 @@ MR_INLINE int _device_take(struct mr_device *device, int descriptor,
return ret;
}
MR_INLINE void _device_release(struct mr_device *device, uint32_t mask)
static void _device_release(struct mr_device *device, uint32_t mask)
{
/* If the device is not FDX, the read/writing must be locked */
mask = (device->fdx == true) ? mask : _MR_OPERATE_MASK_ALL;
@@ -220,7 +213,7 @@ MR_INLINE void _device_release(struct mr_device *device, uint32_t mask)
MR_BIT_CLR(device->lock, mask);
}
MR_INLINE int _descriptor_allocate(struct mr_device *device, uint32_t flags)
static int _descriptor_allocate(struct mr_device *device, uint32_t flags)
{
int descriptor = -1;
@@ -234,13 +227,13 @@ MR_INLINE int _descriptor_allocate(struct mr_device *device, uint32_t flags)
mr_critical_enter();
/* Try to allocate the descriptor */
for (int i = 0; i < MR_ARRAY_NUM(_descriptor_map); i++)
for (int i = 0; i < MR_ARRAY_NUM(_descriptor_table); i++)
{
if (_descriptor_map[i].device == NULL)
if (_descriptor_table[i].device == NULL)
{
_descriptor_map[i].device = device;
_descriptor_map[i].flags = flags;
_descriptor_map[i].pos = -1;
_descriptor_table[i].device = device;
_descriptor_table[i].flags = flags;
_descriptor_table[i].pos = -1;
descriptor = i;
break;
}
@@ -253,20 +246,19 @@ MR_INLINE int _descriptor_allocate(struct mr_device *device, uint32_t flags)
return (descriptor >= 0) ? descriptor : MR_ENOMEM;
}
MR_INLINE void _descriptor_free(int descriptor)
static void _descriptor_free(int descriptor)
{
/* Critical section enter */
mr_critical_enter();
/* Free the descriptor */
_descriptor_map[descriptor].device = NULL;
_descriptor_table[descriptor].device = NULL;
/* Critical section exit */
mr_critical_exit();
}
MR_INLINE int _event_create(struct mr_device *device, int descriptor,
const struct mr_event *event)
static int _event_create(struct mr_device *device, int descriptor, const struct mr_event *event)
{
int ret;
@@ -274,13 +266,11 @@ MR_INLINE int _event_create(struct mr_device *device, int descriptor,
mr_critical_enter();
/* Check if the event exists */
for (struct mr_list *list = device->elist.next; list != &device->elist;
list = list->next)
for (struct mr_list *list = device->elist.next; list != &device->elist; list = list->next)
{
struct _event *_event = MR_CONTAINER_OF(list, struct _event, list);
if ((_event->descriptor == descriptor) &&
(_event->event == event->event))
if ((_event->descriptor == descriptor) && (_event->event == event->event))
{
ret = MR_EEXIST;
goto _exit;
@@ -315,8 +305,8 @@ _exit:
return ret;
}
MR_INLINE int _event_destroy(const struct mr_device *device, int descriptor,
const struct mr_event *event)
static int _event_destroy(const struct mr_device *device, int descriptor,
const struct mr_event *event)
{
int ret;
@@ -324,13 +314,11 @@ MR_INLINE int _event_destroy(const struct mr_device *device, int descriptor,
mr_critical_enter();
/* Find the event */
for (struct mr_list *list = device->elist.next; list != &device->elist;
list = list->next)
for (struct mr_list *list = device->elist.next; list != &device->elist; list = list->next)
{
struct _event *_event = MR_CONTAINER_OF(list, struct _event, list);
if ((_event->descriptor != descriptor) ||
(_event->event != event->event))
if ((_event->descriptor != descriptor) || (_event->event != event->event))
{
continue;
}
@@ -359,14 +347,13 @@ _exit:
return ret;
}
MR_INLINE void _event_destroy_all(const struct mr_device *device, int descriptor)
static void _event_destroy_all(const struct mr_device *device, int descriptor)
{
/* Critical section enter */
mr_critical_enter();
/* Destroy all events for the specified descriptor */
for (struct mr_list *list = device->elist.next; list != &device->elist;
list = list->next)
for (struct mr_list *list = device->elist.next; list != &device->elist; list = list->next)
{
struct _event *_event = MR_CONTAINER_OF(list, struct _event, list);
@@ -393,12 +380,10 @@ MR_INLINE void _event_destroy_all(const struct mr_device *device, int descriptor
mr_critical_exit();
}
MR_INLINE void _event_handler(const struct mr_device *device, uint32_t event,
void *args)
static void _event_handler(const struct mr_device *device, uint32_t event, void *args)
{
/* Trigger events */
for (struct mr_list *list = device->elist.next; list != &device->elist;
list = list->next)
for (struct mr_list *list = device->elist.next; list != &device->elist; list = list->next)
{
struct _event *_event = MR_CONTAINER_OF(list, struct _event, list);
uint32_t mask = (_event->self == true) ? event : event & _MR_EVENT_MASK;
@@ -413,8 +398,7 @@ MR_INLINE void _event_handler(const struct mr_device *device, uint32_t event,
_event->hold = true;
/* Call the callback if the event matches */
_event->callback(_event->descriptor, _event->event, args,
_event->op_data);
_event->callback(_event->descriptor, _event->event, args, _event->op_data);
/* Release the event */
_event->hold = false;
@@ -429,9 +413,8 @@ MR_INLINE void _event_handler(const struct mr_device *device, uint32_t event,
}
}
static int _device_register(struct mr_device *device, const char *path,
uint32_t type, struct mr_device_ops *ops,
const void *driver, const char *to_path)
static int _device_register(struct mr_device *device, const char *path, uint32_t type,
struct mr_device_ops *ops, const void *driver, const char *to_path)
{
static struct mr_device_ops null_ops = {NULL};
struct mr_device *to_device = &_root_device;
@@ -456,8 +439,8 @@ static int _device_register(struct mr_device *device, const char *path,
device->parent = NULL;
device->type = type & (~MR_DEVICE_TYPE_FDX);
device->fdx = MR_BIT_IS_SET(type, MR_DEVICE_TYPE_FDX);
device->flags = (ops->read != NULL ? MR_FLAG_RDONLY : 0) |
(ops->write != NULL ? MR_FLAG_WRONLY : 0);
device->flags =
(ops->read != NULL ? MR_FLAG_RDONLY : 0) | (ops->write != NULL ? MR_FLAG_WRONLY : 0);
device->ref_count = 0;
device->lock = 0;
device->ops = ops;
@@ -541,13 +524,6 @@ static int _device_isr(struct mr_device *device, uint32_t event, void *args)
}
}
#ifdef MR_USE_AIO_EXT
/* Release the device based on event */
uint32_t mask = (event & MR_EVENT_RD) ? _MR_OPERATE_MASK_RD : 0;
mask |= (event & MR_EVENT_WR) ? _MR_OPERATE_MASK_WR : 0;
_device_release(device, mask);
#endif /* MR_USE_AIO_EXT */
/* Call the event handler */
_event_handler(device, event, &ret);
ret = MR_EOK;
@@ -608,7 +584,7 @@ _exit:
static int _device_close(int descriptor)
{
/* Get the device */
struct mr_device *device = _descriptor_map[descriptor].device;
struct mr_device *device = _descriptor_table[descriptor].device;
if (device == NULL)
{
return MR_EINVAL;
@@ -646,10 +622,10 @@ _exit:
return ret;
}
static ssize_t _device_read(int descriptor, void *buf, size_t count, bool async)
static ssize_t _device_read(int descriptor, void *buf, size_t count)
{
/* Find the device */
struct mr_device *device = _descriptor_map[descriptor].device;
struct mr_device *device = _descriptor_table[descriptor].device;
if (device == NULL)
{
return MR_EINVAL;
@@ -669,49 +645,20 @@ static ssize_t _device_read(int descriptor, void *buf, size_t count, bool async)
}
/* Get the position */
int pos = _descriptor_map[descriptor].pos;
#ifdef MR_USE_AIO_EXT
if (async == true)
{
/* Check if the asynchronous operation is supported */
if (device->ops->aread == NULL)
{
ret = MR_EPERM;
goto _exit;
}
/* Asynchronous operation */
ret = device->ops->aread(device, pos, buf, count);
/* If the asynchronous operation succeeds, the device is released only
* after the operation is completed */
if ((ret == 0) && (count > 0))
{
return ret;
}
/* Skip synchronous operation */
goto _exit;
}
#endif /* MR_USE_AIO_EXT */
int pos = _descriptor_table[descriptor].pos;
/* Synchronous operation */
ret = device->ops->read(device, pos, buf, count);
#ifdef MR_USE_AIO_EXT
_exit:
#endif /* MR_USE_AIO_EXT */
/* Release the device */
_device_release(device, _MR_OPERATE_MASK_RD);
return ret;
}
static ssize_t _device_write(int descriptor, const void *buf, size_t count,
bool async)
static ssize_t _device_write(int descriptor, const void *buf, size_t count)
{
/* Find the device */
struct mr_device *device = _descriptor_map[descriptor].device;
struct mr_device *device = _descriptor_table[descriptor].device;
if (device == NULL)
{
return MR_EINVAL;
@@ -731,39 +678,11 @@ static ssize_t _device_write(int descriptor, const void *buf, size_t count,
}
/* Get the position */
int pos = _descriptor_map[descriptor].pos;
#ifdef MR_USE_AIO_EXT
if (async == true)
{
/* Check if the asynchronous operation is supported */
if (device->ops->awrite == NULL)
{
ret = MR_EPERM;
goto _exit;
}
/* Asynchronous operation */
ret = device->ops->awrite(device, pos, buf, count);
/* If the asynchronous operation succeeds, the device is released only
* after the operation is completed */
if ((ret == 0) && (count > 0))
{
return ret;
}
/* Skip synchronous operation */
goto _exit;
}
#endif /* MR_USE_AIO_EXT */
int pos = _descriptor_table[descriptor].pos;
/* Synchronous operation */
ret = device->ops->write(device, pos, buf, count);
#ifdef MR_USE_AIO_EXT
_exit:
#endif /* MR_USE_AIO_EXT */
/* Release the device */
_device_release(device, _MR_OPERATE_MASK_WR);
return ret;
@@ -772,7 +691,7 @@ _exit:
static int _device_ioctl(int descriptor, int cmd, void *args)
{
/* Find the device */
struct mr_device *device = _descriptor_map[descriptor].device;
struct mr_device *device = _descriptor_table[descriptor].device;
if (device == NULL)
{
return MR_EINVAL;
@@ -786,7 +705,7 @@ static int _device_ioctl(int descriptor, int cmd, void *args)
}
/* Get the position */
int pos = _descriptor_map[descriptor].pos;
int pos = _descriptor_table[descriptor].pos;
/* Control the device */
switch (cmd)
@@ -801,7 +720,7 @@ static int _device_ioctl(int descriptor, int cmd, void *args)
}
/* Set the position */
_descriptor_map[descriptor].pos = *(int *)args;
_descriptor_table[descriptor].pos = *(int *)args;
ret = MR_EOK;
break;
}
@@ -870,8 +789,8 @@ size_t _mr_descriptor_map_get(struct mr_descriptor **descriptor_map)
{
MR_ASSERT(descriptor_map != NULL);
*descriptor_map = _descriptor_map;
return sizeof(_descriptor_map) / sizeof(struct mr_descriptor);
*descriptor_map = _descriptor_table;
return sizeof(_descriptor_table) / sizeof(struct mr_descriptor);
}
/**
@@ -886,9 +805,8 @@ size_t _mr_descriptor_map_get(struct mr_descriptor **descriptor_map)
*
* @return The error code.
*/
int mr_device_register_to(struct mr_device *device, const char *path,
uint32_t type, struct mr_device_ops *ops,
const void *driver, const char *to_path)
int mr_device_register_to(struct mr_device *device, const char *path, uint32_t type,
struct mr_device_ops *ops, const void *driver, const char *to_path)
{
MR_ASSERT((device != NULL) && (device->magic != _MAGIC_NUMBER));
MR_ASSERT(path != NULL);
@@ -904,8 +822,7 @@ int mr_device_register_to(struct mr_device *device, const char *path,
return ret;
_exit:
MR_LOG_E("Register '%s' to '%s' failed: %s.\r\n", path, to_path,
mr_strerror(ret));
MR_LOG_E("Register '%s' to '%s' failed: %s.\r\n", path, to_path, mr_strerror(ret));
return ret;
}
@@ -920,9 +837,8 @@ _exit:
*
* @return The error code.
*/
int mr_device_register(struct mr_device *device, const char *path,
uint32_t type, struct mr_device_ops *ops,
const void *driver)
int mr_device_register(struct mr_device *device, const char *path, uint32_t type,
struct mr_device_ops *ops, const void *driver)
{
MR_ASSERT((device != NULL) && (device->magic != _MAGIC_NUMBER));
MR_ASSERT(path != NULL);
@@ -1063,7 +979,7 @@ ssize_t mr_device_read(int descriptor, void *buf, size_t count)
}
/* Read the device */
ssize_t ret = _device_read(descriptor, buf, count, false);
ssize_t ret = _device_read(descriptor, buf, count);
if (ret < 0)
{
goto _exit;
@@ -1097,7 +1013,7 @@ ssize_t mr_device_write(int descriptor, const void *buf, size_t count)
}
/* Write the device */
ssize_t ret = _device_write(descriptor, buf, count, false);
ssize_t ret = _device_write(descriptor, buf, count);
if (ret < 0)
{
goto _exit;
@@ -1142,77 +1058,3 @@ _exit:
MR_LOG_E("Ioctl '%d' failed: %s.\r\n", descriptor, mr_strerror(ret));
return ret;
}
#ifdef MR_USE_AIO_EXT
/**
* @brief This function read data asynchronously from a device.
*
* @param descriptor The descriptor of the device.
* @param buf The buffer to be read.
* @param count The count of read.
*
* @return The size of the actual read if the operation is completed, 0 if the
* operation is not completed, otherwise an error code.
*/
ssize_t mr_device_aread(int descriptor, void *buf, size_t count)
{
MR_ASSERT((buf != NULL) || (count == 0));
/* Check if the descriptor is valid */
if (_descriptor_is_valid(descriptor) == false)
{
return MR_EINVAL;
}
/* Read the device */
ssize_t ret = _device_read(descriptor, buf, count, true);
if (ret < 0)
{
goto _exit;
}
/* Return actual read size */
return ret;
_exit:
MR_LOG_E("Aread '%d' failed: %s.\r\n", descriptor, mr_strerror((int)ret));
return ret;
}
/**
* @brief This function write data to a device.
*
* @param descriptor The descriptor of the device.
* @param buf The buffer to be written.
* @param count The count of write.
*
* @return The size of the actual write if the operation is completed, 0 if the
* operation is not completed, otherwise an error code.
*/
ssize_t mr_device_awrite(int descriptor, const void *buf, size_t count)
{
MR_ASSERT((buf != NULL) || (count == 0));
/* Check if the descriptor is valid */
if (_descriptor_is_valid(descriptor) == false)
{
return MR_EINVAL;
}
/* Write the device */
ssize_t ret = _device_write(descriptor, buf, count, true);
if (ret < 0)
{
goto _exit;
}
/* Return actual write size */
return ret;
_exit:
MR_LOG_E("Awrite '%d' failed: %s.\r\n", descriptor, mr_strerror((int)ret));
return ret;
}
#endif /* MR_USE_AIO_EXT */