IR Receive

This sample demonstrates how to receive data in IR interrupt mode.

Use the P2_6 pin as a PWM output pin, outputting a PWM waveform to simulate sender data. Connect the PWM output pin to the IR input pin.

Data reception occurs within the IR interrupt. When the data volume exceeds the IR FIFO capacity, multiple consecutive data receptions are required.

Requirements

For requirements, please refer to the Requirements.

Wiring

Connect the PWM output pin P2_6 to the IR receiver pin P2_5.

Configurations

  1. The following macro can be configured to modify the pin definitions.

    #define IR_RX_PIN               P2_5
    #define PWM_OUT_PIN             P2_6
    
  2. The following macros can be configured to modify PWM configuration information.

    #define PWM_PERIOD              26.3   //uint:us
    #define PWM_DUTY_CYCLE          50     //uint:percent
    #define PWM_HIGH_COUNT          ((((PWM_PERIOD)*(PWM_DUTY_CYCLE*40))/100)-1)
    #define PWM_LOW_COUNT           ((((PWM_PERIOD)*((100-PWM_DUTY_CYCLE)*40))/100)-1)
    

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

  1. After initialization is complete, the PWM begins to output waveforms with a frequency set to 38KHz, matching the IR reception frequency. In the main function, the TIM PWM output is repeatedly enabled and disabled every 500 microseconds to simulate 500 microseconds of data with and without a carrier. The PWM waveform is as shown in the diagram.

This should be the image of the IR PWM waveform

PWM output waveform

  1. When the PWM outputs a waveform, the IR receiver interprets the 500 microsecond PWM waveform as a mark data. When the PWM does not output a waveform, the IR receiver interprets the 500 microseconds of low level as a space data.

  2. When the number of data counted by the IR receiver reaches the set threshold, it triggers the IR IR_INT_RF_LEVEL interrupt, and the current data is received within the IR interrupt.

  3. In the main program, after the PWM output changes several times, it will stop outputting the PWM waveform, at which point the IR detects a low level input. When the low level input time reaches the preset counter value, it triggers the IR_INT_RX_CNT_THR interrupt, and all remaining data is received.

    IR_INT_RX_CNT_THR
    len = xx
    [io_ir]io_handle_ir_msg: IR RX data[0] = 0x80000012
    [io_ir]io_handle_ir_msg: IR RX data[1] = 0x00000012
    ...
    [io_ir]io_handle_ir_msg: IR RX data[xx] = 0x00000200
    

Note

The carrier data 0x800000012 indicates a high-level output for 12 carrier cycles, and 0x12 represents a low-level output for 12 carrier cycles.

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directory for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\ir\rx\proj

  • Source code directory: sdk\samples\peripheral\ir\rx\src

Initialization

