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
TSL1410R/tsl1410r.h@45:c42166b2878c, 2016-02-15 (annotated)
- Committer:
- mjr
- Date:
- Mon Feb 15 20:30:32 2016 +0000
- Revision:
- 45:c42166b2878c
- Parent:
- 43:7a6364d82a41
- Child:
- 47:df7a88cd249c
More work in progress on CCD speedups;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mjr | 45:c42166b2878c | 1 | // DMA VERSION - NOT WORKING |
mjr | 45:c42166b2878c | 2 | |
mjr | 45:c42166b2878c | 3 | // I'm saving this code for now, since it was somewhat promising but doesn't |
mjr | 45:c42166b2878c | 4 | // quite work. The idea here was to read the ADC via DMA, operating the ADC |
mjr | 45:c42166b2878c | 5 | // in continuous mode. This speeds things up pretty impressively (by about |
mjr | 45:c42166b2878c | 6 | // a factor of 3 vs having the MCU read each result from the ADC sampling |
mjr | 45:c42166b2878c | 7 | // register), but I can't figure out how to get a stable enough signal out of |
mjr | 45:c42166b2878c | 8 | // it. I think the problem is that the timing isn't precise enough in detecting |
mjr | 45:c42166b2878c | 9 | // when the DMA completes each write. We have to clock the next pixel onto the |
mjr | 45:c42166b2878c | 10 | // CCD output each time we complete a sample, and we have to do so quickly so |
mjr | 45:c42166b2878c | 11 | // that the next pixel charge is stable at the ADC input pin by the time the |
mjr | 45:c42166b2878c | 12 | // ADC sample interval starts. I'm seeing a ton of noise, which I think means |
mjr | 45:c42166b2878c | 13 | // that the new pixel isn't ready for the ADC in time. |
mjr | 45:c42166b2878c | 14 | // |
mjr | 45:c42166b2878c | 15 | // I've tried a number of approaches, none of which works: |
mjr | 45:c42166b2878c | 16 | // |
mjr | 45:c42166b2878c | 17 | // - Skip every other sample, so that we can spend one whole sample just |
mjr | 45:c42166b2878c | 18 | // clocking in the next pixel. We discard the "odds" samples that are taken |
mjr | 45:c42166b2878c | 19 | // during pixel changes, and use only the "even" samples where the pixel is |
mjr | 45:c42166b2878c | 20 | // stable the entire time. I'd think the extra sample would give us plenty |
mjr | 45:c42166b2878c | 21 | // of time to stabilize the next pixel, but it doesn't seem to work out that |
mjr | 45:c42166b2878c | 22 | // way. I think the problem might be that the latency of the MCU responding |
mjr | 45:c42166b2878c | 23 | // to each sample completion is long enough relative to the sampling interval |
mjr | 45:c42166b2878c | 24 | // that we can't reliably respond to the ADC done condition fast enough. I've |
mjr | 45:c42166b2878c | 25 | // tried basing the sample completion detection on the DMA byte counter and |
mjr | 45:c42166b2878c | 26 | // the ADC interrupt. The DMA byte counter is updated after the DMA transfer |
mjr | 45:c42166b2878c | 27 | // is done, so that's probably just too late in the cycle. The ADC interrupt |
mjr | 45:c42166b2878c | 28 | // should be concurrent with the DMA transfer starting, but in practice it |
mjr | 45:c42166b2878c | 29 | // still doesn't give us good results. |
mjr | 45:c42166b2878c | 30 | // |
mjr | 45:c42166b2878c | 31 | // - Use DMA, but with the ADC in single-sample mode. This bypasses the latency |
mjr | 45:c42166b2878c | 32 | // problem by ensuring that the ADC doesn't start a new sample until we've |
mjr | 45:c42166b2878c | 33 | // definitely finished clocking in the next pixel. But it defeats the whole |
mjr | 45:c42166b2878c | 34 | // purpose by eliminating the speed improvement - the speeds are comparable to |
mjr | 45:c42166b2878c | 35 | // doing the transfers via the MCU. This surprises me because I'd have expected |
mjr | 45:c42166b2878c | 36 | // that the DMA would run concurrently with the MCU pixel clocking code, but |
mjr | 45:c42166b2878c | 37 | // maybe there's enough bus contention between the MCU and DMA in this case that |
mjr | 45:c42166b2878c | 38 | // there's no true overlapping of the operation. Or maybe the interrupt dispatch |
mjr | 45:c42166b2878c | 39 | // adds enough overhead to negate any overlapping. I haven't actually been able |
mjr | 45:c42166b2878c | 40 | // to get good data out of this mode, either, but I gave up early because of the |
mjr | 45:c42166b2878c | 41 | // lack of any speed improvement. |
mjr | 45:c42166b2878c | 42 | |
mjr | 2:c174f9ee414a | 43 | /* |
mjr | 2:c174f9ee414a | 44 | * TSL1410R interface class. |
mjr | 2:c174f9ee414a | 45 | * |
mjr | 2:c174f9ee414a | 46 | * This provides a high-level interface for the Taos TSL1410R linear CCD array sensor. |
mjr | 2:c174f9ee414a | 47 | */ |
mjr | 2:c174f9ee414a | 48 | |
mjr | 35:e959ffba78fd | 49 | #include "mbed.h" |
mjr | 35:e959ffba78fd | 50 | #include "config.h" |
mjr | 43:7a6364d82a41 | 51 | #include "AltAnalogIn.h" |
mjr | 45:c42166b2878c | 52 | #include "SimpleDMA.h" |
mjr | 2:c174f9ee414a | 53 | |
mjr | 35:e959ffba78fd | 54 | #ifndef TSL1410R_H |
mjr | 35:e959ffba78fd | 55 | #define TSL1410R_H |
mjr | 45:c42166b2878c | 56 | #define TSL1410R_DMA |
mjr | 35:e959ffba78fd | 57 | |
mjr | 35:e959ffba78fd | 58 | // For faster GPIO on the clock pin, we write the IOPORT registers directly. |
mjr | 35:e959ffba78fd | 59 | // PORT_BASE gives us the memory mapped location of the IOPORT register set |
mjr | 35:e959ffba78fd | 60 | // for a pin; PINMASK gives us the bit pattern to write to the registers. |
mjr | 35:e959ffba78fd | 61 | // |
mjr | 35:e959ffba78fd | 62 | // - To turn a pin ON: PORT_BASE(pin)->PSOR |= PINMASK(pin) |
mjr | 35:e959ffba78fd | 63 | // - To turn a pin OFF: PORT_BASE(pin)->PCOR |= PINMASK(pin) |
mjr | 35:e959ffba78fd | 64 | // - To toggle a pin: PORT_BASE(pin)->PTOR |= PINMASK(pin) |
mjr | 35:e959ffba78fd | 65 | // |
mjr | 35:e959ffba78fd | 66 | // When used in a loop where the port address and pin mask are cached in |
mjr | 35:e959ffba78fd | 67 | // local variables, this runs at the same speed as the FastIO library - about |
mjr | 35:e959ffba78fd | 68 | // 78ns per pin write on the KL25Z. Not surprising since it's doing the same |
mjr | 35:e959ffba78fd | 69 | // thing, and the compiler should be able to reduce a pin write to a single ARM |
mjr | 35:e959ffba78fd | 70 | // instruction when the port address and mask are in local register variables. |
mjr | 35:e959ffba78fd | 71 | // The advantage over the FastIO library is that this approach allows for pins |
mjr | 35:e959ffba78fd | 72 | // to be assigned dynamically at run-time, which we prefer because it allows for |
mjr | 35:e959ffba78fd | 73 | // configuration changes to be made on the fly rather than having to recompile |
mjr | 35:e959ffba78fd | 74 | // the program. |
mjr | 43:7a6364d82a41 | 75 | #define GPIO_PORT(pin) (((unsigned int)(pin)) >> PORT_SHIFT) |
mjr | 43:7a6364d82a41 | 76 | #define GPIO_PORT_BASE(pin) ((FGPIO_Type *)(FPTA_BASE + GPIO_PORT(pin) * 0x40)) |
mjr | 43:7a6364d82a41 | 77 | #define GPIO_PINMASK(pin) gpio_set(pin) |
mjr | 2:c174f9ee414a | 78 | |
mjr | 35:e959ffba78fd | 79 | class TSL1410R |
mjr | 2:c174f9ee414a | 80 | { |
mjr | 2:c174f9ee414a | 81 | public: |
mjr | 43:7a6364d82a41 | 82 | TSL1410R(int nPixSensor, PinName siPin, PinName clockPin, PinName ao1Pin, PinName ao2Pin) |
mjr | 43:7a6364d82a41 | 83 | : nPixSensor(nPixSensor), si(siPin), clock(clockPin), ao1(ao1Pin), ao2(ao2Pin) |
mjr | 17:ab3cec0c8bf4 | 84 | { |
mjr | 35:e959ffba78fd | 85 | // we're in parallel mode if ao2 is a valid pin |
mjr | 35:e959ffba78fd | 86 | parallel = (ao2Pin != NC); |
mjr | 35:e959ffba78fd | 87 | |
mjr | 35:e959ffba78fd | 88 | // remember the clock pin port base and pin mask for fast access |
mjr | 35:e959ffba78fd | 89 | clockPort = GPIO_PORT_BASE(clockPin); |
mjr | 35:e959ffba78fd | 90 | clockMask = GPIO_PINMASK(clockPin); |
mjr | 35:e959ffba78fd | 91 | |
mjr | 43:7a6364d82a41 | 92 | // clear out power-on random data by clocking through all pixels twice |
mjr | 17:ab3cec0c8bf4 | 93 | clear(); |
mjr | 17:ab3cec0c8bf4 | 94 | clear(); |
mjr | 43:7a6364d82a41 | 95 | |
mjr | 45:c42166b2878c | 96 | // set up our DMA channel for reading from our analog in pin |
mjr | 45:c42166b2878c | 97 | ao1.initDMA(&adc_dma); |
mjr | 45:c42166b2878c | 98 | |
mjr | 45:c42166b2878c | 99 | // Set up our DMA channel for writing the sensor SCLK - we use the PTOR |
mjr | 45:c42166b2878c | 100 | // (toggle) register to flip the bit on each write. To pad the timing |
mjr | 45:c42166b2878c | 101 | // to the rate required by the CCD, do a no-op 0 write to PTOR after |
mjr | 45:c42166b2878c | 102 | // each toggle. This gives us a 16-byte buffer, which we can make |
mjr | 45:c42166b2878c | 103 | // circular in the DMA controller. |
mjr | 45:c42166b2878c | 104 | static const uint32_t clkseq[] = { clockMask, 0, clockMask, 0 }; |
mjr | 45:c42166b2878c | 105 | clk_dma.destination(&clockPort->PTOR, false, 32); |
mjr | 45:c42166b2878c | 106 | clk_dma.source(clkseq, true, 32, 16); // set up our circular source buffer |
mjr | 45:c42166b2878c | 107 | clk_dma.trigger(Trigger_ADC0); // software trigger |
mjr | 45:c42166b2878c | 108 | clk_dma.setCycleSteal(false); // do the entire transfer on each trigger |
mjr | 45:c42166b2878c | 109 | |
mjr | 43:7a6364d82a41 | 110 | totalTime = 0.0; nRuns = 0; // $$$ |
mjr | 17:ab3cec0c8bf4 | 111 | } |
mjr | 43:7a6364d82a41 | 112 | |
mjr | 43:7a6364d82a41 | 113 | float totalTime; int nRuns; // $$$ |
mjr | 2:c174f9ee414a | 114 | |
mjr | 45:c42166b2878c | 115 | // ADC interrupt handler - on each ADC event, |
mjr | 45:c42166b2878c | 116 | static TSL1410R *instance; |
mjr | 45:c42166b2878c | 117 | static void _aiIRQ() { } |
mjr | 45:c42166b2878c | 118 | |
mjr | 17:ab3cec0c8bf4 | 119 | // Read the pixels. |
mjr | 17:ab3cec0c8bf4 | 120 | // |
mjr | 17:ab3cec0c8bf4 | 121 | // 'n' specifies the number of pixels to sample, and is the size of |
mjr | 17:ab3cec0c8bf4 | 122 | // the output array 'pix'. This can be less than the full number |
mjr | 17:ab3cec0c8bf4 | 123 | // of pixels on the physical device; if it is, we'll spread the |
mjr | 17:ab3cec0c8bf4 | 124 | // sample evenly across the full length of the device by skipping |
mjr | 17:ab3cec0c8bf4 | 125 | // one or more pixels between each sampled pixel to pad out the |
mjr | 17:ab3cec0c8bf4 | 126 | // difference between the sample size and the physical CCD size. |
mjr | 17:ab3cec0c8bf4 | 127 | // For example, if the physical sensor has 1280 pixels, and 'n' is |
mjr | 17:ab3cec0c8bf4 | 128 | // 640, we'll read every other pixel and skip every other pixel. |
mjr | 17:ab3cec0c8bf4 | 129 | // If 'n' is 160, we'll read every 8th pixel and skip 7 between |
mjr | 17:ab3cec0c8bf4 | 130 | // each sample. |
mjr | 17:ab3cec0c8bf4 | 131 | // |
mjr | 17:ab3cec0c8bf4 | 132 | // The reason that we provide this subset mode (where 'n' is less |
mjr | 17:ab3cec0c8bf4 | 133 | // than the physical pixel count) is that reading a pixel is the most |
mjr | 17:ab3cec0c8bf4 | 134 | // time-consuming part of the scan. For each pixel we read, we have |
mjr | 17:ab3cec0c8bf4 | 135 | // to wait for the pixel's charge to transfer from its internal smapling |
mjr | 17:ab3cec0c8bf4 | 136 | // capacitor to the CCD's output pin, for that charge to transfer to |
mjr | 17:ab3cec0c8bf4 | 137 | // the KL25Z input pin, and for the KL25Z ADC to get a stable reading. |
mjr | 17:ab3cec0c8bf4 | 138 | // This all takes on the order of 20us per pixel. Skipping a pixel |
mjr | 17:ab3cec0c8bf4 | 139 | // only requires a clock pulse, which takes about 350ns. So we can |
mjr | 17:ab3cec0c8bf4 | 140 | // skip 60 pixels in the time it takes to sample 1 pixel. |
mjr | 2:c174f9ee414a | 141 | // |
mjr | 2:c174f9ee414a | 142 | // We clock an SI pulse at the beginning of the read. This starts the |
mjr | 2:c174f9ee414a | 143 | // next integration cycle: the pixel array will reset on the SI, and |
mjr | 17:ab3cec0c8bf4 | 144 | // the integration starts 18 clocks later. So by the time this method |
mjr | 17:ab3cec0c8bf4 | 145 | // returns, the next sample will have been integrating for npix-18 clocks. |
mjr | 17:ab3cec0c8bf4 | 146 | // That's usually enough time to allow immediately reading the next |
mjr | 17:ab3cec0c8bf4 | 147 | // sample. If more integration time is required, the caller can simply |
mjr | 2:c174f9ee414a | 148 | // sleep/spin for the desired additional time, or can do other work that |
mjr | 17:ab3cec0c8bf4 | 149 | // takes the desired additional time. |
mjr | 2:c174f9ee414a | 150 | // |
mjr | 2:c174f9ee414a | 151 | // If the caller has other work to tend to that takes longer than the |
mjr | 2:c174f9ee414a | 152 | // desired maximum integration time, it can call clear() to clock out |
mjr | 2:c174f9ee414a | 153 | // the current pixels and start a fresh integration cycle. |
mjr | 43:7a6364d82a41 | 154 | void read(register uint16_t *pix, int n) |
mjr | 17:ab3cec0c8bf4 | 155 | { |
mjr | 45:c42166b2878c | 156 | Timer t; t.start(); //float tDMA, tPix; // $$$ |
mjr | 43:7a6364d82a41 | 157 | |
mjr | 35:e959ffba78fd | 158 | // get the clock pin pointers into local variables for fast access |
mjr | 45:c42166b2878c | 159 | register volatile uint32_t *clockPTOR = &clockPort->PTOR; |
mjr | 43:7a6364d82a41 | 160 | register const uint32_t clockMask = this->clockMask; |
mjr | 35:e959ffba78fd | 161 | |
mjr | 17:ab3cec0c8bf4 | 162 | // start the next integration cycle by pulsing SI and one clock |
mjr | 17:ab3cec0c8bf4 | 163 | si = 1; |
mjr | 43:7a6364d82a41 | 164 | clock = 1; |
mjr | 17:ab3cec0c8bf4 | 165 | si = 0; |
mjr | 43:7a6364d82a41 | 166 | clock = 0; |
mjr | 17:ab3cec0c8bf4 | 167 | |
mjr | 17:ab3cec0c8bf4 | 168 | // figure how many pixels to skip on each read |
mjr | 43:7a6364d82a41 | 169 | int skip = nPixSensor/n - 1; |
mjr | 17:ab3cec0c8bf4 | 170 | |
mjr | 43:7a6364d82a41 | 171 | ///$$$ |
mjr | 43:7a6364d82a41 | 172 | static int done=0; |
mjr | 43:7a6364d82a41 | 173 | if (done++ == 0) printf("nPixSensor=%d, n=%d, skip=%d, parallel=%d\r\n", nPixSensor, n, skip, parallel); |
mjr | 43:7a6364d82a41 | 174 | |
mjr | 17:ab3cec0c8bf4 | 175 | // read all of the pixels |
mjr | 43:7a6364d82a41 | 176 | int dst; |
mjr | 35:e959ffba78fd | 177 | if (parallel) |
mjr | 17:ab3cec0c8bf4 | 178 | { |
mjr | 43:7a6364d82a41 | 179 | // Parallel mode - read pixels from each half sensor concurrently. |
mjr | 43:7a6364d82a41 | 180 | // Divide 'n' (the output pixel count) by 2 to get the loop count, |
mjr | 43:7a6364d82a41 | 181 | // since we're going to do 2 pixels on each iteration. |
mjr | 43:7a6364d82a41 | 182 | for (n /= 2, dst = 0 ; dst < n ; ++dst) |
mjr | 17:ab3cec0c8bf4 | 183 | { |
mjr | 43:7a6364d82a41 | 184 | // Take the clock high. The TSL1410R will connect the next |
mjr | 43:7a6364d82a41 | 185 | // pixel pair's hold capacitors to the A01 and AO2 lines |
mjr | 43:7a6364d82a41 | 186 | // (respectively) on the clock rising edge. |
mjr | 45:c42166b2878c | 187 | *clockPTOR = clockMask; |
mjr | 43:7a6364d82a41 | 188 | |
mjr | 43:7a6364d82a41 | 189 | // Start the ADC sampler for AO1. The TSL1410R sample |
mjr | 43:7a6364d82a41 | 190 | // stabilization time per the data sheet is 120ns. This is |
mjr | 43:7a6364d82a41 | 191 | // fast enough that we don't need an explicit delay, since |
mjr | 43:7a6364d82a41 | 192 | // the instructions to execute this call will take longer |
mjr | 43:7a6364d82a41 | 193 | // than that. |
mjr | 43:7a6364d82a41 | 194 | ao1.start(); |
mjr | 35:e959ffba78fd | 195 | |
mjr | 43:7a6364d82a41 | 196 | // take the clock low while we're waiting for the reading |
mjr | 45:c42166b2878c | 197 | *clockPTOR = clockMask; |
mjr | 43:7a6364d82a41 | 198 | |
mjr | 43:7a6364d82a41 | 199 | // Read the first half-sensor pixel from AO1 |
mjr | 35:e959ffba78fd | 200 | pix[dst] = ao1.read_u16(); |
mjr | 35:e959ffba78fd | 201 | |
mjr | 43:7a6364d82a41 | 202 | // Read the second half-sensor pixel from AO2, and store it |
mjr | 43:7a6364d82a41 | 203 | // in the destination array at the current index PLUS 'n', |
mjr | 43:7a6364d82a41 | 204 | // which you will recall contains half the output pixel count. |
mjr | 43:7a6364d82a41 | 205 | // This second pixel is halfway up the sensor from the first |
mjr | 43:7a6364d82a41 | 206 | // pixel, so it goes halfway up the output array from the |
mjr | 43:7a6364d82a41 | 207 | // current output position. |
mjr | 43:7a6364d82a41 | 208 | ao2.start(); |
mjr | 43:7a6364d82a41 | 209 | pix[dst + n] = ao2.read_u16(); |
mjr | 35:e959ffba78fd | 210 | |
mjr | 43:7a6364d82a41 | 211 | // Clock through the skipped pixels |
mjr | 43:7a6364d82a41 | 212 | for (int i = skip ; i > 0 ; --i) |
mjr | 35:e959ffba78fd | 213 | { |
mjr | 45:c42166b2878c | 214 | *clockPTOR = clockMask; |
mjr | 45:c42166b2878c | 215 | *clockPTOR = clockMask; |
mjr | 45:c42166b2878c | 216 | *clockPTOR = 0; // pad the timing with an extra nop write |
mjr | 35:e959ffba78fd | 217 | } |
mjr | 35:e959ffba78fd | 218 | } |
mjr | 35:e959ffba78fd | 219 | } |
mjr | 35:e959ffba78fd | 220 | else |
mjr | 35:e959ffba78fd | 221 | { |
mjr | 35:e959ffba78fd | 222 | // serial mode - read all pixels in a single file |
mjr | 45:c42166b2878c | 223 | |
mjr | 45:c42166b2878c | 224 | // clock in the first pixel |
mjr | 45:c42166b2878c | 225 | clock = 1; |
mjr | 45:c42166b2878c | 226 | clock = 0; |
mjr | 45:c42166b2878c | 227 | |
mjr | 45:c42166b2878c | 228 | // start the ADC DMA transfer |
mjr | 45:c42166b2878c | 229 | ao1.startDMA(pix, n, true); |
mjr | 45:c42166b2878c | 230 | |
mjr | 45:c42166b2878c | 231 | // We do 4 clock PTOR writes per clocked pixel (the skipped pixels |
mjr | 45:c42166b2878c | 232 | // plus the pixel we actually want to sample), at 32 bits (4 bytes) |
mjr | 45:c42166b2878c | 233 | // each, giving 16 bytes per pixel for the overall write. |
mjr | 45:c42166b2878c | 234 | int clk_dma_len = (skip+1)*16; |
mjr | 45:c42166b2878c | 235 | clk_dma.start(clk_dma_len); |
mjr | 45:c42166b2878c | 236 | |
mjr | 45:c42166b2878c | 237 | // start the first sample |
mjr | 45:c42166b2878c | 238 | ao1.start(); |
mjr | 45:c42166b2878c | 239 | |
mjr | 45:c42166b2878c | 240 | // read all pixels |
mjr | 45:c42166b2878c | 241 | for (dst = n*2 ; dst > 0 ; dst -= 2) |
mjr | 35:e959ffba78fd | 242 | { |
mjr | 45:c42166b2878c | 243 | // wait for the current ADC sample to finish |
mjr | 45:c42166b2878c | 244 | while (adc_dma.remaining() >= dst) { } |
mjr | 35:e959ffba78fd | 245 | |
mjr | 45:c42166b2878c | 246 | // start the next analog read while we're finishing the DMA transfers |
mjr | 43:7a6364d82a41 | 247 | ao1.start(); |
mjr | 35:e959ffba78fd | 248 | |
mjr | 45:c42166b2878c | 249 | // re-arm the clock DMA |
mjr | 45:c42166b2878c | 250 | //clk_dma.restart(clk_dma_len); |
mjr | 17:ab3cec0c8bf4 | 251 | } |
mjr | 45:c42166b2878c | 252 | |
mjr | 45:c42166b2878c | 253 | // wait for the DMA transfer to finish |
mjr | 45:c42166b2878c | 254 | while (adc_dma.isBusy()) { } |
mjr | 45:c42166b2878c | 255 | |
mjr | 45:c42166b2878c | 256 | // apply the 12-bit to 16-bit rescaling to all values |
mjr | 45:c42166b2878c | 257 | for (int i = 0 ; i < n ; ++i) |
mjr | 45:c42166b2878c | 258 | pix[i] <<= 4; |
mjr | 17:ab3cec0c8bf4 | 259 | } |
mjr | 17:ab3cec0c8bf4 | 260 | |
mjr | 43:7a6364d82a41 | 261 | //$$$ |
mjr | 43:7a6364d82a41 | 262 | if (done==1) printf(". done: dst=%d\r\n", dst); |
mjr | 43:7a6364d82a41 | 263 | |
mjr | 17:ab3cec0c8bf4 | 264 | // clock out one extra pixel to leave A1 in the high-Z state |
mjr | 45:c42166b2878c | 265 | *clockPTOR = clockMask; |
mjr | 45:c42166b2878c | 266 | *clockPTOR = clockMask; |
mjr | 43:7a6364d82a41 | 267 | |
mjr | 45:c42166b2878c | 268 | if (n >= 64) { totalTime += t.read(); nRuns += 1; } // $$$ |
mjr | 17:ab3cec0c8bf4 | 269 | } |
mjr | 2:c174f9ee414a | 270 | |
mjr | 2:c174f9ee414a | 271 | // Clock through all pixels to clear the array. Pulses SI at the |
mjr | 2:c174f9ee414a | 272 | // beginning of the operation, which starts a new integration cycle. |
mjr | 2:c174f9ee414a | 273 | // The caller can thus immediately call read() to read the pixels |
mjr | 2:c174f9ee414a | 274 | // integrated while the clear() was taking place. |
mjr | 17:ab3cec0c8bf4 | 275 | void clear() |
mjr | 17:ab3cec0c8bf4 | 276 | { |
mjr | 35:e959ffba78fd | 277 | // get the clock pin pointers into local variables for fast access |
mjr | 35:e959ffba78fd | 278 | register FGPIO_Type *clockPort = this->clockPort; |
mjr | 35:e959ffba78fd | 279 | register uint32_t clockMask = this->clockMask; |
mjr | 35:e959ffba78fd | 280 | |
mjr | 17:ab3cec0c8bf4 | 281 | // clock in an SI pulse |
mjr | 17:ab3cec0c8bf4 | 282 | si = 1; |
mjr | 43:7a6364d82a41 | 283 | clockPort->PSOR = clockMask; |
mjr | 17:ab3cec0c8bf4 | 284 | si = 0; |
mjr | 43:7a6364d82a41 | 285 | clockPort->PCOR = clockMask; |
mjr | 17:ab3cec0c8bf4 | 286 | |
mjr | 40:cc0d9814522b | 287 | // if in serial mode, clock all pixels across both sensor halves; |
mjr | 40:cc0d9814522b | 288 | // in parallel mode, the pixels are clocked together |
mjr | 43:7a6364d82a41 | 289 | int n = parallel ? nPixSensor/2 : nPixSensor; |
mjr | 40:cc0d9814522b | 290 | |
mjr | 17:ab3cec0c8bf4 | 291 | // clock out all pixels |
mjr | 40:cc0d9814522b | 292 | for (int i = 0 ; i < n + 1 ; ++i) { |
mjr | 43:7a6364d82a41 | 293 | clock = 1; // $$$clockPort->PSOR = clockMask; |
mjr | 43:7a6364d82a41 | 294 | clock = 0; // $$$clockPort->PCOR = clockMask; |
mjr | 17:ab3cec0c8bf4 | 295 | } |
mjr | 17:ab3cec0c8bf4 | 296 | } |
mjr | 2:c174f9ee414a | 297 | |
mjr | 2:c174f9ee414a | 298 | private: |
mjr | 45:c42166b2878c | 299 | SimpleDMA adc_dma; // DMA controller for reading the analog input |
mjr | 45:c42166b2878c | 300 | SimpleDMA clk_dma; // DMA controller for the sensor SCLK (writes the PTOR register to toggle the clock bit) |
mjr | 45:c42166b2878c | 301 | char *dmabuf; // buffer for DMA transfers |
mjr | 43:7a6364d82a41 | 302 | int nPixSensor; // number of pixels in physical sensor array |
mjr | 40:cc0d9814522b | 303 | DigitalOut si; // GPIO pin for sensor SI (serial data) |
mjr | 40:cc0d9814522b | 304 | DigitalOut clock; // GPIO pin for sensor SCLK (serial clock) |
mjr | 40:cc0d9814522b | 305 | FGPIO_Type *clockPort; // IOPORT base address for clock pin - cached for fast writes |
mjr | 35:e959ffba78fd | 306 | uint32_t clockMask; // IOPORT register bit mask for clock pin |
mjr | 43:7a6364d82a41 | 307 | AltAnalogIn ao1; // GPIO pin for sensor AO1 (analog output 1) - we read sensor data from this pin |
mjr | 43:7a6364d82a41 | 308 | AltAnalogIn ao2; // GPIO pin for sensor AO2 (analog output 2) - 2nd sensor data pin, when in parallel mode |
mjr | 40:cc0d9814522b | 309 | bool parallel; // true -> running in parallel mode (we read AO1 and AO2 separately on each clock) |
mjr | 2:c174f9ee414a | 310 | }; |
mjr | 2:c174f9ee414a | 311 | |
mjr | 2:c174f9ee414a | 312 | #endif /* TSL1410R_H */ |
mjr | 45:c42166b2878c | 313 |