diff options
Diffstat (limited to 'bsps/arm/lpc176x/start/adc.c')
-rwxr-xr-x | bsps/arm/lpc176x/start/adc.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/bsps/arm/lpc176x/start/adc.c b/bsps/arm/lpc176x/start/adc.c new file mode 100755 index 0000000000..7098166718 --- /dev/null +++ b/bsps/arm/lpc176x/start/adc.c @@ -0,0 +1,245 @@ +/** + * @file adc.c + * + * @ingroup lpc176x + * + * @brief ADC library for the lpc176x bsp. + */ + +/* + * Copyright (c) 2014 Taller Technologies. + * + * @author Diaz Marcos (marcos.diaz@tallertechnologies.com) + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +#include <rtems/status-checks.h> +#include <bsp/adc.h> +#include <bsp/adc-defs.h> + +static lpc176x_adc_device *const adc_device = + (lpc176x_adc_device *) AD0_BASE_ADDR; + +static const lpc176x_adc_pin_map adc_pinmap[ ADC_DEVICES_COUNT ] = +{ + { + .pin_number = 23u, + .pin_function = LPC176X_PIN_FUNCTION_01 + }, + { + .pin_number = 24u, + .pin_function = LPC176X_PIN_FUNCTION_01 + }, + { + .pin_number = 25u, + .pin_function = LPC176X_PIN_FUNCTION_01 + }, + { + .pin_number = 26u, + .pin_function = LPC176X_PIN_FUNCTION_01 + }, + { + .pin_number = 62u, + .pin_function = LPC176X_PIN_FUNCTION_11 + }, + { + .pin_number = 63u, + .pin_function = LPC176X_PIN_FUNCTION_11 + }, + { + .pin_number = 3u, + .pin_function = LPC176X_PIN_FUNCTION_10 + }, + { + .pin_number = 2u, + .pin_function = LPC176X_PIN_FUNCTION_10 + } +}; + +/** + * @brief Checks for a valid pin number for an ADC + * + * @param pin_number The pin to check + * @param adc_number The returned ADC device corresponding to that pin. + * + * @return true if valid, false otherwise. + */ +static bool valid_pin_number ( + const lpc176x_pin_number pin_number, + lpc176x_adc_number *const adc_number + ) +{ + bool found = false; + lpc176x_adc_number adc_device = ADC_0; + + while (!found && (adc_device < ADC_DEVICES_COUNT)) + { + if (adc_pinmap[adc_device].pin_number == pin_number) + { + *adc_number = adc_device; + found = true; + } + ++adc_device; + } + + return found; +} + +/** + * @brief Turns on the device and sets its clock divisor. + * + */ +static void turn_on_and_set_clkdiv( void ) +{ + const uint32_t clkdiv = LPC176X_CCLK / ( LPC176X_PCLKDIV * MAX_ADC_CLK ); + + adc_device->ADCR = ADC_CR_PDN | ADC_CR_CLKDIV( clkdiv ); +} + +rtems_status_code adc_open( const lpc176x_pin_number pin_number ) +{ + rtems_status_code sc = RTEMS_INVALID_NUMBER; + lpc176x_adc_number adc_number = 0; + if ( valid_pin_number( pin_number, &adc_number ) ) { + sc = + lpc176x_module_enable( LPC176X_MODULE_ADC, LPC176X_MODULE_PCLK_DEFAULT ); + RTEMS_CHECK_SC( sc, "enable adc module" ); + + turn_on_and_set_clkdiv(); + lpc176x_pin_select( adc_pinmap[ adc_number ].pin_number, + adc_pinmap[ adc_number ].pin_function ); + lpc176x_pin_set_mode( adc_pinmap[ adc_number ].pin_number, + LPC176X_PIN_MODE_NONE ); + } + + return sc; +} + +rtems_status_code adc_close( void ) +{ + adc_device->ADCR &= ~ADC_CR_PDN; + + return lpc176x_module_disable( LPC176X_MODULE_ADC ); +} + +/** + * @brief Starts the conversion for the given channel. + * + * @param number The channel to start the conversion. + */ +static inline void start_conversion( const lpc176x_adc_number number ) +{ + adc_device->ADCR = + ADC_CR_SEL_SET( adc_device->ADCR, ( 1 << number ) ) | ADC_CR_START_NOW; +} + +/** + * @brief Stops the conversion. + * + */ +static inline void stop_conversion( void ) +{ + adc_device->ADCR &= ~ADC_CR_START_NOW; +} + +/** + * @brief Gets float percentage of the result of a conversion. + * + * @param data The result of a conversion. + * @return A float percentage (between 0.0f and 1.0f). + */ +static inline float get_float( const uint32_t data ) +{ + return ( (float) data / (float) ADC_RANGE ); +} + + +/** + * @brief Reads the ADC value for the given ADC number. + * + * @param adc_number Which ADC device read. + * @return The read value. + */ +static uint32_t read( const lpc176x_adc_number adc_number ) +{ + uint32_t data; + + start_conversion( adc_number ); + + do { + data = adc_device->ADGDR; + } while ( !ADC_DATA_CONVERSION_DONE( data ) ); + + stop_conversion(); + + return ADC_DR_VALUE( data ); +} + +/** + * @brief Checks if the passed parameters are ordered from lowest + * to highest. + * + * @param a The suggested lowest value. + * @param b The suggested middle value. + * @param c The suggested highest value. + * @return True if it is in the right order, false otherwise. + */ +static inline bool lowest_to_highest_ordered( + const uint32_t a, + const uint32_t b, + const uint32_t c +) +{ + return ( ( a <= b ) && ( b <= c ) ); +} + +/** + * @brief Gets median value from the three passed parameters. + * + * @param a The first parameter. + * @param b The second parameter. + * @param c The third parameter. + * + * @return The median of the three parameters. + */ +static uint32_t get_median( + const uint32_t a, + const uint32_t b, + const uint32_t c +) +{ + uint32_t median; + + if ( lowest_to_highest_ordered( a, b, c) + || lowest_to_highest_ordered( c, b, a ) ) { + median = b; + } else if ( lowest_to_highest_ordered( b, a, c ) + || lowest_to_highest_ordered( c, a, b ) ) { + median = a; + } else { + median = c; + } + + return median; +} + +rtems_status_code adc_read( + const lpc176x_pin_number pin_number , + float *const result +) +{ + rtems_status_code sc = RTEMS_INVALID_NUMBER; + lpc176x_adc_number adc_number = 0; + if ( valid_pin_number( pin_number, &adc_number ) ) { + const uint32_t first = read( adc_number ); + const uint32_t second = read( adc_number ); + const uint32_t third = read( adc_number ); + const uint32_t median = get_median( first, second, third ); + *result = get_float( median ); + sc = RTEMS_SUCCESSFUL; + } + + return sc; +} |