The initialization flow for peripherals can refer to Initialization Flow in General Introduction.

  1. Call Pad_Config() and Pinmux_Config() to configure the PAD and PINMUX of the corresponding pins.

    void board_ir_init(void)
    {
        Pad_Config(IR_RX_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_DISABLE, PAD_OUT_LOW);
    
        Pinmux_Config(IR_RX_PIN, IRDA_RX);
    }
    
    void board_pwm_init(void)
    {
        Pad_Config(PWM_OUT_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    
        Pinmux_Config(PWM_OUT_PIN, PWM_OUT_PIN_PINMUX);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the IR clock.

  3. Initialize the IR peripheral:

    1. Define the IR_InitTypeDef type IR_InitStruct, and call IR_StructInit() to pre-fill IR_InitStruct with default values.

    2. Modify the IR_InitStruct parameters as needed. The IR initialization parameter configuration is shown in the table below.

    3. Call IR_Init() to initialize the IR peripheral.

IR Initialization Parameters

IR Hardware Parameters

Setting in the IR_InitStruct

IR

Sample Clock

IR_InitTypeDef::IR_Freq

38000

IR Mode

IR_InitTypeDef::IR_Mode

IR_MODE_RX

IR Rx Mode

IR_InitTypeDef::IR_RxStartMode

IR_RX_AUTO_MODE

FIFO Threshold Level

IR_InitTypeDef::IR_RxFIFOThrLevel

10

IR Rx Trigger Mode

IR_InitTypeDef::IR_RxTriggerMode

IR_RX_FALL_EDGE

IR Rx Counter Threshold Type

IR_InitTypeDef::IR_RxCntThrType

IR_RX_Count_Low_Level

IR Rx Counter Threshold

IR_InitTypeDef::IR_RxCntThr

0x200

  1. Call IR_Cmd() to enable the IR peripheral.

  2. Call IR_INTConfig() and IR_MaskINTConfig() to configure the IR receive FIFO data count greater than the set receive threshold interrupt IR_INT_RF_LEVEL and the receive level timeout interrupt IR_INT_RX_CNT_THR. Configure NVIC, for details refer to Interrupt Configuration.

  3. Call RCC_PeriphClockCmd() to enable the TIM clock.

  4. Initialize the TIM peripheral:

    1. Define the TIM_TimeBaseInitTypeDef type TIM_InitStruct, and call TIM_StructInit() to pre-fill IR_InitStruct with default values.

    2. Modify the TIM_InitStruct parameters as needed. The TIM initialization parameter configuration is shown in the table below.

    3. Call TIM_TimeBaseInit() to initialize the TIM peripheral.

TIM Initialization Parameters

TIM Hardware Parameters

Setting in the TIM_InitStruct

TIM

TIM Mode

TIM_TimeBaseInitTypeDef::TIM_Mode

TIM_Mode_UserDefine

PWM Enable

TIM_TimeBaseInitTypeDef::TIM_PWM_En

ENABLE

PWM High Count

TIM_TimeBaseInitTypeDef::TIM_PWM_High_Count

PWM_HIGH_COUNT

PWM Low Count

TIM_TimeBaseInitTypeDef::TIM_PWM_Low_Count

PWM_LOW_COUNT

Functional Implementation

The flow of receiving data via IR through interruption is shown in the figure:

Here should be IR rx interrupt flow

IR receive data through interrupt flow

  1. In ir_demo, the loop enables and disables PWM output to simulate IR carrier data. After 50 cycles, the PWM will stop outputting the waveform.

void ir_demo(void)
{
    ...
    for (uint32_t i = 0; i < 50; i++)
    {
        TIM_Cmd(PWM_TIMER_NUM, ENABLE);
        platform_delay_us(500);
        TIM_Cmd(PWM_TIMER_NUM, DISABLE);
        platform_delay_us(500);
    }
}
  1. When the number of data in the IR receive FIFO reaches the set receive threshold, it triggers the IR_INT_RF_LEVEL interrupt. Within the interrupt, call IR_GetRxDataLen() and IR_ReceiveBuf() to receive the current IR data.

  2. After the PWM stops outputting the waveform, when the IR detects a low-level duration exceeding the set carrier cycle of IR_InitTypeDef::IR_RxCntThr, it triggers the IR_INT_RX_CNT_THR interrupt. Within the interrupt, call IR_GetRxDataLen() and IR_ReceiveBuf() to receive the remaining IR data.

    void IR_Handler(void)
    {
        uint16_t len = 0;
        ITStatus int_status_rfl = IR_GetINTStatus(IR_INT_RF_LEVEL);
        ITStatus int_status_rxcnt = IR_GetINTStatus(IR_INT_RX_CNT_THR);
    
        /* Mask IR all interrupt */
        IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE);
    
        /* Receive by interrupt */
        if (int_status_rfl == SET)
        {
            len = IR_GetRxDataLen();
            IR_ReceiveBuf(IR_Rx_Data.DataBuf + IR_RX_Count, len);
            IR_Rx_Data.DataLen += len;
            IR_RX_Count += len;
            IR_ClearRxFIFO();
            IR_ClearINTPendingBit(IR_INT_RF_LEVEL_CLR);
        }
    
        /* Stop to receive IR data */
        if (int_status_rxcnt == SET)
        {
            DBG_DIRECT("IR_INT_RX_CNT_THR");
            /* Read remaining data */
            len = IR_GetRxDataLen();
            IR_ReceiveBuf(IR_Rx_Data.DataBuf + IR_RX_Count, len);
            IR_Rx_Data.DataLen += len;
            IR_RX_Count += len;
            ...
    
            memset(&IR_Rx_Data, 0, sizeof(IR_Rx_Data));
            IR_RX_Count = 0;
    
            IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR);
        }
    
        /* Unmask IR all interrupt */
        IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE);
    }