添加文档

This commit is contained in:
MacRsh
2023-02-25 21:38:32 +08:00
parent 02d463e07b
commit 9599963085
4 changed files with 496 additions and 0 deletions

213
document/device.md Normal file
View File

@@ -0,0 +1,213 @@
`mr-library`
# **设备框架**
**device** 设备框架对驱动设备进行了抽象。应用层通过使用设备框架对底层设备进行交互。底层驱动仅需适配对应接口,即可实现对应功能,且底层驱动变化对应用层无影响,降低了应用程序移植成本,提高了程序可靠性。
#### **设备结构体**
```
struct mr_device
{
/* Device object */
struct mr_object object; /* 内核对象 */
/* Device properties */
enum mr_device_type type; /* 设备类型 */
mr_uint16_t support_flag; /* 设备支持标志 */
mr_uint16_t open_flag; /* 设备打开标志 */
mr_uint8_t ref_count; /* 设备被引用次数 */
/* Device operations and callbacks */
struct mr_device_ops *ops; /* 设备操作方法 */
mr_err_t (*rx_callback)(mr_device_t device, void *args); /* 设备接收回调函数 */
mr_err_t (*tx_callback)(mr_device_t device, void *args); /* 设备发送回调函数 */
/* Hardware private data */
void *private_data; /* 设备私有数据 */
};
```
#### **设备类型**
```
enum mr_device_type
{
MR_DEVICE_TYPE_PIN,
MR_DEVICE_TYPE_SPI_BUS,
MR_DEVICE_TYPE_SPI,
MR_DEVICE_TYPE_I2C,
MR_DEVICE_TYPE_UART,
MR_DEVICE_TYPE_ADC,
MR_DEVICE_TYPE_DAC,
MR_DEVICE_TYPE_PWM,
MR_DEVICE_TYPE_TIMER,
MR_DEVICE_TYPE_WDT,
MR_DEVICE_TYPE_FLASH,
MR_DEVICE_TYPE_SDRAM,
/* ... */
};
```
#### **设备支持标志**
#### **设备打开标志**
#### **设备操作方法**
```
struct mr_device_ops
{
mr_err_t (*open)(mr_device_t device);
mr_err_t (*close)(mr_device_t device);
mr_err_t (*ioctl)(mr_device_t device, int cmd, void *args);
mr_size_t (*read)(mr_device_t device, mr_off_t pos, void *buf, mr_size_t count);
mr_size_t (*write)(mr_device_t device, mr_off_t pos, const void *buf, mr_size_t count);
};
```
`open` 初始化设备,使设备能够完成后续操作。该函数在设备整个生命周期内只会被调用一次。
`close` 关闭设备,解除设备的资源占用。该函数在设备整个生命周期内只会被调用一次。
`ioctl` 控制设备,响应设备的各种控制命令。
`read` 从设备读取数据。
`write` 向设备写入数据。
## **设备对外暴露接口**
#### **将设备注册到内核**
```
mr_err_t mr_device_register(mr_device_t device, const char *name);
```
|参数|描述|
|:--|:--|
|device|设备句柄|
|name|设备名称|
|**返回**|— —|
|对象句柄|寻找成功|
|MR_NULL|寻找失败|
注:设备名称不可以重复,建议使用 xxx1、xxx2 方式为设备命名。如果设备是挂载在某个设备下的,建议使用 xxx10、xxx11 方式为设备命名xxx10 即为 xxx1 设备下的 0号设备
#### **打开设备**
```
mr_device_t mr_device_open(char *name, mr_uint16_t flags);
```
|参数|描述|
|:--|:--|
|name|设备名称|
|flags|打开设备的方式|
|**返回**|— —|
|设备句柄|打开成功|
|MR_NULL|打开失败|
#### **关闭设备**
```
mr_err_t mr_device_close(mr_device_t device);
```
|参数|描述|
|:--|:--|
|device|设备句柄|
|**返回**|— —|
|MR_ERR_OK|关闭成功|
|Other|关闭失败,返回错误码|
#### **控制设备**
```
mr_err_t mr_device_ioctl(mr_device_t device, int cmd, void *args);
```
|参数|描述|
|:--|:--|
|device|设备句柄|
|cmd|控制命令|
|args|控制参数|
|**返回**|— —|
|MR_ERR_OK|关闭成功|
|Other|关闭失败,返回错误码|
#### **从设备读取数据**
```
mr_size_t mr_device_read(mr_device_t device, mr_off_t pos, void *buf, mr_size_t count);
```
|参数|描述|
|:--|:--|
|device|设备句柄|
|pos|偏移值|
|buf|内存缓冲区,读取到的数据将保存到缓冲区中|
|count|读取数据数量|
|**返回**|— —|
|实际读取数据数量|读取成功|
|0|读取失败|
pos 偏移量请参考实际设备确定,例如 pin 设备的 pos 即为 相对 0 号 io 的偏移值。如不需要偏移请传入 0 。
#### **向设备写入数据**
```
mr_size_t mr_device_write(mr_device_t device, mr_off_t pos, void *buf, mr_size_t count);
```
|参数|描述|
|:--|:--|
|device|设备句柄|
|pos|偏移值|
|buf|内存缓冲区,缓冲区数据将被写入到设备|
|count|写入数据数量|
|**返回**|— —|
|实际写入数据数量|写入成功|
|0|写入失败|
pos 偏移量请参考实际设备确定,例如 pin 设备的 pos 即为 相对 0 号 io 的偏移值。如不需要偏移请传入 0 。
## **设备框架使用示例**
下面的代码为访问 PIN 设备示例。
1. 通过 `mr_device_open()` 打开设备,获得设备句柄。
2. 通过 `mr_device_ioctl()` 控制 GPIO 初始化。
3. 通过 `mr_device_write()` 向 GPIO 写入电平数据。
4. 通过 `mr_device_read()` 从 GPIO 读取电平数据。
5. 通过 `mr_device_close()` 关闭 PIN 设备。
```
/* 定义高低电平(内核中已存在)*/
#define MR_HIGH 1
#define MR_LOW 0
/* 计算 GPIO C13 的标号 */
#define GPIO_NUM ('C' - 'A') * 16 + 13;
/* 定义一个设备指针 */
mr_device_t device;
int main(void)
{
/* 使用可读可写的方式打开 pin 设备 */
device = mr_device_open("pin", MR_OPEN_RDWR);
/* 使用设置参数命令,将 GPIO C13 配置成推挽输出模式 */
mr_uint8_t pin_num = GPIO_NUM;
mr_device_ioctl(device, MR_CMD_SET_PARAM | MR_PIN_OUTPUT, &pin_num);
/* 向 GPIO C13 写入 高电平 */
mr_uint8_t value = MR_HIGH;
mr_device_write(device, pin_num, &value, 1);
/* 使用设置参数命令,将 GPIO C13 配置成输入模式 */
mr_device_ioctl(device, MR_CMD_SET_PARAM | MR_PIN_INPUT, &pin_num);
/* 从 GPIO C13 读取电平 */
mr_device_read(device, pin_num, &value, 1);
/* 关闭 pin 设备 */
mr_device_close(device);
}
```

