IR Receive
This example demonstrates the usage method of the infrared reception function.
Use another EVB to download the program that sends IR data as the IR data sender to send IR data to this EVB.
Receive data within the IR interrupt. If the amount of data is greater than the FIFO of the IR, it is necessary to receive data continuously multiple times.
For examples of the IR sender, please refer to IR Transmit.
Requirements
The sample supports the following development kits:
Hardware Platforms |
Board Name |
---|---|
RTL8752H HDK |
RTL8752H EVB |
For more requirements, please refer to Quick Start.
Wiring
Use another EVB to download the IR TX program, and connect the IR receive pin P2_5 to the transmit pin of the other EVB.
Building and Downloading
This sample can be found in the SDK folder:
Project file: board\evb\io_sample\IR\Rx\mdk
Project file: board\evb\io_sample\IR\Rx\gcc
Please follow these steps to build and run the example:
Open sample project file.
To build the target, follow the steps listed on the Generating App Image in Quick Start.
After a successful compilation, the app bin
app_MP_xxx.bin
will be generated in the directorymdk\bin
orgcc\bin
.To download app bin into EVB board, follow the steps listed on the MP Tool Download in Quick Start.
Press reset button on EVB board and it will start running.
Experimental Verification
When the number of IR reception counters reaches the set threshold, it indicates that the IR data reception is complete. The system then enters the IR interrupt and prints the received data. The received data is the content defined by the IR transmitter.
[io_ir]io_handle_ir_msg: IR RX data[0] = xxx
[io_ir]io_handle_ir_msg: IR RX data[1] = xxx
...
Code Overview
This chapter will be introduced according to the following several parts:
Peripheral initialization will be introduced in chapter Initialization.
Functional implementation after initialization will be introduced in chapter Function Implementation.
Source Code Directory
Project directory:
sdk\board\evb\io_sample\IR\Rx
Source code directory:
sdk\src\sample\io_sample\IR\Rx
Source files are currently categorized into several groups as below.
└── Project: ir_rx
└── 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
├── ancs.c
├── app.c
├── app_task.c
└── io_ir.c
Initialization
When the EVB reset is initiated, the main()
function is called, and the following process will be executed:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
global_data_init();
board_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
Note
le_gap_init()
, gap_lib_init()
, app_le_gap_init
, and app_le_profile_init
are related to the initialization of the privacy management module. Refer to the initialization process description in LE Peripheral Privacy.
The specific initialization process related to peripherals is as follows:
In
global_data_init
, executeglobal_data_ir_init
, which is a global initialization function that initializes the global variableIR_Rx_Data
and resets the IR receive data.void global_data_adc_init(void) { /* Initialize adc k value! */ APP_PRINT_INFO0("[io_adc] global_data_adc_init"); bool adc_k_status = false; adc_k_status = ADC_CalibrationInit(); if (false == adc_k_status) { APP_PRINT_ERROR0("[io_adc] global_data_adc_init: ADC_CalibrationInit fail!"); } memset(&ADC_Recv_Buffer, 0, sizeof(ADC_Recv_Buffer)); }
In
board_init
, executeboard_ir_init
, which is responsible for PAD/PINMUX settings and includes the following process:Configure PAD: Set pin, PINMUX mode, PowerOn, internal pull-none, output disabled.
Configure PINMUX: Assign the pin to the IRDA_RX function.
After executing
os_sched_start()
to start task scheduling, in theapp_main_task
main task, executedriver_init
to initialize and configure the peripheral drivers.In
driver_init
, executedriver_ir_init
, which is the initialization function for the IR peripheral, including the following process:Enable RCC clock.
Set IR receiving frequency to 38kHz.
Set IR to auto-receive mode.
Set IR receiving threshold to 30, discard the latest data when IR receiving FIFO is full, filter out noise data below 50ns.
Set the level type for trigger receive counter threshold interrupt to high level, set IR_RxCntThr to 0x1F40.
Enable IR peripheral receiving function, clear IR receiving FIFO.
void driver_ir_init(void) { /* 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 = 38000;/* IR carrier freqency is 38KHz */ IR_InitStruct.IR_Mode = IR_MODE_RX;/* IR receiveing mode */ IR_InitStruct.IR_RxStartMode = IR_RX_AUTO_MODE; IR_InitStruct.IR_RxFIFOThrLevel = IR_RX_FIFO_THR_LEVEL; /* Configure RX FIFO threshold level to trigger IR_INT_RF_LEVEL interrupt */ IR_InitStruct.IR_RxFIFOFullCtrl = IR_RX_FIFO_FULL_DISCARD_NEWEST;/* Discard the lastest received dta if RX FIFO is full */ IR_InitStruct.IR_RxFilterTime = IR_RX_FILTER_TIME_50ns;/* If high to low or low to high transition time <= 50ns,Filter out it. */ IR_InitStruct.IR_RxTriggerMode = IR_RX_FALL_EDGE;/* Configure trigger type */ IR_InitStruct.IR_RxCntThrType = IR_RX_Count_High_Level;/* IR_RX_Count_High_Level is counting high level */ IR_InitStruct.IR_RxCntThr = 0x1F40;/* Configure RX counter threshold.You can use it to decide to stop receiving IR data */ IR_Init(&IR_InitStruct); IR_Cmd(IR_MODE_RX, ENABLE); IR_ClearRxFIFO(); /* 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
Execute
os_sched_start()
to start task scheduling. When the stack is ready, executeapp_handle_dev_state_evt
and executeir_demo
.Configure the IR receive FIFO data count greater than the set receive threshold interrupt
IR_INT_RF_LEVEL
and receive level timeout interruptIR_INT_RX_CNT_THR
.Unmask the
IR_INT_RF_LEVEL
andIR_INT_RX_CNT_THR
interrupts.
void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause) { ... if (gap_dev_state.gap_init_state != new_state.gap_init_state) { if (new_state.gap_init_state == GAP_INIT_STATE_STACK_READY) { APP_PRINT_INFO0("GAP stack ready"); /*stack ready*/ ir_demo(); } } ... } void ir_demo(void) { /* Enable IR threshold interrupt. when RX FIFO offset >= threshold value, trigger interrupt*/ /* Enable IR counter threshold interrupt to stop receiving data */ IR_INTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, ENABLE); IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); }
Send IR data to the IR transceiver module. When the number of data in the IR receive FIFO reaches the set reception threshold (set to 30 in this example), it triggers the
IR_INT_RF_LEVEL
interrupt. Alternatively, when the number of the receive counter reaches the set threshold (set to 0x1F40 in this example), it triggers theIR_INT_RX_CNT_THR
interrupt, entering the interrupt handler functionIR_Handler
.Mask the
IR_INT_TF_LEVEL
andIR_INT_RX_CNT_THR
interrupts.If the triggered interrupt is
IR_INT_TF_LEVEL
, IR needs to receive data from the FIFO. Store the data in DataBuf and record the length of the received data.If the triggered interrupt is
IR_INT_RX_CNT_THR
, it indicates that the IR data reception stop condition has been triggered. Store the remaining data in DataBuf, record the length of the received data, and print the data content.Clear the
IR_INT_RX_CNT_THR
interrupt pending bit.Unmask the
IR_INT_RF_LEVEL
andIR_INT_RX_CNT_THR
interrupts.
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_ClearINTPendingBit(IR_INT_RF_LEVEL_CLR); } /* Stop to receive IR data */ if (int_status_rxcnt == SET) { /* 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; T_IO_MSG int_ir_msg; int_ir_msg.type = IO_MSG_TYPE_IR; int_ir_msg.subtype = 0; int_ir_msg.u.buf = (void *)(&IR_Rx_Data); if (false == app_send_msg_to_apptask(&int_ir_msg)) { APP_PRINT_ERROR0("[io_ir]IR_INT_RX_CNT_THR: Send int_ir_msg failed!"); //Add user code here! IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR); return; } IR_ClearINTPendingBit(IR_INT_RX_CNT_THR_CLR); } /* Unmask IR all interrupt */ IR_MaskINTConfig(IR_INT_RF_LEVEL | IR_INT_RX_CNT_THR, DISABLE); } void io_handle_ir_msg(T_IO_MSG *io_ir_msg) { IR_Data_TypeDef *p_buf = io_ir_msg->u.buf; for (uint16_t i = 0; i < p_buf->DataLen; i++) { APP_PRINT_INFO2("[io_ir]io_handle_ir_msg: IR RX data[%d] = 0x%x", i, p_buf->DataBuf[i]); } memset(&IR_Rx_Data, 0, sizeof(IR_Rx_Data)); IR_RX_Count = 0; }