KeyScan in DLPS Mode

This sample code guide is designed to help users easily and comprehensively understand KeyScan sample. This sample demonstrates how KeyScan works in DLPS mode.

Requirements

For hardware requirements, please refer to the Requirements.

Wiring

The EVB is connected to a matrix keyboard module, connect P0_2 to ROW0, P0_3 to ROW1, P0_0 to COLUMN0, and P0_1 to COLUMN1. The hardware connection of KeyScan sample code is shown in the figure below.

../../../_images/KeyScan_Sample_Code_Hardware_Connection_Diagram.png

KeyScan Sample Code Hardware Connection Diagram

Configurations

  1. The following macros can be configured to modify pin definitions.

    • #define COLUMN0               ADC_0

    • #define COLUMN1               ADC_1

    • #define ROW0                  ADC_2

    • #define ROW1                  ADC_3

  2. The entry function is as follows, call this function in main() to run this sample code. For more details, please refer to the Initialization.

    keyscan_demo_dlps();
    

Building and Downloading

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

Experimental Verification

  1. Press the Reset button on the EVB, the system is in idle state and will enter DLPS mode.

  2. When keys are pressed, the system will be woken up, KeyScan starts scan. After the scan ends, it enters the KeyScan interrupt and prints the key information.

    io_demo_task: pKeyData->key[xx] xx
    
  3. After all the keys are released, print the following log, the system is in idle state and will re-enter DLPS mode.

    keyscan_release_handle: All key release
    

Code Overview

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

Source Code Directory

  • For project directory, please refer to Source Code Directory.

  • Source code directory: sdk\src\sample\io_demo\keyscan\dlps\keyscan_demo_dlps.c.

KeyScan Initialization

The initialization flow for peripherals can refer to Initialization Flow.

KeyScan initialization flow is shown in the following figure.

../../../_images/KEYSCAN_Initialization_Flow_Chart.png

KeyScan Initialization Flow Chart

  1. Call Pad_Config() and Pinmux_Config() to initialize the pin.

    static void board_keyscan_init(void)
    {
       Pad_Config(COLUMN0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
       Pad_Config(COLUMN1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_NONE, PAD_OUT_ENABLE, PAD_OUT_LOW);
       Pad_Config(ROW0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
       Pad_Config(ROW1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
    
       Pinmux_Config(COLUMN0, KEY_COL_0);
       Pinmux_Config(COLUMN1, KEY_COL_1);
       Pinmux_Config(ROW0, KEY_ROW_0);
       Pinmux_Config(ROW1, KEY_ROW_1);
    }
    
  2. Call RCC_PeriphClockCmd() to enable the KeyScan clock and function.

  3. Initialize the KeyScan peripheral:

    1. Define the KEYSCAN_InitTypeDef type KeyScan_InitStruct, and call KeyScan_StructInit() to pre-fill KeyScan_InitStruct with default values.

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

    3. Call KeyScan_Init() to initialize the KeyScan peripheral.

    KeyScan Initialization Parameters

    KeyScan Hardware Parameters

    Setting in the KeyScan_InitStruct

    KeyScan

    Column Size

    KEYSCAN_InitTypeDef::colSize

    2

    Row Size

    KEYSCAN_InitTypeDef::rowSize

    2

    Scan Interval

    KEYSCAN_InitTypeDef::scanInterval

    0xFA

    Debounce Enable

    KEYSCAN_InitTypeDef::debounceEn

    KeyScan_Debounce_Disable

    Clock Divider

    KEYSCAN_InitTypeDef::clockdiv

    0x3E8

    Release Timer Count

    KEYSCAN_InitTypeDef::releasecnt

    0x01

  4. Call KeyScan_INTConfig() to enable the KeyScan scan end interrupt KEYSCAN_INT_SCAN_END and the KeyScan all release interrupt KEYSCAN_INT_ALL_RELEASE.

  5. Call NVIC_Init() to enable NVIC of KeyScan.

  6. Call KeyScan_Cmd() to enable KeyScan.

DLPS Mode Initialization

  1. Call power_check_cb_register() to register inquiry callback function to DLPS Framework. This function will be called each time before entering DLPS to decide whether DLPS is allowed to enter. DLPS will be disallowed if any inquiry callback function returns false.

  2. Call io_dlps_register() to initialize IO store/restore and do not need to worry about which IO peripheral requires specific handling.

  3. Call io_dlps_register_enter_cb() to register callbacks to DLPS enter stage. Function io_dlps_enter will be executed while entering from DLPS:

    1. Call Pad_ControlSelectValue() to switch COLUMN0 and COLUMN1 and ROW0 and ROW1 to software mode.

    2. Call System_WakeUpPinEnable() to to enable the wake-up function of ROW0 and ROW1.

  4. Call io_dlps_register_exit_cb() to register callbacks to DLPS exit stage. Function io_dlps_exit will be executed while exiting from DLPS:

    1. Call Pad_ControlSelectValue() to switch COLUMN0 and COLUMN1 and ROW0 and ROW1 to PINMUX mode.

    2. Call System_WakeUpInterruptValue() to check wake up pin interrupt status. If it is found that the system is woken up by ROW0 or ROW1, set keyscanallowdlps to false to not allow the system to enter DLPS mode.

  5. Call bt_power_mode_set() to set Bluetooth MAC deep sleep mode.

  6. Call power_mode_set() to switch the system to DLPS mode.

Functional Implementation

Interrupt Handle

  1. After the scan key matrix is completed, the KeyScan scan end interrupt is triggered.

    1. Call KeyScan_GetFlagState() to check KEYSCAN_INT_FLAG_SCAN_END interrupt flag state.

    2. Call KeyScan_INTMask() to mask KEYSCAN_INT_SCAN_END interrupt.

    3. Call KeyScan_GetFlagState() to check the FIFO empty flag state, if KEYSCAN_FLAG_EMPTY flag is set:

      1. Call KeyScan_GetFifoDataNum() to get KeyScan FIFO data number.

      2. Call KeyScan_Read() to read data from KeyScan FIFO.

      3. If new buttons are pressed:

        1. Send a message to the task, and after the task receives the message, it will print log.

        2. Call KeyScan_ClearINTPendingBit() to clear KEYSCAN_INT_SCAN_END interrupt.

        3. Call KeyScan_INTMask() to unmask KEYSCAN_INT_SCAN_END interrupt.

      4. If no new buttons are pressed:

        1. Call KeyScan_ClearINTPendingBit() to clear KEYSCAN_INT_SCAN_END interrupt.

        2. Call KeyScan_INTMask() to unmask KEYSCAN_INT_SCAN_END interrupt.

  2. When the release time count reaches the set value, if no key is pressed, the KeyScan all release interrupt is triggered.

    1. Call KeyScan_GetFlagState() to check KEYSCAN_INT_FLAG_ALL_RELEASE interrupt flag state.

    2. Call KeyScan_INTMask() to mask KEYSCAN_INT_ALL_RELEASE interrupt.

    3. Send a message to the task, and after the task receives the message, it will print log and set keyscanallowdlps to true to allow the system to enter DLPS mode.

    4. Call KeyScan_ClearINTPendingBit() to clear KEYSCAN_INT_ALL_RELEASE interrupt.

    5. Call KeyScan_INTMask() to unmask KEYSCAN_INT_ALL_RELEASE interrupt.