Input Key

This sample uses the GPIO input function to detect the GPIO input signal by interrupt.

This sample starts with configuring the GPIO as input and enabling the interrupt function. An interrupt is triggered and the interrupt handler prints information when a GPIO input change is detected.

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 P4_0 to the external input signal.

Building and Downloading

This sample can be found in the SDK folder:

Project file: board\evb\io_sample\GPIO\Input_key\mdk

Project file: board\evb\io_sample\GPIO\Input_key\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

Control the external input signal to change from high level to low level, P4_0 detects the falling edge signal triggering an interrupt, displaying the following log.

[app] app_handle_io_msg: GPIO input msg.

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\GPIO\Input_key

  • Source code directory: sdk\src\sample\io_sample\GPIO\Input_key

Source files are currently categorized into several groups as below.

└── Project: input_key
    └── 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
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_gpio.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            ├── main.c
            ├── ancs.c
            ├── app.c
            ├── app_task.c
            └── io_gpio.c

Initialization

After the EVB resets, 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);
    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:

  1. In board_init, execute board_gpio_init, which is responsible for PAD/PINMUX settings and includes the following process:

    1. Configure PAD: Set pin, PINMUX mode, PowerOn, internal pull-up, output disable.

    2. Configure PINMUX: Assign pin to GPIO function.

  2. After executing os_sched_start() to start task scheduling, in the app_main_task main task, execute driver_init to initialize and configure the peripheral drivers.

  3. In driver_init, execute driver_gpio_init, which is the initialization function for the GPIO peripheral, including the following process:

    1. Enable RCC clock.

    2. Configure GPIO mode as input mode.

    3. Enable GPIO interrupt.

    4. Set GPIO interrupt trigger mode to edge trigger, and set GPIO interrupt polarity to falling edge trigger.

    5. Enable GPIO debounce function and configure debounce time.

    6. Mask GPIO interrupt, enable GPIO interrupt, clear GPIO interrupt flag, and unmask GPIO interrupt.

    void driver_gpio_init(void)
    {
        /* Initialize GPIO peripheral */
        RCC_PeriphClockCmd(APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE);
    
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_StructInit(&GPIO_InitStruct);
        GPIO_InitStruct.GPIO_Pin        = GPIO_PIN_INPUT;
        GPIO_InitStruct.GPIO_Mode       = GPIO_Mode_IN;
        GPIO_InitStruct.GPIO_ITCmd      = ENABLE;
        GPIO_InitStruct.GPIO_ITTrigger  = GPIO_INT_Trigger_EDGE;
        GPIO_InitStruct.GPIO_ITPolarity = GPIO_INT_POLARITY_ACTIVE_LOW;
        GPIO_InitStruct.GPIO_ITDebounce = GPIO_INT_DEBOUNCE_ENABLE;
        GPIO_InitStruct.GPIO_DebounceTime = 10;/* unit:ms , can be 1~64 ms */
        GPIO_Init(&GPIO_InitStruct);
    
        GPIO_MaskINTConfig(GPIO_PIN_INPUT, ENABLE);
        GPIO_INTConfig(GPIO_PIN_INPUT, ENABLE);
        GPIO_ClearINTPendingBit(GPIO_PIN_INPUT);
        GPIO_MaskINTConfig(GPIO_PIN_INPUT, DISABLE);
    
        NVIC_InitTypeDef NVIC_InitStruct;
        NVIC_InitStruct.NVIC_IRQChannel = GPIO_PIN_INPUT_IRQN;
        NVIC_InitStruct.NVIC_IRQChannelPriority = 3;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
    }
    

Functional Implementation

  1. When P4_0 detects an external falling edge signal input, it enters the interrupt service handling function GPIO_Input_Handler.

    1. Disable and mask the GPIO interrupt. Clear the interrupt flag, unmask the interrupt, and re-enable the interrupt when exiting the interrupt function.

    2. Define the message type IO_MSG_TYPE_GPIO and send a msg to the task. In the msg message handling function, when a GPIO message is detected, print the GPIO information.

    void GPIO_Input_Handler(void)
    {
        GPIO_INTConfig(GPIO_PIN_INPUT, DISABLE);
        GPIO_MaskINTConfig(GPIO_PIN_INPUT, ENABLE);
    
        T_IO_MSG int_gpio_msg;
    
        int_gpio_msg.type = IO_MSG_TYPE_GPIO;
        int_gpio_msg.subtype = 0;
        if (false == app_send_msg_to_apptask(&int_gpio_msg))
        {
            APP_PRINT_ERROR0("[io_gpio] GPIO_Input_Handler: Send int_gpio_msg failed!");
            GPIO_ClearINTPendingBit(GPIO_PIN_INPUT);
            return;
        }
    
        GPIO_ClearINTPendingBit(GPIO_PIN_INPUT);
        GPIO_MaskINTConfig(GPIO_PIN_INPUT, DISABLE);
        GPIO_INTConfig(GPIO_PIN_INPUT, ENABLE);
    }
    
    void app_handle_io_msg(T_IO_MSG io_msg)
    {
        uint16_t msg_type = io_msg.type;
    
        switch (msg_type)
        {
        ...
        case IO_MSG_TYPE_GPIO:
            {
                APP_PRINT_INFO0("[app] app_handle_io_msg: GPIO input msg.");
            }
            break;
        ...
        }
    }
    

Troubleshooting

GPIO False Trigger Interrupt

GPIO edge-type interrupts will be self-triggered when enabling the GPIO interrupt in the following four modes:

  • PAD input = high, rising edge triggered interrupt.

  • PAD input = high, double edge triggered interrupt.

  • PAD input = low, falling edge triggered interrupt.

  • PAD input = low, double edge triggered interrupt.

The below flow can be used to enable edge interrupt in these cases to avoid self-triggered interrupt:

  1. Mask GPIO interrupt: GPIO_MaskINTConfig(GPIO_PIN, ENABLE).

  2. Enable edge interrupt: GPIO_INTConfig(GPIO_PIN, ENABLE).

  3. Clear GPIO interrupt state: GPIO_ClearPendingBit(GPIO_PIN).

  4. Unmask GPIO interrupt: GPIO_MaskINTConfig(GPIO_PIN, DISABLE).

The following flow can modify the GPIO interrupt configurations to avoid self-triggered interrupt:

  1. Mask GPIO interrupt: GPIO_MaskINTConfig(GPIO_PIN, ENABLE).

  2. Modify GPIO interrupt configurations (change interrupt trigger edge and polarity): GPIO_SetITTrigger(GPIO_PIN, GPIO_TriggerMode) GPIO_SetITPolarity(GPIO_PIN, GPIO_ITPolarity)....

  3. Clear GPIO interrupt state: GPIO_ClearPendingBit(GPIO_PIN).

  4. Unmask GPIO interrupt: GPIO_MaskINTConfig(GPIO_PIN, DISABLE).