331 lines
8.2 KiB
C
331 lines
8.2 KiB
C
/*
|
|
* (c) danielinux 2019
|
|
* GPLv.2
|
|
*
|
|
* See LICENSE for details
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#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();
|
|
}
|
|
|
|
|