/* * (c) danielinux 2019 * GPLv.2 * * See LICENSE for details */ #include #include #include #include #include "system.h" #include "button.h" #include "systick.h" #include "unicore-mx/stm32/gpio.h" #include "unicore-mx/stm32/exti.h" #include "unicore-mx/stm32/rcc.h" #include "unicore-mx/stm32/f4/rcc.h" #include "unicore-mx/stm32/adc.h" #include "unicore-mx/stm32/f4/adc.h" #include "unicore-mx/stm32/f4/nvic.h" // Uncomment to enable debug //#define BUTTON_DEBUG #ifdef BUTTON_DEBUG # define DBG printf #else # define DBG(...) do {} while (0) #endif #define BUTTON_DEBOUNCE_TIME 50 #define BUTTON_HOLD_TIME 1500 static volatile int button_press_pending = 0; static void input_run(uint32_t ev, void *arg); static void input_init(void); const char button_task_name[] = "Input"; // PA8 + PA9 // ROTARY encoder // PC0 // BUTTON void pin_exti_init(void) { int i; uint32_t exti_irq; rcc_periph_clock_enable(RCC_SYSCFG); rcc_periph_clock_enable(RCC_GPIOA); gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO9 | GPIO8 | GPIO7 | GPIO6 | GPIO5); nvic_enable_irq(NVIC_EXTI9_5_IRQ); nvic_set_priority(NVIC_EXTI9_5_IRQ, 1); exti_select_source(GPIO5, GPIOA); exti_select_source(GPIO6, GPIOA); exti_select_source(GPIO7, GPIOA); exti_select_source(GPIO8, GPIOA); exti_select_source(GPIO9, GPIOA); } void pin_exti_start_read(void) { exti_set_trigger(GPIO5|GPIO6|GPIO7|GPIO8|GPIO9, EXTI_TRIGGER_BOTH); exti_enable_request(GPIO5); exti_enable_request(GPIO6); exti_enable_request(GPIO7); exti_enable_request(GPIO8); exti_enable_request(GPIO9); } static void button_setup(void) { int i; uint32_t exti_irq; rcc_periph_clock_enable(RCC_SYSCFG); rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); rcc_periph_clock_enable(RCC_GPIOC); gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO10); gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO4); gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO0); nvic_enable_irq(NVIC_EXTI4_IRQ); nvic_enable_irq(NVIC_EXTI0_IRQ); nvic_enable_irq(NVIC_EXTI15_10_IRQ); nvic_set_priority(NVIC_EXTI4_IRQ, 1); nvic_set_priority(NVIC_EXTI0_IRQ, 1); nvic_set_priority(NVIC_EXTI15_10_IRQ, 1); exti_select_source(GPIO10, GPIOA); exti_select_source(GPIO4, GPIOB); exti_select_source(GPIO0, GPIOC); } enum button_state { IDLE = 0, PRESSING, PRESSED, HOLD, RELEASING, }; static volatile enum button_state button_status = 0; static volatile uint32_t rot_up = 0; static volatile uint32_t rot_down = 0; static void button_start_read(void) { exti_set_trigger(GPIO0, EXTI_TRIGGER_RISING); exti_set_trigger(GPIO10|GPIO4, EXTI_TRIGGER_RISING); exti_enable_request(GPIO10); exti_enable_request(GPIO4); exti_enable_request(GPIO0); } void isr_exti_rot1(void) { exti_reset_request(GPIO4); if (gpio_get(GPIOA, GPIO10) == 0) return; rot_down++; } void isr_exti_rot0(void) { exti_reset_request(GPIO10); if (gpio_get(GPIOB, GPIO4) == 0) return; rot_up++; } void isr_exti_button(void) { button_press_pending = !!(gpio_get(GPIOC, GPIO0)); exti_reset_request(GPIO0); } static uint32_t t0s, t0us; static uint32_t t1s, t1us; static uint32_t time_diff_ms(uint32_t s_a, uint32_t us_a, uint32_t s_b, uint32_t us_b) { uint32_t res = 0; res = (s_a - s_b) * 1000; if (us_b > us_a) { us_a += 1000000; res -= 1000; } res += (us_a - us_b) / 1000; return res; } typedef void (*exti_trigger_callback_fn)(uint32_t pin, uint8_t front, uint32_t s, uint32_t us); static exti_trigger_callback_fn exti_trigger_callback[5]; void exti_set_callback(uint32_t pin, void (*cb)(uint32_t pin, uint8_t front, uint32_t s, uint32_t us)) { int i; for (i = 0; i < 5; i++) { if (Channel_Pin[i] == pin) { DBG("Setting callback for EXTI on ch %d\r\n", i); exti_trigger_callback[i] = cb; return; } } } void exti_clear_callback(uint32_t pin) { int i; for (i = 0; i < 5; i++) { if (Channel_Pin[i] == pin) { DBG("Clearing callback for EXTI on ch %d\r\n", i); exti_trigger_callback[i] = NULL; return; } } } struct trig_timeval { int channel; uint32_t pin; int front; uint32_t tv_sec; uint32_t tv_usec; }; static struct trig_timeval trig_tv[32] = {}; static volatile uint8_t trig_pending = 0; void isr_exti_channel(void) { uint32_t ts, tus; gettime(&ts, &tus); DBG("EXTI\r\n"); if (exti_get_flag_status(GPIO9)) { DBG("c1\r\n"); if (exti_trigger_callback[1]) { gettime(&ts, &tus); trig_tv[trig_pending].channel = 1; trig_tv[trig_pending].pin = GPIO9; trig_tv[trig_pending].front = !!gpio_get(GPIOA,GPIO9); trig_tv[trig_pending].tv_sec = ts; trig_tv[trig_pending].tv_usec = tus; trig_pending++; } exti_reset_request(GPIO9); } if (exti_get_flag_status(GPIO8)) { DBG("c0\r\n"); if (exti_trigger_callback[0]) { gettime(&ts, &tus); trig_tv[trig_pending].channel = 0; trig_tv[trig_pending].pin = GPIO8; trig_tv[trig_pending].front = !!gpio_get(GPIOA,GPIO8); trig_tv[trig_pending].tv_sec = ts; trig_tv[trig_pending].tv_usec = tus; trig_pending++; } exti_reset_request(GPIO8); } if (exti_get_flag_status(GPIO7)) { if (exti_trigger_callback[2]) { gettime(&ts, &tus); trig_tv[trig_pending].channel = 2; trig_tv[trig_pending].pin = GPIO7; trig_tv[trig_pending].front = !!gpio_get(GPIOA,GPIO7); trig_tv[trig_pending].tv_sec = ts; trig_tv[trig_pending].tv_usec = tus; trig_pending++; } exti_reset_request(GPIO7); } if (exti_get_flag_status(GPIO6)) { if (exti_trigger_callback[3]) { gettime(&ts, &tus); trig_tv[trig_pending].channel = 3; trig_tv[trig_pending].pin = GPIO6; trig_tv[trig_pending].front = !!gpio_get(GPIOA,GPIO6); trig_tv[trig_pending].tv_sec = ts; trig_tv[trig_pending].tv_usec = tus; trig_pending++; } exti_reset_request(GPIO6); } if (exti_get_flag_status(GPIO5)) { if (exti_trigger_callback[4]) { gettime(&ts, &tus); trig_tv[trig_pending].channel = 4; trig_tv[trig_pending].pin = GPIO5; trig_tv[trig_pending].front = !!gpio_get(GPIOA,GPIO5); trig_tv[trig_pending].tv_sec = ts; trig_tv[trig_pending].tv_usec = tus; trig_pending++; } exti_reset_request(GPIO5); } } void exti_poll(void) { int i; uint32_t pin; for (i = 0; i < trig_pending; i++) { if (exti_trigger_callback[trig_tv[i].channel]) { DBG("EXTI cb!\r\n"); exti_trigger_callback[trig_tv[i].channel](trig_tv[i].pin, trig_tv[i].front, trig_tv[i].tv_sec, trig_tv[i].tv_usec); } } trig_pending = 0; } /* Button interface */ struct user_button { enum button_state state; uint32_t transition_start_timestamp; }; static struct user_button Buttons[N_BUTTONS]; int button_poll(void (*callback)(uint8_t press, int hold)) { int b = 0; int st; static uint32_t last_event = 0; static uint32_t pressed_start = 0; while(rot_down > 0) { callback('-',0); rot_down--; } while(rot_up > 0) { callback('+',0); rot_up--; } if (jiffies - last_event < BUTTON_DEBOUNCE_TIME) return; last_event = jiffies; st = !!gpio_get(GPIOC, GPIO0); if (!st) { pressed_start = 0; } if ((button_press_pending) && st) { if ((pressed_start == 0) || ((jiffies - pressed_start) > BUTTON_HOLD_TIME)) { pressed_start = jiffies; callback('*', 0); return 1; } } button_press_pending = 0; return 0; } void button_init(void) { memset(Buttons, 0, sizeof(struct user_button) * N_BUTTONS); button_setup(); button_start_read(); }