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.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
AltAnalogIn/AltAnalogIn.h@47:df7a88cd249c, 2016-02-18 (annotated)
- Committer:
- mjr
- Date:
- Thu Feb 18 07:32:20 2016 +0000
- Revision:
- 47:df7a88cd249c
- Parent:
- 45:c42166b2878c
- Child:
- 48:058ace2aed1d
3-channel linked DMA scheme for CCD image capture working
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| mjr | 43:7a6364d82a41 | 1 | #ifndef ALTANALOGIN_H |
| mjr | 43:7a6364d82a41 | 2 | #define ALTANALOGIN_H |
| mjr | 43:7a6364d82a41 | 3 | |
| mjr | 43:7a6364d82a41 | 4 | // This is a slightly modified version of Scissors's FastAnalogIn. |
| mjr | 43:7a6364d82a41 | 5 | // |
| mjr | 43:7a6364d82a41 | 6 | // This version is optimized for reading from multiple inputs. The KL25Z has |
| mjr | 43:7a6364d82a41 | 7 | // multiple ADC channels, but the multiplexer hardware only allows sampling one |
| mjr | 43:7a6364d82a41 | 8 | // at a time. The entire sampling process from start to finish is serialized |
| mjr | 43:7a6364d82a41 | 9 | // in the multiplexer, so we unfortunately can't overlap the sampling times |
| mjr | 43:7a6364d82a41 | 10 | // for multiple channels - we have to wait in sequence for the sampling period |
| mjr | 43:7a6364d82a41 | 11 | // on each channel, one after the other. |
| mjr | 43:7a6364d82a41 | 12 | // |
| mjr | 43:7a6364d82a41 | 13 | // The base version of FastAnalogIn uses the hardware's continuous conversion |
| mjr | 43:7a6364d82a41 | 14 | // feature to speed up sampling. When sampling multiple inputs, that feature |
| mjr | 43:7a6364d82a41 | 15 | // becomes useless, and in fact the way FastAnalogIn uses it creates additional |
| mjr | 43:7a6364d82a41 | 16 | // overhead for multiple input sampling. But FastAnalogIn still has some speed |
| mjr | 43:7a6364d82a41 | 17 | // advantages over the base mbed AnalogIn implementation, since it sets all of |
| mjr | 43:7a6364d82a41 | 18 | // the other conversion settings to the fastest options. This version keeps the |
| mjr | 43:7a6364d82a41 | 19 | // other speed-ups from FastAnalogIn, but dispenses with the continuous sampling. |
| mjr | 43:7a6364d82a41 | 20 | |
| mjr | 43:7a6364d82a41 | 21 | /* |
| mjr | 43:7a6364d82a41 | 22 | * Includes |
| mjr | 43:7a6364d82a41 | 23 | */ |
| mjr | 43:7a6364d82a41 | 24 | #include "mbed.h" |
| mjr | 43:7a6364d82a41 | 25 | #include "pinmap.h" |
| mjr | 45:c42166b2878c | 26 | #include "SimpleDMA.h" |
| mjr | 45:c42166b2878c | 27 | |
| mjr | 45:c42166b2878c | 28 | // KL25Z definitions |
| mjr | 45:c42166b2878c | 29 | #if defined TARGET_KLXX |
| mjr | 45:c42166b2878c | 30 | |
| mjr | 45:c42166b2878c | 31 | // Maximum ADC clock for KL25Z in 12-bit mode - 18 MHz per the data sheet |
| mjr | 45:c42166b2878c | 32 | #define MAX_FADC_12BIT 18000000 |
| mjr | 45:c42166b2878c | 33 | |
| mjr | 45:c42166b2878c | 34 | #define CHANNELS_A_SHIFT 5 // bit position in ADC channel number of A/B mux |
| mjr | 45:c42166b2878c | 35 | #define ADC_CFG1_ADLSMP 0x10 // long sample time mode |
| mjr | 45:c42166b2878c | 36 | #define ADC_SC1_AIEN 0x40 // interrupt enable |
| mjr | 45:c42166b2878c | 37 | #define ADC_SC2_ADLSTS(mode) (mode) // long sample time select - bits 1:0 of CFG2 |
| mjr | 45:c42166b2878c | 38 | #define ADC_SC2_DMAEN 0x04 // DMA enable |
| mjr | 45:c42166b2878c | 39 | #define ADC_SC3_CONTINUOUS 0x08 // continuous conversion mode |
| mjr | 45:c42166b2878c | 40 | |
| mjr | 47:df7a88cd249c | 41 | #define ADC_8BIT 0 // 8-bit resolution |
| mjr | 47:df7a88cd249c | 42 | #define ADC_12BIT 1 // 12-bit resolution |
| mjr | 47:df7a88cd249c | 43 | #define ADC_10BIT 2 // 10-bit resolution |
| mjr | 47:df7a88cd249c | 44 | #define ADC_16BIT 3 // 16-bit resolution |
| mjr | 47:df7a88cd249c | 45 | |
| mjr | 45:c42166b2878c | 46 | #else |
| mjr | 45:c42166b2878c | 47 | #error "This target is not currently supported" |
| mjr | 45:c42166b2878c | 48 | #endif |
| mjr | 43:7a6364d82a41 | 49 | |
| mjr | 43:7a6364d82a41 | 50 | #if !defined TARGET_LPC1768 && !defined TARGET_KLXX && !defined TARGET_LPC408X && !defined TARGET_LPC11UXX && !defined TARGET_K20D5M |
| mjr | 43:7a6364d82a41 | 51 | #error "Target not supported" |
| mjr | 43:7a6364d82a41 | 52 | #endif |
| mjr | 43:7a6364d82a41 | 53 | |
| mjr | 45:c42166b2878c | 54 | /** A class similar to AnalogIn, but much faster. This class is optimized |
| mjr | 45:c42166b2878c | 55 | * for taking a string of readings from a single input. |
| mjr | 43:7a6364d82a41 | 56 | * |
| mjr | 45:c42166b2878c | 57 | * This is a heavily modified version of the popular FastAnalogIn class. |
| mjr | 45:c42166b2878c | 58 | * Like FastAnalogIn, this class uses the continuous conversion mode to |
| mjr | 45:c42166b2878c | 59 | * achieve faster read times. It adds interrupt callbacks on each |
| mjr | 45:c42166b2878c | 60 | * conversion, and DMA transfer of the input data to memory (or to another |
| mjr | 45:c42166b2878c | 61 | * peripheral) using the SimpleDMA class. DMA makes a huge difference - |
| mjr | 45:c42166b2878c | 62 | * it speeds up the sampling time by about 3x and gets us fairly close to |
| mjr | 45:c42166b2878c | 63 | * the speeds claimed by the manufacturer. Reading through the MCU code |
| mjr | 45:c42166b2878c | 64 | * seems to add at least a few microseconds per sample, which is significant |
| mjr | 45:c42166b2878c | 65 | * when trying to get close to the theoretical speed limits for the ADC |
| mjr | 45:c42166b2878c | 66 | * hardware, which are around 1.5us. |
| mjr | 43:7a6364d82a41 | 67 | * |
| mjr | 45:c42166b2878c | 68 | * This class can be used with or without DMA. By default, you take samples |
| mjr | 45:c42166b2878c | 69 | * directly. Call start() to initiate sampling, and call one of the |
| mjr | 45:c42166b2878c | 70 | * read routines (read() or read_u16()) to wait for the sample to complete |
| mjr | 45:c42166b2878c | 71 | * and fetch the value. In this mode, samples are taken individually. |
| mjr | 45:c42166b2878c | 72 | * The start() and read routines are separated so that the caller can |
| mjr | 45:c42166b2878c | 73 | * perform other work, if desired, while the ADC hardware takes the sample. |
| mjr | 43:7a6364d82a41 | 74 | * |
| mjr | 45:c42166b2878c | 75 | * To use with DMA, set up a SimpleDMA object, and call initDMA() to tie |
| mjr | 45:c42166b2878c | 76 | * it to the analog input. Call startDMA() to initiate a transfer. We'll |
| mjr | 45:c42166b2878c | 77 | * start reading the analog input in continuous mode; each time a sample |
| mjr | 45:c42166b2878c | 78 | * completes, it will trigger a DMA transfer to the destination. startDMA() |
| mjr | 45:c42166b2878c | 79 | * returns immediately, so the caller can continue with other tasks while |
| mjr | 45:c42166b2878c | 80 | * the samples are taken. |
| mjr | 43:7a6364d82a41 | 81 | * |
| mjr | 45:c42166b2878c | 82 | * IMPORTANT! This class does not play nicely with regular AnalogIn objects, |
| mjr | 45:c42166b2878c | 83 | * nor with the original FastAnalogIn, because all of these classes set global |
| mjr | 45:c42166b2878c | 84 | * configuration registers in the ADC hardware at setup time and then will |
| mjr | 45:c42166b2878c | 85 | * assume that no one else is messing with them. Each library requires |
| mjr | 45:c42166b2878c | 86 | * exclusive access to and control over the hardware, so they can't be mixed |
| mjr | 45:c42166b2878c | 87 | * in the same program. |
| mjr | 45:c42166b2878c | 88 | */ |
| mjr | 43:7a6364d82a41 | 89 | class AltAnalogIn { |
| mjr | 43:7a6364d82a41 | 90 | |
| mjr | 43:7a6364d82a41 | 91 | public: |
| mjr | 43:7a6364d82a41 | 92 | /** Create an AltAnalogIn, connected to the specified pin |
| mjr | 43:7a6364d82a41 | 93 | * |
| mjr | 43:7a6364d82a41 | 94 | * @param pin AnalogIn pin to connect to |
| mjr | 43:7a6364d82a41 | 95 | * @param enabled Enable the ADC channel (default = true) |
| mjr | 43:7a6364d82a41 | 96 | */ |
| mjr | 45:c42166b2878c | 97 | AltAnalogIn(PinName pin, bool continuous = false); |
| mjr | 43:7a6364d82a41 | 98 | |
| mjr | 43:7a6364d82a41 | 99 | ~AltAnalogIn( void ) |
| mjr | 43:7a6364d82a41 | 100 | { |
| mjr | 43:7a6364d82a41 | 101 | } |
| mjr | 43:7a6364d82a41 | 102 | |
| mjr | 45:c42166b2878c | 103 | // Initialize DMA. This connects the analog in port to the |
| mjr | 45:c42166b2878c | 104 | // given DMA object. |
| mjr | 45:c42166b2878c | 105 | // |
| mjr | 45:c42166b2878c | 106 | // DMA transfers from the analog in port often use continuous |
| mjr | 45:c42166b2878c | 107 | // conversion mode. Note, however, that we don't automatically |
| mjr | 45:c42166b2878c | 108 | // assume this - single sample mode is the default, which means |
| mjr | 45:c42166b2878c | 109 | // that you must manually start each sample. If you want to use |
| mjr | 45:c42166b2878c | 110 | // continuous mode, you need to set that separately (via the |
| mjr | 45:c42166b2878c | 111 | // constructor). |
| mjr | 45:c42166b2878c | 112 | void initDMA(SimpleDMA *dma); |
| mjr | 45:c42166b2878c | 113 | |
| mjr | 43:7a6364d82a41 | 114 | /** Start a sample. This sets the ADC multiplexer to read from |
| mjr | 43:7a6364d82a41 | 115 | * this input and activates the sampler. |
| mjr | 43:7a6364d82a41 | 116 | */ |
| mjr | 43:7a6364d82a41 | 117 | inline void start() |
| mjr | 43:7a6364d82a41 | 118 | { |
| mjr | 43:7a6364d82a41 | 119 | // update the MUX bit in the CFG2 register only if necessary |
| mjr | 43:7a6364d82a41 | 120 | static int lastMux = -1; |
| mjr | 43:7a6364d82a41 | 121 | if (lastMux != ADCmux) |
| mjr | 43:7a6364d82a41 | 122 | { |
| mjr | 43:7a6364d82a41 | 123 | // remember the new register value |
| mjr | 43:7a6364d82a41 | 124 | lastMux = ADCmux; |
| mjr | 43:7a6364d82a41 | 125 | |
| mjr | 43:7a6364d82a41 | 126 | // select the multiplexer for our ADC channel |
| mjr | 43:7a6364d82a41 | 127 | if (ADCmux) |
| mjr | 43:7a6364d82a41 | 128 | ADC0->CFG2 |= ADC_CFG2_MUXSEL_MASK; |
| mjr | 43:7a6364d82a41 | 129 | else |
| mjr | 43:7a6364d82a41 | 130 | ADC0->CFG2 &= ~ADC_CFG2_MUXSEL_MASK; |
| mjr | 43:7a6364d82a41 | 131 | } |
| mjr | 43:7a6364d82a41 | 132 | |
| mjr | 45:c42166b2878c | 133 | // update the SC2 and SC3 bits only if we're changing inputs |
| mjr | 45:c42166b2878c | 134 | static uint32_t lastid = 0; |
| mjr | 45:c42166b2878c | 135 | if (id != lastid) |
| mjr | 45:c42166b2878c | 136 | { |
| mjr | 45:c42166b2878c | 137 | // set our ADC0 SC2 and SC3 configuration bits |
| mjr | 45:c42166b2878c | 138 | ADC0->SC2 = sc2; |
| mjr | 45:c42166b2878c | 139 | ADC0->SC3 = sc3; |
| mjr | 45:c42166b2878c | 140 | |
| mjr | 45:c42166b2878c | 141 | // we're the active one now |
| mjr | 45:c42166b2878c | 142 | lastid = id; |
| mjr | 45:c42166b2878c | 143 | } |
| mjr | 45:c42166b2878c | 144 | |
| mjr | 45:c42166b2878c | 145 | // set our SC1 bits - this initiates the sample |
| mjr | 45:c42166b2878c | 146 | ADC0->SC1[0] = sc1; |
| mjr | 43:7a6364d82a41 | 147 | } |
| mjr | 43:7a6364d82a41 | 148 | |
| mjr | 45:c42166b2878c | 149 | // stop sampling |
| mjr | 45:c42166b2878c | 150 | void stop() |
| mjr | 45:c42166b2878c | 151 | { |
| mjr | 45:c42166b2878c | 152 | // set the channel bits to binary 11111 to disable sampling |
| mjr | 45:c42166b2878c | 153 | ADC0->SC1[0] = 0x1F; |
| mjr | 45:c42166b2878c | 154 | } |
| mjr | 45:c42166b2878c | 155 | |
| mjr | 45:c42166b2878c | 156 | // wait for the current sample to complete |
| mjr | 45:c42166b2878c | 157 | inline void wait() |
| mjr | 45:c42166b2878c | 158 | { |
| mjr | 45:c42166b2878c | 159 | while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) == 0); |
| mjr | 45:c42166b2878c | 160 | } |
| mjr | 43:7a6364d82a41 | 161 | |
| mjr | 43:7a6364d82a41 | 162 | |
| mjr | 43:7a6364d82a41 | 163 | /** Returns the raw value |
| mjr | 43:7a6364d82a41 | 164 | * |
| mjr | 43:7a6364d82a41 | 165 | * @param return Unsigned integer with converted value |
| mjr | 43:7a6364d82a41 | 166 | */ |
| mjr | 43:7a6364d82a41 | 167 | inline uint16_t read_u16() |
| mjr | 43:7a6364d82a41 | 168 | { |
| mjr | 43:7a6364d82a41 | 169 | // wait for the hardware to signal that the sample is completed |
| mjr | 45:c42166b2878c | 170 | wait(); |
| mjr | 43:7a6364d82a41 | 171 | |
| mjr | 43:7a6364d82a41 | 172 | // return the result register value |
| mjr | 43:7a6364d82a41 | 173 | return (uint16_t)ADC0->R[0] << 4; // convert 12-bit to 16-bit, padding with zeroes |
| mjr | 43:7a6364d82a41 | 174 | } |
| mjr | 43:7a6364d82a41 | 175 | |
| mjr | 43:7a6364d82a41 | 176 | /** Returns the scaled value |
| mjr | 43:7a6364d82a41 | 177 | * |
| mjr | 43:7a6364d82a41 | 178 | * @param return Float with scaled converted value to 0.0-1.0 |
| mjr | 43:7a6364d82a41 | 179 | */ |
| mjr | 43:7a6364d82a41 | 180 | float read(void) |
| mjr | 43:7a6364d82a41 | 181 | { |
| mjr | 43:7a6364d82a41 | 182 | unsigned short value = read_u16(); |
| mjr | 43:7a6364d82a41 | 183 | return value / 65535.0f; |
| mjr | 43:7a6364d82a41 | 184 | } |
| mjr | 43:7a6364d82a41 | 185 | |
| mjr | 43:7a6364d82a41 | 186 | /** An operator shorthand for read() |
| mjr | 43:7a6364d82a41 | 187 | */ |
| mjr | 43:7a6364d82a41 | 188 | operator float() { return read(); } |
| mjr | 43:7a6364d82a41 | 189 | |
| mjr | 43:7a6364d82a41 | 190 | |
| mjr | 43:7a6364d82a41 | 191 | private: |
| mjr | 45:c42166b2878c | 192 | uint32_t id; // unique ID |
| mjr | 45:c42166b2878c | 193 | SimpleDMA *dma; // DMA controller, if used |
| mjr | 45:c42166b2878c | 194 | FunctionPointer _callback; // interrupt callback |
| mjr | 45:c42166b2878c | 195 | char ADCnumber; // ADC number of our input pin |
| mjr | 45:c42166b2878c | 196 | char ADCmux; // multiplexer for our input pin (0=A, 1=B) |
| mjr | 45:c42166b2878c | 197 | uint32_t sc1; // SC1 register settings for this input |
| mjr | 45:c42166b2878c | 198 | uint32_t sc2; // SC2 register settings for this input |
| mjr | 45:c42166b2878c | 199 | uint32_t sc3; // SC3 register settings for this input |
| mjr | 43:7a6364d82a41 | 200 | }; |
| mjr | 43:7a6364d82a41 | 201 | |
| mjr | 43:7a6364d82a41 | 202 | #endif |
