Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
AltAnalogIn/AltAnalogIn.h@116:7a67265d7c19, 2021-10-01 (annotated)
- Committer:
- arnoz
- Date:
- Fri Oct 01 08:19:46 2021 +0000
- Revision:
- 116:7a67265d7c19
- Parent:
- 104:6e06e0f4b476
- Correct information regarding your last merge
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 | 48:058ace2aed1d | 4 | // This is a modified version of Scissors's FastAnalogIn, customized |
mjr | 104:6e06e0f4b476 | 5 | // for the needs of the Pinscape linear image sensor interfaces. This |
mjr | 104:6e06e0f4b476 | 6 | // class has a bunch of features to make it even faster than FastAnalogIn, |
mjr | 104:6e06e0f4b476 | 7 | // including support for 8-bit and 12-bit resolution modes, continuous |
mjr | 104:6e06e0f4b476 | 8 | // sampling mode, coordination with DMA to move samples into memory |
mjr | 104:6e06e0f4b476 | 9 | // asynchronously, and client selection of the ADC timing modes. |
mjr | 48:058ace2aed1d | 10 | // |
mjr | 104:6e06e0f4b476 | 11 | // We need all of this special ADC handling because the image sensors |
mjr | 104:6e06e0f4b476 | 12 | // have special timing requirements that we can only meet with the |
mjr | 104:6e06e0f4b476 | 13 | // fastest modes offered by the KL25Z ADC. The image sensors all |
mjr | 104:6e06e0f4b476 | 14 | // operate by sending pixel data as a serial stream of analog samples, |
mjr | 104:6e06e0f4b476 | 15 | // so the minimum time to read a frame is approximately <number of |
mjr | 104:6e06e0f4b476 | 16 | // pixels in the frame> times <ADC sampling time per sample>. The |
mjr | 104:6e06e0f4b476 | 17 | // sensors we currently support vary from 1280 to 1546 pixels per frame. |
mjr | 104:6e06e0f4b476 | 18 | // With the fastest KL25Z modes, that works out to about 3ms per frame, |
mjr | 104:6e06e0f4b476 | 19 | // which is just fast enough for our purposes. Using only the default |
mjr | 104:6e06e0f4b476 | 20 | // modes in the mbed libraries, frame times are around 30ms, which is |
mjr | 104:6e06e0f4b476 | 21 | // much too slow to accurately track a fast-moving plunger. |
mjr | 104:6e06e0f4b476 | 22 | // |
mjr | 104:6e06e0f4b476 | 23 | // This class works ONLY with the KL25Z. |
mjr | 43:7a6364d82a41 | 24 | // |
mjr | 100:1ff35c07217c | 25 | // Important! This class can't coexist at run-time with the standard |
mjr | 104:6e06e0f4b476 | 26 | // mbed library version of AnalogIn, or with the original version of |
mjr | 100:1ff35c07217c | 27 | // FastAnalogIn. All of these classes program the ADC configuration |
mjr | 100:1ff35c07217c | 28 | // registers with their own custom settings. These registers are a |
mjr | 100:1ff35c07217c | 29 | // global resource, and the different classes all assume they have |
mjr | 100:1ff35c07217c | 30 | // exclusive control, so they don't try to coordinate with anyone else |
mjr | 100:1ff35c07217c | 31 | // programming the registers. A program that uses AltAnalogIn in one |
mjr | 100:1ff35c07217c | 32 | // place will have to use AltAnalogIn exclusively throughout the |
mjr | 100:1ff35c07217c | 33 | // program for all ADC interaction. (It *is* okay to statically link |
mjr | 100:1ff35c07217c | 34 | // the different classes, as long as only one is actually used at |
mjr | 100:1ff35c07217c | 35 | // run-time. The Pinscape software does this, and selects the one to |
mjr | 100:1ff35c07217c | 36 | // use at run-time according to which plunger class is selected.) |
mjr | 43:7a6364d82a41 | 37 | |
mjr | 43:7a6364d82a41 | 38 | /* |
mjr | 43:7a6364d82a41 | 39 | * Includes |
mjr | 43:7a6364d82a41 | 40 | */ |
mjr | 43:7a6364d82a41 | 41 | #include "mbed.h" |
mjr | 43:7a6364d82a41 | 42 | #include "pinmap.h" |
mjr | 45:c42166b2878c | 43 | #include "SimpleDMA.h" |
mjr | 45:c42166b2878c | 44 | |
mjr | 45:c42166b2878c | 45 | // KL25Z definitions |
mjr | 45:c42166b2878c | 46 | #if defined TARGET_KLXX |
mjr | 45:c42166b2878c | 47 | |
mjr | 100:1ff35c07217c | 48 | // Maximum ADC clock for KL25Z in <= 12-bit mode - 18 MHz per the data sheet |
mjr | 45:c42166b2878c | 49 | #define MAX_FADC_12BIT 18000000 |
mjr | 45:c42166b2878c | 50 | |
mjr | 100:1ff35c07217c | 51 | // Maximum ADC clock for KL25Z in 16-bit mode - 12 MHz per the data sheet |
mjr | 100:1ff35c07217c | 52 | #define MAX_FADC_16BIT 12000000 |
mjr | 100:1ff35c07217c | 53 | |
mjr | 45:c42166b2878c | 54 | #define CHANNELS_A_SHIFT 5 // bit position in ADC channel number of A/B mux |
mjr | 45:c42166b2878c | 55 | #define ADC_CFG1_ADLSMP 0x10 // long sample time mode |
mjr | 45:c42166b2878c | 56 | #define ADC_SC1_AIEN 0x40 // interrupt enable |
mjr | 45:c42166b2878c | 57 | #define ADC_SC2_ADLSTS(mode) (mode) // long sample time select - bits 1:0 of CFG2 |
mjr | 45:c42166b2878c | 58 | #define ADC_SC2_DMAEN 0x04 // DMA enable |
mjr | 100:1ff35c07217c | 59 | #define ADC_SC2_ADTRG 0x40 // Hardware conversion trigger |
mjr | 45:c42166b2878c | 60 | #define ADC_SC3_CONTINUOUS 0x08 // continuous conversion mode |
mjr | 100:1ff35c07217c | 61 | #define ADC_SC3_AVGE 0x04 // averaging enabled |
mjr | 100:1ff35c07217c | 62 | #define ADC_SC3_AVGS_4 0x00 // 4-sample averaging |
mjr | 100:1ff35c07217c | 63 | #define ADC_SC3_AVGS_8 0x01 // 8-sample averaging |
mjr | 100:1ff35c07217c | 64 | #define ADC_SC3_AVGS_16 0x02 // 16-sample averaging |
mjr | 100:1ff35c07217c | 65 | #define ADC_SC3_AVGS_32 0x03 // 32-sample averaging |
mjr | 100:1ff35c07217c | 66 | #define ADC_SC3_CAL 0x80 // calibration - set to begin calibration |
mjr | 100:1ff35c07217c | 67 | #define ADC_SC3_CALF 0x40 // calibration failed flag |
mjr | 45:c42166b2878c | 68 | |
mjr | 47:df7a88cd249c | 69 | #define ADC_8BIT 0 // 8-bit resolution |
mjr | 47:df7a88cd249c | 70 | #define ADC_12BIT 1 // 12-bit resolution |
mjr | 47:df7a88cd249c | 71 | #define ADC_10BIT 2 // 10-bit resolution |
mjr | 47:df7a88cd249c | 72 | #define ADC_16BIT 3 // 16-bit resolution |
mjr | 47:df7a88cd249c | 73 | |
mjr | 100:1ff35c07217c | 74 | // SIM_SOPT7 - enable alternative conversion triggers |
mjr | 100:1ff35c07217c | 75 | #define ADC0ALTTRGEN 0x80 |
mjr | 100:1ff35c07217c | 76 | |
mjr | 100:1ff35c07217c | 77 | // SIM_SOPT7 ADC0TRGSEL bits for TPMn, n = 0..2 |
mjr | 100:1ff35c07217c | 78 | #define ADC0TRGSEL_TPM(n) (0x08 | (n)) // select TPMn overflow |
mjr | 100:1ff35c07217c | 79 | |
mjr | 100:1ff35c07217c | 80 | |
mjr | 45:c42166b2878c | 81 | #else |
mjr | 45:c42166b2878c | 82 | #error "This target is not currently supported" |
mjr | 45:c42166b2878c | 83 | #endif |
mjr | 43:7a6364d82a41 | 84 | |
mjr | 43:7a6364d82a41 | 85 | #if !defined TARGET_LPC1768 && !defined TARGET_KLXX && !defined TARGET_LPC408X && !defined TARGET_LPC11UXX && !defined TARGET_K20D5M |
mjr | 43:7a6364d82a41 | 86 | #error "Target not supported" |
mjr | 43:7a6364d82a41 | 87 | #endif |
mjr | 43:7a6364d82a41 | 88 | |
mjr | 48:058ace2aed1d | 89 | |
mjr | 43:7a6364d82a41 | 90 | class AltAnalogIn { |
mjr | 43:7a6364d82a41 | 91 | |
mjr | 43:7a6364d82a41 | 92 | public: |
mjr | 43:7a6364d82a41 | 93 | /** Create an AltAnalogIn, connected to the specified pin |
mjr | 43:7a6364d82a41 | 94 | * |
mjr | 43:7a6364d82a41 | 95 | * @param pin AnalogIn pin to connect to |
mjr | 100:1ff35c07217c | 96 | * @param continuous true to enable continue sampling mode |
mjr | 100:1ff35c07217c | 97 | * @param long_sample_clocks long sample mode: 0 to disable, ADC clock count to enable (6, 10, 16, or 24) |
mjr | 100:1ff35c07217c | 98 | * @param averaging number of averaging cycles (1, 4, 8, 16, 32) |
mjr | 100:1ff35c07217c | 99 | * @param sample_bits sample size in bits (8, 10, 12, 16) |
mjr | 43:7a6364d82a41 | 100 | */ |
mjr | 100:1ff35c07217c | 101 | AltAnalogIn(PinName pin, bool continuous = false, int long_sample_clocks = 0, int averaging = 1, int sample_bits = 8); |
mjr | 43:7a6364d82a41 | 102 | |
mjr | 43:7a6364d82a41 | 103 | ~AltAnalogIn( void ) |
mjr | 43:7a6364d82a41 | 104 | { |
mjr | 43:7a6364d82a41 | 105 | } |
mjr | 43:7a6364d82a41 | 106 | |
mjr | 100:1ff35c07217c | 107 | // Calibrate the ADC. Per the KL25Z reference manual, this should be |
mjr | 100:1ff35c07217c | 108 | // done after each CPU reset to get the best accuracy from the ADC. |
mjr | 100:1ff35c07217c | 109 | // |
mjr | 100:1ff35c07217c | 110 | // The calibration process runs synchronously (blocking) and takes |
mjr | 100:1ff35c07217c | 111 | // about 2ms. Per the reference manual guidelines, we calibrate |
mjr | 100:1ff35c07217c | 112 | // using the same timing parameters configured in the constructor, |
mjr | 100:1ff35c07217c | 113 | // but we use the maximum averaging rounds. |
mjr | 45:c42166b2878c | 114 | // |
mjr | 100:1ff35c07217c | 115 | // The calibration depends on the timing parameters, so if multiple |
mjr | 100:1ff35c07217c | 116 | // AltAnalogIn objects will be used in the same application, the |
mjr | 100:1ff35c07217c | 117 | // configuration established for one object might not be ideal for |
mjr | 100:1ff35c07217c | 118 | // another. The advice in the reference manual is to calibrate once |
mjr | 100:1ff35c07217c | 119 | // at the settings where the highest accuracy will be needed. It's |
mjr | 100:1ff35c07217c | 120 | // also possible to capture the configuration data from the ADC |
mjr | 100:1ff35c07217c | 121 | // registers after a configuration and restore them later by writing |
mjr | 100:1ff35c07217c | 122 | // the same values back to the registers, for relatively fast switching |
mjr | 100:1ff35c07217c | 123 | // between calibration sets, but that's beyond the scope of this class. |
mjr | 100:1ff35c07217c | 124 | void calibrate(); |
mjr | 100:1ff35c07217c | 125 | |
mjr | 100:1ff35c07217c | 126 | // Initialize DMA. This connects the ADC port to the given DMA |
mjr | 100:1ff35c07217c | 127 | // channel. This doesn't actually initiate a transfer; this just |
mjr | 100:1ff35c07217c | 128 | // connects the ADC to the DMA channel for later transfers. Use |
mjr | 100:1ff35c07217c | 129 | // the DMA object to set up a transfer, and use one of the trigger |
mjr | 100:1ff35c07217c | 130 | // modes (e.g., start() for software triggering) to initiate a |
mjr | 100:1ff35c07217c | 131 | // sample. |
mjr | 45:c42166b2878c | 132 | void initDMA(SimpleDMA *dma); |
mjr | 100:1ff35c07217c | 133 | |
mjr | 100:1ff35c07217c | 134 | // Enable interrupts. This doesn't actually set up a handler; the |
mjr | 100:1ff35c07217c | 135 | // caller is responsible for that. This merely sets the ADC registers |
mjr | 100:1ff35c07217c | 136 | // so that the ADC generates an ADC0_IRQ interrupt request each time |
mjr | 100:1ff35c07217c | 137 | // the sample completes. |
mjr | 100:1ff35c07217c | 138 | // |
mjr | 100:1ff35c07217c | 139 | // Note that the interrupt handler must read from ADC0->R[0] before |
mjr | 100:1ff35c07217c | 140 | // returning, which has the side effect of clearning the COCO (conversion |
mjr | 100:1ff35c07217c | 141 | // complete) flag in the ADC registers. When interrupts are enabled, |
mjr | 100:1ff35c07217c | 142 | // the ADC asserts the ADC0_IRQ interrupt continuously as long as the |
mjr | 100:1ff35c07217c | 143 | // COCO flag is set, so if the ISR doesn't explicitly clear COCO before |
mjr | 100:1ff35c07217c | 144 | // it returns, another ADC0_IRQ interrupt will immediate occur as soon |
mjr | 100:1ff35c07217c | 145 | // as the ISR returns, so we'll be stuck in an infinite loop of calling |
mjr | 100:1ff35c07217c | 146 | // the ISR over and over. |
mjr | 100:1ff35c07217c | 147 | void enableInterrupts(); |
mjr | 45:c42166b2878c | 148 | |
mjr | 100:1ff35c07217c | 149 | // Start a sample. This sets the ADC multiplexer to read from |
mjr | 100:1ff35c07217c | 150 | // this input and activates the sampler. |
mjr | 43:7a6364d82a41 | 151 | inline void start() |
mjr | 43:7a6364d82a41 | 152 | { |
mjr | 100:1ff35c07217c | 153 | // select my channel |
mjr | 100:1ff35c07217c | 154 | selectChannel(); |
mjr | 100:1ff35c07217c | 155 | |
mjr | 100:1ff35c07217c | 156 | // set our SC1 bits - this initiates the sample |
mjr | 100:1ff35c07217c | 157 | ADC0->SC1[1] = sc1; |
mjr | 100:1ff35c07217c | 158 | ADC0->SC1[0] = sc1; |
mjr | 100:1ff35c07217c | 159 | } |
mjr | 100:1ff35c07217c | 160 | |
mjr | 100:1ff35c07217c | 161 | // Set the ADC to trigger on a TPM channel, and start sampling on |
mjr | 100:1ff35c07217c | 162 | // the trigger. This can be used to start ADC samples in sync with a |
mjr | 100:1ff35c07217c | 163 | // clock signal we're generating via a TPM. The ADC is triggered each |
mjr | 100:1ff35c07217c | 164 | // time the TPM counter overflows, which makes it trigger at the start |
mjr | 100:1ff35c07217c | 165 | // of each PWM period on the unit. |
mjr | 100:1ff35c07217c | 166 | void setTriggerTPM(int tpmUnitNumber); |
mjr | 100:1ff35c07217c | 167 | |
mjr | 100:1ff35c07217c | 168 | // stop sampling |
mjr | 100:1ff35c07217c | 169 | void stop() |
mjr | 100:1ff35c07217c | 170 | { |
mjr | 100:1ff35c07217c | 171 | // set the channel bits to binary 11111 to disable sampling |
mjr | 100:1ff35c07217c | 172 | ADC0->SC1[0] = 0x1F; |
mjr | 100:1ff35c07217c | 173 | } |
mjr | 100:1ff35c07217c | 174 | |
mjr | 100:1ff35c07217c | 175 | // Resume sampling after a pause. |
mjr | 100:1ff35c07217c | 176 | inline void resume() |
mjr | 100:1ff35c07217c | 177 | { |
mjr | 100:1ff35c07217c | 178 | // restore our SC1 bits |
mjr | 100:1ff35c07217c | 179 | ADC0->SC1[1] = sc1; |
mjr | 100:1ff35c07217c | 180 | ADC0->SC1[0] = sc1; |
mjr | 100:1ff35c07217c | 181 | } |
mjr | 100:1ff35c07217c | 182 | |
mjr | 100:1ff35c07217c | 183 | // Wait for the current sample to complete. |
mjr | 100:1ff35c07217c | 184 | // |
mjr | 100:1ff35c07217c | 185 | // IMPORTANT! DO NOT use this if DMA is enabled on the ADC. It'll |
mjr | 100:1ff35c07217c | 186 | // always gets stuck in an infinite loop, because the CPU will never |
mjr | 100:1ff35c07217c | 187 | // be able to observe the COCO bit being set when DMA is enabled. The |
mjr | 100:1ff35c07217c | 188 | // reason is that the DMA controller always reads its configured source |
mjr | 100:1ff35c07217c | 189 | // address when triggered. The DMA source address for the ADC is the |
mjr | 100:1ff35c07217c | 190 | // ADC result register ADC0->R[0], and reading that register by any |
mjr | 100:1ff35c07217c | 191 | // means clears COCO. And the DMA controller ALWAYS gets to it first, |
mjr | 100:1ff35c07217c | 192 | // so the CPU will never see COCO set when DMA is enabled. It doesn't |
mjr | 100:1ff35c07217c | 193 | // matter whether or not a DMA transfer is actually running, either - |
mjr | 100:1ff35c07217c | 194 | // it's enough to merely enable DMA on the ADC. |
mjr | 100:1ff35c07217c | 195 | inline void wait() |
mjr | 100:1ff35c07217c | 196 | { |
mjr | 100:1ff35c07217c | 197 | while (!isReady()) ; |
mjr | 100:1ff35c07217c | 198 | } |
mjr | 100:1ff35c07217c | 199 | |
mjr | 100:1ff35c07217c | 200 | // Is the sample ready? |
mjr | 100:1ff35c07217c | 201 | // |
mjr | 100:1ff35c07217c | 202 | // NOTE: As with wait(), the CPU will NEVER observe the COCO bit being |
mjr | 100:1ff35c07217c | 203 | // set if DMA is enabled on the ADC. This will always return false if |
mjr | 100:1ff35c07217c | 204 | // DMA is enabled. (Not our choice - it's a hardware feature.) |
mjr | 100:1ff35c07217c | 205 | inline bool isReady() |
mjr | 100:1ff35c07217c | 206 | { |
mjr | 100:1ff35c07217c | 207 | return (ADC0->SC1[0] & ADC_SC1_COCO_MASK) != 0; |
mjr | 100:1ff35c07217c | 208 | } |
mjr | 100:1ff35c07217c | 209 | |
mjr | 100:1ff35c07217c | 210 | |
mjr | 100:1ff35c07217c | 211 | private: |
mjr | 100:1ff35c07217c | 212 | uint32_t id; // unique ID |
mjr | 100:1ff35c07217c | 213 | SimpleDMA *dma; // DMA controller, if used |
mjr | 100:1ff35c07217c | 214 | char ADCnumber; // ADC number of our input pin |
mjr | 100:1ff35c07217c | 215 | char ADCmux; // multiplexer for our input pin (0=A, 1=B) |
mjr | 100:1ff35c07217c | 216 | uint32_t sc1; // SC1 register settings for this input |
mjr | 100:1ff35c07217c | 217 | uint32_t sc1_aien; |
mjr | 100:1ff35c07217c | 218 | uint32_t sc2; // SC2 register settings for this input |
mjr | 100:1ff35c07217c | 219 | uint32_t sc3; // SC3 register settings for this input |
mjr | 100:1ff35c07217c | 220 | |
mjr | 100:1ff35c07217c | 221 | // Switch to this channel if it's not the currently selected channel. |
mjr | 100:1ff35c07217c | 222 | // We do this as part of start() (software triggering) or any hardware |
mjr | 100:1ff35c07217c | 223 | // trigger setup. |
mjr | 100:1ff35c07217c | 224 | static int lastMux; |
mjr | 100:1ff35c07217c | 225 | static uint32_t lastId; |
mjr | 100:1ff35c07217c | 226 | void selectChannel() |
mjr | 100:1ff35c07217c | 227 | { |
mjr | 43:7a6364d82a41 | 228 | // update the MUX bit in the CFG2 register only if necessary |
mjr | 43:7a6364d82a41 | 229 | if (lastMux != ADCmux) |
mjr | 43:7a6364d82a41 | 230 | { |
mjr | 43:7a6364d82a41 | 231 | // remember the new register value |
mjr | 43:7a6364d82a41 | 232 | lastMux = ADCmux; |
mjr | 43:7a6364d82a41 | 233 | |
mjr | 43:7a6364d82a41 | 234 | // select the multiplexer for our ADC channel |
mjr | 43:7a6364d82a41 | 235 | if (ADCmux) |
mjr | 43:7a6364d82a41 | 236 | ADC0->CFG2 |= ADC_CFG2_MUXSEL_MASK; |
mjr | 43:7a6364d82a41 | 237 | else |
mjr | 43:7a6364d82a41 | 238 | ADC0->CFG2 &= ~ADC_CFG2_MUXSEL_MASK; |
mjr | 43:7a6364d82a41 | 239 | } |
mjr | 43:7a6364d82a41 | 240 | |
mjr | 45:c42166b2878c | 241 | // update the SC2 and SC3 bits only if we're changing inputs |
mjr | 100:1ff35c07217c | 242 | if (id != lastId) |
mjr | 45:c42166b2878c | 243 | { |
mjr | 45:c42166b2878c | 244 | // set our ADC0 SC2 and SC3 configuration bits |
mjr | 45:c42166b2878c | 245 | ADC0->SC2 = sc2; |
mjr | 45:c42166b2878c | 246 | ADC0->SC3 = sc3; |
mjr | 45:c42166b2878c | 247 | |
mjr | 45:c42166b2878c | 248 | // we're the active one now |
mjr | 100:1ff35c07217c | 249 | lastId = id; |
mjr | 45:c42166b2878c | 250 | } |
mjr | 45:c42166b2878c | 251 | } |
mjr | 45:c42166b2878c | 252 | |
mjr | 100:1ff35c07217c | 253 | // Unselect the channel. This clears our internal flag for which |
mjr | 100:1ff35c07217c | 254 | // configuration was selected last, so that we restore settings on |
mjr | 100:1ff35c07217c | 255 | // the next start or trigger operation. |
mjr | 100:1ff35c07217c | 256 | void unselectChannel() { lastId = 0; } |
mjr | 100:1ff35c07217c | 257 | }; |
mjr | 43:7a6364d82a41 | 258 | |
mjr | 100:1ff35c07217c | 259 | // 8-bit sampler subclass |
mjr | 100:1ff35c07217c | 260 | class AltAnalogIn_8bit : public AltAnalogIn |
mjr | 100:1ff35c07217c | 261 | { |
mjr | 100:1ff35c07217c | 262 | public: |
mjr | 100:1ff35c07217c | 263 | AltAnalogIn_8bit(PinName pin, bool continuous = false, int long_sample_clocks = 0, int averaging = 1) : |
mjr | 100:1ff35c07217c | 264 | AltAnalogIn(pin, continuous, long_sample_clocks, averaging, 8) { } |
mjr | 100:1ff35c07217c | 265 | |
mjr | 43:7a6364d82a41 | 266 | /** Returns the raw value |
mjr | 43:7a6364d82a41 | 267 | * |
mjr | 43:7a6364d82a41 | 268 | * @param return Unsigned integer with converted value |
mjr | 43:7a6364d82a41 | 269 | */ |
mjr | 43:7a6364d82a41 | 270 | inline uint16_t read_u16() |
mjr | 43:7a6364d82a41 | 271 | { |
mjr | 43:7a6364d82a41 | 272 | // wait for the hardware to signal that the sample is completed |
mjr | 45:c42166b2878c | 273 | wait(); |
mjr | 43:7a6364d82a41 | 274 | |
mjr | 43:7a6364d82a41 | 275 | // return the result register value |
mjr | 48:058ace2aed1d | 276 | return (uint16_t)ADC0->R[0] << 8; // convert 16-bit to 16-bit, padding with zeroes |
mjr | 43:7a6364d82a41 | 277 | } |
mjr | 43:7a6364d82a41 | 278 | |
mjr | 43:7a6364d82a41 | 279 | /** Returns the scaled value |
mjr | 43:7a6364d82a41 | 280 | * |
mjr | 43:7a6364d82a41 | 281 | * @param return Float with scaled converted value to 0.0-1.0 |
mjr | 43:7a6364d82a41 | 282 | */ |
mjr | 43:7a6364d82a41 | 283 | float read(void) |
mjr | 43:7a6364d82a41 | 284 | { |
mjr | 43:7a6364d82a41 | 285 | unsigned short value = read_u16(); |
mjr | 43:7a6364d82a41 | 286 | return value / 65535.0f; |
mjr | 43:7a6364d82a41 | 287 | } |
mjr | 43:7a6364d82a41 | 288 | |
mjr | 43:7a6364d82a41 | 289 | /** An operator shorthand for read() |
mjr | 43:7a6364d82a41 | 290 | */ |
mjr | 43:7a6364d82a41 | 291 | operator float() { return read(); } |
mjr | 100:1ff35c07217c | 292 | }; |
mjr | 43:7a6364d82a41 | 293 | |
mjr | 100:1ff35c07217c | 294 | // 16-bit sampler subclass |
mjr | 100:1ff35c07217c | 295 | class AltAnalogIn_16bit : public AltAnalogIn |
mjr | 100:1ff35c07217c | 296 | { |
mjr | 100:1ff35c07217c | 297 | public: |
mjr | 100:1ff35c07217c | 298 | AltAnalogIn_16bit(PinName pin, bool continuous = false, int long_sample_clocks = 0, int averaging = 1) : |
mjr | 100:1ff35c07217c | 299 | AltAnalogIn(pin, continuous, long_sample_clocks, averaging, 16) { } |
mjr | 100:1ff35c07217c | 300 | |
mjr | 100:1ff35c07217c | 301 | /** Returns the raw value |
mjr | 100:1ff35c07217c | 302 | * |
mjr | 100:1ff35c07217c | 303 | * @param return Unsigned integer with converted value |
mjr | 100:1ff35c07217c | 304 | */ |
mjr | 100:1ff35c07217c | 305 | inline uint16_t read_u16() |
mjr | 100:1ff35c07217c | 306 | { |
mjr | 100:1ff35c07217c | 307 | // wait for the hardware to signal that the sample is completed |
mjr | 100:1ff35c07217c | 308 | wait(); |
mjr | 43:7a6364d82a41 | 309 | |
mjr | 100:1ff35c07217c | 310 | // return the result register value |
mjr | 100:1ff35c07217c | 311 | return (uint16_t)ADC0->R[0]; |
mjr | 100:1ff35c07217c | 312 | } |
mjr | 100:1ff35c07217c | 313 | |
mjr | 100:1ff35c07217c | 314 | /** Returns the scaled value |
mjr | 100:1ff35c07217c | 315 | * |
mjr | 100:1ff35c07217c | 316 | * @param return Float with scaled converted value to 0.0-1.0 |
mjr | 100:1ff35c07217c | 317 | */ |
mjr | 100:1ff35c07217c | 318 | float read(void) |
mjr | 100:1ff35c07217c | 319 | { |
mjr | 100:1ff35c07217c | 320 | unsigned short value = read_u16(); |
mjr | 100:1ff35c07217c | 321 | return value / 65535.0f; |
mjr | 100:1ff35c07217c | 322 | } |
mjr | 100:1ff35c07217c | 323 | |
mjr | 100:1ff35c07217c | 324 | /** An operator shorthand for read() |
mjr | 100:1ff35c07217c | 325 | */ |
mjr | 100:1ff35c07217c | 326 | operator float() { return read(); } |
mjr | 43:7a6364d82a41 | 327 | }; |
mjr | 43:7a6364d82a41 | 328 | |
mjr | 43:7a6364d82a41 | 329 | #endif |