Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:03

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMLPC176X
0005  *
0006  * @brief GPIO library for the lpc176x bsp.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 Taller Technologies.
0011  *
0012  * @author  Boretto Martin    (martin.boretto@tallertechnologies.com)
0013  * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
0014  * @author  Lenarduzzi Federico  (federico.lenarduzzi@tallertechnologies.com)
0015  * @author  Daniel Chicco  (daniel.chicco@tallertechnologies.com)
0016  *
0017  * The license and distribution terms for this file may be
0018  * found in the file LICENSE in this distribution or at
0019  * http://www.rtems.org/license/LICENSE.
0020  */
0021 
0022 #include <assert.h>
0023 #include <bsp/irq.h>
0024 #include <bsp/io.h>
0025 #include <bsp/lpc-gpio.h>
0026 #include <rtems/status-checks.h>
0027 
0028 static uint32_t                              function_vector_size = 0u;
0029 static lpc176x_registered_interrupt_function function_vector[
0030   LPC176X_RESERVED_ISR_FUNCT_SIZE ];
0031 static bool isr_installed = false;
0032 
0033 rtems_status_code lpc176x_gpio_config(
0034   const lpc176x_pin_number     pin,
0035   const lpc176x_gpio_direction dir
0036 )
0037 {
0038   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0039 
0040   if ( ( pin < LPC176X_MAX_PORT_NUMBER ) &&
0041        ( dir < LPC176X_GPIO_FUNCTION_COUNT ) ) {
0042     const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
0043     const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
0044 
0045     lpc176x_pin_select( pin, LPC176X_PIN_FUNCTION_00 );
0046 
0047     LPC176X_SET_BIT( LPC176X_FIO[ port ].dir, pin_of_port, dir );
0048 
0049     status_code = RTEMS_SUCCESSFUL;
0050   }
0051 
0052   /* else implies that the pin or the egde are out of range. Also,
0053      an invalid number is returned. */
0054 
0055   return status_code;
0056 }
0057 
0058 /**
0059  * @brief Check for a rising edge and call the interrupt function.
0060  *
0061  * @param statR Rising edge interrupt.
0062  * @param pin The pin to check.
0063  * @param registered_isr_function Interrupt to check.
0064  * @return TRUE if is a rising edge. FALSE otherwise.
0065  */
0066 static bool lpc176x_check_rising_edge_and_call(
0067   const uint32_t                              statR,
0068   const lpc176x_registered_interrupt_function registered_isr_function,
0069   const uint32_t                              pin
0070 )
0071 {
0072   bool is_rising = false;
0073 
0074   if ( statR & LPC176X_PIN_BIT( pin ) ) {
0075     registered_isr_function.function( registered_isr_function.pin,
0076       LPC176X_GPIO_INTERRUPT_RISING );
0077     is_rising = true;
0078   }
0079 
0080   /* else implies that the current interrupt is not STATR. Also,
0081      there is nothing to do. */
0082 
0083   return is_rising;
0084 }
0085 
0086 /**
0087  * @brief Check for a falling edge and call the interrupt function.
0088  *
0089  * @param statR Falling edge interrupt.
0090  * @param pin The pin to check.
0091  * @param registered_isr_function Interrupt to check.
0092  * @return TRUE if is a falling edge. FALSE otherwise.
0093  */
0094 static bool lpc176x_check_falling_edge_and_call(
0095   const uint32_t                              statF,
0096   const lpc176x_registered_interrupt_function registered_isr_function,
0097   const uint32_t                              pin
0098 )
0099 {
0100   bool is_falling = false;
0101 
0102   if ( statF & LPC176X_PIN_BIT( pin ) ) {
0103     registered_isr_function.function( registered_isr_function.pin,
0104       LPC176X_GPIO_INTERRUPT_FALLING );
0105     is_falling = true;
0106   }
0107 
0108   /* else implies that the current interrupt is not STATF. Also,
0109      there is nothing to do. */
0110 
0111   return is_falling;
0112 }
0113 
0114 /**
0115  * @brief Returns the interrupts base address according to the current port.
0116  *
0117  * @param  port Input/Output port.
0118  * @return Interrupt base address.
0119  */
0120 static lpc176x_interrupt_control*lpc176x_get_interrupt_address(
0121   const lpc176x_gpio_ports port )
0122 {
0123   lpc176x_interrupt_control *interrupt;
0124 
0125   switch ( port ) {
0126     case ( LPC176X_GPIO_PORT_0 ):
0127       interrupt = (lpc176x_interrupt_control *) LPC176X_IO0_INT_BASE_ADDRESS;
0128       break;
0129     case ( LPC176X_GPIO_PORT_2 ):
0130       interrupt = (lpc176x_interrupt_control *) LPC176X_IO2_INT_BASE_ADDRESS;
0131       break;
0132     case ( LPC176X_GPIO_PORT_1 ):
0133     case ( LPC176X_GPIO_PORT_3 ):
0134     case ( LPC176X_GPIO_PORT_4 ):
0135     default:
0136       interrupt = NULL;
0137   }
0138 
0139   return interrupt;
0140 }
0141 
0142 /**
0143  * @brief Checks the type of the current interrupt.
0144  *
0145  * @param registered_isr_function Interrupt to check.
0146  */
0147 static void check_for_interrupt(
0148   const lpc176x_registered_interrupt_function registered_isr_function )
0149 {
0150   assert( registered_isr_function.pin < LPC176X_MAX_PORT_NUMBER );
0151 
0152   const lpc176x_gpio_ports port = LPC176X_IO_PORT(
0153     registered_isr_function.pin );
0154   const uint32_t pin = LPC176X_IO_PORT_BIT( registered_isr_function.pin );
0155 
0156   lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
0157   assert( interrupt != NULL );
0158 
0159   bool is_rising_edge = lpc176x_check_rising_edge_and_call( interrupt->StatR,
0160     registered_isr_function,
0161     pin );
0162 
0163   bool is_falling_edge = lpc176x_check_falling_edge_and_call( interrupt->StatF,
0164     registered_isr_function,
0165     pin );
0166 
0167   if ( is_rising_edge || is_falling_edge ) {
0168     interrupt->Clr = LPC176X_PIN_BIT( pin );
0169   }
0170 
0171   /* else implies that the current interrupt is not CLR. Also,
0172      there is nothing to do. */
0173 }
0174 
0175 /**
0176  * @brief Checks all interrupts types.
0177  *
0178  * @param arg Interrupt to check.
0179  */
0180 static inline void lpc176x_gpio_isr( void *arg )
0181 {
0182   unsigned int i;
0183 
0184   for ( i = 0; i < function_vector_size; ++i ) {
0185     check_for_interrupt( function_vector[ i ] );
0186   }
0187 }
0188 
0189 /**
0190  * @brief Depending of the current edge sets rising/falling interrupt.
0191  *
0192  * @param edge Current edge.
0193  * @param pin_of_port Pin of the port to set the interrupt.
0194  * @param interrupt To enable the falling o rising edge.
0195  */
0196 static void lpc176x_set_falling_or_rising_interrupt(
0197   const lpc176x_gpio_interrupt edge,
0198   const uint32_t               pin_of_port,
0199   lpc176x_interrupt_control   *interrupt
0200 )
0201 {
0202   if ( edge & LPC176X_GPIO_INTERRUPT_RISING ) {
0203     LPC176X_SET_BIT( interrupt->EnR, pin_of_port, LPC176X_INT_ENABLE );
0204   }
0205 
0206   /* else implies that it should not install the interrupt for a RISING edge.
0207       Also, there is nothing to do. */
0208 
0209   if ( edge & LPC176X_GPIO_INTERRUPT_FALLING ) {
0210     LPC176X_SET_BIT( interrupt->EnF, pin_of_port, LPC176X_INT_ENABLE );
0211   }
0212 
0213   /* else implies that it should not install the interrupt for a FALLING edge.
0214       Also, there is nothing to do. */
0215 }
0216 
0217 /**
0218  * @brief Registers the pin and the callbacks functions.
0219  *
0220  * @param edge Current edge.
0221  * @param pin The pin to configure.
0222  * @param isr_funct Callback function to set.
0223  */
0224 static void lpc176x_register_pin_and_callback(
0225   const lpc176x_gpio_interrupt          edge,
0226   const lpc176x_pin_number              pin,
0227   const lpc176x_gpio_interrupt_function isr_funct
0228 )
0229 {
0230   if ( edge ) {
0231     assert( function_vector_size < LPC176X_RESERVED_ISR_FUNCT_SIZE );
0232     function_vector[ function_vector_size ].function = isr_funct;
0233     function_vector[ function_vector_size ].pin = pin;
0234     ++function_vector_size;
0235   }
0236 
0237   /* else implies that the current interrupt is DISABLED or BOTH. Also,
0238      there is nothing to do. */
0239 }
0240 
0241 /**
0242  * @brief Installs the interrupt handler.
0243  *
0244  * @param edge Which edge enable.
0245  * @return  RTEMS_SUCCESSFUL if the installation was success.
0246  */
0247 static rtems_status_code lpc176x_install_interrupt_handler(
0248   const lpc176x_gpio_interrupt edge )
0249 {
0250   rtems_status_code status_code = RTEMS_SUCCESSFUL;
0251 
0252   if ( !isr_installed && edge ) {
0253     status_code = rtems_interrupt_handler_install( LPC176X_IRQ_EINT_3,
0254       "gpio_interrupt",
0255       RTEMS_INTERRUPT_UNIQUE,
0256       lpc176x_gpio_isr,
0257       NULL );
0258     isr_installed = true;
0259   }
0260 
0261   /* else implies that the interrupts have been previously installed. Also,
0262      there is nothing to do. */
0263 
0264   return status_code;
0265 }
0266 
0267 /**
0268  * @brief Configures the pin as input, enables interrupt for an
0269  * edge/s and sets isrfunct as the function to call when that
0270  * interrupt occurs.
0271  *
0272  * @param pin The pin to configure.
0273  * @param edge Which edge or edges will activate the interrupt.
0274  * @param isrfunct The function that is called when the interrupt occurs.
0275  * @return RTEMS_SUCCESSFUL if the configuration was success.
0276  */
0277 static rtems_status_code lpc176x_check_edge_and_set_gpio_interrupts(
0278   const lpc176x_pin_number              pin,
0279   const lpc176x_gpio_interrupt          edge,
0280   const lpc176x_gpio_interrupt_function isr_funct
0281 )
0282 {
0283   rtems_status_code status_code = RTEMS_SUCCESSFUL;
0284 
0285   const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
0286   const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
0287 
0288   lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
0289 
0290   assert( interrupt != NULL );
0291 
0292   lpc176x_gpio_config( pin, LPC176X_GPIO_FUNCTION_INPUT );
0293 
0294   lpc176x_set_falling_or_rising_interrupt( edge, pin_of_port, interrupt );
0295 
0296   lpc176x_register_pin_and_callback( edge, pin, isr_funct );
0297 
0298   status_code = lpc176x_install_interrupt_handler( edge );
0299 
0300   return status_code;
0301 }
0302 
0303 rtems_status_code lpc176x_gpio_config_input_with_interrupt(
0304   const lpc176x_pin_number              pin,
0305   const lpc176x_gpio_interrupt          edge,
0306   const lpc176x_gpio_interrupt_function isr_funct
0307 )
0308 {
0309   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0310 
0311   if ( ( pin < LPC176X_MAX_PORT_NUMBER )
0312        && ( edge < LPC176X_GPIO_INTERRUPT_COUNT ) ) {
0313     status_code = lpc176x_check_edge_and_set_gpio_interrupts( pin,
0314       edge,
0315       isr_funct );
0316   }
0317 
0318   /* else implies that the pin or the egde are out of range. Also,
0319      an invalid number is returned. */
0320 
0321   return status_code;
0322 }
0323 
0324 rtems_status_code lpc176x_gpio_set_pin( const lpc176x_pin_number pin )
0325 {
0326   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0327 
0328   if ( pin < LPC176X_MAX_PORT_NUMBER ) {
0329     const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
0330     const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
0331 
0332     LPC176X_FIO[ port ].set = LPC176X_PIN_BIT( pin_of_port );
0333 
0334     status_code = RTEMS_SUCCESSFUL;
0335   }
0336 
0337   /* else implies that the pin or the egde are out of range. Also,
0338      an invalid number is returned. */
0339 
0340   return status_code;
0341 }
0342 
0343 rtems_status_code lpc176x_gpio_clear_pin( const lpc176x_pin_number pin )
0344 {
0345   rtems_status_code status_code = RTEMS_INVALID_NUMBER;
0346 
0347   if ( pin < LPC176X_MAX_PORT_NUMBER ) {
0348     const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
0349     const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
0350 
0351     LPC176X_FIO[ port ].clr = LPC176X_PIN_BIT( pin_of_port );
0352 
0353     status_code = RTEMS_SUCCESSFUL;
0354   }
0355 
0356   /* else implies that the pin or the egde are out of range. Also,
0357      an invalid number is returned. */
0358 
0359   return status_code;
0360 }
0361 
0362 rtems_status_code lpc176x_gpio_write_pin(
0363   const lpc176x_pin_number pin,
0364   const bool               value
0365 )
0366 {
0367   rtems_status_code status_code;
0368 
0369   if ( value ) {
0370     status_code = lpc176x_gpio_set_pin( pin );
0371   } else {
0372     status_code = lpc176x_gpio_clear_pin( pin );
0373   }
0374 
0375   return status_code;
0376 }
0377 
0378 inline rtems_status_code lpc176x_gpio_get_pin_value(
0379   const lpc176x_pin_number pin,
0380   bool                    *pin_value
0381 )
0382 {
0383   assert( pin < LPC176X_MAX_PORT_NUMBER );
0384 
0385   rtems_status_code status_code = RTEMS_SUCCESSFUL;
0386 
0387   const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
0388   const uint32_t           pin_of_port = LPC176X_IO_PORT_BIT( pin );
0389   *pin_value = ( LPC176X_FIO[ port ].pin & LPC176X_PIN_BIT( pin_of_port ) );
0390 
0391   return status_code;
0392 }