7.3.5. 设计说明¶
7.3.5.1. 源码说明¶
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层接口头文件及寄存器定义
7.3.5.2. 模块架构¶
linux内核中rc的基本框架如下图所示:

红外信号的编码和解码工作由CIR协议负责完成。在完成编码后,应用层需要发送的信号被编码为一系列的带有宽度的高低电平(pulse/space),CIR driver在发送端就是需要将这一系列的pulse/space写入发送FIFO发送出去。在接收红外信号时,CIR driver需要将接收到的一系列高低电平送入到CIR协议进行解码,最终将解码得到的scancode返回给driver层,最终送给app程序完成红外信号的接收。所以,CIR驱动的主要任务有:
将编码得到的高低电平信号以游码的形式写入TX-FIFO,发送红外信号
将CIR模块接收的RX-FIFO中的游码正确表示为高低电平的形式,相邻的高电平或低电平需要进行合并。
根据用户空间传递的红外参数,对CIR的底层寄存器进行配置,如配置载波频率,配置占空比等
由于红外信号的数据量都很少,所以在红外信号的发送端,一般是利用循环将所有的数据一次性全部发送出去,而不会采用中断或DMA的方式。在红外信号的接收端,一般是采用中断的方式进行数据的接收,在接收完成后,调用相应的CIR协议解码函数进行解码。
CIR模块理论上可以支持任何的红外协议,对不同红外协议的支持可以通过对载波配置寄存器的设置来实现。luban-lite中目前提供了NEC和RC5协议的编解码,默认配置的是NEC协议。
7.3.5.3. 关键流程设计¶
7.3.5.3.1. 初始化流程¶
CIR模块的初始化流程如下:
释放clock和reset信号
设置噪声阈值,接收激活阈值,空闲阈值等底层配置
设置TX-FIFO和RX-FIFO的阈值
将所选择的CIR协议注册到cir_raw_handler_list链表
7.3.5.3.3. CIR协议注册¶
cir的driver层驱动定义了一个全局链表cir_raw_handler_list,在系统启动时,会根据menuconfig中所选择的红外协议进行注册,实际就是将红外协议添加到链表cir_raw_handler_list,可将NEC和RC5协议同时注册到链表。应用层的代码通过 rt_device_control
设置将要使用的红外协议。在对数据进行编解码时,会查找cir_raw_handler_list链表上是否已注册要使用的红外协议,如已注册,则调用协议的编解码函数。
7.3.5.4. 数据结构设计¶
7.3.5.4.1. driver层数据结构¶
typedef struct aic_cir
{
struct rt_device dev;
aic_cir_ctrl_t aic_cir_ctrl;
cir_config_t config;
} aic_cir_t;
7.3.5.4.2. 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 */
};
7.3.5.5. 接口设计¶
7.3.5.5.1. driver层接口设计¶
7.3.5.5.1.1. drv_cir_init¶
函数原型 |
rt_err_t drv_cir_init(rt_device_t pdev) |
---|---|
功能说明 |
CIR模块初始化 |
参数定义 |
pdev: 指向CIR设备的指针 |
返回值 |
执行成功返回RT_EOK |
注意事项 |
7.3.5.5.1.2. drv_cir_open¶
函数原型 |
rt_err_t drv_cir_open(rt_device_t pdev, rt_uint16_t oflag) |
---|---|
功能说明 |
打开红外模块 |
参数定义 |
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
|
7.3.5.5.1.3. drv_cir_close¶
函数原型 |
rt_err_t drv_cir_close(rt_device_t pdev) |
---|---|
功能说明 |
关闭红外模块 |
参数定义 |
pdev: 指向CIR设备的指针
|
返回值 |
执行成功返回RT_EOK |
注意事项 |
7.3.5.5.1.4. 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 |
注意事项 |
7.3.5.5.2. hal层接口设计¶
7.3.5.5.2.1. 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
|
7.3.5.5.2.2. hal_cir_send_data¶
函数原型 |
void hal_cir_send_data(aic_cir_ctrl_t * aic_cir_ctrl, uint8_t * tx_data, uint32_t size); |
---|---|
功能说明 |
CIR发送数据 |
参数定义 |
aic_cir_ctrl: 指向aic_cir_ctrl_t的指针
tx_data: 指向要发送的数据指针
size: 发送的数据字节数
|
返回值 |
执行成功返回0 |
注意事项 |
7.3.5.5.2.3. 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 |
注意事项 |