Class similar to AnalogIn that uses burst mode to run continious background conversions so when the input is read, the last value can immediatly be returned.

Dependents:   KL25Z_FFT_Demo test_armmath KL25Z_FFT_Demo_tony KL25Z_FFT_Demo_tony ... more

Supported devices

  • LPC1768
  • LPC4088
  • LPC11u24
  • KLxx
  • K20D50M

Introduction

When you read an AnalogIn object it will enable the corresponding ADC channel, depending on the implementation do either one or multiple measurements for more accuracy, and return that value to your program. This way the ADC is only active when it is required, and it is fairly straightforward. However the downside is, is that an ADC is relatively slow. On the LPC1768 it runs at 200kHz -> in that time it could also have done 500 instructions.

FastAnalogIn

This library uses the 'burst' feature of the microcontroller. This allows the ADC on the background to perform the AD conversions without requiring intervention from the microcontroller's core. Also there are no interrupts used, so also your time-sensitive code is not affected.

What the burst feature does is check which AD-channels are enabled, and he converts the enabled AD-channels one at a time. The result he stores in a register, where each channel has its own register. So this library checks which pins are used (you may make several FastAnalogIn objects, both for different pins and for the same pin, generally not extremely useful, but it is supported), and enables the relevant channels.

Reading a pin is done exactly the same for the user as AnalogIn, the read and read_us functions both work the same, and also the float operator is supported. However now it doesn't have to start a new conversion, so minus some overhead it can almost directly return the last measured value, no need to wait on the ADC!

Enable/Disable

FastAnalogIn has a few extra options that normal AnalogIn does not have: specifically you can either choose to have a FastAnalogIn object enabled or disabled. This is done with either the enable(bool enabled) and disable() functions, where enable(false) is equal to disable(), or by adding a second true/false argument to the constructor to either have it enabled at the beginning or disabled. By default it will be enabled.

LPC1768 & LPC4088
When a FastAnalogIn object is enabled, its corresponding ADC channel is also being scanned by the ADC and so it works as described above. When it is disabled you can still use the read functions, only now it will only enable the ADC channel for one conversion (actually two since for some reason the first conversion seems a bit weird), and when that conversion is done it will disable it again.

Since the ADC has to do the conversions one channel at a time, it becomes slower per channel if you enable many channels. For example, if you want to sample a sensor at a very high rate, and you also want to monitor your battery voltage. Then there is no reason to run an AD conversion on your battery continiously, so you can disable that channel and only run it once in a while.

KLxx
Multiple Fast instances can be declared of which only ONE can be continuous (all others must be non-continuous).
Example:

FastAnalogIn   speed(PTC2);           // Fast continuous
FastAnalogIn   temp1(PTC2, 0);        // Fast non-continuous.
FastAnalogIn   temp2(PTB3, 0);        // Fast non-continuous.

Downsides

Of course there are always downsides present. The extra power consumption probably won't be relevant for most, but still it is there. Aditionally there is no median filter like the normal AnalogIn has. Finally if you use AnalogIn you know exactly when the conversion happened, with FastAnalogIn you only know it was recently done but not exactly when.

AnalogIn + FastAnalogIn

Don't run both AnalogIn and FastAnalogIn objects in parallel as the results are unpredictable.
Both objects modify microcontroller registers, and neither of them bothers to inform the other one.
That's also the reason the disable() function was added.

