/* * Copyright (c) 2019, Erich Styger * * SPDX-License-Identifier: BSD-3-Clause */ #include "platform.h" #if PL_CONFIG_USE_BUTTONS #include "buttons.h" #include "McuButton.h" #include "McuRTOS.h" #include "McuDebounce.h" #include "McuRTT.h" #include "fsl_port.h" /* for KBI and pull up selection */ #include "Event.h" /* Buttons */ /* User button SW2: PTA14 */ #define PINS_SW2_GPIO GPIOA #define PINS_SW2_PORT PORTA #define PINS_SW2_PIN 14U static McuBtn_Handle_t btnSW2; bool BTN_SW2ButtonIsPressed(void) { return McuBtn_IsOn(btnSW2); } static uint32_t GetButtons(void) { uint32_t val = 0; if (McuBtn_IsOn(btnSW2)) { val |= BTN_SW2; } return val; } static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons); #define TIMER_PERIOD_MS 20 /* frequency of timer */ static McuDbnc_Desc_t data = { .state = MCUDBMC_STATE_IDLE, .timerPeriodMs = TIMER_PERIOD_MS, .timer = NULL, .debounceTimeMs = 100, .repeatTimeMs = 300, .longKeyTimeMs = 1000, .getButtons = GetButtons, .onDebounceEvent = OnDebounceEvent, }; static void OnDebounceEvent(McuDbnc_EventKinds event, uint32_t buttons) { switch(event) { case MCUDBNC_EVENT_PRESSED: SEGGER_printf("pressed: %d\r\n", buttons); EVNT_SetEvent(EVNT_SW1_PRESSED); break; case MCUDBNC_EVENT_PRESSED_REPEAT: SEGGER_printf("repeat: %d\r\n", buttons); EVNT_SetEvent(EVNT_SW1_PRESSED_REPEAT); break; case MCUDBNC_EVENT_LONG_PRESSED: SEGGER_printf("long pressed: %d\r\n", buttons); EVNT_SetEvent(EVNT_SW1_LPRESSED); #if PL_CONFIG_USE_GUI_KEY_NAV if (buttons&BTN_UP) { LV_ButtonEvent(LV_BTN_MASK_UP, LV_MASK_PRESSED_LONG); } if (buttons&BTN_DOWN) { LV_ButtonEvent(LV_BTN_MASK_DOWN, LV_MASK_PRESSED_LONG); } if (buttons&BTN_LEFT) { LV_ButtonEvent(LV_BTN_MASK_LEFT, LV_MASK_PRESSED_LONG); } if (buttons&BTN_RIGHT) { LV_ButtonEvent(LV_BTN_MASK_RIGHT, LV_MASK_PRESSED_LONG); } if (buttons&BTN_CENTER) { LV_ButtonEvent(LV_BTN_MASK_CENTER, LV_MASK_PRESSED_LONG); } #endif break; case MCUDBNC_EVENT_LONG_PRESSED_REPEAT: SEGGER_printf("long repeat: %d\r\n", buttons); EVNT_SetEvent(EVNT_SW1_LPRESSED_REPEAT); break; case MCUDBNC_EVENT_RELEASED: SEGGER_printf("released: %d\r\n", buttons); EVNT_SetEvent(EVNT_SW1_RELEASED); #if PL_CONFIG_USE_RASPY_UART RASPYU_OnJoystickEvent(0); #endif #if PL_CONFIG_USE_GUI_KEY_NAV if (buttons&BTN_UP) { LV_ButtonEvent(LV_BTN_MASK_UP, LV_MASK_RELEASED); } if (buttons&BTN_DOWN) { LV_ButtonEvent(LV_BTN_MASK_DOWN, LV_MASK_RELEASED); } if (buttons&BTN_LEFT) { LV_ButtonEvent(LV_BTN_MASK_LEFT, LV_MASK_RELEASED); } if (buttons&BTN_RIGHT) { LV_ButtonEvent(LV_BTN_MASK_RIGHT, LV_MASK_RELEASED); } if (buttons&BTN_CENTER) { LV_ButtonEvent(LV_BTN_MASK_CENTER, LV_MASK_RELEASED); } #endif break; default: case MCUDBNC_EVENT_END: (void)xTimerStop(data.timer, pdMS_TO_TICKS(100)); /* stop timer */ SEGGER_printf("end: %d\r\n", buttons); break; } } #if McuLib_CONFIG_SDK_USE_FREERTOS static void vTimerCallbackDebounce(TimerHandle_t pxTimer) { /* called with TIMER_PERIOD_MS during debouncing */ (void)pxTimer; /* not used */ McuDbnc_Process(&data); } static void StartDebounce(uint32_t buttons, bool fromISR) { BaseType_t res; BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (data.state==MCUDBMC_STATE_IDLE) { data.scanValue = buttons; data.state = MCUDBMC_STATE_START; McuDbnc_Process(&data); if (fromISR) { res = xTimerStartFromISR(data.timer, &xHigherPriorityTaskWoken); } else { res = xTimerStart(data.timer, pdMS_TO_TICKS(100)); } #ifdef NDEBUG (void)res; /* avoid compiler warning about unused variable */ #endif assert(res==pdPASS); if (fromISR) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } } #endif #if !PL_CONFIG_USE_KBI #if McuLib_CONFIG_SDK_USE_FREERTOS static void PollButtons(void) { if (McuBtn_IsOn(btnSW2)) { StartDebounce(BTN_SW2, false); } } static void BtnTask(void *pv) { for(;;) { PollButtons(); vTaskDelay(pdMS_TO_TICKS(50)); } } #endif #else void PORTA_IRQHandler(void) { /* SW2 is on PORTA (PINS_SW2_PORT) */ uint32_t flags; flags = GPIO_PortGetInterruptFlags(PINS_SW2_GPIO); if (flags&(1U<PCR[pin]; return *(port_pin_config_t *)(addr); } void BTN_EnablePullup(void) { /* V2 has no pull-up on the board, need to turn on internal pull-up */ McuBtn_EnablePullResistor(btnSW2); } void BTN_Init(void) { McuBtn_Config_t btnConfig; McuBtn_GetDefaultConfig(&btnConfig); btnConfig.isLowActive = true; btnConfig.hw.gpio = PINS_SW2_GPIO; btnConfig.hw.port = PINS_SW2_PORT; btnConfig.hw.pin = PINS_SW2_PIN; btnSW2 = McuBtn_InitButton(&btnConfig); #if PL_IS_INTRO_ZUMO_K22_V2 /* has no pull-ups on the board, need to turn on internal pull-ups */ port_pin_config_t portConfig; portConfig = PORT_GetPinConfig(PINS_SW2_PORT, PINS_SW2_PIN); /* get current config */ portConfig.pullSelect = kPORT_PullUp; PORT_SetPinConfig(PINS_SW2_PORT, PINS_SW2_PIN, &portConfig); #endif #if !PL_LOCAL_CONFIG_USE_RESET_PIN /* SW1: enable and turn on pull-up resistor for PTA14 (push button) */ // PORT_PDD_SetPinPullSelect(PORTA_BASE_PTR, 14, PORT_PDD_PULL_UP); // PORT_PDD_SetPinPullEnable(PORTA_BASE_PTR, 14, PORT_PDD_PULL_ENABLE); /* this is not implemented yet for the SDK: need to disable reset functionality and enable pull-ups */ #endif #if PL_CONFIG_USE_KBI PORT_SetPinInterruptConfig(PINS_SW2_PORT, PINS_SW2_PIN, kPORT_InterruptFallingEdge); /* SW2 is on Port A */ NVIC_SetPriority(PORTA_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); EnableIRQ(PORTA_IRQn); #elif McuLib_CONFIG_SDK_USE_FREERTOS /* use task for button polling */ if (xTaskCreate( BtnTask, /* pointer to the task */ "Btn", /* task name for kernel awareness debugging */ 500/sizeof(StackType_t), /* task stack size */ (void*)NULL, /* optional task startup argument */ tskIDLE_PRIORITY+4, /* initial priority */ (TaskHandle_t*)NULL /* optional task handle to create */ ) != pdPASS) { for(;;){} /* error! probably out of memory */ } #endif #if McuLib_CONFIG_SDK_USE_FREERTOS data.timer = xTimerCreate( "tmrDbnc", /* name */ pdMS_TO_TICKS(TIMER_PERIOD_MS), /* period/time */ pdTRUE, /* auto reload */ (void*)2, /* timer ID */ vTimerCallbackDebounce); /* callback */ if (data.timer==NULL) { for(;;); /* failure! */ } #endif } void BTN_Deinit(void) { #if PL_CONFIG_USE_KBI #if TINYK22_HAT_VERSION==3 DisableIRQ(PORTB_IRQn); /* all buttons are on Port B */ #elif TINYK22_HAT_VERSION==4 || TINYK22_HAT_VERSION==5 DisableIRQ(PORTA_IRQn); /* left and right are on Port A */ DisableIRQ(PORTB_IRQn); /* up, down, push are on Port B */ #endif #endif btnSW2 = McuBtn_DeinitButton(btnSW2); } #endif /* PL_CONFIG_USE_BUTTONS */