设计说明
源码说明
CIR模块的源码位于 bsp/artinchip/:
bsp/artinchip/drv/cir/drv_cir.c,cir driver层接口实现
bsp/artinchip/include/drv/drv_cir.h,cir driver层接口头文件
bsp/artinchip/drv/cir/nec_decoder.c,NEC协议编解码实现
bsp/artinchip/drv/cir/rc5_decoder.c,RC5协议编解码实现
bsp/artinchip/drv/cir/ir_raw.c,编解码调用及注册接口实现
bsp/artinchip/drv/cir/ir_raw.h,编解码调用及注册接口头文件
bsp/artinchip/hal/cir/hal_cir.c,cir hal层接口实现
bsp/artinchip/include/hal/hal_cir.h,cir hal层接口头文件及寄存器定义
模块架构
内核中rc的基本框架如下图所示:
红外信号的编码和解码工作由CIR协议负责完成。在完成编码后,应用层需要发送的信号被编码为一系列的带有宽度的高低电平(pulse/space),CIR driver在发送端就是需要将这一系列的pulse/space写入发送FIFO发送出去。在接收红外信号时,CIR driver需要将接收到的一系列高低电平送入到CIR协议进行解码,最终将解码得到的scancode返回给driver层,最终送给app程序完成红外信号的接收。所以,CIR驱动的主要任务有:
1.将编码得到的高低电平信号以游码的形式写入TX-FIFO,发送红外信号
2.将CIR模块接收的RX-FIFO中的游码正确表示为高低电平的形式,相邻的高电平或低电平需要进行合并。
3.根据用户空间传递的红外参数,对CIR的底层寄存器进行配置,如配置载波频率,配置占空比等
由于红外信号的数据量都很少,所以在红外信号的发送端,一般是利用循环将所有的数据一次性全部发送出去,而不会采用中断或DMA的方式。在红外信号的接收端,一般是采用中断的方式进行数据的接收,在接收完成后,调用相应的CIR协议解码函数进行解码。
CIR模块理论上可以支持任何的红外协议,对不同红外协议的支持可以通过对载波配置寄存器的设置来实现。luban-lite中目前提供了NEC和RC5协议的编解码,默认配置的是NEC协议。
关键流程设计
初始化流程
CIR模块的初始化流程如下:
1.释放clock和reset信号
2.设置噪声阈值,接收激活阈值,空闲阈值等底层配置
3.设置TX-FIFO和RX-FIFO的阈值
4.将所选择的CIR协议注册到cir_raw_handler_list链表
中断处理流程
CIR模块使能RX的溢出中断、RXFIFO可用中断、接收完成中断。
中断执行流程如下:
CIR协议注册
cir的driver层驱动定义了一个全局链表cir_raw_handler_list,在系统启动时,会根据menuconfig中所选择的红外协议进行注册,实际就是将红外协议添加到链表cir_raw_handler_list,可将NEC和RC5协议同时注册到链表。应用层的代码通过 rt_device_control 设置将要使用的红外协议。在对数据进行编解码时,会查找cir_raw_handler_list链表上是否已注册要使用的红外协议,如已注册,则调用协议的编解码函数。
数据结构设计
driver层数据结构
typedef struct aic_cir
{
struct rt_device dev;
aic_cir_ctrl_t aic_cir_ctrl;
cir_config_t config;
} aic_cir_t;
2
3
4
5
6
hal层数据结构
typedef enum {
CIR_EVENT_RECEIVE_COMPLETE,
CIR_EVENT_ERROR,
} cir_event_t;
typedef struct aic_cir_ctrl aic_cir_ctrl_t;
struct aic_cir_ctrl {
unsigned long cir_base;
uint8_t irq_num;
uint8_t clk_idx;
void (*callback)(aic_cir_ctrl_t *aic_cir_ctrl, cir_event_t event,
void *arg);
void *arg;
uint8_t tx_data[128];
uint8_t rx_data[128];
uint32_t rx_idx;
uint8_t rx_level;
uint8_t rx_flag; /* Indicates if rxfifo has received data */
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
接口设计
driver层接口设计
drv_cir_init
函数原型 | rt_err_t drv_cir_init(rt_device_t pdev) |
---|---|
功能说明 | CIR模块初始化 |
参数定义 | pdev: 指向CIR设备的指针 |
返回值 | 执行成功返回RT_EOK |
注意事项 |
drv_cir_open
函数原型 | rt_err_t drv_cir_init(rt_device_t pdev) |
---|---|
功能说明 | 打开红外模块 |
参数定义 | pdev: 指向CIR设备的指针 oflag: 打开设备时设置的标志 |
返回值 | 执行成功返回RT_EOK,否则返回-RT_EINVAL |
注意事项 | oflag可设置的值: RT_DEVICE_FLAG_WRONLY RT_DEVICE_FLAG_RDONLY RT_DEVICE_FLAG_RDWR RT_DEVICE_FLAG_INT_RX 设置RT_DEVICE_FLAG_RDONLY时,必须同时设置RT_DEVICE_FLAG_INT_RX |
drv_cir_close
函数原型 | rt_err_t drv_cir_close(rt_device_t pdev) |
---|---|
功能说明 | 关闭红外模块 |
参数定义 | pdev: 指向CIR设备的指针 |
返回值 | 执行成功返回RT_EOK |
注意事项 |
drv_cir_read
函数原型 | rt_size_t drv_cir_read(rt_device_t pdev, rt_off_t pos, void *buffer, rt_size_t size) |
---|---|
功能说明 | 读取CIR接收到的红外信号 |
参数定义 | pdev: 指向CIR设备的指针 buffer: 指向接收数据的指针 size: 读取的数据字节数 |
返回值 | 执行成功返回0 |
注意事项 |
hal层接口设计
hal_cir_set_tx_carrier
函数原型 | int hal_cir_set_tx_carrier(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t protocol, uint32_t tx_duty); |
---|---|
功能说明 | 设置CIR的发送载波参数 |
参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 protocol: 使用的CIR协议 tx_duty: 协议的占空比 |
返回值 | 执行成功返回0 |
注意事项 | protocol取值: NEC, 0; RC5, 1 tx_duty: 若占空比为33%,则tx_duty设置为33 |
hal_cir_send_data
函数原型 | void halcir_send_data(aic_cir_ctrl_t * aiccir_ctrl, uint8_t * tx_data, uint32_t size); |
---|---|
功能说明 | CIR发送数据 |
参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 tx_data: 指向要发送的数据指针 size: 发送的数据字节数 |
返回值 | 执行成功返回0 |
注意事项 |
hal_cir_set_rx_sample_clock
函数原型 | void hal_cir_set_rx_sample_clock(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t protocol); |
---|---|
功能说明 | 设置CIR接收采样时钟 |
参数定义 | aic_cir_ctrl: 指向aic_cir_ctrl_t的指针 protocol: 使用的CIR协议 |
返回值 | 执行成功返回0 |
注意事项 |