ruuvi.drivers.c  ${PROJECT_VERSION}
Drivers for external sensors and peripherals on embedded systems.
ruuvi_nrf5_sdk15_gpio_interrupt.c
Go to the documentation of this file.
1 
10 #if RUUVI_NRF5_SDK15_GPIO_INTERRUPT_ENABLED
11 #include "ruuvi_nrf5_sdk15_error.h"
12 #include "ruuvi_nrf5_sdk15_gpio.h"
13 #include "ruuvi_interface_gpio.h"
14 
15 
16 #include <stdbool.h>
17 #include "nrf.h"
18 #include "nrf_drv_gpiote.h"
19 
20 //Pointer to look-up table for event handlers
21 static ri_gpio_interrupt_fp_t * pin_event_handlers;
22 static uint8_t max_interrupts = 0;
23 
25  ri_gpio_interrupt_fp_t * const interrupt_table,
26  const uint16_t interrupt_table_size)
27 {
28  if (NULL == interrupt_table) { return RD_ERROR_NULL; }
29 
30  if (!ri_gpio_is_init()) { return RD_ERROR_INVALID_STATE; }
31 
32  // Check module initialization status by max interrupts
33  if (0 != max_interrupts) { return RD_ERROR_INVALID_STATE; }
34 
35  /* Driver initialization
36  The GPIOTE driver is a shared resource that can be used by multiple modules in an application.
37  Therefore, it can be initialized only once. If a module is using the driver,
38  it must check if it has already been initialized by calling the function nrf_drv_gpiote_is_init.
39  If this function returns false, the module must initialize the driver by calling the function nrf_drv_gpiote_init.
40 
41  The following code example shows how to initialize the driver:
42  */
43  ret_code_t err_code = NRF_SUCCESS;
44 
45  if (!nrf_drv_gpiote_is_init())
46  {
47  err_code = nrf_drv_gpiote_init();
48  }
49 
50  pin_event_handlers = interrupt_table;
51  max_interrupts = interrupt_table_size;
52  return ruuvi_nrf5_sdk15_to_ruuvi_error (err_code);
53 }
54 
56 {
57  if (0 == max_interrupts) { return RD_SUCCESS; }
58 
59  pin_event_handlers = NULL;
60  max_interrupts = 0;
61  return RD_SUCCESS;
62 }
63 
65 {
66  return (0 != max_interrupts);
67 }
68 
69 static void in_pin_handler (const nrf_drv_gpiote_pin_t pin,
70  const nrf_gpiote_polarity_t action)
71 {
72  if (max_interrupts <= pin) { return; }
73 
74  ri_gpio_evt_t event;
75  ri_gpio_state_t state;
76 
77  if (NULL != pin_event_handlers[pin])
78  {
79  switch (action)
80  {
81  case NRF_GPIOTE_POLARITY_LOTOHI:
83  break;
84 
85  case NRF_GPIOTE_POLARITY_HITOLO:
86  event.slope = RI_GPIO_SLOPE_HITOLO;
87  break;
88 
89  default:
90  // Determine slope from current state
91  ri_gpio_read (nrf_to_ruuvi_pin (pin), &state);
92  event.slope = (state == RI_GPIO_LOW) ? RI_GPIO_SLOPE_HITOLO : RI_GPIO_SLOPE_LOTOHI;
93  break;
94  }
95 
96  //Call event handler.
97  event.pin = nrf_to_ruuvi_pin (pin);
98  (pin_event_handlers[pin]) (event);
99  }
100 }
101 
103  ri_gpio_id_t pin,
104  const ri_gpio_slope_t slope,
105  const ri_gpio_mode_t mode,
106  const ri_gpio_interrupt_fp_t handler)
107 {
108  rd_status_t err_code = RD_SUCCESS;
109 
111  {
112  err_code |= RD_ERROR_INVALID_STATE;
113  }
114  else if (RI_GPIO_ID_UNUSED == pin)
115  {
116  // No action needed
117  }
118  else
119  {
120  // nRF5 devices have 32 pins per port. Pack the port-pin representation into 8 bits for interrupt table.
121  uint8_t nrf_pin = ruuvi_to_nrf_pin_map (pin);
122 
123  if (nrf_pin >= max_interrupts) { return RD_ERROR_INVALID_PARAM; }
124 
125  ret_code_t nrf_code = NRF_SUCCESS;
126  nrf_gpiote_polarity_t polarity = NRF_GPIOTE_POLARITY_TOGGLE;
127  nrf_gpio_pin_pull_t pull = NRF_GPIO_PIN_NOPULL;
128 
129  switch (slope)
130  {
132  polarity = NRF_GPIOTE_POLARITY_TOGGLE;
133  break;
134 
136  polarity = NRF_GPIOTE_POLARITY_LOTOHI;
137  break;
138 
140  polarity = NRF_GPIOTE_POLARITY_HITOLO;
141  break;
142 
143  default:
144  err_code |= RD_ERROR_INVALID_PARAM;
145  }
146 
147  switch (mode)
148  {
150  pull = NRF_GPIO_PIN_NOPULL;
151  break;
152 
154  pull = NRF_GPIO_PIN_PULLUP;
155  break;
156 
158  pull = NRF_GPIO_PIN_PULLDOWN;
159  break;
160 
161  default:
162  err_code |= RD_ERROR_INVALID_PARAM;
163  }
164 
165  // high-accuracy mode consumes excess power
166  // is_watcher is used if we track an output pin.
167  nrf_drv_gpiote_in_config_t in_config =
168  {
169  .is_watcher = false,
170  .hi_accuracy = false,
171  .pull = pull,
172  .sense = polarity
173  };
174  pin_event_handlers[nrf_pin] = handler;
175  nrf_code |= nrf_drv_gpiote_in_init (nrf_pin, &in_config, in_pin_handler);
176  nrf_drv_gpiote_in_event_enable (nrf_pin, true);
177  err_code |= ruuvi_nrf5_sdk15_to_ruuvi_error (nrf_code);
178  }
179 
180  return err_code;
181 }
182 
184 {
185  rd_status_t err_code = RD_SUCCESS;
186 
187  if (RI_GPIO_ID_UNUSED != pin)
188  {
189  uint8_t nrf_pin = ruuvi_to_nrf_pin_map (pin);
190 
191  if (NULL != pin_event_handlers && NULL != pin_event_handlers[nrf_pin])
192  {
193  nrf_drv_gpiote_in_event_disable (nrf_pin);
194  nrf_drv_gpiote_in_uninit (nrf_pin);
195  pin_event_handlers[nrf_pin] = NULL;
196  }
197  }
198 
199  return err_code;
200 }
201 
202 #endif
#define RD_ERROR_INVALID_PARAM
Invalid Parameter.
#define RD_ERROR_NULL
Null Pointer.
uint32_t rd_status_t
bitfield for representing errors
rd_status_t ruuvi_nrf5_sdk15_to_ruuvi_error(const ret_code_t error)
convert nrf5 sdk15 error code into Ruuvi error code.
#define RD_SUCCESS
Internal Error.
#define RD_ERROR_INVALID_STATE
Invalid state, operation disallowed in this state.
ri_gpio_slope_t
Enable implementation selected by application.
rd_status_t ri_gpio_interrupt_enable(const ri_gpio_id_t pin, const ri_gpio_slope_t slope, const ri_gpio_mode_t mode, const ri_gpio_interrupt_fp_t handler)
Enable interrupt on a pin.
bool ri_gpio_is_init(void)
return true if GPIO is init, false otherwise.
rd_status_t ri_gpio_interrupt_init(ri_gpio_interrupt_fp_t *const interrupt_table, const uint16_t max_interrupts)
Initialize interrupt functionality to GPIO. Takes address of interrupt table as a pointer to avoid ty...
void(* ri_gpio_interrupt_fp_t)(const ri_gpio_evt_t)
rd_status_t ri_gpio_interrupt_uninit(void)
Uninitialize interrupt functionality of GPIO.
rd_status_t ri_gpio_interrupt_disable(const ri_gpio_id_t pin)
Disable interrupt on a pin.
bool ri_gpio_interrupt_is_init(void)
Check if interrupt module is initialized.
rd_status_t ri_gpio_read(const ri_gpio_id_t pin, ri_gpio_state_t *const p_state)
Read state of a pin of a port into bool high If there are several ports the platform driver must impl...
Header to enable and disable module compilation.
uint16_t ri_gpio_id_t
port<<8 + pin
#define RI_GPIO_ID_UNUSED
Enable implementation selected by application.
ri_gpio_mode_t
@ RI_GPIO_MODE_INPUT_PULLUP
Input, can be read. Pulled up by internal resistor, value depends on IC.
@ RI_GPIO_MODE_INPUT_NOPULL
Input, can be read. No pull resistors.
@ RI_GPIO_MODE_INPUT_PULLDOWN
Input, can be read. Pulled dpwn by internal resistor, value depends on IC.
ri_gpio_state_t
States of GPIO pins.
@ RI_GPIO_LOW
GPIO electrically low.
ri_gpio_slope_t slope
ri_gpio_slope_t slope of event