Back to home page

LXR

 
 

    


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

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMLPC176X
0005  *
0006  * @brief ADC library for the lpc176x bsp.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 Taller Technologies.
0011  *
0012  * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
0013  *
0014  * The license and distribution terms for this file may be
0015  * found in the file LICENSE in this distribution or at
0016  * http://www.rtems.org/license/LICENSE.
0017  */
0018 #include <rtems/status-checks.h>
0019 #include <bsp/adc.h>
0020 #include <bsp/adc-defs.h>
0021 
0022 static lpc176x_adc_device *const adc_device =
0023   (lpc176x_adc_device *) AD0_BASE_ADDR;
0024 
0025 static const lpc176x_adc_pin_map adc_pinmap[ ADC_DEVICES_COUNT ] =
0026 {
0027   {
0028     .pin_number = 23u,
0029     .pin_function = LPC176X_PIN_FUNCTION_01
0030   },
0031   {
0032     .pin_number = 24u,
0033     .pin_function = LPC176X_PIN_FUNCTION_01
0034   },
0035   {
0036     .pin_number = 25u,
0037     .pin_function = LPC176X_PIN_FUNCTION_01
0038   },
0039   {
0040     .pin_number = 26u,
0041     .pin_function = LPC176X_PIN_FUNCTION_01
0042   },
0043   {
0044     .pin_number = 62u,
0045     .pin_function = LPC176X_PIN_FUNCTION_11
0046   },
0047   {
0048     .pin_number = 63u,
0049     .pin_function = LPC176X_PIN_FUNCTION_11
0050   },
0051   {
0052     .pin_number = 3u,
0053     .pin_function = LPC176X_PIN_FUNCTION_10
0054   },
0055   {
0056     .pin_number = 2u,
0057     .pin_function = LPC176X_PIN_FUNCTION_10
0058   }
0059 };
0060 
0061 /**
0062  * @brief Checks for a valid pin number for an ADC
0063  *
0064  * @param pin_number The pin to check
0065  * @param adc_number The returned ADC device corresponding to that pin.
0066  *
0067  * @return true if valid, false otherwise.
0068  */
0069 static bool valid_pin_number (
0070   const lpc176x_pin_number pin_number,
0071   lpc176x_adc_number *const adc_number
0072   )
0073 {
0074   bool found = false;
0075   lpc176x_adc_number adc_device = ADC_0;
0076 
0077   while (!found && (adc_device < ADC_DEVICES_COUNT))
0078   {
0079     if (adc_pinmap[adc_device].pin_number == pin_number)
0080     {
0081       *adc_number = adc_device;
0082       found = true;
0083     }
0084     ++adc_device;
0085   }
0086 
0087   return found;
0088 }
0089 
0090 /**
0091  * @brief Turns on the device and sets its clock divisor.
0092  *
0093  */
0094 static void turn_on_and_set_clkdiv( void )
0095 {
0096   const uint32_t clkdiv = LPC176X_CCLK / ( LPC176X_PCLKDIV * MAX_ADC_CLK );
0097 
0098   adc_device->ADCR = ADC_CR_PDN | ADC_CR_CLKDIV( clkdiv );
0099 }
0100 
0101 rtems_status_code adc_open( const lpc176x_pin_number pin_number )
0102 {
0103   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0104   lpc176x_adc_number adc_number = 0;
0105   if ( valid_pin_number( pin_number, &adc_number ) ) {
0106     sc =
0107       lpc176x_module_enable( LPC176X_MODULE_ADC, LPC176X_MODULE_PCLK_DEFAULT );
0108     RTEMS_CHECK_SC( sc, "enable adc module" );
0109 
0110     turn_on_and_set_clkdiv();
0111     lpc176x_pin_select( adc_pinmap[ adc_number ].pin_number,
0112       adc_pinmap[ adc_number ].pin_function );
0113     lpc176x_pin_set_mode( adc_pinmap[ adc_number ].pin_number,
0114       LPC176X_PIN_MODE_NONE );
0115   }
0116 
0117   return sc;
0118 }
0119 
0120 rtems_status_code adc_close( void )
0121 {
0122   adc_device->ADCR &= ~ADC_CR_PDN;
0123 
0124   return lpc176x_module_disable( LPC176X_MODULE_ADC );
0125 }
0126 
0127 /**
0128  * @brief Starts the conversion for the given channel.
0129  *
0130  * @param number The channel to start the conversion.
0131  */
0132 static inline void start_conversion( const lpc176x_adc_number number )
0133 {
0134   adc_device->ADCR =
0135     ADC_CR_SEL_SET( adc_device->ADCR, ( 1 << number ) ) | ADC_CR_START_NOW;
0136 }
0137 
0138 /**
0139  * @brief Stops the conversion.
0140  *
0141  */
0142 static inline void stop_conversion( void )
0143 {
0144   adc_device->ADCR &= ~ADC_CR_START_NOW;
0145 }
0146 
0147 /**
0148  * @brief Gets float percentage of the result of a conversion.
0149  *
0150  * @param data The result of a conversion.
0151  * @return A float percentage (between 0.0f and 1.0f).
0152  */
0153 static inline float get_float( const uint32_t data )
0154 {
0155   return ( (float) data / (float) ADC_RANGE );
0156 }
0157 
0158 
0159 /**
0160  * @brief Reads the ADC value for the given ADC number.
0161  *
0162  * @param adc_number Which ADC device read.
0163  * @return The read value.
0164  */
0165 static uint32_t read( const lpc176x_adc_number adc_number )
0166 {
0167   uint32_t data;
0168 
0169   start_conversion( adc_number );
0170 
0171   do {
0172     data = adc_device->ADGDR;
0173   } while ( !ADC_DATA_CONVERSION_DONE( data ) );
0174 
0175   stop_conversion();
0176 
0177   return ADC_DR_VALUE( data );
0178 }
0179 
0180 /**
0181  * @brief Checks if the passed parameters are ordered from lowest
0182  *  to highest.
0183  *
0184  *  @param a The suggested lowest value.
0185  *  @param b The suggested middle value.
0186  *  @param c The suggested highest value.
0187  *  @return  True if it is in the right order, false otherwise.
0188  */
0189 static inline bool lowest_to_highest_ordered(
0190   const uint32_t a,
0191   const uint32_t b,
0192   const uint32_t c
0193 )
0194 {
0195   return ( ( a <= b ) && ( b <= c ) );
0196 }
0197 
0198 /**
0199  * @brief Gets median value from the three passed parameters.
0200  *
0201  * @param  a The first parameter.
0202  * @param  b The second parameter.
0203  * @param  c The third parameter.
0204  *
0205  * @return  The median of the three parameters.
0206  */
0207 static uint32_t get_median(
0208   const uint32_t a,
0209   const uint32_t b,
0210   const uint32_t c
0211 )
0212 {
0213   uint32_t median;
0214 
0215   if ( lowest_to_highest_ordered( a, b, c)
0216               || lowest_to_highest_ordered( c, b, a ) ) {
0217     median = b;
0218   } else if ( lowest_to_highest_ordered( b, a, c )
0219               || lowest_to_highest_ordered( c, a, b ) ) {
0220     median = a;
0221   } else {
0222     median = c;
0223   }
0224 
0225   return median;
0226 }
0227 
0228 rtems_status_code adc_read(
0229   const lpc176x_pin_number pin_number ,
0230   float *const             result
0231 )
0232 {
0233   rtems_status_code sc = RTEMS_INVALID_NUMBER;
0234   lpc176x_adc_number adc_number = 0;
0235   if ( valid_pin_number( pin_number, &adc_number ) ) {
0236     const uint32_t first = read( adc_number );
0237     const uint32_t second = read( adc_number );
0238     const uint32_t third = read( adc_number );
0239     const uint32_t median = get_median( first, second, third );
0240     *result = get_float( median );
0241     sc = RTEMS_SUCCESSFUL;
0242   }
0243 
0244   return sc;
0245 }