source: rtems/bsps/arm/lpc176x/start/adc.c @ c77cd426

5
Last change on this file since c77cd426 was c77cd426, checked in by Joel Sherrill <joel@…>, on Apr 30, 2018 at 10:18:49 PM

Drop executable permissions on .[ch] files

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