IR Transmit

This example demonstrates the use of the IR transmit function.

Data is sent using the IR peripheral to implement the IR transmit function, and the IR transmit waveform is observed using a logic analyzer.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

For more requirements, please refer to Quick Start.

Wiring

Connect the IR transmit pin P2_5 to the logic analyzer.

Building and Downloading

This sample can be found in the SDK folder:

Project file: board\evb\io_sample\IR\Tx\mdk

Project file: board\evb\io_sample\IR\Tx\gcc

Please follow these steps to build and run the example:

  1. Open sample project file.

  2. To build the target, follow the steps listed on the Generating App Image in Quick Start.

  3. After a successful compilation, the app bin app_MP_xxx.bin will be generated in the directory mdk\bin or gcc\bin.

  4. To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.

  5. Press reset button on EVB board and it will start running.

Experimental Verification

Observe the IR TX waveform within the logic analyzer.

Here should be a picture of the IR sending waveforms

IR Transmit Waveform

Code Overview

This chapter will be introduced according to the following several parts:

  1. Source Code Directory.

  2. Peripheral initialization will be introduced in chapter Initialization.

  3. Functional implementation after initialization will be introduced in chapter Function Implementation.

Source Code Directory

  • Project directory: sdk\board\evb\io_sample\IR\Tx

  • Source code directory: sdk\src\sample\io_sample\IR\Tx

Source files are currently categorized into several groups as below.

└── Project: ir_tx
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            ├── ROM.lib
            └── adc.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_ir.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

Initialization

When the EVB reset is initiated, the main function is executed, following these steps:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    __enable_irq();

    ir_demo();

    ...
}

In ir_demo, it includes PAD/PINMUX settings and the initialization process of the IR peripheral.

void ir_demo(void)
{
    ...
    board_ir_init();
    driver_ir_init(IR_TxData.CarrierFreq);
    ...
}

board_ir_init is for PAD and PINMUX settings and includes the following steps:

  1. Configure PAD: set pins, PINMUX mode, PowerOn, internal pull-none and output low.

  2. Configure PINMUX: assign pins to IRDA_TX function.

driver_ir_init is for IR peripheral initialization and includes the following steps:

  1. Enable RCC clock.

  2. Set the IR transmit frequency to 38 kHz.

  3. Set the IR carrier duty cycle to 1/2.

  4. Set the IR to transmit mode.

  5. Set the IR transmission data will not be inverted.

  6. Set the IR transmit FIFO threshold to 2.

  7. Configure the IR to send FIFO data count less than the set send threshold interrupt IR_INT_TF_LEVEL.