Committer:
Sissors
Date:
Sun Mar 20 20:18:12 2016 +0000
Revision:
11:14744c4ac884
Parent:
10:afc3b84dbbd6
Child:
12:46fbc645de4d
Added LPC1114 support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 11:14744c4ac884 1 #if defined(TARGET_LPC11UXX) || defined (TARGET_LPC11XX)
Sissors 8:68082fdde730 2
Sissors 8:68082fdde730 3 #include "FastAnalogIn.h"
Sissors 8:68082fdde730 4 static inline int div_round_up(int x, int y)
Sissors 8:68082fdde730 5 {
Sissors 8:68082fdde730 6 return (x + (y - 1)) / y;
Sissors 8:68082fdde730 7 }
Sissors 8:68082fdde730 8
Sissors 8:68082fdde730 9 #define LPC_IOCON0_BASE (LPC_IOCON_BASE)
Sissors 8:68082fdde730 10 #define LPC_IOCON1_BASE (LPC_IOCON_BASE + 0x60)
Sissors 8:68082fdde730 11 #define MAX_ADC_CLK 4500000
Sissors 8:68082fdde730 12
Sissors 11:14744c4ac884 13 #ifdef TARGET_LPC11UXX
Sissors 8:68082fdde730 14 static const PinMap PinMap_ADC[] = {
Sissors 8:68082fdde730 15 {P0_11, ADC0_0, 0x02},
Sissors 8:68082fdde730 16 {P0_12, ADC0_1, 0x02},
Sissors 8:68082fdde730 17 {P0_13, ADC0_2, 0x02},
Sissors 8:68082fdde730 18 {P0_14, ADC0_3, 0x02},
Sissors 8:68082fdde730 19 {P0_15, ADC0_4, 0x02},
Sissors 8:68082fdde730 20 {P0_16, ADC0_5, 0x01},
Sissors 8:68082fdde730 21 {P0_22, ADC0_6, 0x01},
Sissors 8:68082fdde730 22 {P0_23, ADC0_7, 0x01},
Sissors 8:68082fdde730 23 {NC , NC , 0 }
Sissors 8:68082fdde730 24 };
Sissors 11:14744c4ac884 25 #else
Sissors 11:14744c4ac884 26 static const PinMap PinMap_ADC[] = {
Sissors 11:14744c4ac884 27 {P0_11, ADC0_0, 2},
Sissors 11:14744c4ac884 28 {P1_0 , ADC0_1, 2},
Sissors 11:14744c4ac884 29 {P1_1 , ADC0_2, 2},
Sissors 11:14744c4ac884 30 {P1_2 , ADC0_3, 2},
Sissors 11:14744c4ac884 31 // {P1_3 , ADC0_4, 2}, -- should be mapped to SWDIO only
Sissors 11:14744c4ac884 32 {P1_4 , ADC0_5, 1},
Sissors 11:14744c4ac884 33 {P1_10, ADC0_6, 1},
Sissors 11:14744c4ac884 34 {P1_11, ADC0_7, 1},
Sissors 11:14744c4ac884 35 {NC , NC , 0}
Sissors 11:14744c4ac884 36 };
Sissors 11:14744c4ac884 37 #endif
Sissors 8:68082fdde730 38
Sissors 8:68082fdde730 39 static int channel_usage[8] = {0,0,0,0,0,0,0,0};
Sissors 8:68082fdde730 40
Sissors 8:68082fdde730 41
Sissors 8:68082fdde730 42
Sissors 8:68082fdde730 43 FastAnalogIn::FastAnalogIn(PinName pin, bool enabled)
Sissors 8:68082fdde730 44 {
Sissors 8:68082fdde730 45 ADCnumber = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
Sissors 8:68082fdde730 46 if (ADCnumber == (uint32_t)NC)
Sissors 8:68082fdde730 47 error("ADC pin mapping failed");
Sissors 11:14744c4ac884 48
Sissors 11:14744c4ac884 49 //Seriously software people, can't you guys never keep the namings the same?
Sissors 11:14744c4ac884 50 #ifdef TARGET_LPC11UXX
Sissors 8:68082fdde730 51 datareg = (uint32_t*) (&LPC_ADC->DR0 + ADCnumber);
Sissors 11:14744c4ac884 52 #else
Sissors 11:14744c4ac884 53 datareg = (uint32_t*) (&LPC_ADC->DR[ADCnumber]);
Sissors 11:14744c4ac884 54 #endif
Sissors 8:68082fdde730 55
Sissors 8:68082fdde730 56 // Power up ADC
Sissors 8:68082fdde730 57 LPC_SYSCON->PDRUNCFG &= ~ (1 << 4);
Sissors 8:68082fdde730 58 LPC_SYSCON->SYSAHBCLKCTRL |= ((uint32_t)1 << 13);
Sissors 8:68082fdde730 59
Sissors 8:68082fdde730 60 uint32_t pin_number = (uint32_t)pin;
Sissors 8:68082fdde730 61 __IO uint32_t *reg = (pin_number < 32) ? (__IO uint32_t*)(LPC_IOCON0_BASE + 4 * pin_number) : (__IO uint32_t*)(LPC_IOCON1_BASE + 4 * (pin_number - 32));
Sissors 8:68082fdde730 62
Sissors 8:68082fdde730 63 // set pin to ADC mode
Sissors 8:68082fdde730 64 *reg &= ~(1 << 7); // set ADMODE = 0 (analog mode)
Sissors 8:68082fdde730 65
Sissors 8:68082fdde730 66 uint32_t clkdiv = div_round_up(SystemCoreClock, MAX_ADC_CLK) - 1;
Sissors 8:68082fdde730 67
Sissors 10:afc3b84dbbd6 68 LPC_ADC->CR = (LPC_ADC->CR & 0xFF) // keep current channels
Sissors 8:68082fdde730 69 | (clkdiv << 8) // max of 4.5MHz
Sissors 8:68082fdde730 70 | (1 << 16) // BURST = 1, hardware controlled
Sissors 8:68082fdde730 71 | ( 0 << 17 ); // CLKS = 0, we stick to 10 bit mode
Sissors 8:68082fdde730 72
Sissors 8:68082fdde730 73 pinmap_pinout(pin, PinMap_ADC);
Sissors 8:68082fdde730 74
Sissors 8:68082fdde730 75 //Enable channel
Sissors 8:68082fdde730 76 running = false;
Sissors 8:68082fdde730 77 enable(enabled);
Sissors 8:68082fdde730 78
Sissors 8:68082fdde730 79 }
Sissors 8:68082fdde730 80
Sissors 8:68082fdde730 81 void FastAnalogIn::enable(bool enabled)
Sissors 8:68082fdde730 82 {
Sissors 8:68082fdde730 83 //If currently not running
Sissors 8:68082fdde730 84 if (!running) {
Sissors 8:68082fdde730 85 if (enabled) {
Sissors 8:68082fdde730 86 //Enable the ADC channel
Sissors 8:68082fdde730 87 channel_usage[ADCnumber]++;
Sissors 8:68082fdde730 88 LPC_ADC->CR |= (1<<ADCnumber);
Sissors 8:68082fdde730 89 running = true;
Sissors 8:68082fdde730 90 } else
Sissors 8:68082fdde730 91 disable();
Sissors 8:68082fdde730 92 }
Sissors 8:68082fdde730 93 }
Sissors 8:68082fdde730 94
Sissors 8:68082fdde730 95 void FastAnalogIn::disable( void )
Sissors 8:68082fdde730 96 {
Sissors 8:68082fdde730 97 //If currently running
Sissors 8:68082fdde730 98 if (running) {
Sissors 8:68082fdde730 99 channel_usage[ADCnumber]--;
Sissors 8:68082fdde730 100
Sissors 8:68082fdde730 101 if (channel_usage[ADCnumber]==0)
Sissors 8:68082fdde730 102 LPC_ADC->CR &= ~(1<<ADCnumber);
Sissors 8:68082fdde730 103 }
Sissors 8:68082fdde730 104 running = false;
Sissors 8:68082fdde730 105 }
Sissors 8:68082fdde730 106
Sissors 8:68082fdde730 107 unsigned short FastAnalogIn::read_u16( void )
Sissors 8:68082fdde730 108 {
Sissors 8:68082fdde730 109 unsigned int retval;
Sissors 8:68082fdde730 110 //If object is enabled return current value of datareg
Sissors 8:68082fdde730 111 if (running)
Sissors 8:68082fdde730 112 retval = *datareg;
Sissors 8:68082fdde730 113
Sissors 8:68082fdde730 114 //If it isn't running, enable it and wait until new value is written to datareg
Sissors 8:68082fdde730 115 else {
Sissors 8:68082fdde730 116 //Force a read to clear done bit, enable the ADC channel
Sissors 8:68082fdde730 117 retval = *datareg;
Sissors 8:68082fdde730 118 enable();
Sissors 8:68082fdde730 119 //Wait until it is converted
Sissors 8:68082fdde730 120 while(1) {
Sissors 8:68082fdde730 121 retval = *datareg;
Sissors 8:68082fdde730 122 if ((retval>>31) == 1)
Sissors 8:68082fdde730 123 break;
Sissors 8:68082fdde730 124 }
Sissors 8:68082fdde730 125 //Disable again
Sissors 8:68082fdde730 126 disable();
Sissors 8:68082fdde730 127 }
Sissors 8:68082fdde730 128
Sissors 8:68082fdde730 129 //Do same thing as standard mbed lib, unused bit 0-3, replicate 4-7 in it
Sissors 8:68082fdde730 130 retval &= ~0xFFFF003F;
Sissors 8:68082fdde730 131 retval |= (retval >> 6) & 0x003F;
Sissors 8:68082fdde730 132 return retval;
Sissors 8:68082fdde730 133 }
Sissors 8:68082fdde730 134 #endif //defined TARGET_LPC11UXX