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);