void driver_ir_init(uint32_t vFreq)
{
    /* Enable ir clock */
    RCC_PeriphClockCmd(APBPeriph_IR, APBPeriph_IR_CLOCK, ENABLE);

    /* Initialize ir */
    IR_InitTypeDef IR_InitStruct;
    IR_StructInit(&IR_InitStruct);
    IR_InitStruct.IR_Freq           = vFreq;
    IR_InitStruct.IR_DutyCycle      = 2; /* !< 1/2 duty cycle */
    IR_InitStruct.IR_Mode           = IR_MODE_TX;
    IR_InitStruct.IR_TxInverse      = IR_TX_DATA_NORMAL;
    IR_InitStruct.IR_TxFIFOThrLevel = IR_TX_FIFO_THR_LEVEL;
    IR_Init(&IR_InitStruct);

    /* Enable IR threshold interrupt. when TX FIFO offset <= threshold value, trigger interrupt*/
    IR_INTConfig(IR_INT_TF_LEVEL, ENABLE);

    /* Configure nvic */
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = IR_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

Functional Implementation

  1. Define IR transmission data in ir_demo. Data with carrier is represented by performing a bitwise OR operation with the number of carriers and 0x80000000, while data without carrier is represented by performing a bitwise OR operation with the number of carriers and 0x00000000.

  2. Execute the IR_SendBuf() function to start filling the IR transmission FIFO with transmission data; enable the IR peripheral transmission function.

  3. Record the number of data items that have been transmitted.

    void ir_demo(void)
    {
        /* Data to send */
        IR_TxData.CarrierFreq = 38000;
        IR_TxData.DataLen = 67 + 1; //2+64+1;
        IR_TxData.DataBuf[0] =  0x80000000 | 0x156; //342 about 9ms
        IR_TxData.DataBuf[1] =  0x00000000 | 0xAB; //171 about 4.5ms
        for (uint16_t i = 2; i < IR_TxData.DataLen - 1;)
        {
            IR_TxData.DataBuf[i] =  0x80000000 | 0x15; //21  about 560us
            IR_TxData.DataBuf[i + 1] =  0x00000000 | 0x15; //21  about 565us
            i += 2;
        }
        IR_TxData.DataBuf[30] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[31] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[62] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[63] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[64] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[65] =  0x00000000 | 0x40; //64  about 1690us
        IR_TxData.DataBuf[66] =  0x80000000 | 0x15; //21  about 560us
        IR_TxData.DataBuf[IR_TxData.DataLen - 1] =  0x80000000 | 0x15;
    
        ...
    
        /* Start to send data. */
        IR_SendBuf(IR_TxData.DataBuf, IR_TX_FIFO_SIZE, DISABLE);
        IR_Cmd(IR_MODE_TX, ENABLE);
        /* Record number which has been sent */
        IR_TX_Count = IR_TX_FIFO_SIZE;
    }
    
  4. When the number of data items in the IR transmission FIFO is less than the set transmission threshold (set to 2 in this example), trigger the IR_INT_TF_LEVEL interrupt to enter the interrupt handler function IR_Handler.

    1. Mask the IR_INT_TF_LEVEL interrupt.

    2. Since the IR transmission data may be large (greater than the IR TX FIFO depth), it needs to be sent in batches.

    3. If the remaining number of transmission data items is greater than the size of the transmission FIFO, fill the IR transmission FIFO with (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL) data items and transmit, indicating that the remaining data volume is still greater than the IR TX FIFO depth.

    4. Otherwise, if the remaining number of transmission data items is greater than 0, fill the IR transmission FIFO with the remaining data, indicating that the remaining data volume is less than the IR TX FIFO depth, i.e., transmitting the last batch of data.

    5. Otherwise, if there is no remaining data, disable the IR_INT_TF_LEVEL interrupt, indicating that all IR data has been transmitted.

    6. Unmask the IR_INT_TF_LEVEL interrupt.

    void IR_Handler(void)
    {
        /* Get IR interrupt status */
        ITStatus int_status = IR_GetINTStatus(IR_INT_TF_LEVEL);
    
        /* Mask IR interrupt */
        IR_MaskINTConfig(IR_INT_TF_LEVEL, ENABLE);
    
        /* Continue to send by interrupt */
        if (int_status == SET)
        {
            /* The remaining data is larger than the TX FIFO length */
            if ((IR_TxData.DataLen - IR_TX_Count) >= IR_TX_FIFO_SIZE)
            {
                IR_SendBuf(IR_TxData.DataBuf + IR_TX_Count, (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL), DISABLE);
                IR_TX_Count += (IR_TX_FIFO_SIZE - IR_TX_FIFO_THR_LEVEL);
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
            else if ((IR_TxData.DataLen - IR_TX_Count) > 0)
            {
                /* The remaining data is less than the TX FIFO length */
    
                /*  Configure TX threshold level to zero and trigger interrupt when TX FIFO is empty */
                IR_SetTxThreshold(0);
                IR_SendBuf(IR_TxData.DataBuf + IR_TX_Count, IR_TxData.DataLen - IR_TX_Count, DISABLE);
                IR_TX_Count += (IR_TxData.DataLen - IR_TX_Count);
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
            else
            {
                /* Tx completed */
                /* Disable IR tx empty interrupt */
                IR_INTConfig(IR_INT_TF_LEVEL, DISABLE);
                IR_TX_Count = 0;
    
                /* Clear threshold interrupt */
                IR_ClearINTPendingBit(IR_INT_TF_LEVEL_CLR);
            }
        }
    
        /* Unmask IR interrupt */
        IR_MaskINTConfig(IR_INT_TF_LEVEL, DISABLE);
    }