cursada_mc2
Base de control de temperatura para EDU-CIAA-NXP
Loading...
Searching...
No Matches
buttons_driver.c
Go to the documentation of this file.
1
12#include "buttons_driver.h"
13
14#include <stdbool.h>
15#include <stddef.h>
16
17#define BUTTONS_CANTIDAD 4U
18#define BUTTONS_DEBOUNCE_MS 40U
19
20typedef struct {
21 uint8_t tecla;
22 uint8_t scu_port;
23 uint8_t scu_pin;
24 uint16_t scu_mode;
25 uint8_t scu_func;
26 uint8_t gpio_port;
27 uint8_t gpio_pin;
29 uint32_t pinint_mask;
30 IRQn_Type irqn;
32
39
40/* Tabla fija de relacion entre tecla logica y recursos fisicos del LPC4337. */
42 [0] = {.tecla = TECLA1, .scu_port = 1U, .scu_pin = 0U, .scu_mode = (MD_PUP | MD_EZI | MD_ZI), .scu_func = FUNC0, .gpio_port = 0U, .gpio_pin = 4U, .pinint_selector = 0U, .pinint_mask = PININTCH0, .irqn = PIN_INT0_IRQn},
43 [1] = {.tecla = TECLA2, .scu_port = 1U, .scu_pin = 1U, .scu_mode = (MD_PUP | MD_EZI | MD_ZI), .scu_func = FUNC0, .gpio_port = 0U, .gpio_pin = 8U, .pinint_selector = 1U, .pinint_mask = PININTCH1, .irqn = PIN_INT1_IRQn},
44 [2] = {.tecla = TECLA3, .scu_port = 1U, .scu_pin = 2U, .scu_mode = (MD_PUP | MD_EZI | MD_ZI), .scu_func = FUNC0, .gpio_port = 0U, .gpio_pin = 9U, .pinint_selector = 2U, .pinint_mask = PININTCH2, .irqn = PIN_INT2_IRQn},
45 [3] = {.tecla = TECLA4, .scu_port = 1U, .scu_pin = 6U, .scu_mode = (MD_PUP | MD_EZI | MD_ZI), .scu_func = FUNC0, .gpio_port = 1U, .gpio_pin = 9U, .pinint_selector = 3U, .pinint_mask = PININTCH3, .irqn = PIN_INT3_IRQn},
46};
47
49 [0] = {.armado = true},
50 [1] = {.armado = true},
51 [2] = {.armado = true},
52 [3] = {.armado = true},
53};
54
55static int8_t button_indice_desde_tecla(uint8_t tecla)
56{
57 switch (tecla) {
58 case TECLA1:
59 return 0;
60 case TECLA2:
61 return 1;
62 case TECLA3:
63 return 2;
64 case TECLA4:
65 return 3;
66 default:
67 return -1;
68 }
69}
70
71static bool button_esta_presionado(uint8_t indice)
72{
73 return !Chip_GPIO_GetPinState(LPC_GPIO_PORT, button_hw_[indice].gpio_port, button_hw_[indice].gpio_pin);
74}
75
76void buttons_init(void)
77{
78 uint8_t indice = 0U;
79
80 Chip_GPIO_Init(LPC_GPIO_PORT);
81
82 for (indice = 0U; indice < BUTTONS_CANTIDAD; indice++) {
83 button_estados_[indice].irq_pendiente = false;
84 button_estados_[indice].armado = true;
85 button_estados_[indice].evento_pendiente = false;
87
88 Chip_SCU_PinMux(button_hw_[indice].scu_port,
89 button_hw_[indice].scu_pin,
90 button_hw_[indice].scu_mode,
91 button_hw_[indice].scu_func);
92 Chip_GPIO_SetDir(LPC_GPIO_PORT,
93 button_hw_[indice].gpio_port,
94 (1UL << button_hw_[indice].gpio_pin),
95 0);
96 Chip_SCU_GPIOIntPinSel(button_hw_[indice].pinint_selector,
97 button_hw_[indice].gpio_port,
98 button_hw_[indice].gpio_pin);
99 Chip_PININT_ClearIntStatus(LPC_GPIO_PIN_INT, button_hw_[indice].pinint_mask);
100 Chip_PININT_EnableIntLow(LPC_GPIO_PIN_INT, button_hw_[indice].pinint_mask);
101 Chip_PININT_SetPinModeEdge(LPC_GPIO_PIN_INT, button_hw_[indice].pinint_mask);
102 NVIC_ClearPendingIRQ(button_hw_[indice].irqn);
103 NVIC_EnableIRQ(button_hw_[indice].irqn);
104 }
105}
106
107void button_notify_irq(uint8_t button_id)
108{
109 const int8_t indice = button_indice_desde_tecla(button_id);
110
111 if (indice < 0) {
112 return;
113 }
114
115 /* La ISR solo marca actividad y reinicia la ventana de debounce. */
116 button_estados_[(uint8_t) indice].irq_pendiente = true;
117 button_estados_[(uint8_t) indice].debounce_acumulado_ms = 0U;
118}
119
120void buttons_process(uint32_t delta_ms)
121{
122 uint8_t indice = 0U;
123
124 for (indice = 0U; indice < BUTTONS_CANTIDAD; indice++) {
125 const bool presionado_actual = button_esta_presionado(indice);
126 volatile button_estado_t* estado = &button_estados_[indice];
127
128 /* Cuando la tecla se libera, se rearma para aceptar una nueva pulsacion. */
129 if (estado->armado == false && !presionado_actual) {
130 estado->armado = true;
131 }
132
133 if (!estado->irq_pendiente) {
134 continue;
135 }
136
137 if (!presionado_actual) {
138 estado->irq_pendiente = false;
139 estado->debounce_acumulado_ms = 0U;
140 continue;
141 }
142
144 const uint32_t tiempo_restante = BUTTONS_DEBOUNCE_MS - estado->debounce_acumulado_ms;
145 estado->debounce_acumulado_ms += (delta_ms < tiempo_restante) ? delta_ms : tiempo_restante;
146 }
147
149 continue;
150 }
151
152 estado->irq_pendiente = false;
153 estado->debounce_acumulado_ms = 0U;
154
155 /* Solo se genera un evento por pulsacion hasta que la tecla se suelte. */
156 if (estado->armado) {
157 estado->armado = false;
158 estado->evento_pendiente = true;
159 }
160 }
161}
162
163uint8_t button_get_event(void)
164{
165 uint8_t indice = 0U;
166
167 for (indice = 0U; indice < BUTTONS_CANTIDAD; indice++) {
168 if (!button_estados_[indice].evento_pendiente) {
169 continue;
170 }
171
172 button_estados_[indice].evento_pendiente = false;
173 return button_hw_[indice].tecla;
174 }
175
176 return 0U;
177}
void button_notify_irq(uint8_t button_id)
Notifica al driver que una tecla genero una interrupcion externa.
void buttons_process(uint32_t delta_ms)
Procesa el debounce y actualiza los eventos latcheados de teclas.
uint8_t button_get_event(void)
Devuelve y consume el siguiente evento de tecla confirmado.
static bool button_esta_presionado(uint8_t indice)
#define BUTTONS_DEBOUNCE_MS
static const button_hw_t button_hw_[BUTTONS_CANTIDAD]
static int8_t button_indice_desde_tecla(uint8_t tecla)
#define BUTTONS_CANTIDAD
void buttons_init(void)
Inicializa los pines asociados a los cuatro pulsadores.
static volatile button_estado_t button_estados_[BUTTONS_CANTIDAD]
Interfaz del driver de pulsadores discretos.
#define TECLA4
Identificador de la tecla 4.
#define TECLA1
Identificador de la tecla 1.
#define TECLA2
Identificador de la tecla 2.
#define TECLA3
Identificador de la tecla 3.
uint32_t debounce_acumulado_ms
uint8_t scu_func
uint32_t pinint_mask
uint16_t scu_mode
uint8_t gpio_port
uint8_t gpio_pin
uint8_t scu_pin
uint8_t pinint_selector
IRQn_Type irqn
uint8_t scu_port