Pinscape Controller version 1 fork. This is a fork to allow for ongoing bug fixes to the original controller version, from before the major changes for the expansion board project.

Dependencies:   FastIO FastPWM SimpleDMA mbed

Fork of Pinscape_Controller by Mike R

Committer:
mjr
Date:
Wed Feb 03 22:57:25 2016 +0000
Revision:
40:cc0d9814522b
Parent:
35:e959ffba78fd
Child:
43:7a6364d82a41
Gamma correction option for outputs; work in progress on new config program

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 2:c174f9ee414a 1 /*
mjr 2:c174f9ee414a 2 * TSL1410R interface class.
mjr 2:c174f9ee414a 3 *
mjr 2:c174f9ee414a 4 * This provides a high-level interface for the Taos TSL1410R linear CCD array sensor.
mjr 2:c174f9ee414a 5 */
mjr 2:c174f9ee414a 6
mjr 35:e959ffba78fd 7 #include "mbed.h"
mjr 35:e959ffba78fd 8 #include "config.h"
mjr 35:e959ffba78fd 9 #include "FastAnalogIn.h"
mjr 2:c174f9ee414a 10
mjr 35:e959ffba78fd 11 #ifndef TSL1410R_H
mjr 35:e959ffba78fd 12 #define TSL1410R_H
mjr 35:e959ffba78fd 13
mjr 35:e959ffba78fd 14 // For faster GPIO on the clock pin, we write the IOPORT registers directly.
mjr 35:e959ffba78fd 15 // PORT_BASE gives us the memory mapped location of the IOPORT register set
mjr 35:e959ffba78fd 16 // for a pin; PINMASK gives us the bit pattern to write to the registers.
mjr 35:e959ffba78fd 17 //
mjr 35:e959ffba78fd 18 // - To turn a pin ON: PORT_BASE(pin)->PSOR |= PINMASK(pin)
mjr 35:e959ffba78fd 19 // - To turn a pin OFF: PORT_BASE(pin)->PCOR |= PINMASK(pin)
mjr 35:e959ffba78fd 20 // - To toggle a pin: PORT_BASE(pin)->PTOR |= PINMASK(pin)
mjr 35:e959ffba78fd 21 //
mjr 35:e959ffba78fd 22 // When used in a loop where the port address and pin mask are cached in
mjr 35:e959ffba78fd 23 // local variables, this runs at the same speed as the FastIO library - about
mjr 35:e959ffba78fd 24 // 78ns per pin write on the KL25Z. Not surprising since it's doing the same
mjr 35:e959ffba78fd 25 // thing, and the compiler should be able to reduce a pin write to a single ARM
mjr 35:e959ffba78fd 26 // instruction when the port address and mask are in local register variables.
mjr 35:e959ffba78fd 27 // The advantage over the FastIO library is that this approach allows for pins
mjr 35:e959ffba78fd 28 // to be assigned dynamically at run-time, which we prefer because it allows for
mjr 35:e959ffba78fd 29 // configuration changes to be made on the fly rather than having to recompile
mjr 35:e959ffba78fd 30 // the program.
mjr 35:e959ffba78fd 31 #define GPIO_PORT_BASE(pin) ((FGPIO_Type *)(FPTA_BASE + ((unsigned int)pin >> PORT_SHIFT) * 0x40))
mjr 35:e959ffba78fd 32 #define GPIO_PINMASK(pin) (1 << ((pin & 0x7F) >> 2))
mjr 2:c174f9ee414a 33
mjr 35:e959ffba78fd 34 class TSL1410R
mjr 2:c174f9ee414a 35 {
mjr 2:c174f9ee414a 36 public:
mjr 35:e959ffba78fd 37 TSL1410R(int nPix, PinName siPin, PinName clockPin, PinName ao1Pin, PinName ao2Pin)
mjr 35:e959ffba78fd 38 : nPix(nPix), si(siPin), clock(clockPin), ao1(ao1Pin), ao2(ao2Pin)
mjr 17:ab3cec0c8bf4 39 {
mjr 35:e959ffba78fd 40 // we're in parallel mode if ao2 is a valid pin
mjr 35:e959ffba78fd 41 parallel = (ao2Pin != NC);
mjr 35:e959ffba78fd 42
mjr 35:e959ffba78fd 43 // remember the clock pin port base and pin mask for fast access
mjr 35:e959ffba78fd 44 clockPort = GPIO_PORT_BASE(clockPin);
mjr 35:e959ffba78fd 45 clockMask = GPIO_PINMASK(clockPin);
mjr 35:e959ffba78fd 46
mjr 17:ab3cec0c8bf4 47 // disable continuous conversion mode in FastAnalogIn - since we're
mjr 17:ab3cec0c8bf4 48 // reading discrete pixel values, we want to control when the samples
mjr 17:ab3cec0c8bf4 49 // are taken rather than continuously averaging over time
mjr 35:e959ffba78fd 50 ao1.disable();
mjr 35:e959ffba78fd 51 if (parallel) ao2.disable();
mjr 17:ab3cec0c8bf4 52
mjr 17:ab3cec0c8bf4 53 // clear out power-on noise by clocking through all pixels twice
mjr 17:ab3cec0c8bf4 54 clear();
mjr 17:ab3cec0c8bf4 55 clear();
mjr 17:ab3cec0c8bf4 56 }
mjr 2:c174f9ee414a 57
mjr 17:ab3cec0c8bf4 58 // Read the pixels.
mjr 17:ab3cec0c8bf4 59 //
mjr 17:ab3cec0c8bf4 60 // 'n' specifies the number of pixels to sample, and is the size of
mjr 17:ab3cec0c8bf4 61 // the output array 'pix'. This can be less than the full number
mjr 17:ab3cec0c8bf4 62 // of pixels on the physical device; if it is, we'll spread the
mjr 17:ab3cec0c8bf4 63 // sample evenly across the full length of the device by skipping
mjr 17:ab3cec0c8bf4 64 // one or more pixels between each sampled pixel to pad out the
mjr 17:ab3cec0c8bf4 65 // difference between the sample size and the physical CCD size.
mjr 17:ab3cec0c8bf4 66 // For example, if the physical sensor has 1280 pixels, and 'n' is
mjr 17:ab3cec0c8bf4 67 // 640, we'll read every other pixel and skip every other pixel.
mjr 17:ab3cec0c8bf4 68 // If 'n' is 160, we'll read every 8th pixel and skip 7 between
mjr 17:ab3cec0c8bf4 69 // each sample.
mjr 17:ab3cec0c8bf4 70 //
mjr 17:ab3cec0c8bf4 71 // The reason that we provide this subset mode (where 'n' is less
mjr 17:ab3cec0c8bf4 72 // than the physical pixel count) is that reading a pixel is the most
mjr 17:ab3cec0c8bf4 73 // time-consuming part of the scan. For each pixel we read, we have
mjr 17:ab3cec0c8bf4 74 // to wait for the pixel's charge to transfer from its internal smapling
mjr 17:ab3cec0c8bf4 75 // capacitor to the CCD's output pin, for that charge to transfer to
mjr 17:ab3cec0c8bf4 76 // the KL25Z input pin, and for the KL25Z ADC to get a stable reading.
mjr 17:ab3cec0c8bf4 77 // This all takes on the order of 20us per pixel. Skipping a pixel
mjr 17:ab3cec0c8bf4 78 // only requires a clock pulse, which takes about 350ns. So we can
mjr 17:ab3cec0c8bf4 79 // skip 60 pixels in the time it takes to sample 1 pixel.
mjr 2:c174f9ee414a 80 //
mjr 2:c174f9ee414a 81 // We clock an SI pulse at the beginning of the read. This starts the
mjr 2:c174f9ee414a 82 // next integration cycle: the pixel array will reset on the SI, and
mjr 17:ab3cec0c8bf4 83 // the integration starts 18 clocks later. So by the time this method
mjr 17:ab3cec0c8bf4 84 // returns, the next sample will have been integrating for npix-18 clocks.
mjr 17:ab3cec0c8bf4 85 // That's usually enough time to allow immediately reading the next
mjr 17:ab3cec0c8bf4 86 // sample. If more integration time is required, the caller can simply
mjr 2:c174f9ee414a 87 // sleep/spin for the desired additional time, or can do other work that
mjr 17:ab3cec0c8bf4 88 // takes the desired additional time.
mjr 2:c174f9ee414a 89 //
mjr 2:c174f9ee414a 90 // If the caller has other work to tend to that takes longer than the
mjr 2:c174f9ee414a 91 // desired maximum integration time, it can call clear() to clock out
mjr 2:c174f9ee414a 92 // the current pixels and start a fresh integration cycle.
mjr 18:5e890ebd0023 93 void read(uint16_t *pix, int n)
mjr 17:ab3cec0c8bf4 94 {
mjr 35:e959ffba78fd 95 // get the clock pin pointers into local variables for fast access
mjr 35:e959ffba78fd 96 register FGPIO_Type *clockPort = this->clockPort;
mjr 35:e959ffba78fd 97 register uint32_t clockMask = this->clockMask;
mjr 35:e959ffba78fd 98
mjr 17:ab3cec0c8bf4 99 // start the next integration cycle by pulsing SI and one clock
mjr 17:ab3cec0c8bf4 100 si = 1;
mjr 35:e959ffba78fd 101 clockPort->PSOR |= clockMask; // turn the clock pin on (clock = 1)
mjr 17:ab3cec0c8bf4 102 si = 0;
mjr 35:e959ffba78fd 103 clockPort->PCOR |= clockMask; // turn the clock pin off (clock = 0)
mjr 17:ab3cec0c8bf4 104
mjr 17:ab3cec0c8bf4 105 // figure how many pixels to skip on each read
mjr 17:ab3cec0c8bf4 106 int skip = nPix/n - 1;
mjr 17:ab3cec0c8bf4 107
mjr 17:ab3cec0c8bf4 108 // read all of the pixels
mjr 35:e959ffba78fd 109 if (parallel)
mjr 17:ab3cec0c8bf4 110 {
mjr 35:e959ffba78fd 111 // parallel mode - read pixels from each half sensor concurrently
mjr 35:e959ffba78fd 112 int nPixHalf = nPix/2;
mjr 35:e959ffba78fd 113 for (int src = 0, dst = 0 ; src < nPixHalf ; ++src)
mjr 17:ab3cec0c8bf4 114 {
mjr 35:e959ffba78fd 115 // pulse the clock and start the ADC sampling
mjr 35:e959ffba78fd 116 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 117 ao1.enable();
mjr 35:e959ffba78fd 118 ao2.enable();
mjr 35:e959ffba78fd 119 wait_us(1);
mjr 35:e959ffba78fd 120 clockPort->PCOR |= clockMask;
mjr 35:e959ffba78fd 121
mjr 35:e959ffba78fd 122 // wait for the ADCs to stabilize
mjr 35:e959ffba78fd 123 wait_us(11);
mjr 35:e959ffba78fd 124
mjr 35:e959ffba78fd 125 // read the pixels
mjr 35:e959ffba78fd 126 pix[dst] = ao1.read_u16();
mjr 35:e959ffba78fd 127 pix[dst+n/2] = ao2.read_u16();
mjr 35:e959ffba78fd 128
mjr 40:cc0d9814522b 129 // turn off the ADC until the next pixel is clocked out
mjr 35:e959ffba78fd 130 ao1.disable();
mjr 35:e959ffba78fd 131 ao2.disable();
mjr 35:e959ffba78fd 132
mjr 35:e959ffba78fd 133 // clock skipped pixels
mjr 35:e959ffba78fd 134 for (int i = 0 ; i < skip ; ++i, ++src)
mjr 35:e959ffba78fd 135 {
mjr 35:e959ffba78fd 136 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 137 clockPort->PCOR |= clockMask;
mjr 35:e959ffba78fd 138 }
mjr 35:e959ffba78fd 139 }
mjr 35:e959ffba78fd 140 }
mjr 35:e959ffba78fd 141 else
mjr 35:e959ffba78fd 142 {
mjr 35:e959ffba78fd 143 // serial mode - read all pixels in a single file
mjr 35:e959ffba78fd 144 for (int src = 0, dst = 0 ; src < nPix ; ++src)
mjr 35:e959ffba78fd 145 {
mjr 35:e959ffba78fd 146 // pulse the clock and start the ADC sampling
mjr 35:e959ffba78fd 147 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 148 ao1.enable();
mjr 35:e959ffba78fd 149 wait_us(1);
mjr 35:e959ffba78fd 150 clockPort->PCOR |= clockMask;
mjr 35:e959ffba78fd 151
mjr 35:e959ffba78fd 152 // wait for the ADC sample to stabilize
mjr 35:e959ffba78fd 153 wait_us(11);
mjr 35:e959ffba78fd 154
mjr 35:e959ffba78fd 155 // read the ADC sample
mjr 35:e959ffba78fd 156 pix[dst++] = ao1.read_u16();
mjr 35:e959ffba78fd 157
mjr 35:e959ffba78fd 158 // turn off the ADC until the next pixel is ready
mjr 35:e959ffba78fd 159 ao1.disable();
mjr 35:e959ffba78fd 160
mjr 35:e959ffba78fd 161 // clock skipped pixels
mjr 35:e959ffba78fd 162 for (int i = 0 ; i < skip ; ++i, ++src)
mjr 35:e959ffba78fd 163 {
mjr 35:e959ffba78fd 164 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 165 clockPort->PCOR |= clockMask;
mjr 35:e959ffba78fd 166 }
mjr 17:ab3cec0c8bf4 167 }
mjr 17:ab3cec0c8bf4 168 }
mjr 17:ab3cec0c8bf4 169
mjr 17:ab3cec0c8bf4 170 // clock out one extra pixel to leave A1 in the high-Z state
mjr 35:e959ffba78fd 171 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 172 clockPort->PCOR |= clockMask;
mjr 17:ab3cec0c8bf4 173 }
mjr 2:c174f9ee414a 174
mjr 2:c174f9ee414a 175 // Clock through all pixels to clear the array. Pulses SI at the
mjr 2:c174f9ee414a 176 // beginning of the operation, which starts a new integration cycle.
mjr 2:c174f9ee414a 177 // The caller can thus immediately call read() to read the pixels
mjr 2:c174f9ee414a 178 // integrated while the clear() was taking place.
mjr 17:ab3cec0c8bf4 179 void clear()
mjr 17:ab3cec0c8bf4 180 {
mjr 35:e959ffba78fd 181 // get the clock pin pointers into local variables for fast access
mjr 35:e959ffba78fd 182 register FGPIO_Type *clockPort = this->clockPort;
mjr 35:e959ffba78fd 183 register uint32_t clockMask = this->clockMask;
mjr 35:e959ffba78fd 184
mjr 17:ab3cec0c8bf4 185 // clock in an SI pulse
mjr 17:ab3cec0c8bf4 186 si = 1;
mjr 35:e959ffba78fd 187 clockPort->PSOR |= clockMask;
mjr 17:ab3cec0c8bf4 188 si = 0;
mjr 35:e959ffba78fd 189 clockPort->PCOR |= clockMask;
mjr 17:ab3cec0c8bf4 190
mjr 40:cc0d9814522b 191 // if in serial mode, clock all pixels across both sensor halves;
mjr 40:cc0d9814522b 192 // in parallel mode, the pixels are clocked together
mjr 40:cc0d9814522b 193 int n = parallel ? nPix/2 : nPix;
mjr 40:cc0d9814522b 194
mjr 17:ab3cec0c8bf4 195 // clock out all pixels
mjr 40:cc0d9814522b 196 for (int i = 0 ; i < n + 1 ; ++i) {
mjr 35:e959ffba78fd 197 clockPort->PSOR |= clockMask;
mjr 35:e959ffba78fd 198 clockPort->PCOR |= clockMask;
mjr 17:ab3cec0c8bf4 199 }
mjr 17:ab3cec0c8bf4 200 }
mjr 2:c174f9ee414a 201
mjr 2:c174f9ee414a 202 private:
mjr 35:e959ffba78fd 203 int nPix; // number of pixels in physical sensor array
mjr 40:cc0d9814522b 204 DigitalOut si; // GPIO pin for sensor SI (serial data)
mjr 40:cc0d9814522b 205 DigitalOut clock; // GPIO pin for sensor SCLK (serial clock)
mjr 40:cc0d9814522b 206 FGPIO_Type *clockPort; // IOPORT base address for clock pin - cached for fast writes
mjr 35:e959ffba78fd 207 uint32_t clockMask; // IOPORT register bit mask for clock pin
mjr 40:cc0d9814522b 208 FastAnalogIn ao1; // GPIO pin for sensor AO1 (analog output 1) - we read sensor data from this pin
mjr 40:cc0d9814522b 209 FastAnalogIn ao2; // GPIO pin for sensor AO2 (analog output 2) - 2nd sensor data pin, when in parallel mode
mjr 40:cc0d9814522b 210 bool parallel; // true -> running in parallel mode (we read AO1 and AO2 separately on each clock)
mjr 2:c174f9ee414a 211 };
mjr 2:c174f9ee414a 212
mjr 2:c174f9ee414a 213 #endif /* TSL1410R_H */