RISCV_IR使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 11/11/2022
    1.1
  • add api explain
  • 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.

      ir-5

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