Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo_L432KC_Quadrature_Decoder_with_ADC_and_DAC
Fork of mbed-dev by
targets/hal/TARGET_NXP/TARGET_LPC15XX/analogin_api.c@0:9b334a45a8ff, 2015-10-01 (annotated)
- Committer:
- bogdanm
- Date:
- Thu Oct 01 15:25:22 2015 +0300
- Revision:
- 0:9b334a45a8ff
- Child:
- 73:5d67568caa8f
Initial commit on mbed-dev
Replaces mbed-src (now inactive)
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| bogdanm | 0:9b334a45a8ff | 1 | /* mbed Microcontroller Library |
| bogdanm | 0:9b334a45a8ff | 2 | * Copyright (c) 2006-2013 ARM Limited |
| bogdanm | 0:9b334a45a8ff | 3 | * |
| bogdanm | 0:9b334a45a8ff | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| bogdanm | 0:9b334a45a8ff | 5 | * you may not use this file except in compliance with the License. |
| bogdanm | 0:9b334a45a8ff | 6 | * You may obtain a copy of the License at |
| bogdanm | 0:9b334a45a8ff | 7 | * |
| bogdanm | 0:9b334a45a8ff | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| bogdanm | 0:9b334a45a8ff | 9 | * |
| bogdanm | 0:9b334a45a8ff | 10 | * Unless required by applicable law or agreed to in writing, software |
| bogdanm | 0:9b334a45a8ff | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| bogdanm | 0:9b334a45a8ff | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| bogdanm | 0:9b334a45a8ff | 13 | * See the License for the specific language governing permissions and |
| bogdanm | 0:9b334a45a8ff | 14 | * limitations under the License. |
| bogdanm | 0:9b334a45a8ff | 15 | */ |
| bogdanm | 0:9b334a45a8ff | 16 | #include "mbed_assert.h" |
| bogdanm | 0:9b334a45a8ff | 17 | #include "analogin_api.h" |
| bogdanm | 0:9b334a45a8ff | 18 | #include "cmsis.h" |
| bogdanm | 0:9b334a45a8ff | 19 | #include "pinmap.h" |
| bogdanm | 0:9b334a45a8ff | 20 | |
| bogdanm | 0:9b334a45a8ff | 21 | #define ANALOGIN_MEDIAN_FILTER 1 |
| bogdanm | 0:9b334a45a8ff | 22 | |
| bogdanm | 0:9b334a45a8ff | 23 | #define ADC_10BIT_RANGE 0x3FF |
| bogdanm | 0:9b334a45a8ff | 24 | #define ADC_12BIT_RANGE 0xFFF |
| bogdanm | 0:9b334a45a8ff | 25 | |
| bogdanm | 0:9b334a45a8ff | 26 | #define ADC_RANGE ADC_12BIT_RANGE |
| bogdanm | 0:9b334a45a8ff | 27 | |
| bogdanm | 0:9b334a45a8ff | 28 | static const PinMap PinMap_ADC[] = { |
| bogdanm | 0:9b334a45a8ff | 29 | {P0_8 , ADC0_0, 0}, |
| bogdanm | 0:9b334a45a8ff | 30 | {P0_7 , ADC0_1, 0}, |
| bogdanm | 0:9b334a45a8ff | 31 | {P0_6 , ADC0_2, 0}, |
| bogdanm | 0:9b334a45a8ff | 32 | {P0_5 , ADC0_3, 0}, |
| bogdanm | 0:9b334a45a8ff | 33 | {P0_4 , ADC0_4, 0}, |
| bogdanm | 0:9b334a45a8ff | 34 | {P0_3 , ADC0_5, 0}, |
| bogdanm | 0:9b334a45a8ff | 35 | {P0_2 , ADC0_6, 0}, |
| bogdanm | 0:9b334a45a8ff | 36 | {P0_1 , ADC0_7, 0}, |
| bogdanm | 0:9b334a45a8ff | 37 | {P1_0 , ADC0_8, 0}, |
| bogdanm | 0:9b334a45a8ff | 38 | {P0_31, ADC0_9, 0}, |
| bogdanm | 0:9b334a45a8ff | 39 | {P0_0 , ADC0_10,0}, |
| bogdanm | 0:9b334a45a8ff | 40 | {P0_30, ADC0_11,0}, |
| bogdanm | 0:9b334a45a8ff | 41 | {P1_1 , ADC1_0, 0}, |
| bogdanm | 0:9b334a45a8ff | 42 | {P0_9 , ADC1_1, 0}, |
| bogdanm | 0:9b334a45a8ff | 43 | {P0_10, ADC1_2, 0}, |
| bogdanm | 0:9b334a45a8ff | 44 | {P0_11, ADC1_3, 0}, |
| bogdanm | 0:9b334a45a8ff | 45 | {P1_2 , ADC1_4, 0}, |
| bogdanm | 0:9b334a45a8ff | 46 | {P1_3 , ADC1_5, 0}, |
| bogdanm | 0:9b334a45a8ff | 47 | {P0_13, ADC1_6, 0}, |
| bogdanm | 0:9b334a45a8ff | 48 | {P0_14, ADC1_7, 0}, |
| bogdanm | 0:9b334a45a8ff | 49 | {P0_15, ADC1_8, 0}, |
| bogdanm | 0:9b334a45a8ff | 50 | {P0_16, ADC1_9, 0}, |
| bogdanm | 0:9b334a45a8ff | 51 | {P1_4 , ADC1_10,0}, |
| bogdanm | 0:9b334a45a8ff | 52 | {P1_5 , ADC1_11,0}, |
| bogdanm | 0:9b334a45a8ff | 53 | }; |
| bogdanm | 0:9b334a45a8ff | 54 | |
| bogdanm | 0:9b334a45a8ff | 55 | void analogin_init(analogin_t *obj, PinName pin) { |
| bogdanm | 0:9b334a45a8ff | 56 | obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC); |
| bogdanm | 0:9b334a45a8ff | 57 | MBED_ASSERT(obj->adc != (ADCName)NC); |
| bogdanm | 0:9b334a45a8ff | 58 | |
| bogdanm | 0:9b334a45a8ff | 59 | uint32_t port = (pin >> 5); |
| bogdanm | 0:9b334a45a8ff | 60 | // enable clock for GPIOx |
| bogdanm | 0:9b334a45a8ff | 61 | LPC_SYSCON->SYSAHBCLKCTRL0 |= (1UL << (14 + port)); |
| bogdanm | 0:9b334a45a8ff | 62 | // pin enable |
| bogdanm | 0:9b334a45a8ff | 63 | LPC_SWM->PINENABLE0 &= ~(1UL << obj->adc); |
| bogdanm | 0:9b334a45a8ff | 64 | // configure GPIO as input |
| bogdanm | 0:9b334a45a8ff | 65 | LPC_GPIO_PORT->DIR[port] &= ~(1UL << (pin & 0x1F)); |
| bogdanm | 0:9b334a45a8ff | 66 | |
| bogdanm | 0:9b334a45a8ff | 67 | // power up ADC |
| bogdanm | 0:9b334a45a8ff | 68 | if (obj->adc < ADC1_0) |
| bogdanm | 0:9b334a45a8ff | 69 | { |
| bogdanm | 0:9b334a45a8ff | 70 | // ADC0 |
| bogdanm | 0:9b334a45a8ff | 71 | LPC_SYSCON->PDRUNCFG &= ~(1 << 10); |
| bogdanm | 0:9b334a45a8ff | 72 | LPC_SYSCON->SYSAHBCLKCTRL0 |= (1 << 27); |
| bogdanm | 0:9b334a45a8ff | 73 | } |
| bogdanm | 0:9b334a45a8ff | 74 | else { |
| bogdanm | 0:9b334a45a8ff | 75 | // ADC1 |
| bogdanm | 0:9b334a45a8ff | 76 | LPC_SYSCON->PDRUNCFG &= ~(1 << 11); |
| bogdanm | 0:9b334a45a8ff | 77 | LPC_SYSCON->SYSAHBCLKCTRL0 |= (1 << 28); |
| bogdanm | 0:9b334a45a8ff | 78 | } |
| bogdanm | 0:9b334a45a8ff | 79 | |
| bogdanm | 0:9b334a45a8ff | 80 | // select IRC as asynchronous clock, divided by 1 |
| bogdanm | 0:9b334a45a8ff | 81 | LPC_SYSCON->ADCASYNCCLKSEL = 0; |
| bogdanm | 0:9b334a45a8ff | 82 | LPC_SYSCON->ADCASYNCCLKDIV = 1; |
| bogdanm | 0:9b334a45a8ff | 83 | |
| bogdanm | 0:9b334a45a8ff | 84 | __IO LPC_ADC0_Type *adc_reg = (obj->adc < ADC1_0) ? (__IO LPC_ADC0_Type*)(LPC_ADC0) : (__IO LPC_ADC0_Type*)(LPC_ADC1); |
| bogdanm | 0:9b334a45a8ff | 85 | |
| bogdanm | 0:9b334a45a8ff | 86 | // determine the system clock divider for a 500kHz ADC clock during calibration |
| bogdanm | 0:9b334a45a8ff | 87 | uint32_t clkdiv = (SystemCoreClock / 500000) - 1; |
| bogdanm | 0:9b334a45a8ff | 88 | |
| bogdanm | 0:9b334a45a8ff | 89 | // perform a self-calibration |
| bogdanm | 0:9b334a45a8ff | 90 | adc_reg->CTRL = (1UL << 30) | (clkdiv & 0xFF); |
| bogdanm | 0:9b334a45a8ff | 91 | while ((adc_reg->CTRL & (1UL << 30)) != 0); |
| bogdanm | 0:9b334a45a8ff | 92 | |
| bogdanm | 0:9b334a45a8ff | 93 | // switch to asynchronous mode |
| bogdanm | 0:9b334a45a8ff | 94 | adc_reg->CTRL = (1UL << 8); |
| bogdanm | 0:9b334a45a8ff | 95 | } |
| bogdanm | 0:9b334a45a8ff | 96 | |
| bogdanm | 0:9b334a45a8ff | 97 | static inline uint32_t adc_read(analogin_t *obj) { |
| bogdanm | 0:9b334a45a8ff | 98 | uint32_t channels; |
| bogdanm | 0:9b334a45a8ff | 99 | |
| bogdanm | 0:9b334a45a8ff | 100 | __IO LPC_ADC0_Type *adc_reg = (obj->adc < ADC1_0) ? (__IO LPC_ADC0_Type*)(LPC_ADC0) : (__IO LPC_ADC0_Type*)(LPC_ADC1); |
| bogdanm | 0:9b334a45a8ff | 101 | |
| bogdanm | 0:9b334a45a8ff | 102 | if (obj->adc >= ADC1_0) |
| bogdanm | 0:9b334a45a8ff | 103 | channels = ((obj->adc - ADC1_0) & 0x1F); |
| bogdanm | 0:9b334a45a8ff | 104 | else |
| bogdanm | 0:9b334a45a8ff | 105 | channels = (obj->adc & 0x1F); |
| bogdanm | 0:9b334a45a8ff | 106 | |
| bogdanm | 0:9b334a45a8ff | 107 | // select channel |
| bogdanm | 0:9b334a45a8ff | 108 | adc_reg->SEQA_CTRL &= ~(0xFFF); |
| bogdanm | 0:9b334a45a8ff | 109 | adc_reg->SEQA_CTRL |= (1UL << channels); |
| bogdanm | 0:9b334a45a8ff | 110 | |
| bogdanm | 0:9b334a45a8ff | 111 | // start conversion and sequence enable |
| bogdanm | 0:9b334a45a8ff | 112 | adc_reg->SEQA_CTRL |= ((1UL << 26) | (1UL << 31)); |
| bogdanm | 0:9b334a45a8ff | 113 | |
| bogdanm | 0:9b334a45a8ff | 114 | // Repeatedly get the sample data until DONE bit |
| bogdanm | 0:9b334a45a8ff | 115 | volatile uint32_t data; |
| bogdanm | 0:9b334a45a8ff | 116 | do { |
| bogdanm | 0:9b334a45a8ff | 117 | data = adc_reg->SEQA_GDAT; |
| bogdanm | 0:9b334a45a8ff | 118 | } while ((data & (1UL << 31)) == 0); |
| bogdanm | 0:9b334a45a8ff | 119 | |
| bogdanm | 0:9b334a45a8ff | 120 | // Stop conversion |
| bogdanm | 0:9b334a45a8ff | 121 | adc_reg->SEQA_CTRL &= ~(1UL << 31); |
| bogdanm | 0:9b334a45a8ff | 122 | |
| bogdanm | 0:9b334a45a8ff | 123 | return ((data >> 4) & ADC_RANGE); |
| bogdanm | 0:9b334a45a8ff | 124 | } |
| bogdanm | 0:9b334a45a8ff | 125 | |
| bogdanm | 0:9b334a45a8ff | 126 | static inline void order(uint32_t *a, uint32_t *b) { |
| bogdanm | 0:9b334a45a8ff | 127 | if (*a > *b) { |
| bogdanm | 0:9b334a45a8ff | 128 | uint32_t t = *a; |
| bogdanm | 0:9b334a45a8ff | 129 | *a = *b; |
| bogdanm | 0:9b334a45a8ff | 130 | *b = t; |
| bogdanm | 0:9b334a45a8ff | 131 | } |
| bogdanm | 0:9b334a45a8ff | 132 | } |
| bogdanm | 0:9b334a45a8ff | 133 | |
| bogdanm | 0:9b334a45a8ff | 134 | static inline uint32_t adc_read_u32(analogin_t *obj) { |
| bogdanm | 0:9b334a45a8ff | 135 | uint32_t value; |
| bogdanm | 0:9b334a45a8ff | 136 | #if ANALOGIN_MEDIAN_FILTER |
| bogdanm | 0:9b334a45a8ff | 137 | uint32_t v1 = adc_read(obj); |
| bogdanm | 0:9b334a45a8ff | 138 | uint32_t v2 = adc_read(obj); |
| bogdanm | 0:9b334a45a8ff | 139 | uint32_t v3 = adc_read(obj); |
| bogdanm | 0:9b334a45a8ff | 140 | order(&v1, &v2); |
| bogdanm | 0:9b334a45a8ff | 141 | order(&v2, &v3); |
| bogdanm | 0:9b334a45a8ff | 142 | order(&v1, &v2); |
| bogdanm | 0:9b334a45a8ff | 143 | value = v2; |
| bogdanm | 0:9b334a45a8ff | 144 | #else |
| bogdanm | 0:9b334a45a8ff | 145 | value = adc_read(obj); |
| bogdanm | 0:9b334a45a8ff | 146 | #endif |
| bogdanm | 0:9b334a45a8ff | 147 | return value; |
| bogdanm | 0:9b334a45a8ff | 148 | } |
| bogdanm | 0:9b334a45a8ff | 149 | |
| bogdanm | 0:9b334a45a8ff | 150 | uint16_t analogin_read_u16(analogin_t *obj) { |
| bogdanm | 0:9b334a45a8ff | 151 | uint32_t value = adc_read_u32(obj); |
| bogdanm | 0:9b334a45a8ff | 152 | return (value << 4) | ((value >> 8) & 0x000F); // 12 bit |
| bogdanm | 0:9b334a45a8ff | 153 | } |
| bogdanm | 0:9b334a45a8ff | 154 | |
| bogdanm | 0:9b334a45a8ff | 155 | float analogin_read(analogin_t *obj) { |
| bogdanm | 0:9b334a45a8ff | 156 | uint32_t value = adc_read_u32(obj); |
| bogdanm | 0:9b334a45a8ff | 157 | return (float)value * (1.0f / (float)ADC_RANGE); |
| bogdanm | 0:9b334a45a8ff | 158 | } |
