RISCV_IR使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 11/11/2022 | |
1.1 | 05/08/2023 |
1. 概述¶
IR是通过解析红外接收器接收到的高低电平组合来接受数据的,主要的IR协议格式有NEC、RC5和RC6。
-
FreeRTOS项目IR driver文件位于sc/driver/sysdriver/ir文件夹下。
-
NoNOS项目IR driver文件位于sc/driver/sysdriver/ir文件夹下。
1.1. IR解码方式¶
根据当前SigmaStar IR设计,IR_IN信号可以通过四种解码模式进行解码:Full模式、Raw模式、SW模式和RC模式。当IR_IN信号是NEC/NEC-like格式,可以使用Full/Raw/SW模式解码。当IR_IN信号是RC格式,可以用RC/SW模式解码(目前驱动只支持RC5格式)。当IR_IN信号为other格式时,只能使用SW方式解码(需要搭配解码器才可使用)。
-
Full mode
硬件可以识别IR_IN信号格式和用户代码是否填写请求,并向软件发送关键编码。
-
Raw mode
硬件只能识别IR_IN信号格式。它无法知道哪一部分是用户编码或关键编码。这需要由软件来决定。
-
SW mode
硬件无法从IR_IN信号识别任何格式。软件需要解码格式、用户编码和关键编码本身。
-
RC mode
像Full mode,但它用于RC格式。
从下面框图可以看出,红外译码主要有两种路径。上面的路径是Full/Raw/SW模式,下面的路径是RC模式。
图1-1 IR decode block diagram
1.2. 各协议电平标准¶
NEC format:
-
Logic0 : 0.56ms high + 0.56ms low
-
Logic1 : 0.56ms high + 1.68ms low
-
Header code : 9ms high pulse
-
Off code : 4.5ms low pulse:
-
Customer code : 8-bits customer code + 8-bits inverse or 16-bits customer code
-
Command code : 8-bits command code + 8-bits inverse
-
Total cycle time : 108ms
-
Repeat key : 9ms Header code and 2.5ms Off code
图1-2 NEC format standard
NEC-like format:
-
Logic0 : short high + short low (usually 1:1)
-
Logic1 : short high + long low (usually 1:3)
-
Header code : ultra long high width
-
Off code : ultra long low width
RC5 format:
-
Logic0 : 888us high + 888us low (Manchester code)
-
Logic1 : 888us low + 888us high (Manchester code)
-
Start bits : 2-bits logic1
-
Toggle bit : Inverted every time when the key is released and pressed again
-
Customer code : 5-bits customer code
-
Command code : 6-bits command code
-
Total cycle time : 114ms
-
If a key is held over 114ms, it will repeat the signal every cycle time
图1-3 RC5 format standard
RC5-Extend format:
-
Same as RC5 expect the second bit of SB is represented the 6th bit of address code
图1-4 RC5-Extend format standard
RC6 mode 0 format:
-
Logic0 : 444us low + 444us high (Manchester code)
-
Logic1 : 444us high + 444us low (Manchester code)
(Note the logic length is half of RC5 format and the level order is opposite)
-
Header code : 2.666ms high pulse + 888us low pulse
-
Start bit : 1-bit logic1
-
Mode bits : 3-bit logic0 (in mode 0)
-
Toggle bit : Inverted every time when the key is released and pressed again
-
Customer code : 8-bits customer code
-
Command code : 8-bits key code
-
If a key is held over 114ms, it will repeat the signal every cycle time.
图1-5 RC6 mode 0 format standard
2. RISCV配置¶
2.1. 配置padmux¶
IR的padmux配置只需要在对应的chipname.sys的padmux
属性添加如下内容:
第一列为引脚索引号,可以在sc//drivers/sysdriver/gpio/hal//{chipname}/pub/gpio.h中查到;
第二列为模式定义,在sc/drivers/sysdriver/gpio/hal/{chipname}/src/mhal_pinmux.c中ST_PadMuxInfo数组里,罗列了所有引脚的复用关系,查询该引脚支持哪些复用功能可以查询该数组;
第三列为引脚及搭配模式的索引名称,可在sc/drivers/sysdriver/padmux/drv/pub/mdrv_puse.h里查询。
1. PAD_PM_IR_RX PINMUX_FOR_IR_IN_MODE_1 MDRV_PUSE_IR //IR0 2. 3. PAD_OUTP_TX0_CH_0 PINMUX_FOR_IR0_MODE_1 MDRV_PUSE_IR1 //IR1 4. PAD_SR_IO0 PINMUX_FOR_IR0_MODE_2 MDRV_PUSE_IR1 //IR1 5. PAD_SAR_ADC_20 PINMUX_FOR_IR0_MODE_3 MDRV_PUSE_IR1 //IR1 6. 7. PAD_OUTN_TX0_CH_0 PINMUX_FOR_IR1_MODE_1 MDRV_PUSE_IR2 //IR2 8. PAD_SR_IO1 PINMUX_FOR_IR1_MODE_2 MDRV_PUSE_IR2 //IR2 9. PAD_SAR_ADC_21 PINMUX_FOR_IR1_MODE_3 MDRV_PUSE_IR2 //IR2 10. 11. PAD_OUTP_TX0_CH_1 PINMUX_FOR_IR2_MODE_1 MDRV_PUSE_IR3 //IR3 12. PAD_SR_IO2 PINMUX_FOR_IR2_MODE_2 MDRV_PUSE_IR3 //IR3 13. PAD_SAR_ADC_22 PINMUX_FOR_IR2_MODE_3 MDRV_PUSE_IR3 //IR3 14. 15. PAD_OUTN_TX0_CH_1 PINMUX_FOR_IR3_MODE_1 MDRV_PUSE_IR4 //IR4 16. PAD_SR_IO3 PINMUX_FOR_IR3_MODE_2 MDRV_PUSE_IR4 //IR4 17. PAD_SAR_ADC_23 PINMUX_FOR_IR3_MODE_3 MDRV_PUSE_IR4 //IR4
2.2. 配置sysdesc¶
chipname.sys文件位于/sc/driver/sysdriver/sysdesc/hal/chipname/pub,
IR的sysdesc配置只需要在对应的chipname.sys中配置如下信息(可以根据需求选择性配置IR设备的数量,最多可以同时配置5组IR设备):
<ir0> [reg_u32_u16] 0x2007A00 0x200; [mode_u32] 1; [camclk_u32] CAMCLK_ir; [interrupts_u32_u32] INT_FIQ_IR INT_FIQ_IR_RC; [header_code_u32_u32] 0x00 0xFF; [status_u8] 0;
<ir1> [reg_u32_u16] 0x2225800 0x200; [mode_u32] 1; [camclk_u32] CAMCLK_ir_nonpm0; [interrupts_u32_u32] INT_FIQ_IR_NONPM0 0xFFFF; [header_code_u32_u32] 0x00 0xFF; [status_u8] 0;
<ir2> [reg_u32_u16] 0x2225A00 0x200; [mode_u32] 1; [camclk_u32] CAMCLK_ir_nonpm1; [interrupts_u32_u32] INT_FIQ_IR_NONPM1 0xFFFF; [header_code_u32_u32] 0x00 0xFF; [status_u8] 1;
<ir3> [reg_u32_u16] 0x2225C00 0x200; [mode_u32] 1; [camclk_u32] CAMCLK_ir_nonpm2; [interrupts_u32_u32] INT_FIQ_IR_NONPM2 0xFFFF; [header_code_u32_u32] 0x00 0xFF; [status_u8] 0;
<ir4> [reg_u32_u16] 0x2225E00 0x200; [mode_u32] 1; [camclk_u32] CAMCLK_ir_nonpm3; [interrupts_u32_u32] INT_FIQ_IR_NONPM3 0xFFFF; [header_code_u32_u32] 0x00 0xFF; [status_u8] 0;
IR sysdesc配置说明:
属性 | 描述 | 设定值 | 备注 |
---|---|---|---|
reg_u32_u16 | 设定寄存器bank地址 | 详见上述内容 | 禁止修改 |
mode_u32 | 设定初始化解码模式 | 1/ 2/ 3对应FULL/ RAW/ RC5 | 可根据需要修改 |
camclk_u32 | 设定时钟源 | 详见上述内容 | 不需要更改 |
interrupts_u32_u32 | 设定中断号 | 详见上述内容 | 不需要更改 |
header_code_u32_u32 | 遥控器发送的关键编码及对应的键值 | 0x00~0XFF,不同遥控器的编码及对应键值不同 | 可根据需要修改 |
status_u8 | 选择是否使能IR驱动 | "0"→disable, "1"→enable | 可根据需要修改 |
图2-1 逻辑分析仪解析的遥控器信号
3. 调试与测试¶
3.1. 硬件连接¶
将红外接收头按照原理图中指示方向连接到开发板。
图3-1 IR接收器(group 0)安装示例
图3-2 IR接收器(group 1)安装示例
图3-3 IR接收器(group 2)安装示例
图3-4 IR接收器(group 3)安装示例
图3-5 IR接收器(group 4)安装示例
3.2. API使用说明¶
/** * drv_ir_config - config IR device and select decode mode * @group: IR device index; * @decode_mode: 0->select FULL MODE; 1->select RAW MODE; 2->select RC5 MODE * @ir_handle: function to be called when the IR signal occurs. * * Returns 0 on success, -IR_CONFIG_ERR if the IR group does not exist. */ int drv_ir_config(u32 group, u32 decode_mode, ir_decode ir_handle) { struct ir_hw_decoder *ir_dev = drv_ir_get_addr(group); if (ir_dev->group < HAL_IR_GROUP) { ir_dev->hal_ir_dev->decode_mode = decode_mode; ir_dev->calbak_input_key = ir_handle; hal_ir_config(ir_dev->hal_ir_dev); } else { ir_dbg("fail to change decode mode\n"); return -IR_CONFIG_ERR; } return 0; }
/** * drv_ir_key_dequeue - get the IR command code * @group: IR device index; * * Returns command code on decode success, 0 if the IR signal is not generated. */ u32 drv_ir_key_dequeue(u32 group) { u32 data = 0x00; struct ir_hw_decoder *ir_dev = drv_ir_get_addr(group); if (!ir_dev->queue_lock) return data; if (ir_dev->queue.front == ir_dev->queue.rear) { ir_dbg("the data queue of ir%u is empty\n", ir_dev->group); } else { data = ir_dev->queue.item[ir_dev->queue.front]; ir_dev->queue.front = (ir_dev->queue.front + 1) % DRV_IR_MAXQUEUE; } ir_dev->queue_lock = 0; return data; }
3.3. Demo application¶
图3-6 Demo application介绍
-
目录1,inc,存放的是模块(module)内部的头文件,不被其他模块使用的头文件
-
目录2,pub,存放的是会被其他模块使用的头文件
-
目录3,src,则是模块的源代码文件
-
函数4,rtos_application_initcall(),用来指定application模块的入口函数,第一个参数是函数名,第二个参数用于设置模块入口函数的执行顺序,一般都配置为0,当存在多个application模块时,可以通过配置参数0,1,2,3来决定application函数的执行顺序
-
Bench模块的入口函数RtosAppMainEntry()只是单纯的调用coremark_main()函数,执行coremark操作
3.4. FreeRTOS Demo的使用¶
demo源码位于sc/driver/sysdriver/ir/drv/src/drv_ir_test.c,烧录后可在命令行输入命令:ir [group_id] [decode_mode]
,按下按键即可获取遥控器关键编码:
#include "drv_ir.h" #include "sys_sys_isw_cli.h" #define __VER_IR__ //决定是否启用IR命令行 #if defined(__VER_IR__) void ir_get_value(struct sstar_ir_dev *ir_dev) //ir_decode { u32 data; data = drv_ir_key_dequeue(ir_dev); if(data) printf("IR%u KEY VALUE [0x%x]\n", ir_dev->group, data); //data即遥控器关键编码 return; } static int _IRTest(CLI_t *pCli, char *p) { u32 group_id; u32 decode_mode; struct sstar_ir_dev *ir_dev = NULL; if(CliTokenCount(pCli) == 2) { if (CliTokenPopNum(pCli, &group_id, 0) != eCLI_PARSE_OK) goto _IR_HELP_EXIT; if (CliTokenPopNum(pCli, &decode_mode, 0) != eCLI_PARSE_OK) goto _IR_HELP_EXIT; cliPrintf("group_id:%d, decode_mode:%d\n", group_id, decode_mode); //eg: ir 0 1 //group_id:0~4, decode_mode:1/2/3对应FULL/RAW/RC5 ir_dev = drv_ir_get_addr(group_id); if (!ir_dev) { cliPrintf("ir group inexistence\n"); return eCLI_PARSE_ERROR; } ir_dev->decode_mode = decode_mode; ir_dev->calbak_input_key = ir_get_value; if (drv_ir_config(ir_dev)) { cliPrintf("ir group inexistence\n"); return eCLI_PARSE_ERROR; } } else { _IR_HELP_EXIT: cliPrintf("Plz key in : ir [group_id] [decode_mode] \n"); return eCLI_PARSE_INVALID_PARAMETER; } return eCLI_PARSE_OK; } SS_RTOS_CLI_CMD(ir, "Infrared receiver setup ", "", _IRTest); #endif
3.5. NoNOS Demo的使用¶
demo源码位于sc/driver/sysdriver/ir/drv/src/ir_ut.c,将该源码按照3.2的方法填充到bench.c
#include "sys_sys_isw_cli.h" #include "ms_platform.h" #include "registers.h" #include "core_portme.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include "drv_ir.h" #include "initcall.h" #define MODE 1 //解码模式 #define IR_GROUP 5 //决定启动几组IR设备 void ir_get_value(struct sstar_ir_dev *ir_dev) { u32 data; data = drv_ir_key_dequeue(ir_dev); if(data) printf("IR%u KEY VALUE [0x%x]\n", ir_dev->group, data); return; } int RtosAppMainEntry(void) { u32 i; u32 DecoMode; u32 IRGroupId[IR_GROUP]; struct sstar_ir_dev *ir_dev[IR_GROUP]; DecoMode = MODE; for(i = 0; i < sizeof(IRGroupId) / sizeof(IRGroupId[0]); i++ ) { IRGroupId[i] = i; } drv_ir_probe(); for(i = 0; i < sizeof(IRGroupId) / sizeof(IRGroupId[0]); i++) { ir_dev[i] = drv_ir_get_addr(IRGroupId[i]); if (!ir_dev[i]) { printf("ir group[%u] inexistence\n", i); return -1; } ir_dev[i]->decode_mode = DecoMode; ir_dev[i]->calbak_input_key = ir_get_value; drv_ir_config(ir_dev[i]); } while(1); return 0; } rtos_application_initcall(RtosAppMainEntry, 0);