]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC23XX/analogin_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC23XX / analogin_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "mbed_assert.h"
17 #include "analogin_api.h"
18 #include "cmsis.h"
19 #include "pinmap.h"
20
21 #define ANALOGIN_MEDIAN_FILTER      1
22
23 #define ADC_10BIT_RANGE             0x3FF
24 #define ADC_12BIT_RANGE             0xFFF
25
26 static inline int div_round_up(int x, int y) {
27   return (x + (y - 1)) / y;
28 }
29
30 static const PinMap PinMap_ADC[] = {
31     {P0_23, ADC0_0, 1},
32     {P0_24, ADC0_1, 1},
33     {P0_25, ADC0_2, 1},
34     {P0_26, ADC0_3, 1},
35     {P1_30, ADC0_4, 3},
36     {P1_31, ADC0_5, 3},
37     {NC,    NC,     0}
38 };
39
40 #define ADC_RANGE    ADC_10BIT_RANGE
41
42
43 void analogin_init(analogin_t *obj, PinName pin) {
44     obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
45     MBED_ASSERT(obj->adc != (ADCName)NC);
46     
47     // ensure power is turned on
48     LPC_SC->PCONP |= (1 << 12);
49     
50     // set PCLK of ADC to /1
51     LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
52     LPC_SC->PCLKSEL0 |= (0x1 << 24);
53     uint32_t PCLK = SystemCoreClock;
54     
55     // calculate minimum clock divider
56     //  clkdiv = divider - 1
57     uint32_t MAX_ADC_CLK = 13000000;
58     uint32_t clkdiv = div_round_up(PCLK, MAX_ADC_CLK) - 1;
59     
60     // Set the generic software-controlled ADC settings
61     LPC_ADC->ADCR = (0 << 0)      // SEL: 0 = no channels selected
62                   | (clkdiv << 8) // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz at fastest
63                   | (0 << 16)     // BURST: 0 = software control
64                   | (0 << 17)     // CLKS: not applicable
65                   | (1 << 21)     // PDN: 1 = operational
66                   | (0 << 24)     // START: 0 = no start
67                   | (0 << 27);    // EDGE: not applicable
68     
69     pinmap_pinout(pin, PinMap_ADC);
70 }
71
72 static inline uint32_t adc_read(analogin_t *obj) {
73     // Select the appropriate channel and start conversion
74     LPC_ADC->ADCR &= ~0xFF;
75     LPC_ADC->ADCR |= 1 << (int)obj->adc;
76     LPC_ADC->ADCR |= 1 << 24;
77     
78     // Repeatedly get the sample data until DONE bit
79     unsigned int data;
80     do {
81         data = LPC_ADC->ADGDR;
82     } while ((data & ((unsigned int)1 << 31)) == 0);
83     
84     // Stop conversion
85     LPC_ADC->ADCR &= ~(1 << 24);
86     
87     return (data >> 6) & ADC_RANGE; // 10 bit
88 }
89
90 static inline void order(uint32_t *a, uint32_t *b) {
91     if (*a > *b) {
92         uint32_t t = *a;
93         *a = *b;
94         *b = t;
95     }
96 }
97
98 static inline uint32_t adc_read_u32(analogin_t *obj) {
99     uint32_t value;
100 #if ANALOGIN_MEDIAN_FILTER
101     uint32_t v1 = adc_read(obj);
102     uint32_t v2 = adc_read(obj);
103     uint32_t v3 = adc_read(obj);
104     order(&v1, &v2);
105     order(&v2, &v3);
106     order(&v1, &v2);
107     value = v2;
108 #else
109     value = adc_read(obj);
110 #endif
111     return value;
112 }
113
114 uint16_t analogin_read_u16(analogin_t *obj) {
115     uint32_t value = adc_read_u32(obj);
116     
117     return (value << 6) | ((value >> 4) & 0x003F); // 10 bit
118 }
119
120 float analogin_read(analogin_t *obj) {
121     uint32_t value = adc_read_u32(obj);
122     return (float)value * (1.0f / (float)ADC_RANGE);
123 }