source: rtems/bsps/arm/lpc176x/gpio/lpc-gpio.c @ e945b049

5
Last change on this file since e945b049 was e945b049, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 25, 2018 at 8:43:38 AM

bsp/lpc176x: Move source files to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/**
2 * @file lpc-gpio.c
3 *
4 * @ingroup lpc176x
5 *
6 * @brief GPIO library for the lpc176x bsp.
7 */
8
9/*
10 * Copyright (c) 2014 Taller Technologies.
11 *
12 * @author  Boretto Martin    (martin.boretto@tallertechnologies.com)
13 * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
14 * @author  Lenarduzzi Federico  (federico.lenarduzzi@tallertechnologies.com)
15 * @author  Daniel Chicco  (daniel.chicco@tallertechnologies.com)
16 *
17 * The license and distribution terms for this file may be
18 * found in the file LICENSE in this distribution or at
19 * http://www.rtems.org/license/LICENSE.
20 */
21
22#include <assert.h>
23#include <bsp/irq.h>
24#include <bsp/io.h>
25#include <bsp/lpc-gpio.h>
26#include <rtems/status-checks.h>
27
28static uint32_t                              function_vector_size = 0u;
29static lpc176x_registered_interrupt_function function_vector[
30  LPC176X_RESERVED_ISR_FUNCT_SIZE ];
31static bool isr_installed = false;
32
33rtems_status_code lpc176x_gpio_config(
34  const lpc176x_pin_number     pin,
35  const lpc176x_gpio_direction dir
36)
37{
38  rtems_status_code status_code = RTEMS_INVALID_NUMBER;
39
40  if ( ( pin < LPC176X_MAX_PORT_NUMBER ) &&
41       ( dir < LPC176X_GPIO_FUNCTION_COUNT ) ) {
42    const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
43    const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
44
45    lpc176x_pin_select( pin, LPC176X_PIN_FUNCTION_00 );
46
47    LPC176X_SET_BIT( LPC176X_FIO[ port ].dir, pin_of_port, dir );
48
49    status_code = RTEMS_SUCCESSFUL;
50  }
51
52  /* else implies that the pin or the egde are out of range. Also,
53     an invalid number is returned. */
54
55  return status_code;
56}
57
58/**
59 * @brief Check for a rising edge and call the interrupt function.
60 *
61 * @param statR Rising edge interrupt.
62 * @param pin The pin to check.
63 * @param registered_isr_function Interrupt to check.
64 * @return TRUE if is a rising edge. FALSE otherwise.
65 */
66static bool lpc176x_check_rising_edge_and_call(
67  const uint32_t                              statR,
68  const lpc176x_registered_interrupt_function registered_isr_function,
69  const uint32_t                              pin
70)
71{
72  bool is_rising = false;
73
74  if ( statR & LPC176X_PIN_BIT( pin ) ) {
75    registered_isr_function.function( registered_isr_function.pin,
76      LPC176X_GPIO_INTERRUPT_RISING );
77    is_rising = true;
78  }
79
80  /* else implies that the current interrupt is not STATR. Also,
81     there is nothing to do. */
82
83  return is_rising;
84}
85
86/**
87 * @brief Check for a falling edge and call the interrupt function.
88 *
89 * @param statR Falling edge interrupt.
90 * @param pin The pin to check.
91 * @param registered_isr_function Interrupt to check.
92 * @return TRUE if is a falling edge. FALSE otherwise.
93 */
94static bool lpc176x_check_falling_edge_and_call(
95  const uint32_t                              statF,
96  const lpc176x_registered_interrupt_function registered_isr_function,
97  const uint32_t                              pin
98)
99{
100  bool is_falling = false;
101
102  if ( statF & LPC176X_PIN_BIT( pin ) ) {
103    registered_isr_function.function( registered_isr_function.pin,
104      LPC176X_GPIO_INTERRUPT_FALLING );
105    is_falling = true;
106  }
107
108  /* else implies that the current interrupt is not STATF. Also,
109     there is nothing to do. */
110
111  return is_falling;
112}
113
114/**
115 * @brief Returns the interrupts base address according to the current port.
116 *
117 * @param  port Input/Output port.
118 * @return Interrupt base address.
119 */
120static lpc176x_interrupt_control*lpc176x_get_interrupt_address(
121  const lpc176x_gpio_ports port )
122{
123  lpc176x_interrupt_control *interrupt;
124
125  switch ( port ) {
126    case ( LPC176X_GPIO_PORT_0 ):
127      interrupt = (lpc176x_interrupt_control *) LPC176X_IO0_INT_BASE_ADDRESS;
128      break;
129    case ( LPC176X_GPIO_PORT_2 ):
130      interrupt = (lpc176x_interrupt_control *) LPC176X_IO2_INT_BASE_ADDRESS;
131      break;
132    case ( LPC176X_GPIO_PORT_1 ):
133    case ( LPC176X_GPIO_PORT_3 ):
134    case ( LPC176X_GPIO_PORT_4 ):
135    default:
136      interrupt = NULL;
137  }
138
139  return interrupt;
140}
141
142/**
143 * @brief Checks the type of the current interrupt.
144 *
145 * @param registered_isr_function Interrupt to check.
146 */
147static void check_for_interrupt(
148  const lpc176x_registered_interrupt_function registered_isr_function )
149{
150  assert( registered_isr_function.pin < LPC176X_MAX_PORT_NUMBER );
151
152  const lpc176x_gpio_ports port = LPC176X_IO_PORT(
153    registered_isr_function.pin );
154  const uint32_t pin = LPC176X_IO_PORT_BIT( registered_isr_function.pin );
155
156  lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
157  assert( interrupt != NULL );
158
159  bool is_rising_edge = lpc176x_check_rising_edge_and_call( interrupt->StatR,
160    registered_isr_function,
161    pin );
162
163  bool is_falling_edge = lpc176x_check_falling_edge_and_call( interrupt->StatF,
164    registered_isr_function,
165    pin );
166
167  if ( is_rising_edge || is_falling_edge ) {
168    interrupt->Clr = LPC176X_PIN_BIT( pin );
169  }
170
171  /* else implies that the current interrupt is not CLR. Also,
172     there is nothing to do. */
173}
174
175/**
176 * @brief Checks all interrupts types.
177 *
178 * @param arg Interrupt to check.
179 */
180static inline void lpc176x_gpio_isr( void *arg )
181{
182  unsigned int i;
183
184  for ( i = 0; i < function_vector_size; ++i ) {
185    check_for_interrupt( function_vector[ i ] );
186  }
187}
188
189/**
190 * @brief Depending of the current edge sets rising/falling interrupt.
191 *
192 * @param edge Current edge.
193 * @param pin_of_port Pin of the port to set the interrupt.
194 * @param interrupt To enable the falling o rising edge.
195 */
196static void lpc176x_set_falling_or_rising_interrupt(
197  const lpc176x_gpio_interrupt edge,
198  const uint32_t               pin_of_port,
199  lpc176x_interrupt_control   *interrupt
200)
201{
202  if ( edge & LPC176X_GPIO_INTERRUPT_RISING ) {
203    LPC176X_SET_BIT( interrupt->EnR, pin_of_port, LPC176X_INT_ENABLE );
204  }
205
206  /* else implies that it should not install the interrupt for a RISING edge.
207      Also, there is nothing to do. */
208
209  if ( edge & LPC176X_GPIO_INTERRUPT_FALLING ) {
210    LPC176X_SET_BIT( interrupt->EnF, pin_of_port, LPC176X_INT_ENABLE );
211  }
212
213  /* else implies that it should not install the interrupt for a FALLING edge.
214      Also, there is nothing to do. */
215}
216
217/**
218 * @brief Registers the pin and the callbacks functions.
219 *
220 * @param edge Current edge.
221 * @param pin The pin to configure.
222 * @param isr_funct Callback function to set.
223 */
224static void lpc176x_register_pin_and_callback(
225  const lpc176x_gpio_interrupt          edge,
226  const lpc176x_pin_number              pin,
227  const lpc176x_gpio_interrupt_function isr_funct
228)
229{
230  if ( edge ) {
231    assert( function_vector_size < LPC176X_RESERVED_ISR_FUNCT_SIZE );
232    function_vector[ function_vector_size ].function = isr_funct;
233    function_vector[ function_vector_size ].pin = pin;
234    ++function_vector_size;
235  }
236
237  /* else implies that the current interrupt is DISABLED or BOTH. Also,
238     there is nothing to do. */
239}
240
241/**
242 * @brief Installs the interrupt handler.
243 *
244 * @param edge Which edge enable.
245 * @return  RTEMS_SUCCESSFUL if the installation was success.
246 */
247static rtems_status_code lpc176x_install_interrupt_handler(
248  const lpc176x_gpio_interrupt edge )
249{
250  rtems_status_code status_code = RTEMS_SUCCESSFUL;
251
252  if ( !isr_installed && edge ) {
253    status_code = rtems_interrupt_handler_install( LPC176X_IRQ_EINT_3,
254      "gpio_interrupt",
255      RTEMS_INTERRUPT_UNIQUE,
256      lpc176x_gpio_isr,
257      NULL );
258    isr_installed = true;
259  }
260
261  /* else implies that the interrupts have been previously installed. Also,
262     there is nothing to do. */
263
264  return status_code;
265}
266
267/**
268 * @brief Configures the pin as input, enables interrupt for an
269 * edge/s and sets isrfunct as the function to call when that
270 * interrupt occurs.
271 *
272 * @param pin The pin to configure.
273 * @param edge Which edge or edges will activate the interrupt.
274 * @param isrfunct The function that is called when the interrupt occurs.
275 * @return RTEMS_SUCCESSFUL if the configuration was success.
276 */
277static rtems_status_code lpc176x_check_edge_and_set_gpio_interrupts(
278  const lpc176x_pin_number              pin,
279  const lpc176x_gpio_interrupt          edge,
280  const lpc176x_gpio_interrupt_function isr_funct
281)
282{
283  rtems_status_code status_code = RTEMS_SUCCESSFUL;
284
285  const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
286  const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
287
288  lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
289
290  assert( interrupt != NULL );
291
292  lpc176x_gpio_config( pin, LPC176X_GPIO_FUNCTION_INPUT );
293
294  lpc176x_set_falling_or_rising_interrupt( edge, pin_of_port, interrupt );
295
296  lpc176x_register_pin_and_callback( edge, pin, isr_funct );
297
298  status_code = lpc176x_install_interrupt_handler( edge );
299
300  return status_code;
301}
302
303rtems_status_code lpc176x_gpio_config_input_with_interrupt(
304  const lpc176x_pin_number              pin,
305  const lpc176x_gpio_interrupt          edge,
306  const lpc176x_gpio_interrupt_function isr_funct
307)
308{
309  rtems_status_code status_code = RTEMS_INVALID_NUMBER;
310
311  if ( ( pin < LPC176X_MAX_PORT_NUMBER )
312       && ( edge < LPC176X_GPIO_INTERRUPT_COUNT ) ) {
313    status_code = lpc176x_check_edge_and_set_gpio_interrupts( pin,
314      edge,
315      isr_funct );
316  }
317
318  /* else implies that the pin or the egde are out of range. Also,
319     an invalid number is returned. */
320
321  return status_code;
322}
323
324rtems_status_code lpc176x_gpio_set_pin( const lpc176x_pin_number pin )
325{
326  rtems_status_code status_code = RTEMS_INVALID_NUMBER;
327
328  if ( pin < LPC176X_MAX_PORT_NUMBER ) {
329    const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
330    const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
331
332    LPC176X_FIO[ port ].set = LPC176X_PIN_BIT( pin_of_port );
333
334    status_code = RTEMS_SUCCESSFUL;
335  }
336
337  /* else implies that the pin or the egde are out of range. Also,
338     an invalid number is returned. */
339
340  return status_code;
341}
342
343rtems_status_code lpc176x_gpio_clear_pin( const lpc176x_pin_number pin )
344{
345  rtems_status_code status_code = RTEMS_INVALID_NUMBER;
346
347  if ( pin < LPC176X_MAX_PORT_NUMBER ) {
348    const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
349    const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
350
351    LPC176X_FIO[ port ].clr = LPC176X_PIN_BIT( pin_of_port );
352
353    status_code = RTEMS_SUCCESSFUL;
354  }
355
356  /* else implies that the pin or the egde are out of range. Also,
357     an invalid number is returned. */
358
359  return status_code;
360}
361
362rtems_status_code lpc176x_gpio_write_pin(
363  const lpc176x_pin_number pin,
364  const bool               value
365)
366{
367  rtems_status_code status_code;
368
369  if ( value ) {
370    status_code = lpc176x_gpio_set_pin( pin );
371  } else {
372    status_code = lpc176x_gpio_clear_pin( pin );
373  }
374
375  return status_code;
376}
377
378inline rtems_status_code lpc176x_gpio_get_pin_value(
379  const lpc176x_pin_number pin,
380  bool                    *pin_value
381)
382{
383  assert( pin < LPC176X_MAX_PORT_NUMBER );
384
385  rtems_status_code status_code = RTEMS_SUCCESSFUL;
386
387  const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
388  const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
389  *pin_value = ( LPC176X_FIO[ port ].pin & LPC176X_PIN_BIT( pin_of_port ) );
390
391  return status_code;
392}
Note: See TracBrowser for help on using the repository browser.