source: rtems/c/src/lib/libbsp/arm/lpc176x/adc/adc.c @ 1c0663b

4.115
Last change on this file since 1c0663b was d4edbdbc, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 20, 2015 at 1:09:26 PM

Replace www.rtems.com with www.rtems.org

  • Property mode set to 100755
File size: 5.4 KB
Line 
1/**
2 * @file adc.c
3 *
4 * @ingroup lpc176x
5 *
6 * @brief ADC library for the lpc176x bsp.
7 */
8
9/*
10 * Copyright (c) 2014 Taller Technologies.
11 *
12 * @author  Diaz Marcos (marcos.diaz@tallertechnologies.com)
13 *
14 * The license and distribution terms for this file may be
15 * found in the file LICENSE in this distribution or at
16 * http://www.rtems.org/license/LICENSE.
17 */
18#include <rtems/status-checks.h>
19#include <bsp/adc.h>
20#include <bsp/adc-defs.h>
21
22static lpc176x_adc_device *const adc_device = AD0_BASE_ADDR;
23
24static const lpc176x_adc_pin_map adc_pinmap[ ADC_DEVICES_COUNT ] =
25{
26  {
27    .pin_number = 23u,
28    .pin_function = LPC176X_PIN_FUNCTION_01
29  },
30  {
31    .pin_number = 24u,
32    .pin_function = LPC176X_PIN_FUNCTION_01
33  },
34  {
35    .pin_number = 25u,
36    .pin_function = LPC176X_PIN_FUNCTION_01
37  },
38  {
39    .pin_number = 26u,
40    .pin_function = LPC176X_PIN_FUNCTION_01
41  },
42  {
43    .pin_number = 62u,
44    .pin_function = LPC176X_PIN_FUNCTION_11
45  },
46  {
47    .pin_number = 63u,
48    .pin_function = LPC176X_PIN_FUNCTION_11
49  },
50  {
51    .pin_number = 3u,
52    .pin_function = LPC176X_PIN_FUNCTION_10
53  },
54  {
55    .pin_number = 2u,
56    .pin_function = LPC176X_PIN_FUNCTION_10
57  }
58};
59
60/**
61 * @brief Checks for a valid pin number for an ADC
62 *
63 * @param pin_number The pin to check
64 * @param adc_number The returned ADC device corresponding to that pin.
65 *
66 * @return true if valid, false otherwise.
67 */
68static bool valid_pin_number (
69  const lpc176x_pin_number pin_number,
70  lpc176x_adc_number *const adc_number
71  )
72{
73  bool found = false;
74  lpc176x_adc_number adc_device = ADC_0;
75
76  while (!found && (adc_device < ADC_DEVICES_COUNT))
77  {
78    if (adc_pinmap[adc_device].pin_number == pin_number)
79    {
80      *adc_number = adc_device;
81      found = true;
82    }
83    ++adc_device;
84  }
85
86  return found;
87}
88
89/**
90 * @brief Turns on the device and sets its clock divisor.
91 *
92 */
93static void turn_on_and_set_clkdiv( void )
94{
95  const uint32_t clkdiv = LPC176X_CCLK / ( LPC176X_PCLKDIV * MAX_ADC_CLK );
96
97  adc_device->ADCR = ADC_CR_PDN | ADC_CR_CLKDIV( clkdiv );
98}
99
100rtems_status_code adc_open( const lpc176x_pin_number pin_number )
101{
102  rtems_status_code sc = RTEMS_INVALID_NUMBER;
103  lpc176x_adc_number adc_number = 0;
104  if ( valid_pin_number( pin_number, &adc_number ) ) {
105    sc =
106      lpc176x_module_enable( LPC176X_MODULE_ADC, LPC176X_MODULE_PCLK_DEFAULT );
107    RTEMS_CHECK_SC( sc, "enable adc module" );
108
109    turn_on_and_set_clkdiv();
110    lpc176x_pin_select( adc_pinmap[ adc_number ].pin_number,
111      adc_pinmap[ adc_number ].pin_function );
112    lpc176x_pin_set_mode( adc_pinmap[ adc_number ].pin_number,
113      LPC176X_PIN_MODE_NONE );
114  }
115
116  return sc;
117}
118
119rtems_status_code adc_close( void )
120{
121  adc_device->ADCR &= ~ADC_CR_PDN;
122
123  return lpc176x_module_disable( LPC176X_MODULE_ADC );
124}
125
126/**
127 * @brief Starts the conversion for the given channel.
128 *
129 * @param number The channel to start the conversion.
130 */
131static inline void start_conversion( const lpc176x_adc_number number )
132{
133  adc_device->ADCR =
134    ADC_CR_SEL_SET( adc_device->ADCR, ( 1 << number ) ) | ADC_CR_START_NOW;
135}
136
137/**
138 * @brief Stops the conversion.
139 *
140 */
141static inline void stop_conversion( void )
142{
143  adc_device->ADCR &= ~ADC_CR_START_NOW;
144}
145
146/**
147 * @brief Gets float percentage of the result of a conversion.
148 *
149 * @param data The result of a conversion.
150 * @return A float percentage (between 0.0f and 1.0f).
151 */
152static inline float get_float( const uint32_t data )
153{
154  return ( (float) data / (float) ADC_RANGE );
155}
156
157
158/**
159 * @brief Reads the ADC value for the given ADC number.
160 *
161 * @param adc_number Which ADC device read.
162 * @return The read value.
163 */
164static uint32_t read( const lpc176x_adc_number adc_number )
165{
166  uint32_t data;
167
168  start_conversion( adc_number );
169
170  do {
171    data = adc_device->ADGDR;
172  } while ( !ADC_DATA_CONVERSION_DONE( data ) );
173
174  stop_conversion();
175
176  return ADC_DR_VALUE( data );
177}
178
179/**
180 * @brief Checks if the passed parameters are ordered from lowest
181 *  to highest.
182 *
183 *  @param a The suggested lowest value.
184 *  @param b The suggested middle value.
185 *  @param c The suggested highest value.
186 *  @return  True if it is in the right order, false otherwise.
187 */
188static inline bool lowest_to_highest_ordered(
189  const uint32_t a,
190  const uint32_t b,
191  const uint32_t c
192)
193{
194  return ( ( a <= b ) && ( b <= c ) );
195}
196
197/**
198 * @brief Gets median value from the three passed parameters.
199 *
200 * @param  a The first parameter.
201 * @param  b The second parameter.
202 * @param  c The third parameter.
203 *
204 * @return  The median of the three parameters.
205 */
206static uint32_t get_median(
207  const uint32_t a,
208  const uint32_t b,
209  const uint32_t c
210)
211{
212  uint32_t median;
213
214  if ( lowest_to_highest_ordered( a, b, c)
215              || lowest_to_highest_ordered( c, b, a ) ) {
216    median = b;
217  } else if ( lowest_to_highest_ordered( b, a, c )
218              || lowest_to_highest_ordered( c, a, b ) ) {
219    median = a;
220  } else {
221    median = c;
222  }
223
224  return median;
225}
226
227rtems_status_code adc_read(
228  const lpc176x_pin_number pin_number ,
229  float *const             result
230)
231{
232  rtems_status_code sc = RTEMS_INVALID_NUMBER;
233  lpc176x_adc_number adc_number = 0;
234  if ( valid_pin_number( pin_number, &adc_number ) ) {
235    const uint32_t first = read( adc_number );
236    const uint32_t second = read( adc_number );
237    const uint32_t third = read( adc_number );
238    const uint32_t median = get_median( first, second, third );
239    *result = get_float( median );
240    sc = RTEMS_SUCCESSFUL;
241  }
242
243  return sc;
244}
Note: See TracBrowser for help on using the repository browser.