/** * @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; }