1 /***************************************************************************//** 2 * @file 3 * @brief Keyscan (KEYSCAN) peripheral API 4 ******************************************************************************* 5 * # License 6 * <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b> 7 ******************************************************************************* 8 * 9 * SPDX-License-Identifier: Zlib 10 * 11 * The licensor of this software is Silicon Laboratories Inc. 12 * 13 * This software is provided 'as-is', without any express or implied 14 * warranty. In no event will the authors be held liable for any damages 15 * arising from the use of this software. 16 * 17 * Permission is granted to anyone to use this software for any purpose, 18 * including commercial applications, and to alter it and redistribute it 19 * freely, subject to the following restrictions: 20 * 21 * 1. The origin of this software must not be misrepresented; you must not 22 * claim that you wrote the original software. If you use this software 23 * in a product, an acknowledgment in the product documentation would be 24 * appreciated but is not required. 25 * 2. Altered source versions must be plainly marked as such, and must not be 26 * misrepresented as being the original software. 27 * 3. This notice may not be removed or altered from any source distribution. 28 * 29 ******************************************************************************/ 30 31 #include "sl_hal_keyscan.h" 32 #if defined(KEYSCAN_COUNT) && (KEYSCAN_COUNT > 0) 33 #include "sl_assert.h" 34 #include "em_bus.h" 35 36 /***************************************************************************//** 37 * @addtogroup keyscan KEYSCAN - Keyboard Scan 38 * @brief Keyscan (KEYSCAN) Peripheral API 39 * @details 40 * This module contains functions to control the KEYSCAN peripheral of Silicon 41 * Labs 32-bit MCUs and SoCs. The KEYSCAN module connects through rows and 42 * columns of GPIOs to an external mechanical keypad. 43 * @{ 44 ******************************************************************************/ 45 46 /***************************************************************************//** 47 * Initializes KEYSCAN module. 48 ******************************************************************************/ sl_hal_keyscan_init(const sl_hal_keyscan_config_t * p_config)49void sl_hal_keyscan_init(const sl_hal_keyscan_config_t *p_config) 50 { 51 // Wait to be ready 52 sl_hal_keyscan_wait_ready(); 53 54 if (KEYSCAN->EN == KEYSCAN_EN_EN) { 55 // Disable KEYSCAN module 56 KEYSCAN->EN_CLR = KEYSCAN_EN_EN; 57 while (KEYSCAN->EN & _KEYSCAN_EN_DISABLING_MASK) { 58 // Wait for disabling to finished 59 } 60 } 61 62 // A sanity check of configuration parameters. 63 EFM_ASSERT(p_config->clock_divider <= _KEYSCAN_CFG_CLKDIV_MASK); 64 EFM_ASSERT(p_config->column_number <= KEYSCAN_COLNUM); 65 EFM_ASSERT(p_config->row_number <= KEYSCAN_ROWNUM); 66 EFM_ASSERT(p_config->scan_delay <= SL_HAL_KEYSCAN_DELAY_32MS); 67 EFM_ASSERT(p_config->debounce_delay <= SL_HAL_KEYSCAN_DELAY_32MS); 68 EFM_ASSERT(p_config->stable_delay <= SL_HAL_KEYSCAN_DELAY_32MS); 69 70 // Set configuration 71 KEYSCAN->CFG = ((p_config->clock_divider) << _KEYSCAN_CFG_CLKDIV_SHIFT) 72 | ((p_config->auto_start_enable) << _KEYSCAN_CFG_AUTOSTART_SHIFT) 73 | ((p_config->single_press_enable) << _KEYSCAN_CFG_SINGLEPRESS_SHIFT) 74 | ((p_config->column_number - 1) << _KEYSCAN_CFG_NUMCOLS_SHIFT) 75 | ((p_config->row_number - 1) << _KEYSCAN_CFG_NUMROWS_SHIFT); 76 77 KEYSCAN->DELAY = ((p_config->scan_delay) << _KEYSCAN_DELAY_SCANDLY_SHIFT) 78 | ((p_config->debounce_delay) << _KEYSCAN_DELAY_DEBDLY_SHIFT) 79 | ((p_config->stable_delay) << _KEYSCAN_DELAY_STABDLY_SHIFT); 80 } 81 82 /***************************************************************************//** 83 * Enables KEYSCAN module. 84 ******************************************************************************/ sl_hal_keyscan_enable(void)85void sl_hal_keyscan_enable(void) 86 { 87 if (KEYSCAN->EN != 0U) { 88 // Wait for synchronization before writing to EN register 89 sl_hal_keyscan_wait_sync(); 90 } 91 92 // Enable KEYSCAN module 93 KEYSCAN->EN_SET = KEYSCAN_EN_EN; 94 } 95 96 /***************************************************************************//** 97 * Disables KEYSCAN module. 98 ******************************************************************************/ sl_hal_keyscan_disable(void)99void sl_hal_keyscan_disable(void) 100 { 101 // Quick exit if we want to disable KEYSCAN and it's already disabled. 102 if (KEYSCAN->EN == 0U) { 103 return; 104 } 105 106 // Stop scan if running 107 if (KEYSCAN->STATUS & _KEYSCAN_STATUS_RUNNING_MASK) { 108 sl_hal_keyscan_stop_scan(); 109 } 110 111 // Wait for synchronization to complete 112 sl_hal_keyscan_wait_sync(); 113 114 // Disable module 115 KEYSCAN->EN_CLR = KEYSCAN_EN_EN; 116 } 117 118 /***************************************************************************//** 119 * Restores KEYSCAN to its reset state. 120 * 121 * @note 122 * The register STATUS get reset value after enabling the module because 123 * it is of type RSYNC 124 ******************************************************************************/ sl_hal_keyscan_reset(void)125void sl_hal_keyscan_reset(void) 126 { 127 // Stop scan if running 128 if (KEYSCAN->STATUS & _KEYSCAN_STATUS_RUNNING_MASK) { 129 sl_hal_keyscan_stop_scan(); 130 } 131 132 sl_hal_keyscan_enable(); 133 134 // Wait for synchronization to complete 135 sl_hal_keyscan_wait_sync(); 136 137 // Software reset command 138 KEYSCAN->SWRST_SET = KEYSCAN_SWRST_SWRST; 139 } 140 141 /** @} (end addtogroup keyscan) */ 142 #endif /* defined(KEYSCAN_COUNT) && (KEYSCAN_COUNT > 0) */ 143