添加文档
This commit is contained in:
213
document/device.md
Normal file
213
document/device.md
Normal 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);
|
||||
}
|
||||
```
|
||||
@@ -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
164
document/spi.md
Normal 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|
|
||||
Reference in New Issue
Block a user