From e945b049dc650ee2270740585a2c6d14bd925279 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 25 Apr 2018 10:43:38 +0200 Subject: bsp/lpc176x: Move source files to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/arm/lpc176x/btimer/btimer.c | 388 +-------------- bsps/arm/lpc176x/can/can.c | 543 +++++++++++++++++++++ bsps/arm/lpc176x/gpio/lpc-gpio.c | 392 +++++++++++++++ bsps/arm/lpc176x/pwm/pwmout.c | 211 ++++++++ bsps/arm/lpc176x/start/adc.c | 245 ++++++++++ bsps/arm/lpc176x/start/bspidle.c | 30 ++ bsps/arm/lpc176x/start/dma-copy.c | 220 +++++++++ bsps/arm/lpc176x/start/dma.c | 117 +++++ bsps/arm/lpc176x/start/io.c | 349 +++++++++++++ bsps/arm/lpc176x/start/restart.c | 35 ++ bsps/arm/lpc176x/start/system-clocks.c | 124 +++++ bsps/arm/lpc176x/start/watchdog.c | 102 ++++ bsps/arm/lpc176x/timer/timer.c | 407 +++++++++++++++ c/src/lib/libbsp/arm/lpc176x/Makefile.am | 26 +- c/src/lib/libbsp/arm/lpc176x/adc/adc.c | 245 ---------- .../arm/lpc176x/benchmark_timer/benchmark_timer.c | 45 -- c/src/lib/libbsp/arm/lpc176x/can/can.c | 543 --------------------- c/src/lib/libbsp/arm/lpc176x/gpio/lpc-gpio.c | 392 --------------- c/src/lib/libbsp/arm/lpc176x/misc/bspidle.c | 30 -- c/src/lib/libbsp/arm/lpc176x/misc/dma-copy.c | 220 --------- c/src/lib/libbsp/arm/lpc176x/misc/dma.c | 117 ----- c/src/lib/libbsp/arm/lpc176x/misc/io.c | 349 ------------- c/src/lib/libbsp/arm/lpc176x/misc/restart.c | 35 -- c/src/lib/libbsp/arm/lpc176x/misc/system-clocks.c | 124 ----- c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c | 211 -------- c/src/lib/libbsp/arm/lpc176x/watchdog/watchdog.c | 102 ---- 26 files changed, 2801 insertions(+), 2801 deletions(-) create mode 100755 bsps/arm/lpc176x/can/can.c create mode 100644 bsps/arm/lpc176x/gpio/lpc-gpio.c create mode 100755 bsps/arm/lpc176x/pwm/pwmout.c create mode 100755 bsps/arm/lpc176x/start/adc.c create mode 100644 bsps/arm/lpc176x/start/bspidle.c create mode 100644 bsps/arm/lpc176x/start/dma-copy.c create mode 100644 bsps/arm/lpc176x/start/dma.c create mode 100644 bsps/arm/lpc176x/start/io.c create mode 100644 bsps/arm/lpc176x/start/restart.c create mode 100644 bsps/arm/lpc176x/start/system-clocks.c create mode 100644 bsps/arm/lpc176x/start/watchdog.c create mode 100644 bsps/arm/lpc176x/timer/timer.c delete mode 100755 c/src/lib/libbsp/arm/lpc176x/adc/adc.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/benchmark_timer/benchmark_timer.c delete mode 100755 c/src/lib/libbsp/arm/lpc176x/can/can.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/gpio/lpc-gpio.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/bspidle.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/dma-copy.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/dma.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/io.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/restart.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/misc/system-clocks.c delete mode 100755 c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c delete mode 100644 c/src/lib/libbsp/arm/lpc176x/watchdog/watchdog.c 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 -#include +#include #include -#include -#include -#include - -/** - * @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 - 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 - 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 +#include +#include +#include +#include +#include + +/** + * @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 +#include +#include +#include +#include + +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 +#include +#include + +/** + * @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 +#include +#include + +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 + * + * + * 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 +#include + +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 + * + * + * 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 +#include +#include + +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 + * + * + * 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 +#include +#include + +/** + * @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 +#include +#include +#include +#include + +/** + * @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 + * + * + * 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 +#include + +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 + * + * + * 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 +#include + +/** + * @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 +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include + +/** + * @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 diff --git a/c/src/lib/libbsp/arm/lpc176x/Makefile.am b/c/src/lib/libbsp/arm/lpc176x/Makefile.am index c62474c43c..b443893f6b 100644 --- a/c/src/lib/libbsp/arm/lpc176x/Makefile.am +++ b/c/src/lib/libbsp/arm/lpc176x/Makefile.am @@ -72,33 +72,33 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/rtc/rtc-support.c librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/rtc/rtc-config.c # GPIO -librtemsbsp_a_SOURCES += gpio/lpc-gpio.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/gpio/lpc-gpio.c # CAN -librtemsbsp_a_SOURCES += can/can.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/can/can.c # PWMOUT -librtemsbsp_a_SOURCES += pwmout/pwmout.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/pwm/pwmout.c # ADC -librtemsbsp_a_SOURCES += adc/adc.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/adc.c # Timer -librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/btimer/btimer.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/timer/timer.c # Benchmark Timer -librtemsbsp_a_SOURCES += benchmark_timer/benchmark_timer.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/btimer/btimer.c # Misc -librtemsbsp_a_SOURCES += misc/system-clocks.c -librtemsbsp_a_SOURCES += misc/dma.c -librtemsbsp_a_SOURCES += misc/dma-copy.c -librtemsbsp_a_SOURCES += misc/bspidle.c -librtemsbsp_a_SOURCES += misc/io.c -librtemsbsp_a_SOURCES += misc/restart.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/system-clocks.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/dma.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/dma-copy.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/bspidle.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/io.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/restart.c # Watchdog -librtemsbsp_a_SOURCES += watchdog/watchdog.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc176x/start/watchdog.c # Cache librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/cache/nocache.c diff --git a/c/src/lib/libbsp/arm/lpc176x/adc/adc.c b/c/src/lib/libbsp/arm/lpc176x/adc/adc.c deleted file mode 100755 index 7098166718..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/adc/adc.c +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @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 -#include -#include - -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/c/src/lib/libbsp/arm/lpc176x/benchmark_timer/benchmark_timer.c b/c/src/lib/libbsp/arm/lpc176x/benchmark_timer/benchmark_timer.c deleted file mode 100644 index 359d89086d..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/benchmark_timer/benchmark_timer.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file timerbenchmark.c - * - * @ingroup lpc176x - * - * @brief Timer benchmark functions 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 -#include -#include - -#include - -static uint32_t benchmark_timer_base; - -void benchmark_timer_initialize( void ) -{ - benchmark_timer_base = lpc176x_timer_get_timer_value( LPC176X_TIMER_1 ); -} - -benchmark_timer_t benchmark_timer_read( void ) -{ - uint32_t delta = lpc176x_timer_get_timer_value( LPC176X_TIMER_1 ) - - benchmark_timer_base; - - return delta; -} - -void benchmark_timer_disable_subtracting_average_overhead( bool find_avg_ovhead ) -{ -} diff --git a/c/src/lib/libbsp/arm/lpc176x/can/can.c b/c/src/lib/libbsp/arm/lpc176x/can/can.c deleted file mode 100755 index e5ffc29b7a..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/can/can.c +++ /dev/null @@ -1,543 +0,0 @@ -/** - * @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 -#include -#include -#include -#include -#include - -/** - * @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/c/src/lib/libbsp/arm/lpc176x/gpio/lpc-gpio.c b/c/src/lib/libbsp/arm/lpc176x/gpio/lpc-gpio.c deleted file mode 100644 index e7f07fe657..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/gpio/lpc-gpio.c +++ /dev/null @@ -1,392 +0,0 @@ -/** - * @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 -#include -#include -#include -#include - -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/c/src/lib/libbsp/arm/lpc176x/misc/bspidle.c b/c/src/lib/libbsp/arm/lpc176x/misc/bspidle.c deleted file mode 100644 index 24bb1db887..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/bspidle.c +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @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 - * - * - * 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 -#include - -void*bsp_idle_thread( const uintptr_t ignored ) -{ - while ( true ) { - } -} diff --git a/c/src/lib/libbsp/arm/lpc176x/misc/dma-copy.c b/c/src/lib/libbsp/arm/lpc176x/misc/dma-copy.c deleted file mode 100644 index 0e0b37dbd3..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/dma-copy.c +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file - * - * @ingroup lpc176x_dma - * - * @brief Direct memory access (DMA) support. - */ - -/* - * Copyright (c) 2008, 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * 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 -#include -#include - -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/c/src/lib/libbsp/arm/lpc176x/misc/dma.c b/c/src/lib/libbsp/arm/lpc176x/misc/dma.c deleted file mode 100644 index 10c7701484..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/dma.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @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 - * - * - * 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 -#include -#include - -/** - * @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/c/src/lib/libbsp/arm/lpc176x/misc/io.c b/c/src/lib/libbsp/arm/lpc176x/misc/io.c deleted file mode 100644 index c25fe94c0b..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/io.c +++ /dev/null @@ -1,349 +0,0 @@ -/** - * @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 -#include -#include -#include -#include - -/** - * @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/c/src/lib/libbsp/arm/lpc176x/misc/restart.c b/c/src/lib/libbsp/arm/lpc176x/misc/restart.c deleted file mode 100644 index d6e5783f53..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/restart.c +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @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 - * - * - * 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 -#include - -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/c/src/lib/libbsp/arm/lpc176x/misc/system-clocks.c b/c/src/lib/libbsp/arm/lpc176x/misc/system-clocks.c deleted file mode 100644 index dd1a0308c6..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/misc/system-clocks.c +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @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 - * - * - * 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 -#include - -/** - * @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/c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c b/c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c deleted file mode 100755 index dc30475f89..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c +++ /dev/null @@ -1,211 +0,0 @@ -/** - * @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 -#include -#include - -/** - * @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/c/src/lib/libbsp/arm/lpc176x/watchdog/watchdog.c b/c/src/lib/libbsp/arm/lpc176x/watchdog/watchdog.c deleted file mode 100644 index bae9b4e1b1..0000000000 --- a/c/src/lib/libbsp/arm/lpc176x/watchdog/watchdog.c +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @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 -#include -#include -#include -#include -#include - -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 -- cgit v1.2.3