View File

@@ -7,6 +7,7 @@
`mr-library` 框架中,容器由 `名称``类型``链表` 组成。`名称` 用于对容器进行介绍和检索,也可用于为对象添加前缀名。`类型` 则是对容器的定义,不同类别的对象经过分类后被注册到对应的容器中。`链表` 是容器的链接方式,对象则是通过链表放入容器中。
```
/* 容器结构体 */
struct mr_container
{
char *name;
@@ -15,10 +16,24 @@ struct mr_container
};
```
#### **寻找容器**
```
mr_container_t mr_container_find(enum mr_container_type type);
```
|参数|描述|
|:--|:--|
|type|容器的类型,只能是 mr_container_type 中的类型|
|**返回**|— —|
|容器句柄|寻找成功|
|MR_NULL|寻找失败|
## **对象**
`mr-library` 框架中,容器由 `名称``状态``链表` 组成。`名称` 是对象名,也是容器查找等操作所依托的基础。`状态` 则保存有该对象的状态,主动操作或错误调用等情况发生时,状态也会随之改变。`链表` 则是对象的链接方式,当对象被注册到容器后,该对象将被加入到对应容器的链表中。
```
/* 对象结构体 */
struct mr_object
{
char *name;
@@ -27,6 +42,110 @@ struct mr_object
};
```
#### **从容器中寻找对象**
```
mr_object_t mr_object_find(char *name, enum mr_container_type type);
```
|参数|描述|
|:--|:--|
|name|对象名称|
|type|对象注册的容器类型,只能是 mr_container_type 中的类型|
|**返回**|— —|
|对象句柄|寻找成功|
|MR_NULL|寻找失败|
#### **初始化对象**
```
void mr_object_init(mr_object_t object, const char *name);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|name|对象名称|
#### **创建动态对象**
```
mr_object_t mr_object_create(char *name);
```
|参数|描述|
|:--|:--|
|name|对象名称|
|**返回**|— —|
|对象句柄|创建成功|
|MR_NULL|创建失败|
#### **注册对象到容器**
```
mr_err_t mr_object_register(mr_object_t object, enum mr_container_type type);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|type|对象注册的容器类型,只能是 mr_container_type 中的类型|
|**返回**|— —|
|MR_ERR_OK|注册成功|
|Other|注册失败,返回错误码|
#### **将对象从容器中注销**
```
mr_err_t mr_object_unregister(mr_object_t object);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|**返回**|— —|
|MR_ERR_OK|注销成功|
|Other|注销失败,返回错误码|
#### **删除对象**
```
mr_err_t mr_object_delete(mr_object_t object);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|**返回**|— —|
|MR_ERR_OK|删除成功|
|Other|删除失败,返回错误码|
#### **将对象移动到指定容器**
```
mr_err_t mr_object_move(mr_object_t object, enum mr_container_type dest_type);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|type|对象要移动到的容器类型,只能是 mr_container_type 中的类型|
|**返回**|— —|
|MR_ERR_OK|删除成功|
|Other|删除失败,返回错误码|
#### **重命名对象**
```
void mr_object_rename(mr_object_t object, char *new_name);
```
|参数|描述|
|:--|:--|
|object|对象句柄|
|name|重命名名称|
## **类型**
所有的类型命都以 `mr` 开头然后是 `类型` 最后以 `_t` 结尾。

164
document/spi.md Normal file
View File

@@ -0,0 +1,164 @@
`mr-library`
# **SPI设备**
**spi设备** 可以分为 2 种SPI 总线和 SPI 设备。SPI 设备挂载在 SPI 总线上,每个 SPI 设备都可以获取 SPI 总线,然后开始传输数据。
#### **SPI 总线结构体**
```
struct mr_spi_bus
{
struct mr_device parent;
struct mr_spi_bus_ops *ops;
volatile mr_uint8_t lock;
struct mr_spi_device *owner;
};
```
#### **SPI 设备结构体**
```
struct mr_spi_device
{
struct mr_device parent;
struct mr_spi_config config;
struct mr_spi_bus *bus;
};
```
通过结构体我们可以看到 SPI 总线包含一个 SPI 设备指针,用来获取当前占用总线的 SPI 设备。SPI 设备也拥有一个SPI 总线指针,用来指示设备挂载在哪个总线。
#### **SPI设备配置结构体**
```
struct mr_spi_config
{
mr_uint32_t baud_rate; /* 速率 */
mr_uint8_t master_slave; /* 主从模式 */
mr_uint8_t mode; /* SPI模式 */
mr_uint8_t bit_order; /* 高低位优先 */
mr_uint8_t data_bits; /* 数据位数 */
mr_uint8_t cs_active; /* cs有效电平 */
};
```
## **SPI设备**
根据设备框架结构SPI 总线在使用前应已注册到内核中,而我们的 SPI 设备还暂未注册到内核,设备框架还无法使用,因此我们在使用前需先向内核注册一个 SPI设备。
#### **向内核注册 SPI 设备**
```
mr_err_t mr_spi_device_register(mr_spi_device_t spi_device,
const char *name,
mr_uint16_t support_flag,
void *cs_data);
```
|参数|描述|
|:--|:--|
|spi_device|SPI 设备句柄|
|name|SPI 设备名称|
|support_flag|SPI 设备支持标志|
|cs_data|SPI 设备 cs 引脚标号|
|**返回**|— —|
|MR_ERR_OK|关闭成功|
|Other|关闭失败,返回错误码|
注:在使用前需先创建一个 spi_device 实例并且不能是局部变量也不允许被释放。SPI 设备被注册到内核后,会自动将其配置成默认配置,如下:
```
#define MR_SPI_CONFIG_DEFAULT \
{ \
.baud_rate = 3000000, /* 3M bits/s */ \
.master_slave = MR_SPI_MASTER, /* spi master */ \
.mode = MR_SPI_MODE_0, /* CPOL=0,CPHA=0 */ \
.bit_order = MR_SPI_BIT_ORDER_MSB, /* MSB first sent */ \
.data_bits = MR_SPI_DATA_BITS_8, /* 8 data_bits */ \
.cs_active = MR_SPI_CS_ACTIVE_LOW, /* CS low level active */ \
}
```
## **SPI 设备使用示例**
1. 通过 `mr_spi_device_register()` 将 SPI 设备注册到内核。
2. 通过 `mr_device_open()` 打开设备,获得设备句柄。
3. 通过 `mr_device_ioctl()` 将 SPI 设备挂载到 SPI 总线上。
4. 通过 `mr_device_ioctl()` 配置 SPI 设备参数。
5. 通过 `mr_device_write()` 向 SPI 设备写入数据。
6. 通过 `mr_device_read()` 从 SPI 设备 读取数据。
7. 通过 `mr_device_ioctl()` 控制 SPI 设备全双工传输。
8. 通过 `mr_device_close()` 关闭 SPI 设备。
```
/* 计算 GPIO C13 的标号 */
#define CS_NUM ('C' - 'A') * 16 + 13;
/* 定义一个 SPI 设备 */
struct mr_spi_device spi_device;
mr_base_t spi_device_cs_num = CS_NUM;
/* 定义一个设备指针 */
mr_device_t device;
int main(void)
{
/* 将 SPI 设备注册到内核 */
mr_spi_device_register(&spi_device, "spi10", MR_OPEN_RDWR, &spi_device_cs_num);
/* 使用可读可写的方式打开 spi10 设备 */
device = mr_device_open("spi10", MR_OPEN_RDWR);
/* 使用挂载命令,将 spi10 设备 挂载到 spi1 总线上 */
mr_device_ioctl(device, MR_CMD_ATTACH, "spi1");
/* 使用设置参数命令,修改 spi10 设备速率 */
mr_uint32_t baud_rate = 10000000;
mr_device_ioctl(device, MR_CMD_SET_PARAM | MR_SPI_BAUD_RATE, &baud_rate);
/* 数据缓冲区 */
mr_uint8_t buf[7] = {1,2,3,4,5,6,7};
/* 向 spi10 设备写入 buf 数据 */
mr_device_write(device, 0, buf, 7);
/* 从 spi10 设备读取数据保存到 buf */
mr_device_read(device, 0, buf, 7);
/* 创建一个邮件,同时使用传输命令,控制 SPI 设备全双工传输 */
struct mr_device_msg device_msg = {.send_buf = buf, .recv_buf = buf, .count = 7};
mr_device_ioctl(device, MR_CMD_TRANSFER, &device_msg);
/* 关闭 pin 设备 */
mr_device_close(device);
}
```
## **SPI 设备控制命令补充说明**
SPI 设备支持以下命令:
|命令|描述|传入参数|
|:--|:--|:--|
|MR_CMD_ATTACH|将 SPI 设备挂载到 SPI 总线| SPI 总线名,如:"spi1"|
|MR_CMD_CONFIG|将 SPI 设备配置修改为传入配置|传入 SPI 配置结构体|
|MR_CMD_SET_PARAM|修改 SPI 设备配置|参下|
当使用 `MR_CMD_SET_PARAM` 命令配置参数时,有以下可选命令:
|命令|描述|传入参数|
|:--|:--|:--|
|MR_SPI_BAUD_RATE|配置波特率|波特率10000000|
|MR_SPI_MASTER|配置为主机|MR_NULL|
|MR_SPI_SLAVE|配置为从机|MR_NULL|
|MR_SPI_BIT_ORDER_LSB|配置为低位优先发送|MR_NULL|
|MR_SPI_BIT_ORDER_MSB|配置为高位优先发送|MR_NULL|
|MR_SPI_MODE_0|配置为 SPI 模式 0|MR_NULL|
|MR_SPI_MODE_1|配置为 SPI 模式 1|MR_NULL|
|MR_SPI_MODE_2|配置为 SPI 模式 2|MR_NULL|
|MR_SPI_MODE_3|配置为 SPI 模式 3|MR_NULL|
|MR_SPI_DATA_BITS_8|配置为 8bit 数据模式|MR_NULL|
|MR_SPI_DATA_BITS_16|配置为 16bit 数据模式|MR_NULL|
|MR_SPI_CS_ACTIVE_LOW|配置为 CS 低电平有效|MR_NULL|
|MR_SPI_CS_ACTIVE_HIGH|配置为 CS 高电平有效|MR_NULL|