Contiki-NG
Loading...
Searching...
No Matches
gpio-hal-arch.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020, George Oikonomou - https://spd.gr
3 * Copyright (C) 2020 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/**
33 * \addtogroup nrf
34 * @{
35 *
36 * \addtogroup nrf-dev Device drivers
37 * @{
38 *
39 * \addtogroup nrf-gpio GPIO HAL driver
40 * @{
41 *
42 * \file
43 * GPIO HAL implementation for the nRF
44 * \author
45 * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
46 *
47 */
48/*---------------------------------------------------------------------------*/
49#include "contiki.h"
50
51#include "dev/gpio-hal.h"
52
53#include "nrfx_gpiote.h"
54
55#include "hal/nrf_gpio.h"
56/*---------------------------------------------------------------------------*/
57#define PIN_TO_PORT(pin) (pin >> 5)
58#define PIN_TO_NUM(pin) (pin & 0x1F)
59/*---------------------------------------------------------------------------*/
60/* Newer nrfx uses either a multi-instance or a single-instance GPIOTE API. */
61#if NRFX_API_VER_AT_LEAST(3, 2, 0)
62#if defined(NRF54L15_XXAA)
63/* nRF54L15 has two GPIOTE instances: GPIOTE20 for P1, GPIOTE30 for P0. */
64static const nrfx_gpiote_t gpiote_instance_p0 = NRFX_GPIOTE_INSTANCE(30);
65static const nrfx_gpiote_t gpiote_instance_p1 = NRFX_GPIOTE_INSTANCE(20);
66
67/* Older nRF54L15 MDK snapshots lacked these aliases. */
68#ifndef GPIOTE20_CH_NUM
69#define GPIOTE20_CH_NUM 8
70#endif
71#ifndef GPIOTE30_CH_NUM
72#define GPIOTE30_CH_NUM 4
73#endif
74
75/* Get the appropriate GPIOTE instance for a given pin */
76static inline const nrfx_gpiote_t *
77get_gpiote_instance(uint32_t pin)
78{
79 uint8_t port = PIN_TO_PORT(pin);
80 return (port == 0) ? &gpiote_instance_p0 : &gpiote_instance_p1;
81}
82#else
83static const nrfx_gpiote_t gpiote_instance = NRFX_GPIOTE_INSTANCE(0);
84
85static inline const nrfx_gpiote_t *
86get_gpiote_instance(uint32_t pin)
87{
88 (void)pin;
89 return &gpiote_instance;
90}
91#endif
92
93void
94gpio_hal_arch_interrupt_enable_nrfx_v3(gpio_hal_port_t port, gpio_hal_pin_t pin)
95{
96 uint32_t pin_number = NRF_GPIO_PIN_MAP(port, pin);
97 const nrfx_gpiote_t *p_instance = get_gpiote_instance(pin_number);
98 nrfx_gpiote_trigger_enable(p_instance, pin_number, true);
99}
100
101void
102gpio_hal_arch_interrupt_disable_nrfx_v3(gpio_hal_port_t port, gpio_hal_pin_t pin)
103{
104 uint32_t pin_number = NRF_GPIO_PIN_MAP(port, pin);
105 const nrfx_gpiote_t *p_instance = get_gpiote_instance(pin_number);
106 nrfx_gpiote_trigger_disable(p_instance, pin_number);
107}
108#endif /* NRFX_API_VER_AT_LEAST(3, 2, 0) */
109/*---------------------------------------------------------------------------*/
110/**
111 * @brief GPIO event handler
112 *
113 * @param pin GPIO pin
114 * @param action Action
115 */
116#if NRFX_API_VER_AT_LEAST(3, 2, 0)
117static void
118pin_event_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t trigger, void *p_context)
119{
120 gpio_hal_port_t port;
121 gpio_hal_pin_mask_t pin_mask;
122
123 port = PIN_TO_PORT(pin);
124 pin_mask = gpio_hal_pin_to_mask(PIN_TO_NUM(pin));
125
126 gpio_hal_event_handler(port, pin_mask);
127}
128#else
129static void
130pin_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
131{
132 gpio_hal_port_t port;
133 gpio_hal_pin_mask_t pin_mask;
134
135 port = PIN_TO_PORT(pin);
136 pin_mask = gpio_hal_pin_to_mask(PIN_TO_NUM(pin));
137
138 gpio_hal_event_handler(port, pin_mask);
139}
140#endif
141/*---------------------------------------------------------------------------*/
142void
144{
145#if NRFX_API_VER_AT_LEAST(3, 2, 0)
146#if defined(NRF54L15_XXAA)
147 if(!nrfx_gpiote_init_check(&gpiote_instance_p0)) {
148 nrfx_gpiote_init(&gpiote_instance_p0, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
149 }
150 if(!nrfx_gpiote_init_check(&gpiote_instance_p1)) {
151 nrfx_gpiote_init(&gpiote_instance_p1, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
152 }
153#else
154 if(!nrfx_gpiote_init_check(&gpiote_instance)) {
155 nrfx_gpiote_init(&gpiote_instance, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
156 }
157#endif
158#else
159 if(!nrfx_gpiote_is_init()) {
160 nrfx_gpiote_init(NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
161 }
162#endif
163}
164/*---------------------------------------------------------------------------*/
165void
167{
169 uint32_t pin_number = NRF_GPIO_PIN_MAP(port, pin);
170
171#if NRFX_API_VER_AT_LEAST(3, 2, 0)
172 const nrfx_gpiote_t *p_instance = get_gpiote_instance(pin_number);
173 uint8_t channel;
174 nrfx_err_t err;
175
176 nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_NOPULL;
177
178 nrfx_gpiote_trigger_config_t trigger_config = {
179 .trigger = NRFX_GPIOTE_TRIGGER_NONE,
180 };
181
182 nrfx_gpiote_handler_config_t handler_config = {
183 .handler = pin_event_handler,
184 .p_context = NULL,
185 };
186
187 tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH;
188 if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) {
189 trigger_config.trigger = NRFX_GPIOTE_TRIGGER_LOTOHI;
190 } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) {
191 trigger_config.trigger = NRFX_GPIOTE_TRIGGER_HITOLO;
192 } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) {
193 trigger_config.trigger = NRFX_GPIOTE_TRIGGER_TOGGLE;
194 }
195
196 if(trigger_config.trigger != NRFX_GPIOTE_TRIGGER_NONE) {
197 err = nrfx_gpiote_channel_get(p_instance, pin_number, &channel);
198 if(err == NRFX_ERROR_INVALID_PARAM) {
199 err = nrfx_gpiote_channel_alloc(p_instance, &channel);
200 }
201 if(err == NRFX_SUCCESS) {
202 trigger_config.p_in_channel = &channel;
203 }
204 }
205
206 tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK;
207 if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) {
208 pull_config = NRF_GPIO_PIN_PULLDOWN;
209 } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) {
210 pull_config = NRF_GPIO_PIN_PULLUP;
211 }
212
213 nrfx_gpiote_input_pin_config_t input_pin_config = {
214 .p_pull_config = &pull_config,
215 .p_trigger_config = &trigger_config,
216 .p_handler_config = &handler_config,
217 };
218
219 err = nrfx_gpiote_input_configure(p_instance, pin_number, &input_pin_config);
220 if(err != NRFX_SUCCESS) {
221 return;
222 }
223
224 tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK;
225 if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) {
226 gpio_hal_arch_interrupt_enable_nrfx_v3(port, pin);
227 } else {
228 gpio_hal_arch_interrupt_disable_nrfx_v3(port, pin);
229 }
230#else /* NRFX_API_VER_AT_LEAST(3, 2, 0) */
231 nrfx_gpiote_in_config_t gpiote_config = {
232 .is_watcher = false,
233 .hi_accuracy = true,
234 };
235
236 tmp = cfg & GPIO_HAL_PIN_CFG_EDGE_BOTH;
237 if(tmp == GPIO_HAL_PIN_CFG_EDGE_NONE) {
238 gpiote_config.sense = GPIOTE_CONFIG_POLARITY_None;
239 } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_RISING) {
240 gpiote_config.sense = NRF_GPIOTE_POLARITY_LOTOHI;
241 } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_FALLING) {
242 gpiote_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
243 } else if(tmp == GPIO_HAL_PIN_CFG_EDGE_BOTH) {
244 gpiote_config.sense = NRF_GPIOTE_POLARITY_TOGGLE;
245 }
246
247 tmp = cfg & GPIO_HAL_PIN_CFG_PULL_MASK;
248 if(tmp == GPIO_HAL_PIN_CFG_PULL_NONE) {
249 gpiote_config.pull = NRF_GPIO_PIN_NOPULL;
250 } else if(tmp == GPIO_HAL_PIN_CFG_PULL_DOWN) {
251 gpiote_config.pull = NRF_GPIO_PIN_PULLDOWN;
252 } else if(tmp == GPIO_HAL_PIN_CFG_PULL_UP) {
253 gpiote_config.pull = NRF_GPIO_PIN_PULLUP;
254 }
255
256 nrfx_gpiote_in_init(pin_number, &gpiote_config, pin_event_handler);
257
258 tmp = cfg & GPIO_HAL_PIN_CFG_INT_MASK;
259 if(tmp == GPIO_HAL_PIN_CFG_INT_DISABLE) {
260 nrfx_gpiote_in_event_disable(pin_number);
261 } else if(tmp == GPIO_HAL_PIN_CFG_INT_ENABLE) {
262 nrfx_gpiote_in_event_enable(pin_number, true);
263 }
264#endif /* NRFX_API_VER_AT_LEAST(3, 2, 0) */
265}
266/*---------------------------------------------------------------------------*/
269{
270 uint8_t i;
271 uint32_t pin_number;
272 gpio_hal_pin_cfg_t cfg = GPIO_HAL_PIN_CFG_PULL_NONE |
273 GPIO_HAL_PIN_CFG_EDGE_NONE |
274 GPIO_HAL_PIN_CFG_INT_DISABLE;
275 nrf_gpio_pin_pull_t pull;
276 nrf_gpiote_polarity_t polarity;
277
278 pin_number = NRF_GPIO_PIN_MAP(port, pin);
279
280 /* First, check if the pin is configured as output */
281 if(nrf_gpio_pin_dir_get(pin_number) == NRF_GPIO_PIN_DIR_OUTPUT) {
282 return 0;
283 }
284
285#if defined(NRF54L15_XXAA)
286 /* nRF54L15: Select correct GPIOTE instance based on port */
287 NRF_GPIOTE_Type *gpiote_reg = (port == 0) ? NRF_GPIOTE30 : NRF_GPIOTE20;
288 uint8_t ch_num = (port == 0) ? GPIOTE30_CH_NUM : GPIOTE20_CH_NUM;
289
290 /*
291 * Input pin. Check all GPIOTE channel configurations and figure out which
292 * channel corresponds to our pin of interest. For that channel, read out
293 * the GPIOTE configuration
294 */
295 for(i = 0; i < ch_num; i++) {
296 if(nrf_gpiote_event_pin_get(gpiote_reg, i) == pin_number) {
297 polarity = nrf_gpiote_event_polarity_get(gpiote_reg, i);
298
299 if(polarity == NRF_GPIOTE_POLARITY_LOTOHI) {
300 cfg |= GPIO_HAL_PIN_CFG_EDGE_RISING;
301 } else if(polarity == NRF_GPIOTE_POLARITY_HITOLO) {
302 cfg |= GPIO_HAL_PIN_CFG_EDGE_FALLING;
303 } else if(polarity == NRF_GPIOTE_POLARITY_TOGGLE) {
304 cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH;
305 }
306
307 pull = nrf_gpio_pin_pull_get(pin_number);
308
309 if(pull == NRF_GPIO_PIN_PULLDOWN) {
310 cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN;
311 } else if(pull == NRF_GPIO_PIN_PULLUP) {
312 cfg |= GPIO_HAL_PIN_CFG_PULL_UP;
313 }
314
315 if(nrf_gpiote_int_enable_check(gpiote_reg, 1 << i)) {
316 cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE;
317 }
318 return cfg;
319 }
320 }
321#else
322 /*
323 * Input pin. Check all GPIOTE channel configurations and figure out which
324 * channel corresponds to our pin of interest. For that channel, read out
325 * the GPIOTE configuration
326 */
327 for(i = 0; i < GPIOTE_CH_NUM; i++) {
328 if(nrf_gpiote_event_pin_get(NRF_GPIOTE, i) == pin_number) {
329 polarity = nrf_gpiote_event_polarity_get(NRF_GPIOTE, i);
330
331 if(polarity == NRF_GPIOTE_POLARITY_LOTOHI) {
332 cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH;
333 } else if(polarity == NRF_GPIOTE_POLARITY_HITOLO) {
334 cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH;
335 } else if(polarity == NRF_GPIOTE_POLARITY_TOGGLE) {
336 cfg |= GPIO_HAL_PIN_CFG_EDGE_BOTH;
337 }
338
339 pull = nrf_gpio_pin_pull_get(pin_number);
340
341 if(pull == NRF_GPIO_PIN_PULLDOWN) {
342 cfg |= GPIO_HAL_PIN_CFG_PULL_DOWN;
343 } else if(pull == NRF_GPIO_PIN_PULLUP) {
344 cfg |= GPIO_HAL_PIN_CFG_PULL_UP;
345 }
346
347 if(nrf_gpiote_int_enable_check(NRF_GPIOTE, 1 << i)) {
348 cfg |= GPIO_HAL_PIN_CFG_INT_ENABLE;
349 }
350 return cfg;
351 }
352 }
353#endif
354
355 /* Did not find a GPIOTE channel configured for this pin */
356 return 0;
357}
358/*---------------------------------------------------------------------------*/
359uint8_t
361{
362 return (uint8_t)nrf_gpio_pin_read(NRF_GPIO_PIN_MAP(port, pin));
363}
364/*---------------------------------------------------------------------------*/
365void
367{
368 NRF_GPIO_Type *gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
369
370 if(port >= GPIO_COUNT) {
371 return;
372 }
373
374 nrf_gpio_port_out_set(gpio_regs[port], pins);
375}
376/*---------------------------------------------------------------------------*/
377void
379{
380 NRF_GPIO_Type *gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
381
382 if(port >= GPIO_COUNT) {
383 return;
384 }
385
386 nrf_gpio_port_out_clear(gpio_regs[port], pins);
387}
388/*---------------------------------------------------------------------------*/
389void
391{
392 if(port >= GPIO_COUNT) {
393 return;
394 }
395 gpio_hal_arch_write_pins(port, pins, ~gpio_hal_arch_read_pins(port, pins));
396}
397/*---------------------------------------------------------------------------*/
400{
401 NRF_GPIO_Type *gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
402
403 if(port >= GPIO_COUNT) {
404 return 0;
405 }
406
407 return nrf_gpio_port_in_read(gpio_regs[port]);
408}
409/*---------------------------------------------------------------------------*/
410void
413{
414 NRF_GPIO_Type *gpio_regs[GPIO_COUNT] = GPIO_REG_LIST;
415
416 if(port >= GPIO_COUNT) {
417 return;
418 }
419
420 nrf_gpio_port_out_write(gpio_regs[port], value);
421}
422/*---------------------------------------------------------------------------*/
423/**
424 * @}
425 * @}
426 * @}
427 */
Header file for the GPIO HAL.
gpio_hal_pin_cfg_t gpio_hal_arch_port_pin_cfg_get(gpio_hal_port_t port, gpio_hal_pin_t pin)
Read the configuration of a GPIO pin.
void gpio_hal_arch_port_set_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
Set multiple pins to logical high.
void gpio_hal_arch_init(void)
Perform architecture specific gpio initaliaztion.
void gpio_hal_arch_port_pin_cfg_set(gpio_hal_port_t port, gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
Configure a gpio pin.
uint32_t gpio_hal_pin_mask_t
GPIO pin mask representation.
Definition gpio-hal.h:142
uint32_t gpio_hal_pin_cfg_t
GPIO pin configuration.
Definition gpio-hal.h:118
uint8_t gpio_hal_port_t
A data structure that represents ports.
Definition gpio-hal.h:110
#define gpio_hal_pin_to_mask(pin)
Convert a pin to a pin mask.
Definition gpio-hal.h:255
uint8_t gpio_hal_pin_t
GPIO pin number representation.
Definition gpio-hal.h:103
void gpio_hal_arch_port_clear_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
Clear multiple pins to logical low.
gpio_hal_pin_mask_t gpio_hal_arch_port_read_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
Read multiple pins.
static void pin_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
GPIO event handler.
void gpio_hal_arch_port_toggle_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
Toggle multiple pins.
void gpio_hal_arch_port_write_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins, gpio_hal_pin_mask_t value)
Write multiple pins.
uint8_t gpio_hal_arch_port_read_pin(gpio_hal_port_t port, gpio_hal_pin_t pin)
Read a GPIO pin.