summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-25 10:43:38 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-25 14:31:28 +0200
commite945b049dc650ee2270740585a2c6d14bd925279 (patch)
treeccd1f3cd6bc9bd44435b25918fc4e934a6aff6a4 /bsps
parentbsp/lpc24xx: Move source files to bsps (diff)
downloadrtems-e945b049dc650ee2270740585a2c6d14bd925279.tar.bz2
bsp/lpc176x: Move source files to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps')
-rw-r--r--bsps/arm/lpc176x/btimer/btimer.c388
-rwxr-xr-xbsps/arm/lpc176x/can/can.c543
-rw-r--r--bsps/arm/lpc176x/gpio/lpc-gpio.c392
-rwxr-xr-xbsps/arm/lpc176x/pwm/pwmout.c211
-rwxr-xr-xbsps/arm/lpc176x/start/adc.c245
-rw-r--r--bsps/arm/lpc176x/start/bspidle.c30
-rw-r--r--bsps/arm/lpc176x/start/dma-copy.c220
-rw-r--r--bsps/arm/lpc176x/start/dma.c117
-rw-r--r--bsps/arm/lpc176x/start/io.c349
-rw-r--r--bsps/arm/lpc176x/start/restart.c35
-rw-r--r--bsps/arm/lpc176x/start/system-clocks.c124
-rw-r--r--bsps/arm/lpc176x/start/watchdog.c102
-rw-r--r--bsps/arm/lpc176x/timer/timer.c407
13 files changed, 2788 insertions, 375 deletions
diff --git a/bsps/arm/lpc176x/btimer/btimer.c b/bsps/arm/lpc176x/btimer/btimer.c
index 36c720b4fb..359d89086d 100644
--- a/bsps/arm/lpc176x/btimer/btimer.c
+++ b/bsps/arm/lpc176x/btimer/btimer.c
@@ -1,9 +1,9 @@
/**
- * @file timer.c
+ * @file timerbenchmark.c
*
* @ingroup lpc176x
*
- * @brief Timer controller for the mbed lpc1768 board.
+ * @brief Timer benchmark functions for the lpc176x bsp.
*/
/*
@@ -19,389 +19,27 @@
* http://www.rtems.org/license/LICENSE.
*/
-#include <stdio.h>
-#include <rtems/status-checks.h>
+#include <rtems.h>
#include <bsp.h>
-#include <bsp/irq.h>
-#include <bsp/io.h>
-#include <bsp/timer.h>
-
-/**
- * @brief Represents all the timers.
- */
-const lpc176x_timer timers[ LPC176X_TIMER_COUNT ] =
-{
- {
- .device = (lpc176x_timer_device *) LPC176X_TMR0_BASE_ADDR,
- .module = LPC176X_MODULE_TIMER_0,
- .pinselcap = LPC176X_TIMER0_CAPTURE_PORTS,
- .pinselemat = LPC176X_TIMER0_EMATCH_PORTS,
- },
- {
- .device = (lpc176x_timer_device *) LPC176X_TMR1_BASE_ADDR,
- .module = LPC176X_MODULE_TIMER_1,
- .pinselcap = LPC176X_TIMER1_CAPTURE_PORTS,
- .pinselemat = LPC176X_TIMER1_EMATCH_PORTS,
- },
- {
- .device = (lpc176x_timer_device *) LPC176X_TMR2_BASE_ADDR,
- .module = LPC176X_MODULE_TIMER_2,
- .pinselcap = LPC176X_TIMER2_CAPTURE_PORTS,
- .pinselemat = LPC176X_TIMER2_EMATCH_PORTS,
- },
- {
- .device = (lpc176x_timer_device *) LPC176X_TMR3_BASE_ADDR,
- .module = LPC176X_MODULE_TIMER_3,
- .pinselcap = LPC176X_TIMER3_CAPTURE_PORTS,
- .pinselemat = LPC176X_TIMER3_EMATCH_PORTS,
- }
-};
-
-/**
- * @brief Represents all the functions according to the timers.
- */
-lpc176x_timer_functions functions_vector[ LPC176X_TIMER_COUNT ] =
-{
- {
- .funct_vector = NULL
- },
- {
- .funct_vector = NULL
- },
- {
- .funct_vector = NULL
- },
- {
- .funct_vector = NULL
- }
-};
-
-/**
- * @brief Calls the corresponding interrupt function and pass the timer
- * as parameter.
- *
- * @param timer The specific device.
- * @param interruptnumber Interrupt number.
- */
-static inline void lpc176x_call_desired_isr(
- const lpc176x_timer_number number,
- const lpc176x_isr_function interruptfunction
-)
-{
- if ( ( *functions_vector[ number ].funct_vector )[ interruptfunction ] !=
- NULL ) {
- ( *functions_vector[ number ].funct_vector )[ interruptfunction ]( number );
- }
-
- /* else implies that the function vector points NULL. Also,
- there is nothing to do. */
-}
-
-/**
- * @brief Gets true if the selected interrupt is pending
- *
- * @param number: the number of the timer.
- * @param interrupt: the interrupt we are checking for.
- * @return TRUE if the interrupt is pending.
- */
-static inline bool lpc176x_timer_interrupt_is_pending(
- const lpc176x_timer_number tnumber,
- const lpc176x_isr_function function
-)
-{
- assert( ( tnumber < LPC176X_TIMER_COUNT )
- && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
-
- return ( timers[ tnumber ].device->IR &
- LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function ) );
-}
-
-/**
- * @brief Resets interrupt status for the selected interrupt
- *
- * @param tnumber: the number of the timer
- * @param interrupt: the interrupt we are resetting
- */
-static inline void lpc176x_timer_reset_interrupt(
- const lpc176x_timer_number tnumber,
- const lpc176x_isr_function function
-)
-{
- assert( ( tnumber < LPC176X_TIMER_COUNT )
- && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
- timers[ tnumber ].device->IR =
- LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function );
-}
-
-inline rtems_status_code lpc176x_timer_reset(
- const lpc176x_timer_number tnumber )
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- timers[ tnumber ].device->TCR = LPC176X_TIMER_RESET;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_set_mode(
- const lpc176x_timer_number tnumber,
- const lpc176x_timer_mode mode
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- timers[ tnumber ].device->CTCR = mode;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_start(
- const lpc176x_timer_number tnumber )
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- timers[ tnumber ].device->TCR = LPC176X_TIMER_START;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_is_started(
- const lpc176x_timer_number tnumber,
- bool *is_started
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- *is_started = ( timers[ tnumber ].device->TCR & LPC176X_TIMER_START ) ==
- LPC176X_TIMER_START;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
+#include <rtems/btimer.h>
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_set_resolution(
- const lpc176x_timer_number tnumber,
- const lpc176x_microseconds resolution
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- timers[ tnumber ].device->PR = ( LPC176X_CCLK /
- LPC176X_TIMER_PRESCALER_DIVISOR ) *
- resolution;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-rtems_status_code lpc176x_timer_match_config(
- const lpc176x_timer_number tnumber,
- const lpc176x_match_port match_port,
- const lpc176x_match_function function,
- const uint32_t match_value
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( ( tnumber < LPC176X_TIMER_COUNT )
- && ( match_port < LPC176X_EMATCH_PORTS_COUNT )
- && ( function < LPC176X_TIMER_MATCH_FUNCTION_COUNT ) ) {
- timers[ tnumber ].device->MCR =
- LPC176X_SET_MCR( timers[ tnumber ].device->MCR,
- match_port, function );
- timers[ tnumber ].device->MR[ match_port ] = match_value;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number, or a match port or a function
- is invalid. Also, an invalid number is returned. */
-
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_capture_config(
- const lpc176x_timer_number tnumber,
- const lpc176x_capture_port capture_port,
- const lpc176x_capture_function function
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( ( tnumber < LPC176X_TIMER_COUNT )
- && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT )
- && ( function < LPC176X_TIMER_CAPTURE_FUNCTION_COUNT ) ) {
- timers[ tnumber ].device->CCR =
- LPC176X_SET_CCR( timers[ tnumber ].device->CCR,
- capture_port, function );
- lpc176x_pin_select( timers[ tnumber ].pinselcap[ capture_port ],
- LPC176X_PIN_FUNCTION_11 );
- }
-
- /* else implies that the timer number or the capture port is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-inline rtems_status_code lpc176x_timer_external_match_config(
- const lpc176x_timer_number number,
- const lpc176x_match_port match_port,
- const lpc176x_ext_match_function function
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( ( number < LPC176X_TIMER_COUNT )
- && ( match_port < LPC176X_EMATCH_PORTS_COUNT ) ) {
- timers[ number ].device->EMR =
- LPC176X_SET_EMR( timers[ number ].device->EMR,
- match_port, function );
- lpc176x_pin_select( timers[ number ].pinselemat[ match_port ],
- LPC176X_PIN_FUNCTION_11 );
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number or the match port is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-inline uint32_t lpc176x_timer_get_capvalue(
- const lpc176x_timer_number number,
- const lpc176x_capture_port capture_port
-)
-{
- assert( ( number < LPC176X_TIMER_COUNT )
- && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT ) );
+#include <bsp/timer.h>
- return timers[ number ].device->CR[ capture_port ];
-}
+static uint32_t benchmark_timer_base;
-inline uint32_t lpc176x_timer_get_timer_value(
- const lpc176x_timer_number tnumber )
+void benchmark_timer_initialize( void )
{
- assert( tnumber < LPC176X_TIMER_COUNT );
-
- return timers[ tnumber ].device->TC;
+ benchmark_timer_base = lpc176x_timer_get_timer_value( LPC176X_TIMER_1 );
}
-inline rtems_status_code lpc176x_timer_set_timer_value(
- const lpc176x_timer_number tnumber,
- const uint32_t timer_value
-)
+benchmark_timer_t benchmark_timer_read( void )
{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+ uint32_t delta = lpc176x_timer_get_timer_value( LPC176X_TIMER_1 ) -
+ benchmark_timer_base;
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- timers[ tnumber ].device->TC = timer_value;
- status_code = RTEMS_SUCCESSFUL;
- }
-
- /* else implies that the timer number is invalid. Also,
- an invalid number is returned. */
-
- return status_code;
+ return delta;
}
-void lpc176x_timer_isr( void *arg )
+void benchmark_timer_disable_subtracting_average_overhead( bool find_avg_ovhead )
{
- const lpc176x_timer_number tnumber = (lpc176x_timer_number) arg;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- lpc176x_isr_function i;
-
- for ( i = 0; i < LPC176X_ISR_FUNCTIONS_COUNT; ++i ) {
- if ( lpc176x_timer_interrupt_is_pending( tnumber, i ) ) {
- lpc176x_call_desired_isr( tnumber, i );
- lpc176x_timer_reset_interrupt( tnumber, i );
- }
-
- /* else implies that the current timer is not pending. Also,
- there is nothing to do. */
- }
- }
-
- /* else implies that the timer number is not valid. Also,
- there is nothing to do. */
}
-
-rtems_status_code lpc176x_timer_init( const lpc176x_timer_number tnumber )
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- if ( tnumber < LPC176X_TIMER_COUNT ) {
- status_code = lpc176x_module_enable( timers[ tnumber ].module,
- LPC176X_MODULE_PCLK_DEFAULT );
- RTEMS_CHECK_SC( status_code, "Enabling the timer module." );
-
- status_code = lpc176x_timer_reset( tnumber );
- status_code = lpc176x_timer_set_mode( tnumber,
- LPC176X_TIMER_MODE_TIMER );
- status_code = lpc176x_timer_set_resolution( tnumber,
- LPC176X_TIMER_DEFAULT_RESOLUTION );
-
- timers[ tnumber ].device->MCR = LPC176X_TIMER_CLEAR_FUNCTION;
- timers[ tnumber ].device->CCR = LPC176X_TIMER_CLEAR_FUNCTION;
- timers[ tnumber ].device->EMR = LPC176X_TIMER_CLEAR_FUNCTION;
- }
-
- /* else implies that the timer number is not valid. Also,
- an invalid number is returned. */
-
- return status_code;
-}
-
-rtems_status_code lpc176x_timer_init_with_interrupt(
- const lpc176x_timer_number tnumber,
- const lpc176x_isr_funct_vector *const vector
-)
-{
- rtems_status_code status_code = RTEMS_INVALID_NUMBER;
-
- char isrname[ LPC176X_ISR_NAME_STRING_SIZE ];
-
- snprintf( isrname, LPC176X_ISR_NAME_STRING_SIZE, "TimerIsr%d", tnumber );
-
- if ( tnumber < LPC176X_TIMER_COUNT && vector != NULL ) {
- functions_vector[ tnumber ].funct_vector = vector;
-
- status_code = lpc176x_timer_init( tnumber );
- status_code = rtems_interrupt_handler_install(
- LPC176X_TIMER_VECTOR_NUMBER( tnumber ),
- isrname,
- RTEMS_INTERRUPT_UNIQUE,
- lpc176x_timer_isr,
- (void *) tnumber );
- }
-
- return status_code;
-} \ No newline at end of file
diff --git a/bsps/arm/lpc176x/can/can.c b/bsps/arm/lpc176x/can/can.c
new file mode 100755
index 0000000000..e5ffc29b7a
--- /dev/null
+++ b/bsps/arm/lpc176x/can/can.c
@@ -0,0 +1,543 @@
+/**
+ * @file can.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief CAN controller for the mbed lpc1768 board.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/status-checks.h>
+#include <bsp/irq.h>
+#include <bsp/can.h>
+#include <bsp/can-defs.h>
+#include <bsp/mbed-pinmap.h>
+#include <string.h>
+
+/**
+ * @brief The standard isr to be installed for all the can devices.
+ *
+ * @param arg unused.
+ */
+static void can_isr( void *arg );
+
+/**
+ * @brief Vector of isr for the can_driver .
+ */
+lpc176x_can_isr_vector isr_vector;
+
+/**
+ * @brief Represents all the can devices, and useful things for initialization.
+ */
+static const can_driver_entry can_driver_table[ CAN_DEVICES_NUMBER ] =
+{
+ {
+ .device = (can_device *) CAN1_BASE_ADDR,
+ .module = LPC176X_MODULE_CAN_0,
+ .pconp_pin = LPC176X_SCB_PCONP_CAN_1,
+ .pins = { DIP9, DIP10 },
+ .pinfunction = LPC176X_PIN_FUNCTION_01
+ },
+ {
+ .device = (can_device *) CAN2_BASE_ADDR,
+ .module = LPC176X_MODULE_CAN_1,
+ .pconp_pin = LPC176X_SCB_PCONP_CAN_2,
+ .pins = { DIP30, DIP29 },
+ .pinfunction = LPC176X_PIN_FUNCTION_10
+ }
+};
+
+/**
+ * @brief The CAN acceptance filter.
+ */
+can_acceptance_filter *const acceptance_filter_device =
+ (can_acceptance_filter *) CAN_ACCEPT_BASE_ADDR;
+
+/**
+ * @brief Sets RX and TX pins for the passed can device number.
+ *
+ * @param cannumber CAN controller to be used.
+ */
+static inline void setpins( const lpc176x_can_number cannumber )
+{
+ const can_driver_entry *const can_driver = &can_driver_table[ cannumber ];
+
+ lpc176x_pin_select( can_driver->pins[ CAN_TX_PIN ],
+ can_driver->pinfunction );
+ lpc176x_pin_select( can_driver->pins[ CAN_RX_PIN ],
+ can_driver->pinfunction );
+}
+
+rtems_status_code can_close( const lpc176x_can_number minor )
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+
+ if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
+ sc = RTEMS_SUCCESSFUL;
+ const can_driver_entry *const can_driver = &can_driver_table[ minor ];
+ lpc176x_module_disable( can_driver->module );
+ }
+
+ /*else wrong parameters. return RTEMS_INVALID_NUMBER*/
+
+ return sc;
+}
+
+/**
+ * @brief Enables CAN device.
+ *
+ * @param obj The device to be enabled.
+ */
+static inline void can_enable( const can_driver_entry *const obj )
+{
+ if ( obj->device->MOD & CAN_MOD_RM ) {
+ obj->device->MOD &= ~( CAN_MOD_RM );
+ }
+}
+
+/**
+ * @brief Disables CAN device to set parameters, and returns the previous value
+ * of the MOD register.
+ *
+ * @param obj The device to disable.
+ * @return The previous status of MOD register.
+ */
+static inline uint32_t can_disable( const can_driver_entry *const obj )
+{
+ const uint32_t sm = obj->device->MOD;
+
+ obj->device->MOD |= CAN_MOD_RM;
+
+ return sm;
+}
+
+/**
+ * @brief Resets the error count.
+ *
+ * @param obj which device reset.
+ */
+static inline void can_reset( const can_driver_entry *const obj )
+{
+ can_disable( obj );
+ obj->device->GSR = 0; /* Reset error counter when CANxMOD is in reset*/
+}
+
+/**
+ * @brief This table has the sampling points as close to 75% as possible.
+ * The first value is TSEG1, the second is TSEG2.
+ */
+static const unsigned int timing_pts[ MAX_TSEG1_TSEG2_BITS +
+ 1 ][ CAN_NUMBER_OF_TSEG ] = {
+ { 0x0, 0x0 }, /* 2, 50%*/
+ { 0x1, 0x0 }, /* 3, 67%*/
+ { 0x2, 0x0 }, /* 4, 75%*/
+ { 0x3, 0x0 }, /* 5, 80%*/
+ { 0x3, 0x1 }, /* 6, 67%*/
+ { 0x4, 0x1 }, /* 7, 71%*/
+ { 0x5, 0x1 }, /* 8, 75%*/
+ { 0x6, 0x1 }, /* 9, 78%*/
+ { 0x6, 0x2 }, /* 10, 70%*/
+ { 0x7, 0x2 }, /* 11, 73%*/
+ { 0x8, 0x2 }, /* 12, 75%*/
+ { 0x9, 0x2 }, /* 13, 77%*/
+ { 0x9, 0x3 }, /* 14, 71%*/
+ { 0xA, 0x3 }, /* 15, 73%*/
+ { 0xB, 0x3 }, /* 16, 75%*/
+ { 0xC, 0x3 }, /* 17, 76%*/
+ { 0xD, 0x3 }, /* 18, 78%*/
+ { 0xD, 0x4 }, /* 19, 74%*/
+ { 0xE, 0x4 }, /* 20, 75%*/
+ { 0xF, 0x4 }, /* 21, 76%*/
+ { 0xF, 0x5 }, /* 22, 73%*/
+ { 0xF, 0x6 }, /* 23, 70%*/
+ { 0xF, 0x7 }, /* 24, 67%*/
+};
+
+/**
+ * @brief Checks if divisor is a divisor of value.
+ *
+ * @param value The number to be divided.
+ * @param divisor The divisor to check.
+ *
+ * @return true if "number" is divided by "divisor"; false otherwise.
+ */
+static inline bool is_divisor(
+ const uint32_t value,
+ const uint16_t divisor
+)
+{
+ return ( ( value % divisor ) == 0 );
+}
+
+/**
+ * @brief Gets the size of the two tseg values added according to the given
+ * bitwidth and brp (The CAN prescaler).
+ *
+ * @param bitwidth The total bitwidth of a CAN bit (in pclk clocks).
+ * @param brp The CAN clock prescaler.
+ *
+ * @return The value of tseg1 + tseg2 of the CAN bit. It is useful
+ * to serve for index for timing_pts array).
+ */
+static inline uint32_t get_tseg_bit_size(
+ const uint32_t bitwidth,
+ const uint16_t brp
+)
+{
+ return ( ( bitwidth / ( brp + CAN_BRP_EXTRA_BIT ) ) - CAN_TSEG_EXTRA_BITS );
+}
+
+/**
+ * @brief Gets the brp and tsegbitsize in order to achieve the desired bitwidth.
+ * @details The following must be fullfilled:
+ *(brp + CAN_BRP_EXTRA_BIT) * (tsegbitsize + CAN_TSEG_EXTRA_BITS) == bitwidth
+ *
+ * @param bitwidth The bitwidth that we need to achieve.
+ * @param brp Here it returns the calculated brp value.
+ * @param tsegbitsize Here it returns the calculated tseg bit size value.
+ * @return true if brp and tsegbitsize have been calculated.
+ */
+static inline bool get_brp_and_bitsize(
+ const uint32_t bitwidth,
+ uint16_t *const brp,
+ uint32_t *const tsegbitsize
+)
+{
+ bool hit = false;
+
+ while ( ( !hit ) && ( *brp < bitwidth / MIN_NUMBER_OF_CAN_BITS ) ) {
+ if ( ( is_divisor( bitwidth, *brp + CAN_BRP_EXTRA_BIT ) )
+ && ( get_tseg_bit_size( bitwidth, *brp ) < MAX_TSEG1_TSEG2_BITS ) ) {
+ hit = true;
+ *tsegbitsize = get_tseg_bit_size( bitwidth, *brp );
+ } else { /*Correct values not found, keep looking*/
+ ( *brp )++;
+ }
+ }
+
+ return hit;
+}
+
+/**
+ * @brief Constructs the btr register with the passed arguments.
+ *
+ * @param tsegbitsize The size tseg bits to set.
+ * @param psjw The sjw to set.
+ * @param brp The prescaler value to set.
+ * @return The constructed btr register.
+ */
+static inline uint32_t get_btr(
+ const uint32_t tsegbitsize,
+ const unsigned char psjw,
+ const uint32_t brp
+)
+{
+ const uint32_t tseg2_value_masked =
+ ( ( timing_pts[ tsegbitsize ][ CAN_TSEG2 ] << CAN_BTR_TSEG2_SHIFT ) &
+ CAN_BTR_TSEG2_MASK );
+ const uint32_t tseg1_value_masked =
+ ( ( timing_pts[ tsegbitsize ][ CAN_TSEG1 ] <<
+ CAN_BTR_TSEG1_SHIFT ) & CAN_BTR_TSEG1_MASK );
+ const uint32_t psjw_value_masked =
+ ( ( psjw << CAN_BTR_SJW_SHIFT ) & CAN_BTR_SJW_MASK );
+ const uint32_t brp_value_masked =
+ ( ( brp << CAN_BTR_BRP_SHIFT ) & CAN_BTR_BRP_MASK );
+
+ return tseg1_value_masked | tseg2_value_masked |
+ psjw_value_masked | brp_value_masked;
+}
+
+/**
+ * @brief Calculates and returns a bit timing register (btr) for the desired
+ * canclk frequency using the passed psjw, system clock and peripheral clock.
+ *
+ * @param systemclk The clock of the system (in Hz).
+ * @param pclkdiv The peripheral clock divisor for the can device.
+ * @param canclk The desired frequency for CAN (in Hz).
+ * @param psjw The desired psjw.
+ * @return The btr register value if found, WRONG_BTR_VALUE otherwise.
+ */
+static inline unsigned int can_speed(
+ const unsigned int systemclk,
+ const unsigned int pclkdiv,
+ const unsigned int canclk,
+ const unsigned char psjw
+)
+{
+ uint32_t btr = WRONG_BTR_VALUE;
+ const uint32_t bitwidth = systemclk / ( pclkdiv * canclk );
+
+ /* This is for the brp (prescaler) to start searching a reachable multiple.*/
+ uint16_t brp = bitwidth / MAX_NUMBER_OF_CAN_BITS;
+ uint32_t tsegbitsize;
+
+ if ( get_brp_and_bitsize( bitwidth, &brp, &tsegbitsize ) ) {
+ btr = get_btr( tsegbitsize, psjw, brp );
+ }
+
+ return btr;
+}
+
+/**
+ * @brief Configures the desired CAN device with the desired frequency.
+ *
+ * @param obj The can device to configure.
+ * @param f The desired frequency.
+ *
+ * @return RTEMS_SUCCESSFUL if could be set, RTEMS_INVALID_NUMBER otherwise.
+ */
+static rtems_status_code can_frequency(
+ const can_driver_entry *const obj,
+ const can_freq freq
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ const uint32_t btr = can_speed( LPC176X_CCLK, LPC176X_PCLKDIV, freq, 1 );
+
+ if ( btr != WRONG_BTR_VALUE ) {
+ sc = RTEMS_SUCCESSFUL;
+ uint32_t modmask = can_disable( obj );
+ obj->device->BTR = btr;
+ obj->device->MOD = modmask;
+ } /*else couldnt found a good timing for the desired frequency,
+ return RTEMS_INVALID_NUMBER.*/
+
+ return sc;
+}
+
+/**
+ * @brief Installs the interrupt handler in rtems.
+ */
+static inline rtems_status_code can_initialize( void )
+{
+ return rtems_interrupt_handler_install(
+ LPC176X_IRQ_CAN,
+ "can_interrupt",
+ RTEMS_INTERRUPT_UNIQUE,
+ can_isr,
+ NULL
+ );
+}
+
+rtems_status_code can_open( const lpc176x_can_number minor, can_freq freq )
+{
+ const can_driver_entry *const can_driver = &can_driver_table[ minor ];
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+
+ if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
+ /*Enable CAN and acceptance filter modules.*/
+ sc =
+ lpc176x_module_enable( can_driver->module, LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( sc, "enable can module" );
+ sc = lpc176x_module_enable( LPC176X_MODULE_ACCF,
+ LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( sc, "enable acceptance filter" );
+ /*Set pin functions.*/
+ setpins( minor );
+
+ can_reset( can_driver );
+ can_driver->device->IER = CAN_DEFAULT_INTERRUPT_CONFIGURATION;
+ sc = can_frequency( can_driver, freq );
+ RTEMS_CHECK_SC( sc, "Configure CAN frequency" );
+ can_initialize();
+
+ acceptance_filter_device->AFMR = CAN_ACCF_AFMR_ACCBP; /*Bypass Filter.*/
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Calls the installed isrs, according to the active interrupts.
+ *
+ * @param vector The read vector of active interrupts.
+ * @param number The CAN device to look for interruptions.
+ */
+static inline void call_isrs(
+ const uint32_t vector,
+ const lpc176x_can_number number
+)
+{
+ can_irq_type i;
+
+ for ( i = IRQ_RX; i < CAN_IRQ_NUMBER; ++i ) {
+ if ( ( isr_vector[ i ] != NULL ) && ( vector & ( 1 << i ) ) )
+ isr_vector[ i ]( number );
+
+ /* else this interrupt has not been raised or it hasn't got a handler,
+ so do nothing.*/
+ }
+}
+
+/**
+ * @brief Checks if the passed CAN device is enabled and if it is checks for
+ * active interrupts and calls its installed isr.
+ *
+ * @param number The CAN device to check for interrupts rised.
+ */
+static inline void search_and_call_int( const lpc176x_can_number number )
+{
+ const can_driver_entry *const driver = &can_driver_table[ number ];
+
+ if ( LPC176X_SCB.pconp & driver->pconp_pin ) {
+ /*We must read the whole register at once because it resets when read.*/
+ const uint32_t int_vector = driver->device->ICR & CAN_INTERRUPT_TYPE_MASK;
+ call_isrs( int_vector, number );
+ }
+
+ /*else the device is shut down so we must do nothing.*/
+}
+
+/**
+ * @brief The standard isr to be installed for all the CAN devices.
+ *
+ * @param arg unused.
+ */
+static void can_isr( void *arg )
+{
+ lpc176x_can_number i;
+
+ for ( i = CAN_0; i < CAN_DEVICES_NUMBER; ++i ) {
+ search_and_call_int( i );
+ }
+}
+
+rtems_status_code can_read(
+ const lpc176x_can_number minor,
+ can_message *message
+)
+{
+ rtems_status_code sc = RTEMS_IO_ERROR;
+ const can_driver_entry *const can_driver = &can_driver_table[ minor ];
+ can_device *const dev = can_driver->device;
+ registers_can_message *const msg = &( message->registers );
+
+ can_enable( can_driver );
+
+ if ( dev->GSR & CAN_GSR_RBS_MASK ) {
+ sc = RTEMS_SUCCESSFUL;
+ *msg = dev->receive;
+ dev->CMR = CAN_CMR_RRB_MASK; /* release receive buffer. */
+ } /* else Message not received.*/
+
+ return sc;
+}
+
+/**
+ * @brief Array of masks and control bits for the transmit buffers.
+ * It's used for each transmit buffer in order to see if it's available and to
+ * send data to them.
+ */
+static const can_transmit_info transmit_info[ CAN_NUMBER_OF_TRANSMIT_BUFFERS ]
+ =
+ {
+ {
+ .can_status_mask = 0x00000004U,
+ .not_cc_cmr_value = 0x21U
+ },
+ {
+ .can_status_mask = 0x00000400U,
+ .not_cc_cmr_value = 0x41U
+ },
+ {
+ .can_status_mask = 0x00040000U,
+ .not_cc_cmr_value = 0x81U
+ }
+ };
+
+rtems_status_code can_write(
+ const lpc176x_can_number minor,
+ const can_message *const message
+)
+{
+ const can_driver_entry *const can_driver = &can_driver_table[ minor ];
+ can_device *const obj = can_driver->device;
+ const uint32_t CANStatus = obj->SR;
+
+ const registers_can_message *const msg = &( message->registers );
+ rtems_status_code sc = RTEMS_IO_ERROR;
+ can_transmit_number transmit_buffer;
+
+ can_enable( can_driver );
+
+ for ( transmit_buffer = CAN_TRANSMIT1;
+ ( sc != RTEMS_SUCCESSFUL ) && ( transmit_buffer <
+ CAN_NUMBER_OF_TRANSMIT_BUFFERS );
+ ++transmit_buffer ) {
+ if ( CANStatus & transmit_info[ transmit_buffer ].can_status_mask ) {
+ sc = RTEMS_SUCCESSFUL;
+ obj->transmit[ transmit_buffer ] = *msg;
+ obj->CMR = transmit_info[ transmit_buffer ].not_cc_cmr_value;
+ } /*else can buffer busy, try with the next.*/
+ }
+
+ return sc;
+}
+
+/**
+ * @brief Enables the interrupt type passed to the desired CAN device.
+ *
+ * @param number The CAN device to enable the interrupts.
+ * @param type The type of interrupt to enable.
+ */
+static inline void can_enable_interrupt(
+ const lpc176x_can_number number,
+ const can_irq_type type
+)
+{
+ const can_driver_entry *const driver = &can_driver_table[ number ];
+ const uint32_t ier = 1 << type;
+
+ can_disable( driver );
+ driver->device->IER |= ier;
+ can_enable( driver );
+}
+
+rtems_status_code can_register_isr(
+ const lpc176x_can_number number,
+ const can_irq_type type,
+ const lpc176x_can_isr isr
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+
+ if ( ( 0 <= type ) && ( type < CAN_IRQ_NUMBER ) ) {
+ sc = RTEMS_SUCCESSFUL;
+ isr_vector[ type ] = isr;
+ can_enable_interrupt( number, type );
+ }
+
+ return sc;
+}
+
+rtems_status_code create_can_message(
+ can_message *const msg,
+ const int _id,
+ const char *const _data,
+ const char _len
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+
+ if ( ( _len <= CAN_MAXIMUM_DATA_SIZE ) && ( _id <= CAN10_MAXIMUM_ID ) ) {
+ sc = RTEMS_SUCCESSFUL;
+ msg->low_level.dlc = _len;
+ msg->low_level.type = CANStandard;
+ msg->low_level.rtr = CANData;
+ msg->low_level.id = _id;
+ memcpy( msg->low_level.data, _data, _len );
+ }
+
+ return sc;
+}
+
diff --git a/bsps/arm/lpc176x/gpio/lpc-gpio.c b/bsps/arm/lpc176x/gpio/lpc-gpio.c
new file mode 100644
index 0000000000..e7f07fe657
--- /dev/null
+++ b/bsps/arm/lpc176x/gpio/lpc-gpio.c
@@ -0,0 +1,392 @@
+/**
+ * @file lpc-gpio.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief GPIO library for the lpc176x bsp.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Boretto Martin (martin.boretto@tallertechnologies.com)
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <bsp/irq.h>
+#include <bsp/io.h>
+#include <bsp/lpc-gpio.h>
+#include <rtems/status-checks.h>
+
+static uint32_t function_vector_size = 0u;
+static lpc176x_registered_interrupt_function function_vector[
+ LPC176X_RESERVED_ISR_FUNCT_SIZE ];
+static bool isr_installed = false;
+
+rtems_status_code lpc176x_gpio_config(
+ const lpc176x_pin_number pin,
+ const lpc176x_gpio_direction dir
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( pin < LPC176X_MAX_PORT_NUMBER ) &&
+ ( dir < LPC176X_GPIO_FUNCTION_COUNT ) ) {
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
+ const uint32_t pin_of_port = LPC176X_IO_PORT_BIT( pin );
+
+ lpc176x_pin_select( pin, LPC176X_PIN_FUNCTION_00 );
+
+ LPC176X_SET_BIT( LPC176X_FIO[ port ].dir, pin_of_port, dir );
+
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the pin or the egde are out of range. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+/**
+ * @brief Check for a rising edge and call the interrupt function.
+ *
+ * @param statR Rising edge interrupt.
+ * @param pin The pin to check.
+ * @param registered_isr_function Interrupt to check.
+ * @return TRUE if is a rising edge. FALSE otherwise.
+ */
+static bool lpc176x_check_rising_edge_and_call(
+ const uint32_t statR,
+ const lpc176x_registered_interrupt_function registered_isr_function,
+ const uint32_t pin
+)
+{
+ bool is_rising = false;
+
+ if ( statR & LPC176X_PIN_BIT( pin ) ) {
+ registered_isr_function.function( registered_isr_function.pin,
+ LPC176X_GPIO_INTERRUPT_RISING );
+ is_rising = true;
+ }
+
+ /* else implies that the current interrupt is not STATR. Also,
+ there is nothing to do. */
+
+ return is_rising;
+}
+
+/**
+ * @brief Check for a falling edge and call the interrupt function.
+ *
+ * @param statR Falling edge interrupt.
+ * @param pin The pin to check.
+ * @param registered_isr_function Interrupt to check.
+ * @return TRUE if is a falling edge. FALSE otherwise.
+ */
+static bool lpc176x_check_falling_edge_and_call(
+ const uint32_t statF,
+ const lpc176x_registered_interrupt_function registered_isr_function,
+ const uint32_t pin
+)
+{
+ bool is_falling = false;
+
+ if ( statF & LPC176X_PIN_BIT( pin ) ) {
+ registered_isr_function.function( registered_isr_function.pin,
+ LPC176X_GPIO_INTERRUPT_FALLING );
+ is_falling = true;
+ }
+
+ /* else implies that the current interrupt is not STATF. Also,
+ there is nothing to do. */
+
+ return is_falling;
+}
+
+/**
+ * @brief Returns the interrupts base address according to the current port.
+ *
+ * @param port Input/Output port.
+ * @return Interrupt base address.
+ */
+static lpc176x_interrupt_control*lpc176x_get_interrupt_address(
+ const lpc176x_gpio_ports port )
+{
+ lpc176x_interrupt_control *interrupt;
+
+ switch ( port ) {
+ case ( LPC176X_GPIO_PORT_0 ):
+ interrupt = (lpc176x_interrupt_control *) LPC176X_IO0_INT_BASE_ADDRESS;
+ break;
+ case ( LPC176X_GPIO_PORT_2 ):
+ interrupt = (lpc176x_interrupt_control *) LPC176X_IO2_INT_BASE_ADDRESS;
+ break;
+ case ( LPC176X_GPIO_PORT_1 ):
+ case ( LPC176X_GPIO_PORT_3 ):
+ case ( LPC176X_GPIO_PORT_4 ):
+ default:
+ interrupt = NULL;
+ }
+
+ return interrupt;
+}
+
+/**
+ * @brief Checks the type of the current interrupt.
+ *
+ * @param registered_isr_function Interrupt to check.
+ */
+static void check_for_interrupt(
+ const lpc176x_registered_interrupt_function registered_isr_function )
+{
+ assert( registered_isr_function.pin < LPC176X_MAX_PORT_NUMBER );
+
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT(
+ registered_isr_function.pin );
+ const uint32_t pin = LPC176X_IO_PORT_BIT( registered_isr_function.pin );
+
+ lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
+ assert( interrupt != NULL );
+
+ bool is_rising_edge = lpc176x_check_rising_edge_and_call( interrupt->StatR,
+ registered_isr_function,
+ pin );
+
+ bool is_falling_edge = lpc176x_check_falling_edge_and_call( interrupt->StatF,
+ registered_isr_function,
+ pin );
+
+ if ( is_rising_edge || is_falling_edge ) {
+ interrupt->Clr = LPC176X_PIN_BIT( pin );
+ }
+
+ /* else implies that the current interrupt is not CLR. Also,
+ there is nothing to do. */
+}
+
+/**
+ * @brief Checks all interrupts types.
+ *
+ * @param arg Interrupt to check.
+ */
+static inline void lpc176x_gpio_isr( void *arg )
+{
+ unsigned int i;
+
+ for ( i = 0; i < function_vector_size; ++i ) {
+ check_for_interrupt( function_vector[ i ] );
+ }
+}
+
+/**
+ * @brief Depending of the current edge sets rising/falling interrupt.
+ *
+ * @param edge Current edge.
+ * @param pin_of_port Pin of the port to set the interrupt.
+ * @param interrupt To enable the falling o rising edge.
+ */
+static void lpc176x_set_falling_or_rising_interrupt(
+ const lpc176x_gpio_interrupt edge,
+ const uint32_t pin_of_port,
+ lpc176x_interrupt_control *interrupt
+)
+{
+ if ( edge & LPC176X_GPIO_INTERRUPT_RISING ) {
+ LPC176X_SET_BIT( interrupt->EnR, pin_of_port, LPC176X_INT_ENABLE );
+ }
+
+ /* else implies that it should not install the interrupt for a RISING edge.
+ Also, there is nothing to do. */
+
+ if ( edge & LPC176X_GPIO_INTERRUPT_FALLING ) {
+ LPC176X_SET_BIT( interrupt->EnF, pin_of_port, LPC176X_INT_ENABLE );
+ }
+
+ /* else implies that it should not install the interrupt for a FALLING edge.
+ Also, there is nothing to do. */
+}
+
+/**
+ * @brief Registers the pin and the callbacks functions.
+ *
+ * @param edge Current edge.
+ * @param pin The pin to configure.
+ * @param isr_funct Callback function to set.
+ */
+static void lpc176x_register_pin_and_callback(
+ const lpc176x_gpio_interrupt edge,
+ const lpc176x_pin_number pin,
+ const lpc176x_gpio_interrupt_function isr_funct
+)
+{
+ if ( edge ) {
+ assert( function_vector_size < LPC176X_RESERVED_ISR_FUNCT_SIZE );
+ function_vector[ function_vector_size ].function = isr_funct;
+ function_vector[ function_vector_size ].pin = pin;
+ ++function_vector_size;
+ }
+
+ /* else implies that the current interrupt is DISABLED or BOTH. Also,
+ there is nothing to do. */
+}
+
+/**
+ * @brief Installs the interrupt handler.
+ *
+ * @param edge Which edge enable.
+ * @return RTEMS_SUCCESSFUL if the installation was success.
+ */
+static rtems_status_code lpc176x_install_interrupt_handler(
+ const lpc176x_gpio_interrupt edge )
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+
+ if ( !isr_installed && edge ) {
+ status_code = rtems_interrupt_handler_install( LPC176X_IRQ_EINT_3,
+ "gpio_interrupt",
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc176x_gpio_isr,
+ NULL );
+ isr_installed = true;
+ }
+
+ /* else implies that the interrupts have been previously installed. Also,
+ there is nothing to do. */
+
+ return status_code;
+}
+
+/**
+ * @brief Configures the pin as input, enables interrupt for an
+ * edge/s and sets isrfunct as the function to call when that
+ * interrupt occurs.
+ *
+ * @param pin The pin to configure.
+ * @param edge Which edge or edges will activate the interrupt.
+ * @param isrfunct The function that is called when the interrupt occurs.
+ * @return RTEMS_SUCCESSFUL if the configuration was success.
+ */
+static rtems_status_code lpc176x_check_edge_and_set_gpio_interrupts(
+ const lpc176x_pin_number pin,
+ const lpc176x_gpio_interrupt edge,
+ const lpc176x_gpio_interrupt_function isr_funct
+)
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
+ const uint32_t pin_of_port = LPC176X_IO_PORT_BIT( pin );
+
+ lpc176x_interrupt_control *interrupt = lpc176x_get_interrupt_address( port );
+
+ assert( interrupt != NULL );
+
+ lpc176x_gpio_config( pin, LPC176X_GPIO_FUNCTION_INPUT );
+
+ lpc176x_set_falling_or_rising_interrupt( edge, pin_of_port, interrupt );
+
+ lpc176x_register_pin_and_callback( edge, pin, isr_funct );
+
+ status_code = lpc176x_install_interrupt_handler( edge );
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_gpio_config_input_with_interrupt(
+ const lpc176x_pin_number pin,
+ const lpc176x_gpio_interrupt edge,
+ const lpc176x_gpio_interrupt_function isr_funct
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( pin < LPC176X_MAX_PORT_NUMBER )
+ && ( edge < LPC176X_GPIO_INTERRUPT_COUNT ) ) {
+ status_code = lpc176x_check_edge_and_set_gpio_interrupts( pin,
+ edge,
+ isr_funct );
+ }
+
+ /* else implies that the pin or the egde are out of range. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_gpio_set_pin( const lpc176x_pin_number pin )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( pin < LPC176X_MAX_PORT_NUMBER ) {
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
+ const uint32_t pin_of_port = LPC176X_IO_PORT_BIT( pin );
+
+ LPC176X_FIO[ port ].set = LPC176X_PIN_BIT( pin_of_port );
+
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the pin or the egde are out of range. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_gpio_clear_pin( const lpc176x_pin_number pin )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( pin < LPC176X_MAX_PORT_NUMBER ) {
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
+ const uint32_t pin_of_port = LPC176X_IO_PORT_BIT( pin );
+
+ LPC176X_FIO[ port ].clr = LPC176X_PIN_BIT( pin_of_port );
+
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the pin or the egde are out of range. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_gpio_write_pin(
+ const lpc176x_pin_number pin,
+ const bool value
+)
+{
+ rtems_status_code status_code;
+
+ if ( value ) {
+ status_code = lpc176x_gpio_set_pin( pin );
+ } else {
+ status_code = lpc176x_gpio_clear_pin( pin );
+ }
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_gpio_get_pin_value(
+ const lpc176x_pin_number pin,
+ bool *pin_value
+)
+{
+ assert( pin < LPC176X_MAX_PORT_NUMBER );
+
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+
+ const lpc176x_gpio_ports port = LPC176X_IO_PORT( pin );
+ const uint32_t pin_of_port = LPC176X_IO_PORT_BIT( pin );
+ *pin_value = ( LPC176X_FIO[ port ].pin & LPC176X_PIN_BIT( pin_of_port ) );
+
+ return status_code;
+}
diff --git a/bsps/arm/lpc176x/pwm/pwmout.c b/bsps/arm/lpc176x/pwm/pwmout.c
new file mode 100755
index 0000000000..dc30475f89
--- /dev/null
+++ b/bsps/arm/lpc176x/pwm/pwmout.c
@@ -0,0 +1,211 @@
+/**
+ * @file pwmout.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief PWM-Out controller for the mbed lpc1768 board.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/status-checks.h>
+#include <bsp/pwmout.h>
+#include <bsp/pwmout-defs.h>
+
+/**
+ * @brief The low level device.
+ */
+static lpc176x_pwm_device *const pwm_device =
+ (lpc176x_pwm_device *) PWM1_BASE_ADDR;
+
+/**
+ * @brief The possible output pins for each PWM output.
+ */
+static const lpc176x_pwm_pin pwm_pins[ PWM_OUTPUT_NUMBER ][ PWM_NUMBER_OF_PINS
+] =
+{
+ { { 50u, LPC176X_PIN_FUNCTION_10 }, { 64u, LPC176X_PIN_FUNCTION_01 } },
+ { { 52u, LPC176X_PIN_FUNCTION_10 }, { 65u, LPC176X_PIN_FUNCTION_01 } },
+ { { 53u, LPC176X_PIN_FUNCTION_10 }, { 66u, LPC176X_PIN_FUNCTION_01 } },
+ { { 55u, LPC176X_PIN_FUNCTION_10 }, { 67u, LPC176X_PIN_FUNCTION_01 } },
+ { { 56u, LPC176X_PIN_FUNCTION_10 }, { 68u, LPC176X_PIN_FUNCTION_01 } },
+ { { 58u, LPC176X_PIN_FUNCTION_10 }, { 69u, LPC176X_PIN_FUNCTION_01 } },
+};
+
+/**
+ * @brief The pointers to the low level match registers for each PWM output.
+ */
+static volatile uint32_t *const pwm_match[ PWM_OUTPUT_NUMBER ] = {
+ &PWM1MR1,
+ &PWM1MR2,
+ &PWM1MR3,
+ &PWM1MR4,
+ &PWM1MR5,
+ &PWM1MR6
+};
+
+/**
+ * @brief Checks if a pin number is valid for the given PWM,
+ * and sets the corresponding pin function for that pin.
+ *
+ * @param pin_number The pin number to search.
+ * @param pwm In which PWM search for the pin number.
+ * @param pin_function If the pin number is found, here we return
+ * the pin function for that pin number.
+ * @return True if found, false otherwise.
+ */
+static inline bool is_found_in_this_pwm(
+ const lpc176x_pin_number pin_number,
+ const lpc176x_pwm_number pwm,
+ lpc176x_pin_function *const pin_function
+)
+{
+ lpc176x_pwm_pin_number pnumber = PWM_FIRST_PIN;
+ bool found = false;
+
+ while (!found && ( pnumber < PWM_NUMBER_OF_PINS ))
+ {
+ if ( pwm_pins[ pwm ][ pnumber ].pin_number == pin_number ) {
+ found = true;
+ *pin_function = pwm_pins[ pwm ][ pnumber ].pin_function;
+ }/*else implies that the pin number was not found. Keep looking.*/
+ ++pnumber;
+ }
+ return found;
+}
+
+/**
+ * @brief Checks if a pin number is valid for any PWM,
+ * and sets the corresponding pin function for that pin.
+ *
+ * @param pin_number The pin number to search.
+ * @param pwm If is found here we return in which PWM was found.
+ * @param pin_function If the pin number is found the pin function
+ * for this pin number one will be returned.
+ * @return True if found, false otherwise.
+ */
+static bool is_valid_pin_number(
+ const lpc176x_pin_number pin_number,
+ lpc176x_pwm_number *const pwm,
+ lpc176x_pin_function *const pin_function
+)
+{
+ bool found = false;
+ lpc176x_pwm_number pwm_local = PWMO_1;
+ while(!found && ( pwm_local < PWM_OUTPUT_NUMBER ))
+ {
+ if ( is_found_in_this_pwm( pin_number, pwm_local, pin_function ) ) {
+ *pwm = pwm_local;
+ found = true;
+ } /*else implies that the pin number was not found. Keep looking.*/
+ ++pwm_local;
+ }
+
+ return found;
+}
+
+/**
+ * @brief Sets the period for the given PWM.
+ *
+ * @param pwm The PWM output in which the period will be set.
+ * @param period The period to set.
+ */
+static void set_period(
+ const lpc176x_pwm_number pwm,
+ const lpc176x_microseconds period
+)
+{
+ pwm_device->TCR = PWM_TCR_RESET;
+ pwm_device->MR0 = period * PWM_PRESCALER_USECOND;
+ pwm_device->LER |= PWM_LER_LATCH_MATCH_0;
+ pwm_device->TCR = PWM_TCR_PWM | PWM_TCR_ENABLE;
+}
+
+/**
+ * @brief Sets the pulsewidth for the given PWM.
+ *
+ * @param pwm The PWM output in which the pulsewidth will be set.
+ * @param pwidth The pulse width to set.
+ */
+static void set_pulsewidth(
+ const lpc176x_pwm_number pwm,
+ lpc176x_microseconds pwidth
+)
+{
+ pwidth *= PWM_PRESCALER_USECOND;
+
+ if ( pwm_device->MR0 == pwidth ) {
+ ++pwidth;
+ } /* Not the same as the period, do nothing.*/
+
+ *( pwm_match[ pwm ] ) = pwidth;
+ pwm_device->LER |= PWM_LER_LATCH( pwm );
+}
+
+rtems_status_code pwm_init( const lpc176x_pin_number pin_number )
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ lpc176x_pin_function pin_function;
+ lpc176x_pwm_number pwm;
+
+ if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
+ sc = lpc176x_module_enable( LPC176X_MODULE_PWM_1,
+ LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( sc, "enable pwm module" );
+
+ pwm_device->PR = 0;
+ pwm_device->MCR = PWM_MCR_RESET_ON_MATCH0;
+ pwm_device->PCR |= PWM_PCR_ENABLE_PWM( pwm );
+
+ set_period( pwm, PWM_DEFAULT_PERIOD );
+ set_pulsewidth( pwm, PWM_DEFAULT_PULSEWIDTH );
+
+ lpc176x_pin_select( pin_number, pin_function );
+ } /* else implies that the pin number is not valid.
+ So, a RTEMS_INVALID_NUMBER will be returned.*/
+
+ return sc;
+}
+
+rtems_status_code pwm_period(
+ const lpc176x_pin_number pin_number,
+ const lpc176x_microseconds period
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ lpc176x_pin_function pin_function;
+ lpc176x_pwm_number pwm;
+
+ if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
+ sc = RTEMS_SUCCESSFUL;
+ set_period( pwm, period );
+ } /* else implies that the pin number is not valid.
+ So, a RTEMS_INVALID_NUMBER will be returned.*/
+
+ return sc;
+}
+
+rtems_status_code pwm_pulsewidth(
+ const lpc176x_pin_number pin_number,
+ const lpc176x_microseconds pwidth
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ lpc176x_pin_function pin_function;
+ lpc176x_pwm_number pwm;
+
+ if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
+ sc = RTEMS_SUCCESSFUL;
+ set_pulsewidth( pwm, pwidth );
+ } /* Else wrong pin_number return RTEMS_INVALID_NUMBER*/
+
+ return sc;
+}
diff --git a/bsps/arm/lpc176x/start/adc.c b/bsps/arm/lpc176x/start/adc.c
new file mode 100755
index 0000000000..7098166718
--- /dev/null
+++ b/bsps/arm/lpc176x/start/adc.c
@@ -0,0 +1,245 @@
+/**
+ * @file adc.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief ADC library for the lpc176x bsp.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+#include <rtems/status-checks.h>
+#include <bsp/adc.h>
+#include <bsp/adc-defs.h>
+
+static lpc176x_adc_device *const adc_device =
+ (lpc176x_adc_device *) AD0_BASE_ADDR;
+
+static const lpc176x_adc_pin_map adc_pinmap[ ADC_DEVICES_COUNT ] =
+{
+ {
+ .pin_number = 23u,
+ .pin_function = LPC176X_PIN_FUNCTION_01
+ },
+ {
+ .pin_number = 24u,
+ .pin_function = LPC176X_PIN_FUNCTION_01
+ },
+ {
+ .pin_number = 25u,
+ .pin_function = LPC176X_PIN_FUNCTION_01
+ },
+ {
+ .pin_number = 26u,
+ .pin_function = LPC176X_PIN_FUNCTION_01
+ },
+ {
+ .pin_number = 62u,
+ .pin_function = LPC176X_PIN_FUNCTION_11
+ },
+ {
+ .pin_number = 63u,
+ .pin_function = LPC176X_PIN_FUNCTION_11
+ },
+ {
+ .pin_number = 3u,
+ .pin_function = LPC176X_PIN_FUNCTION_10
+ },
+ {
+ .pin_number = 2u,
+ .pin_function = LPC176X_PIN_FUNCTION_10
+ }
+};
+
+/**
+ * @brief Checks for a valid pin number for an ADC
+ *
+ * @param pin_number The pin to check
+ * @param adc_number The returned ADC device corresponding to that pin.
+ *
+ * @return true if valid, false otherwise.
+ */
+static bool valid_pin_number (
+ const lpc176x_pin_number pin_number,
+ lpc176x_adc_number *const adc_number
+ )
+{
+ bool found = false;
+ lpc176x_adc_number adc_device = ADC_0;
+
+ while (!found && (adc_device < ADC_DEVICES_COUNT))
+ {
+ if (adc_pinmap[adc_device].pin_number == pin_number)
+ {
+ *adc_number = adc_device;
+ found = true;
+ }
+ ++adc_device;
+ }
+
+ return found;
+}
+
+/**
+ * @brief Turns on the device and sets its clock divisor.
+ *
+ */
+static void turn_on_and_set_clkdiv( void )
+{
+ const uint32_t clkdiv = LPC176X_CCLK / ( LPC176X_PCLKDIV * MAX_ADC_CLK );
+
+ adc_device->ADCR = ADC_CR_PDN | ADC_CR_CLKDIV( clkdiv );
+}
+
+rtems_status_code adc_open( const lpc176x_pin_number pin_number )
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ lpc176x_adc_number adc_number = 0;
+ if ( valid_pin_number( pin_number, &adc_number ) ) {
+ sc =
+ lpc176x_module_enable( LPC176X_MODULE_ADC, LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( sc, "enable adc module" );
+
+ turn_on_and_set_clkdiv();
+ lpc176x_pin_select( adc_pinmap[ adc_number ].pin_number,
+ adc_pinmap[ adc_number ].pin_function );
+ lpc176x_pin_set_mode( adc_pinmap[ adc_number ].pin_number,
+ LPC176X_PIN_MODE_NONE );
+ }
+
+ return sc;
+}
+
+rtems_status_code adc_close( void )
+{
+ adc_device->ADCR &= ~ADC_CR_PDN;
+
+ return lpc176x_module_disable( LPC176X_MODULE_ADC );
+}
+
+/**
+ * @brief Starts the conversion for the given channel.
+ *
+ * @param number The channel to start the conversion.
+ */
+static inline void start_conversion( const lpc176x_adc_number number )
+{
+ adc_device->ADCR =
+ ADC_CR_SEL_SET( adc_device->ADCR, ( 1 << number ) ) | ADC_CR_START_NOW;
+}
+
+/**
+ * @brief Stops the conversion.
+ *
+ */
+static inline void stop_conversion( void )
+{
+ adc_device->ADCR &= ~ADC_CR_START_NOW;
+}
+
+/**
+ * @brief Gets float percentage of the result of a conversion.
+ *
+ * @param data The result of a conversion.
+ * @return A float percentage (between 0.0f and 1.0f).
+ */
+static inline float get_float( const uint32_t data )
+{
+ return ( (float) data / (float) ADC_RANGE );
+}
+
+
+/**
+ * @brief Reads the ADC value for the given ADC number.
+ *
+ * @param adc_number Which ADC device read.
+ * @return The read value.
+ */
+static uint32_t read( const lpc176x_adc_number adc_number )
+{
+ uint32_t data;
+
+ start_conversion( adc_number );
+
+ do {
+ data = adc_device->ADGDR;
+ } while ( !ADC_DATA_CONVERSION_DONE( data ) );
+
+ stop_conversion();
+
+ return ADC_DR_VALUE( data );
+}
+
+/**
+ * @brief Checks if the passed parameters are ordered from lowest
+ * to highest.
+ *
+ * @param a The suggested lowest value.
+ * @param b The suggested middle value.
+ * @param c The suggested highest value.
+ * @return True if it is in the right order, false otherwise.
+ */
+static inline bool lowest_to_highest_ordered(
+ const uint32_t a,
+ const uint32_t b,
+ const uint32_t c
+)
+{
+ return ( ( a <= b ) && ( b <= c ) );
+}
+
+/**
+ * @brief Gets median value from the three passed parameters.
+ *
+ * @param a The first parameter.
+ * @param b The second parameter.
+ * @param c The third parameter.
+ *
+ * @return The median of the three parameters.
+ */
+static uint32_t get_median(
+ const uint32_t a,
+ const uint32_t b,
+ const uint32_t c
+)
+{
+ uint32_t median;
+
+ if ( lowest_to_highest_ordered( a, b, c)
+ || lowest_to_highest_ordered( c, b, a ) ) {
+ median = b;
+ } else if ( lowest_to_highest_ordered( b, a, c )
+ || lowest_to_highest_ordered( c, a, b ) ) {
+ median = a;
+ } else {
+ median = c;
+ }
+
+ return median;
+}
+
+rtems_status_code adc_read(
+ const lpc176x_pin_number pin_number ,
+ float *const result
+)
+{
+ rtems_status_code sc = RTEMS_INVALID_NUMBER;
+ lpc176x_adc_number adc_number = 0;
+ if ( valid_pin_number( pin_number, &adc_number ) ) {
+ const uint32_t first = read( adc_number );
+ const uint32_t second = read( adc_number );
+ const uint32_t third = read( adc_number );
+ const uint32_t median = get_median( first, second, third );
+ *result = get_float( median );
+ sc = RTEMS_SUCCESSFUL;
+ }
+
+ return sc;
+}
diff --git a/bsps/arm/lpc176x/start/bspidle.c b/bsps/arm/lpc176x/start/bspidle.c
new file mode 100644
index 0000000000..24bb1db887
--- /dev/null
+++ b/bsps/arm/lpc176x/start/bspidle.c
@@ -0,0 +1,30 @@
+/**
+ * @file
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Idle task.
+ */
+
+/*
+ * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/lpc176x.h>
+
+void*bsp_idle_thread( const uintptr_t ignored )
+{
+ while ( true ) {
+ }
+}
diff --git a/bsps/arm/lpc176x/start/dma-copy.c b/bsps/arm/lpc176x/start/dma-copy.c
new file mode 100644
index 0000000000..0e0b37dbd3
--- /dev/null
+++ b/bsps/arm/lpc176x/start/dma-copy.c
@@ -0,0 +1,220 @@
+/**
+ * @file
+ *
+ * @ingroup lpc176x_dma
+ *
+ * @brief Direct memory access (DMA) support.
+ */
+
+/*
+ * Copyright (c) 2008, 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp/lpc176x.h>
+#include <bsp/dma.h>
+#include <bsp/irq.h>
+
+static rtems_id lpc176x_dma_sema_table[ GPDMA_CH_NUMBER ];
+static bool lpc176x_dma_status_table[ GPDMA_CH_NUMBER ];
+
+static void lpc176x_dma_copy_handler( void *arg )
+{
+ /* Get interrupt status */
+ uint32_t tc = GPDMA_INT_TCSTAT;
+ uint32_t err = GPDMA_INT_ERR_STAT;
+
+ /* Clear interrupt status */
+ GPDMA_INT_TCCLR = tc;
+ GPDMA_INT_ERR_CLR = err;
+
+ if ( ( tc & GPDMA_STATUS_CH_0 ) != 0 ) {
+ rtems_semaphore_release( lpc176x_dma_sema_table[ 0 ] );
+ }
+
+ /* else implies that the channel is not the 0. Also,
+ there is nothing to do. */
+
+ lpc176x_dma_status_table[ 0 ] = ( err & GPDMA_STATUS_CH_0 ) == 0;
+
+ if ( ( tc & GPDMA_STATUS_CH_1 ) != 0 ) {
+ rtems_semaphore_release( lpc176x_dma_sema_table[ 1 ] );
+ }
+
+ /* else implies that the channel is not the 1. Also,
+ there is nothing to do. */
+
+ lpc176x_dma_status_table[ 1 ] = ( err & GPDMA_STATUS_CH_1 ) == 0;
+}
+
+rtems_status_code lpc176x_dma_copy_initialize( void )
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+ rtems_id id0 = RTEMS_ID_NONE;
+ rtems_id id1 = RTEMS_ID_NONE;
+
+ /* Create semaphore for channel 0 */
+ status_code = rtems_semaphore_create( rtems_build_name( 'D', 'M', 'A', '0' ),
+ 0,
+ RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &id0 );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ return status_code;
+ }
+
+ /* else implies that the semaphore to the channel 0 was created succefully.
+ Also, there is nothing to do. */
+
+ /* Create semaphore for channel 1 */
+ status_code = rtems_semaphore_create( rtems_build_name( 'D', 'M', 'A', '1' ),
+ 0,
+ RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE,
+ 0,
+ &id1 );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ rtems_semaphore_delete( id0 );
+
+ return status_code;
+ }
+
+ /* else implies that the semaphore to the channel 1 was created succefully.
+ Also, there is nothing to do. */
+
+ /* Install DMA interrupt handler */
+ status_code = rtems_interrupt_handler_install( LPC176X_IRQ_DMA,
+ "DMA copy",
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc176x_dma_copy_handler,
+ NULL );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ rtems_semaphore_delete( id0 );
+ rtems_semaphore_delete( id1 );
+
+ return status_code;
+ }
+
+ /* else implies that the interrupt handler was installed succefully. Also,
+ there is nothing to do. */
+
+ /* Initialize global data */
+ lpc176x_dma_sema_table[ 0 ] = id0;
+ lpc176x_dma_sema_table[ 1 ] = id1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code lpc176x_dma_copy_release( void )
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+ rtems_status_code status_code_aux = RTEMS_SUCCESSFUL;
+
+ status_code = rtems_interrupt_handler_remove( LPC176X_IRQ_DMA,
+ lpc176x_dma_copy_handler,
+ NULL );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ status_code_aux = status_code;
+ }
+
+ /* else implies that the interrupt handler was removed succefully. Also,
+ there is nothing to do. */
+
+ status_code = rtems_semaphore_delete( lpc176x_dma_sema_table[ 0 ] );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ status_code_aux = status_code;
+ }
+
+ /* else implies that the semaphore to the channel 0 was deleted succefully.
+ Also, there is nothing to do. */
+
+ status_code = rtems_semaphore_delete( lpc176x_dma_sema_table[ 1 ] );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ status_code_aux = status_code;
+ }
+
+ /* else implies that the semaphore to the channel 1 was deleted succefully.
+ Also, there is nothing to do. */
+
+ return status_code_aux;
+}
+
+rtems_status_code lpc176x_dma_copy(
+ unsigned channel,
+ const void *const dest,
+ const void *const src,
+ size_t n,
+ const size_t width
+)
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+ volatile lpc176x_dma_channel *e = GPDMA_CH_BASE_ADDR( channel );
+ uint32_t w = GPDMA_CH_CTRL_W_8;
+
+ switch ( width ) {
+ case 4:
+ w = GPDMA_CH_CTRL_W_32;
+ break;
+ case 2:
+ w = GPDMA_CH_CTRL_W_16;
+ break;
+ }
+
+ n = n >> w;
+
+ if ( n > 0 && n < 4096 ) {
+ e->desc.src = (uint32_t) src;
+ e->desc.dest = (uint32_t) dest;
+ e->desc.lli = 0;
+ e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ( 0, n ) |
+ SET_GPDMA_CH_CTRL_SBSZ( 0, GPDMA_CH_CTRL_BSZ_1 ) |
+ SET_GPDMA_CH_CTRL_DBSZ( 0, GPDMA_CH_CTRL_BSZ_1 ) |
+ SET_GPDMA_CH_CTRL_SW( 0, w ) |
+ SET_GPDMA_CH_CTRL_DW( 0, w ) |
+ GPDMA_CH_CTRL_ITC |
+ GPDMA_CH_CTRL_SI |
+ GPDMA_CH_CTRL_DI;
+ e->cfg = SET_GPDMA_CH_CFG_FLOW( 0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA ) |
+ GPDMA_CH_CFG_IE |
+ GPDMA_CH_CFG_ITC |
+ GPDMA_CH_CFG_EN;
+ } else {
+ status_code = RTEMS_INVALID_SIZE;
+ }
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_dma_copy_wait( const unsigned channel )
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+
+ status_code = rtems_semaphore_obtain( lpc176x_dma_sema_table[ channel ],
+ RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT );
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ return status_code;
+ }
+
+ /* else implies that the semaphore was obtained succefully. Also,
+ there is nothing to do. */
+
+ status_code = lpc176x_dma_status_table[ channel ]
+ ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
+
+ return status_code;
+}
diff --git a/bsps/arm/lpc176x/start/dma.c b/bsps/arm/lpc176x/start/dma.c
new file mode 100644
index 0000000000..10c7701484
--- /dev/null
+++ b/bsps/arm/lpc176x/start/dma.c
@@ -0,0 +1,117 @@
+/**
+ * @file
+ *
+ * @ingroup lpc176x_dma
+ *
+ * @brief Direct memory access (DMA) support.
+ */
+
+/*
+ * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/endian.h>
+#include <bsp/dma.h>
+#include <bsp/io.h>
+
+/**
+ * @brief Table that indicates if a channel is currently occupied.
+ */
+static bool lpc176x_dma_channel_occupation[ GPDMA_CH_NUMBER ];
+
+void lpc176x_dma_initialize( void )
+{
+ /* Enable module power */
+ lpc176x_module_enable( LPC176X_MODULE_GPDMA, LPC176X_MODULE_PCLK_DEFAULT );
+
+ /* Disable module */
+ GPDMA_CONFIG = 0u;
+
+ /* Reset registers */
+ GPDMA_SOFT_SREQ = 0u;
+ GPDMA_SOFT_BREQ = 0u;
+ GPDMA_SOFT_LSREQ = 0u;
+ GPDMA_SOFT_LBREQ = 0u;
+ GPDMA_SYNC = 0u;
+ GPDMA_CH0_CFG = 0u;
+ GPDMA_CH1_CFG = 0u;
+
+ /* Enable module */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ GPDMA_CONFIG = GPDMA_CONFIG_EN;
+#else
+ GPDMA_CONFIG = GPDMA_CONFIG_EN | GPDMA_CONFIG_MODE;
+#endif
+}
+
+rtems_status_code lpc176x_dma_channel_obtain( const unsigned channel )
+{
+ rtems_status_code status_code = RTEMS_INVALID_ID;
+
+ if ( channel < GPDMA_CH_NUMBER ) {
+ rtems_interrupt_level level = 0u;
+ bool occupation = true;
+
+ rtems_interrupt_disable( level );
+ occupation = lpc176x_dma_channel_occupation[ channel ];
+ lpc176x_dma_channel_occupation[ channel ] = true;
+ rtems_interrupt_enable( level );
+
+ status_code = occupation ? RTEMS_RESOURCE_IN_USE : RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the channel is not valid. Also,
+ there is nothing to do. */
+
+ return status_code;
+}
+
+void lpc176x_dma_channel_release( const unsigned channel )
+{
+ if ( channel < GPDMA_CH_NUMBER ) {
+ lpc176x_dma_channel_occupation[ channel ] = false;
+ }
+
+ /* else implies that the channel is not valid. Also,
+ there is nothing to do. */
+}
+
+void lpc176x_dma_channel_disable(
+ const unsigned channel,
+ const bool force
+)
+{
+ if ( channel < GPDMA_CH_NUMBER ) {
+ volatile lpc176x_dma_channel *ch = GPDMA_CH_BASE_ADDR( channel );
+ uint32_t cfg = ch->cfg;
+
+ if ( !force ) {
+ /* Halt */
+ ch->cfg |= GPDMA_CH_CFG_HALT;
+
+ /* Wait for inactive */
+ do {
+ cfg = ch->cfg;
+ } while ( ( cfg & GPDMA_CH_CFG_ACTIVE ) != 0u );
+ }
+
+ /* else implies that the channel is not to be forced. Also,
+ there is nothing to do. */
+
+ /* Disable */
+ ch->cfg &= ~GPDMA_CH_CFG_EN;
+ }
+
+ /* else implies that the channel is not valid. Also,
+ there is nothing to do. */
+}
diff --git a/bsps/arm/lpc176x/start/io.c b/bsps/arm/lpc176x/start/io.c
new file mode 100644
index 0000000000..c25fe94c0b
--- /dev/null
+++ b/bsps/arm/lpc176x/start/io.c
@@ -0,0 +1,349 @@
+/**
+ * @file io.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Input/output module methods.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Boretto Martin (martin.boretto@tallertechnologies.com)
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems/status-checks.h>
+#include <bsp.h>
+#include <bsp/io.h>
+#include <bsp/start.h>
+#include <bsp/system-clocks.h>
+
+/**
+ * @brief Modules table according to the LPC176x
+ */
+static const lpc176x_module_entry lpc176x_module_table[] = {
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_WD, 0, 1, 0 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_ADC, 1, 1, 12 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_0, 1, 1, 13 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_1, 1, 1, 14 ),
+ LPC176X_MODULE_ENTRY(LPC176X_MODULE_ACCF, 0, 1, 15),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_DAC, 0, 1, 11 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPDMA, 1, 1, 29 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPIO, 0, 1, 15 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_I2S, 1, 1, 27 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_MCI, 1, 1, 28 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_MCPWM, 1, 1, 17 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_PCB, 0, 1, 18 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_PWM_0, 1, 1, 5 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_PWM_1, 1, 1, 6 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_QEI, 1, 1, 18 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_RTC, 1, 1, 9 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_SYSCON, 0, 1, 30 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_0, 1, 1, 1 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_1, 1, 1, 2 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_2, 1, 1, 22 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_TIMER_3, 1, 1, 23 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_0, 1, 1, 3 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_1, 1, 1, 4 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_2, 1, 1, 24 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_UART_3, 1, 1, 25 ),
+ LPC176X_MODULE_ENTRY( LPC176X_MODULE_USB, 1, 0, 31 )
+};
+
+inline void lpc176x_pin_select(
+ const uint32_t pin,
+ const lpc176x_pin_function function
+)
+{
+ assert( pin <= LPC176X_IO_INDEX_MAX
+ && function < LPC176X_PIN_FUNCTION_COUNT );
+ const uint32_t pin_selected = LPC176X_PIN_SELECT( pin );
+ volatile uint32_t *const pinsel = &LPC176X_PINSEL[ pin_selected ];
+ const uint32_t shift = LPC176X_PIN_SELECT_SHIFT( pin );
+ *pinsel = SET_FIELD( *pinsel, function,
+ LPC176X_PIN_SELECT_MASK << shift, shift );
+}
+
+void lpc176x_pin_set_mode(
+ const uint32_t pin,
+ const lpc176x_pin_mode mode
+)
+{
+ assert( pin <= LPC176X_IO_INDEX_MAX
+ && mode < LPC176X_PIN_MODE_COUNT );
+ const uint32_t pin_selected = LPC176X_PIN_SELECT( pin );
+ volatile uint32_t *const pinmode = &LPC176X_PINMODE[ pin_selected ];
+ const uint32_t shift = LPC176X_PIN_SELECT_SHIFT( pin );
+ *pinmode = SET_FIELD( *pinmode, mode,
+ LPC176X_PIN_SELECT_MASK << shift, shift );
+}
+
+/**
+ * @brief Checks if the module has power.
+ *
+ * @param has_power Power.
+ * @param index Index to shift.
+ * @param turn_on Turn on/off the power.
+ * @param level Interrupts value.
+ */
+static rtems_status_code check_power(
+ const bool has_power,
+ const unsigned index,
+ const bool turn_on,
+ rtems_interrupt_level level
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( index <= LPC176X_MODULE_BITS_COUNT ) {
+ if ( has_power ) {
+ rtems_interrupt_disable( level );
+
+ if ( turn_on ) {
+ LPC176X_SCB.pconp |= 1u << index;
+ } else {
+ LPC176X_SCB.pconp &= ~( 1u << index );
+ }
+
+ rtems_interrupt_enable( level );
+ }
+
+ /* else implies that the module has not power. Also,
+ there is nothing to do. */
+
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies an invalid index number. Also, the function
+ does not return successful. */
+
+ return status_code;
+}
+
+/**
+ * @brief Sets the correct value according to the specific peripheral clock.
+ *
+ * @param is_first_pclksel Represents the first pclksel.
+ * @param clock The clock to set for this module.
+ * @param clock_shift Value to clock shift.
+ */
+static inline void set_pclksel_value(
+ const uint32_t pclksel,
+ const lpc176x_module_clock clock,
+ const unsigned clock_shift
+)
+{
+ assert( pclksel < LPC176X_SCB_PCLKSEL_COUNT );
+ const uint32_t setclock = ( clock << clock_shift );
+ const uint32_t mask = ~( LPC176X_MODULE_CLOCK_MASK << clock_shift );
+ LPC176X_SCB.pclksel[ pclksel ] = ( LPC176X_SCB.pclksel[ pclksel ] & mask ) |
+ setclock;
+}
+
+/**
+ * @brief Checks if the module has clock.
+ *
+ * @param has_clock Clock.
+ * @param index Index to shift.
+ * @param clock The clock to set for this module.
+ * @param level Interrupts value.
+ */
+static rtems_status_code check_clock(
+ const bool has_clock,
+ const unsigned index,
+ const lpc176x_module_clock clock,
+ rtems_interrupt_level level
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( index <= LPC176X_MODULE_BITS_COUNT ) {
+ if ( has_clock ) {
+ unsigned clock_shift = 2u * index;
+ rtems_interrupt_disable( level );
+
+ if ( clock_shift < LPC176X_MODULE_BITS_COUNT ) {
+ /* Sets the pclksel 0. */
+ set_pclksel_value( LPC176X_SCB_PCLKSEL0, clock, clock_shift );
+ } else {
+ /* Sets the pclksel 1. */
+ clock_shift -= LPC176X_MODULE_BITS_COUNT;
+ set_pclksel_value( LPC176X_SCB_PCLKSEL1, clock, clock_shift );
+ }
+
+ rtems_interrupt_enable( level );
+ }
+
+ /* else implies that the module has not clock. Also,
+ there is nothing to do. */
+
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies an invalid index number. Also, the function
+ does not return successful. */
+
+ return status_code;
+}
+
+/**
+ * @brief Checks the usb module.
+ *
+ * @return RTEMS_SUCCESFUL if the usb module is correct.
+ */
+static rtems_status_code check_usb_module( void )
+{
+ rtems_status_code status_code = RTEMS_INCORRECT_STATE;
+ const uint32_t pllclk = lpc176x_pllclk();
+ const uint32_t usbclk = LPC176X_USB_CLOCK;
+
+ if ( pllclk % usbclk == 0u ) {
+ const uint32_t usbdiv = pllclk / usbclk;
+
+ LPC176X_SCB.usbclksel = LPC176X_SCB_USBCLKSEL_USBDIV( usbdiv ) |
+ LPC176X_SCB_USBCLKSEL_USBSEL( 1 );
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the module has an incorrect pllclk or usbclk value.
+ Also, there is nothing to do. */
+
+ return status_code;
+}
+
+/**
+ * @brief Enables the current module.
+ *
+ * @param module Current module to enable/disable.
+ * @param clock The clock to set for this module.
+ * @param enable TRUE if the module is enable.
+ * @return RTEMS_SUCCESSFULL if the module was enabled successfully.
+ */
+static rtems_status_code enable_disable_module(
+ const lpc176x_module module,
+ const lpc176x_module_clock clock,
+ const bool enable
+)
+{
+ rtems_status_code status_code;
+ rtems_interrupt_level level = 0u;
+
+ const bool has_power = lpc176x_module_table[ module ].power;
+ const bool has_clock = lpc176x_module_table[ module ].clock;
+ const unsigned index = lpc176x_module_table[ module ].index;
+
+ assert( index <= LPC176X_MODULE_BITS_COUNT );
+
+ /* Enable or disable module */
+ if ( enable ) {
+ status_code = check_power( has_power, index, true, level );
+ RTEMS_CHECK_SC( status_code,
+ "Checking index shift to turn on power of the module." );
+
+ if ( module != LPC176X_MODULE_USB ) {
+ status_code = check_clock( has_clock, index, clock, level );
+ RTEMS_CHECK_SC( status_code,
+ "Checking index shift to set pclksel to the current module." );
+ } else {
+ status_code = check_usb_module();
+ RTEMS_CHECK_SC( status_code,
+ "Checking pll clock to set usb clock to the current module." );
+ }
+ } else {
+ status_code = check_power( has_power, index, false, level );
+ RTEMS_CHECK_SC( status_code,
+ "Checking index shift to turn off power of the module." );
+ }
+
+ return status_code;
+}
+
+/**
+ * @brief Enables the module power and clock.
+ *
+ * @param module Device to enable.
+ * @param clock The clock to set for this module.
+ * @param enable Enable or disable the module.
+ * @return RTEMS_SUCCESSFULL if the module was enabled succesfully.
+ */
+static rtems_status_code lpc176x_module_do_enable(
+ const lpc176x_module module,
+ lpc176x_module_clock clock,
+ const bool enable
+)
+{
+ rtems_status_code status_code = RTEMS_SUCCESSFUL;
+
+ if ( (unsigned) module >= LPC176X_MODULE_COUNT ) {
+ return RTEMS_INVALID_ID;
+ }
+
+ /* else implies that the module has a correct value. Also,
+ there is nothing to do. */
+
+ if ( clock == LPC176X_MODULE_PCLK_DEFAULT ) {
+#if ( LPC176X_PCLKDIV == 1u )
+ clock = LPC176X_MODULE_CCLK;
+#elif ( LPC176X_PCLKDIV == 2u )
+ clock = LPC176X_MODULE_CCLK_2;
+#elif ( LPC176X_PCLKDIV == 4u )
+ clock = LPC176X_MODULE_CCLK_4;
+#elif ( LPC176X_PCLKDIV == 8u )
+ clock = LPC176X_MODULE_CCLK_8;
+#else
+#error "Unexpected clock divisor."
+#endif
+ }
+
+ /* else implies that the clock has a correct divisor. */
+
+ if ( ( clock & ~LPC176X_MODULE_CLOCK_MASK ) == 0u ) {
+ status_code = enable_disable_module( module, clock, enable );
+ RTEMS_CHECK_SC( status_code, "Checking the module to enable/disable." );
+ } else {
+ status_code = RTEMS_INVALID_CLOCK;
+ }
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_module_enable(
+ const lpc176x_module module,
+ lpc176x_module_clock clock
+)
+{
+ return lpc176x_module_do_enable( module, clock, true );
+}
+
+inline rtems_status_code lpc176x_module_disable( const lpc176x_module module )
+{
+ return lpc176x_module_do_enable( module,
+ LPC176X_MODULE_PCLK_DEFAULT,
+ false );
+}
+
+bool lpc176x_module_is_enabled( const lpc176x_module module )
+{
+ assert( (unsigned) module < LPC176X_MODULE_COUNT );
+
+ const bool has_power = lpc176x_module_table[ module ].power;
+ bool enabled;
+
+ if ( has_power ) {
+ const unsigned index = lpc176x_module_table[ module ].index;
+ const uint32_t pconp = LPC176X_SCB.pconp;
+
+ enabled = ( pconp & ( 1u << index ) ) != 0u;
+ } else {
+ enabled = true;
+ }
+
+ return enabled;
+}
diff --git a/bsps/arm/lpc176x/start/restart.c b/bsps/arm/lpc176x/start/restart.c
new file mode 100644
index 0000000000..d6e5783f53
--- /dev/null
+++ b/bsps/arm/lpc176x/start/restart.c
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Restart implementation.
+ */
+
+/*
+ * Copyright (c) 2011-2012 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+
+void bsp_restart( const void *const addr )
+{
+ rtems_interrupt_level level;
+
+ void (*start) ( void ) = addr;
+
+ rtems_interrupt_disable( level );
+ (void) level; /* avoid set but not used warning */
+ ( *start )();
+}
diff --git a/bsps/arm/lpc176x/start/system-clocks.c b/bsps/arm/lpc176x/start/system-clocks.c
new file mode 100644
index 0000000000..dd1a0308c6
--- /dev/null
+++ b/bsps/arm/lpc176x/start/system-clocks.c
@@ -0,0 +1,124 @@
+/**
+ * @file
+ *
+ * @ingroup lpc176x_clocks
+ *
+ * @brief System clocks.
+ */
+
+/*
+ * Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/system-clocks.h>
+
+/**
+ * @brief Internal RC oscillator frequency in [Hz].
+ */
+#define LPC176X_OSCILLATOR_INTERNAL 4000000u
+
+#ifndef LPC176X_OSCILLATOR_MAIN
+#error "unknown main oscillator frequency"
+#endif
+
+#ifndef LPC176X_OSCILLATOR_RTC
+#error "unknown RTC oscillator frequency"
+#endif
+
+inline unsigned lpc176x_sysclk( void );
+
+void lpc176x_timer_initialize( void )
+{
+ /* Reset timer */
+ LPC176X_T1TCR = TCR_RST;
+ /* Set timer mode */
+ LPC176X_T1CTCR = 0u;
+ /* Set prescaler to zero */
+ LPC176X_T1PR = 0u;
+ /* Reset all interrupt flags */
+ LPC176X_T1IR = 0xffU;
+ /* Do not stop on a match */
+ LPC176X_T1MCR = 0u;
+ /* No captures */
+ LPC176X_T1CCR = 0u;
+ /* Start timer */
+ LPC176X_T1TCR = TCR_EN;
+}
+
+void lpc176x_micro_seconds_delay( const unsigned us )
+{
+ const unsigned start = lpc176x_get_timer1();
+ const unsigned delay = us * ( LPC176X_PCLK / 1000000u );
+ unsigned elapsed = 0u;
+
+ do {
+ elapsed = lpc176x_get_timer1() - start;
+ } while ( elapsed < delay );
+}
+
+unsigned lpc176x_sysclk( void )
+{
+ return ( LPC176X_SCB.clksrcsel & LPC176X_SCB_CLKSRCSEL_CLKSRC ) != 0u ?
+ LPC176X_OSCILLATOR_MAIN : LPC176X_OSCILLATOR_INTERNAL;
+}
+
+unsigned lpc176x_pllclk( void )
+{
+ const unsigned sysclk = lpc176x_sysclk();
+ const unsigned pllstat = ( LPC176X_SCB.pll_0 ).stat;
+ const unsigned enabled_and_locked = LPC176X_PLL_STAT_PLLE |
+ LPC176X_PLL_STAT_PLOCK;
+ unsigned pllclk = 0u;
+
+ if ( ( pllstat & enabled_and_locked ) == enabled_and_locked ) {
+ unsigned m = LPC176X_PLL_SEL_MSEL_GET( pllstat ) + 1u;
+ pllclk = sysclk * m;
+ }
+
+ /* else implies that the pllstat is unlocked. Also,
+ there is nothing to do. */
+
+ return pllclk;
+}
+
+unsigned lpc176x_cclk( void )
+{
+ const unsigned cclksel = LPC176X_SCB.cclksel;
+ unsigned cclk_in = 0u;
+ unsigned cclk = 0u;
+
+ if ( ( cclksel & LPC176X_SCB_CCLKSEL_CCLKSEL ) != 0u ) {
+ cclk_in = lpc176x_pllclk();
+ } else {
+ cclk_in = lpc176x_sysclk();
+ }
+
+ cclk = cclk_in / LPC176X_SCB_CCLKSEL_CCLKDIV_GET( cclksel );
+
+ return cclk;
+}
+
+CPU_Counter_ticks _CPU_Counter_read( void )
+{
+ return lpc176x_get_timer1();
+}
+
+inline CPU_Counter_ticks _CPU_Counter_difference(
+ CPU_Counter_ticks second,
+ CPU_Counter_ticks first
+)
+{
+ return second - first;
+}
+
diff --git a/bsps/arm/lpc176x/start/watchdog.c b/bsps/arm/lpc176x/start/watchdog.c
new file mode 100644
index 0000000000..bae9b4e1b1
--- /dev/null
+++ b/bsps/arm/lpc176x/start/watchdog.c
@@ -0,0 +1,102 @@
+/**
+ * @file watchdog.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Watchdog controller for the mbed lpc176x family boards.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Boretto Martin (martin.boretto@tallertechnologies.com)
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <rtems/status-checks.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/watchdog.h>
+#include <bsp/io.h>
+
+inline bool lpc176x_been_reset_by_watchdog( void )
+{
+ return ( ( LPC176X_WDMOD & LPC176X_WWDT_MOD_WDTOF ) ==
+ LPC176X_WWDT_MOD_WDTOF );
+}
+
+inline void lpc176x_watchdog_reset( void )
+{
+ LPC176X_WDFEED = LPC176X_WDFEED_CON;
+ LPC176X_WDFEED = LPC176X_WDFEED_CFG;
+}
+
+/**
+ * @brief Enables the watchdog module, sets wd clock and wd timer.
+ *
+ * @param tcount Timer's out value.
+ * @return RTEMS_SUCCESSFUL if the configuration was done successfully.
+ */
+static inline rtems_status_code enable_module_and_set_clocksel(
+ const lpc176x_microseconds tcount )
+{
+ rtems_status_code status_code;
+
+ /* Sets clock. */
+ LPC176X_WDCLKSEL = LPC176X_WWDT_CLKSEL_WDSEL_PCLK;
+
+ /* Enables the watchdog module. */
+ status_code = lpc176x_module_enable( LPC176X_MODULE_WD,
+ LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( status_code, "Enabling the watchdog module." );
+
+ /* Set the watchdog timer constant value. */
+ LPC176X_WDTC = ( LPC176X_CCLK / LPC176X_WD_PRESCALER_DIVISOR ) * tcount;
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_watchdog_config( const lpc176x_microseconds tcount )
+{
+ rtems_status_code status_code = enable_module_and_set_clocksel( tcount );
+
+ /* Setup the Watchdog timer operating mode in WDMOD register. */
+ LPC176X_WDMOD = LPC176X_WWDT_MOD_WDEN | LPC176X_WWDT_MOD_WDRESET;
+
+ /* Enable the Watchdog by writing 0xAA followed by 0x55 to the
+ WDFEED register. */
+ lpc176x_watchdog_reset();
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_watchdog_config_with_interrupt(
+ const lpc176x_wd_isr_funct interrupt,
+ const lpc176x_microseconds tcount
+)
+{
+ rtems_status_code status_code = enable_module_and_set_clocksel( tcount );
+
+ /* Setup the Watchdog timer operating mode in WDMOD register. */
+ LPC176X_WDMOD = LPC176X_WWDT_MOD_WDEN | LPC176X_WWDT_MOD_WDINT;
+
+ status_code = rtems_interrupt_handler_install(
+ LPC176X_WD_INTERRUPT_VECTOR_NUMBER,
+ "watchdog_interrupt",
+ RTEMS_INTERRUPT_UNIQUE,
+ interrupt,
+ NULL );
+
+ /* Enable the Watchdog by writing 0xAA followed by 0x55 to the
+ WDFEED register. */
+ lpc176x_watchdog_reset();
+
+ return status_code;
+} \ No newline at end of file
diff --git a/bsps/arm/lpc176x/timer/timer.c b/bsps/arm/lpc176x/timer/timer.c
new file mode 100644
index 0000000000..36c720b4fb
--- /dev/null
+++ b/bsps/arm/lpc176x/timer/timer.c
@@ -0,0 +1,407 @@
+/**
+ * @file timer.c
+ *
+ * @ingroup lpc176x
+ *
+ * @brief Timer controller for the mbed lpc1768 board.
+ */
+
+/*
+ * Copyright (c) 2014 Taller Technologies.
+ *
+ * @author Boretto Martin (martin.boretto@tallertechnologies.com)
+ * @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
+ * @author Lenarduzzi Federico (federico.lenarduzzi@tallertechnologies.com)
+ * @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <rtems/status-checks.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/io.h>
+#include <bsp/timer.h>
+
+/**
+ * @brief Represents all the timers.
+ */
+const lpc176x_timer timers[ LPC176X_TIMER_COUNT ] =
+{
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR0_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_0,
+ .pinselcap = LPC176X_TIMER0_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER0_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR1_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_1,
+ .pinselcap = LPC176X_TIMER1_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER1_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR2_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_2,
+ .pinselcap = LPC176X_TIMER2_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER2_EMATCH_PORTS,
+ },
+ {
+ .device = (lpc176x_timer_device *) LPC176X_TMR3_BASE_ADDR,
+ .module = LPC176X_MODULE_TIMER_3,
+ .pinselcap = LPC176X_TIMER3_CAPTURE_PORTS,
+ .pinselemat = LPC176X_TIMER3_EMATCH_PORTS,
+ }
+};
+
+/**
+ * @brief Represents all the functions according to the timers.
+ */
+lpc176x_timer_functions functions_vector[ LPC176X_TIMER_COUNT ] =
+{
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ },
+ {
+ .funct_vector = NULL
+ }
+};
+
+/**
+ * @brief Calls the corresponding interrupt function and pass the timer
+ * as parameter.
+ *
+ * @param timer The specific device.
+ * @param interruptnumber Interrupt number.
+ */
+static inline void lpc176x_call_desired_isr(
+ const lpc176x_timer_number number,
+ const lpc176x_isr_function interruptfunction
+)
+{
+ if ( ( *functions_vector[ number ].funct_vector )[ interruptfunction ] !=
+ NULL ) {
+ ( *functions_vector[ number ].funct_vector )[ interruptfunction ]( number );
+ }
+
+ /* else implies that the function vector points NULL. Also,
+ there is nothing to do. */
+}
+
+/**
+ * @brief Gets true if the selected interrupt is pending
+ *
+ * @param number: the number of the timer.
+ * @param interrupt: the interrupt we are checking for.
+ * @return TRUE if the interrupt is pending.
+ */
+static inline bool lpc176x_timer_interrupt_is_pending(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_function function
+)
+{
+ assert( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
+
+ return ( timers[ tnumber ].device->IR &
+ LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function ) );
+}
+
+/**
+ * @brief Resets interrupt status for the selected interrupt
+ *
+ * @param tnumber: the number of the timer
+ * @param interrupt: the interrupt we are resetting
+ */
+static inline void lpc176x_timer_reset_interrupt(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_function function
+)
+{
+ assert( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( function < LPC176X_ISR_FUNCTIONS_COUNT ) );
+ timers[ tnumber ].device->IR =
+ LPC176X_TIMER_INTERRUPT_SOURCE_BIT( function );
+}
+
+inline rtems_status_code lpc176x_timer_reset(
+ const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TCR = LPC176X_TIMER_RESET;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_set_mode(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_timer_mode mode
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->CTCR = mode;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_start(
+ const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TCR = LPC176X_TIMER_START;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_is_started(
+ const lpc176x_timer_number tnumber,
+ bool *is_started
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ *is_started = ( timers[ tnumber ].device->TCR & LPC176X_TIMER_START ) ==
+ LPC176X_TIMER_START;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_set_resolution(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_microseconds resolution
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->PR = ( LPC176X_CCLK /
+ LPC176X_TIMER_PRESCALER_DIVISOR ) *
+ resolution;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_timer_match_config(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_match_port match_port,
+ const lpc176x_match_function function,
+ const uint32_t match_value
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( match_port < LPC176X_EMATCH_PORTS_COUNT )
+ && ( function < LPC176X_TIMER_MATCH_FUNCTION_COUNT ) ) {
+ timers[ tnumber ].device->MCR =
+ LPC176X_SET_MCR( timers[ tnumber ].device->MCR,
+ match_port, function );
+ timers[ tnumber ].device->MR[ match_port ] = match_value;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number, or a match port or a function
+ is invalid. Also, an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_capture_config(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_capture_port capture_port,
+ const lpc176x_capture_function function
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( tnumber < LPC176X_TIMER_COUNT )
+ && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT )
+ && ( function < LPC176X_TIMER_CAPTURE_FUNCTION_COUNT ) ) {
+ timers[ tnumber ].device->CCR =
+ LPC176X_SET_CCR( timers[ tnumber ].device->CCR,
+ capture_port, function );
+ lpc176x_pin_select( timers[ tnumber ].pinselcap[ capture_port ],
+ LPC176X_PIN_FUNCTION_11 );
+ }
+
+ /* else implies that the timer number or the capture port is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline rtems_status_code lpc176x_timer_external_match_config(
+ const lpc176x_timer_number number,
+ const lpc176x_match_port match_port,
+ const lpc176x_ext_match_function function
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( ( number < LPC176X_TIMER_COUNT )
+ && ( match_port < LPC176X_EMATCH_PORTS_COUNT ) ) {
+ timers[ number ].device->EMR =
+ LPC176X_SET_EMR( timers[ number ].device->EMR,
+ match_port, function );
+ lpc176x_pin_select( timers[ number ].pinselemat[ match_port ],
+ LPC176X_PIN_FUNCTION_11 );
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number or the match port is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+inline uint32_t lpc176x_timer_get_capvalue(
+ const lpc176x_timer_number number,
+ const lpc176x_capture_port capture_port
+)
+{
+ assert( ( number < LPC176X_TIMER_COUNT )
+ && ( capture_port < LPC176X_CAPTURE_PORTS_COUNT ) );
+
+ return timers[ number ].device->CR[ capture_port ];
+}
+
+inline uint32_t lpc176x_timer_get_timer_value(
+ const lpc176x_timer_number tnumber )
+{
+ assert( tnumber < LPC176X_TIMER_COUNT );
+
+ return timers[ tnumber ].device->TC;
+}
+
+inline rtems_status_code lpc176x_timer_set_timer_value(
+ const lpc176x_timer_number tnumber,
+ const uint32_t timer_value
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ timers[ tnumber ].device->TC = timer_value;
+ status_code = RTEMS_SUCCESSFUL;
+ }
+
+ /* else implies that the timer number is invalid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+void lpc176x_timer_isr( void *arg )
+{
+ const lpc176x_timer_number tnumber = (lpc176x_timer_number) arg;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ lpc176x_isr_function i;
+
+ for ( i = 0; i < LPC176X_ISR_FUNCTIONS_COUNT; ++i ) {
+ if ( lpc176x_timer_interrupt_is_pending( tnumber, i ) ) {
+ lpc176x_call_desired_isr( tnumber, i );
+ lpc176x_timer_reset_interrupt( tnumber, i );
+ }
+
+ /* else implies that the current timer is not pending. Also,
+ there is nothing to do. */
+ }
+ }
+
+ /* else implies that the timer number is not valid. Also,
+ there is nothing to do. */
+}
+
+rtems_status_code lpc176x_timer_init( const lpc176x_timer_number tnumber )
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ if ( tnumber < LPC176X_TIMER_COUNT ) {
+ status_code = lpc176x_module_enable( timers[ tnumber ].module,
+ LPC176X_MODULE_PCLK_DEFAULT );
+ RTEMS_CHECK_SC( status_code, "Enabling the timer module." );
+
+ status_code = lpc176x_timer_reset( tnumber );
+ status_code = lpc176x_timer_set_mode( tnumber,
+ LPC176X_TIMER_MODE_TIMER );
+ status_code = lpc176x_timer_set_resolution( tnumber,
+ LPC176X_TIMER_DEFAULT_RESOLUTION );
+
+ timers[ tnumber ].device->MCR = LPC176X_TIMER_CLEAR_FUNCTION;
+ timers[ tnumber ].device->CCR = LPC176X_TIMER_CLEAR_FUNCTION;
+ timers[ tnumber ].device->EMR = LPC176X_TIMER_CLEAR_FUNCTION;
+ }
+
+ /* else implies that the timer number is not valid. Also,
+ an invalid number is returned. */
+
+ return status_code;
+}
+
+rtems_status_code lpc176x_timer_init_with_interrupt(
+ const lpc176x_timer_number tnumber,
+ const lpc176x_isr_funct_vector *const vector
+)
+{
+ rtems_status_code status_code = RTEMS_INVALID_NUMBER;
+
+ char isrname[ LPC176X_ISR_NAME_STRING_SIZE ];
+
+ snprintf( isrname, LPC176X_ISR_NAME_STRING_SIZE, "TimerIsr%d", tnumber );
+
+ if ( tnumber < LPC176X_TIMER_COUNT && vector != NULL ) {
+ functions_vector[ tnumber ].funct_vector = vector;
+
+ status_code = lpc176x_timer_init( tnumber );
+ status_code = rtems_interrupt_handler_install(
+ LPC176X_TIMER_VECTOR_NUMBER( tnumber ),
+ isrname,
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc176x_timer_isr,
+ (void *) tnumber );
+ }
+
+ return status_code;
+} \ No newline at end of file