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:
Sat Feb 06 20:21:48 2016 +0000
Revision:
43:7a6364d82a41
Parent:
40:cc0d9814522b
Before floating point plunger ranging

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 43:7a6364d82a41 9 #include "AltAnalogIn.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 43:7a6364d82a41 31 #define GPIO_PORT(pin) (((unsigned int)(pin)) >> PORT_SHIFT)
mjr 43:7a6364d82a41 32 #define GPIO_PORT_BASE(pin) ((FGPIO_Type *)(FPTA_BASE + GPIO_PORT(pin) * 0x40))
mjr 43:7a6364d82a41 33 #define GPIO_PINMASK(pin) gpio_set(pin)
mjr 2:c174f9ee414a 34
mjr 35:e959ffba78fd 35 class TSL1410R
mjr 2:c174f9ee414a 36 {
mjr 2:c174f9ee414a 37 public:
mjr 43:7a6364d82a41 38 TSL1410R(int nPixSensor, PinName siPin, PinName clockPin, PinName ao1Pin, PinName ao2Pin)
mjr 43:7a6364d82a41 39 : nPixSensor(nPixSensor), si(siPin), clock(clockPin), ao1(ao1Pin), ao2(ao2Pin)
mjr 17:ab3cec0c8bf4 40 {
mjr 35:e959ffba78fd 41 // we're in parallel mode if ao2 is a valid pin
mjr 35:e959ffba78fd 42 parallel = (ao2Pin != NC);
mjr 35:e959ffba78fd 43
mjr 35:e959ffba78fd 44 // remember the clock pin port base and pin mask for fast access
mjr 35:e959ffba78fd 45 clockPort = GPIO_PORT_BASE(clockPin);
mjr 35:e959ffba78fd 46 clockMask = GPIO_PINMASK(clockPin);
mjr 35:e959ffba78fd 47
mjr 43:7a6364d82a41 48 // clear out power-on random data by clocking through all pixels twice
mjr 17:ab3cec0c8bf4 49 clear();
mjr 17:ab3cec0c8bf4 50 clear();
mjr 43:7a6364d82a41 51
mjr 43:7a6364d82a41 52 totalTime = 0.0; nRuns = 0; // $$$
mjr 17:ab3cec0c8bf4 53 }
mjr 43:7a6364d82a41 54
mjr 43:7a6364d82a41 55 float totalTime; int nRuns; // $$$
mjr 2:c174f9ee414a 56
mjr 17:ab3cec0c8bf4 57 // Read the pixels.
mjr 17:ab3cec0c8bf4 58 //
mjr 17:ab3cec0c8bf4 59 // 'n' specifies the number of pixels to sample, and is the size of
mjr 17:ab3cec0c8bf4 60 // the output array 'pix'. This can be less than the full number
mjr 17:ab3cec0c8bf4 61 // of pixels on the physical device; if it is, we'll spread the
mjr 17:ab3cec0c8bf4 62 // sample evenly across the full length of the device by skipping
mjr 17:ab3cec0c8bf4 63 // one or more pixels between each sampled pixel to pad out the
mjr 17:ab3cec0c8bf4 64 // difference between the sample size and the physical CCD size.
mjr 17:ab3cec0c8bf4 65 // For example, if the physical sensor has 1280 pixels, and 'n' is
mjr 17:ab3cec0c8bf4 66 // 640, we'll read every other pixel and skip every other pixel.
mjr 17:ab3cec0c8bf4 67 // If 'n' is 160, we'll read every 8th pixel and skip 7 between
mjr 17:ab3cec0c8bf4 68 // each sample.
mjr 17:ab3cec0c8bf4 69 //
mjr 17:ab3cec0c8bf4 70 // The reason that we provide this subset mode (where 'n' is less
mjr 17:ab3cec0c8bf4 71 // than the physical pixel count) is that reading a pixel is the most
mjr 17:ab3cec0c8bf4 72 // time-consuming part of the scan. For each pixel we read, we have
mjr 17:ab3cec0c8bf4 73 // to wait for the pixel's charge to transfer from its internal smapling
mjr 17:ab3cec0c8bf4 74 // capacitor to the CCD's output pin, for that charge to transfer to
mjr 17:ab3cec0c8bf4 75 // the KL25Z input pin, and for the KL25Z ADC to get a stable reading.
mjr 17:ab3cec0c8bf4 76 // This all takes on the order of 20us per pixel. Skipping a pixel
mjr 17:ab3cec0c8bf4 77 // only requires a clock pulse, which takes about 350ns. So we can
mjr 17:ab3cec0c8bf4 78 // skip 60 pixels in the time it takes to sample 1 pixel.
mjr 2:c174f9ee414a 79 //
mjr 2:c174f9ee414a 80 // We clock an SI pulse at the beginning of the read. This starts the
mjr 2:c174f9ee414a 81 // next integration cycle: the pixel array will reset on the SI, and
mjr 17:ab3cec0c8bf4 82 // the integration starts 18 clocks later. So by the time this method
mjr 17:ab3cec0c8bf4 83 // returns, the next sample will have been integrating for npix-18 clocks.
mjr 17:ab3cec0c8bf4 84 // That's usually enough time to allow immediately reading the next
mjr 17:ab3cec0c8bf4 85 // sample. If more integration time is required, the caller can simply
mjr 2:c174f9ee414a 86 // sleep/spin for the desired additional time, or can do other work that
mjr 17:ab3cec0c8bf4 87 // takes the desired additional time.
mjr 2:c174f9ee414a 88 //
mjr 2:c174f9ee414a 89 // If the caller has other work to tend to that takes longer than the
mjr 2:c174f9ee414a 90 // desired maximum integration time, it can call clear() to clock out
mjr 2:c174f9ee414a 91 // the current pixels and start a fresh integration cycle.
mjr 43:7a6364d82a41 92 void read(register uint16_t *pix, int n)
mjr 17:ab3cec0c8bf4 93 {
mjr 43:7a6364d82a41 94 Timer t; t.start(); // $$$
mjr 43:7a6364d82a41 95
mjr 35:e959ffba78fd 96 // get the clock pin pointers into local variables for fast access
mjr 43:7a6364d82a41 97 register volatile uint32_t *clockPSOR = &clockPort->PSOR;
mjr 43:7a6364d82a41 98 register volatile uint32_t *clockPCOR = &clockPort->PCOR;
mjr 43:7a6364d82a41 99 register const uint32_t clockMask = this->clockMask;
mjr 35:e959ffba78fd 100
mjr 17:ab3cec0c8bf4 101 // start the next integration cycle by pulsing SI and one clock
mjr 17:ab3cec0c8bf4 102 si = 1;
mjr 43:7a6364d82a41 103 clock = 1;
mjr 17:ab3cec0c8bf4 104 si = 0;
mjr 43:7a6364d82a41 105 clock = 0;
mjr 17:ab3cec0c8bf4 106
mjr 17:ab3cec0c8bf4 107 // figure how many pixels to skip on each read
mjr 43:7a6364d82a41 108 int skip = nPixSensor/n - 1;
mjr 17:ab3cec0c8bf4 109
mjr 43:7a6364d82a41 110 ///$$$
mjr 43:7a6364d82a41 111 static int done=0;
mjr 43:7a6364d82a41 112 if (done++ == 0) printf("nPixSensor=%d, n=%d, skip=%d, parallel=%d\r\n", nPixSensor, n, skip, parallel);
mjr 43:7a6364d82a41 113
mjr 43:7a6364d82a41 114 // get the clock PSOR and PCOR register addresses for fast access
mjr 43:7a6364d82a41 115
mjr 17:ab3cec0c8bf4 116 // read all of the pixels
mjr 43:7a6364d82a41 117 int dst;
mjr 35:e959ffba78fd 118 if (parallel)
mjr 17:ab3cec0c8bf4 119 {
mjr 43:7a6364d82a41 120 // Parallel mode - read pixels from each half sensor concurrently.
mjr 43:7a6364d82a41 121 // Divide 'n' (the output pixel count) by 2 to get the loop count,
mjr 43:7a6364d82a41 122 // since we're going to do 2 pixels on each iteration.
mjr 43:7a6364d82a41 123 for (n /= 2, dst = 0 ; dst < n ; ++dst)
mjr 17:ab3cec0c8bf4 124 {
mjr 43:7a6364d82a41 125 // Take the clock high. The TSL1410R will connect the next
mjr 43:7a6364d82a41 126 // pixel pair's hold capacitors to the A01 and AO2 lines
mjr 43:7a6364d82a41 127 // (respectively) on the clock rising edge.
mjr 43:7a6364d82a41 128 *clockPSOR = clockMask;
mjr 43:7a6364d82a41 129
mjr 43:7a6364d82a41 130 // Start the ADC sampler for AO1. The TSL1410R sample
mjr 43:7a6364d82a41 131 // stabilization time per the data sheet is 120ns. This is
mjr 43:7a6364d82a41 132 // fast enough that we don't need an explicit delay, since
mjr 43:7a6364d82a41 133 // the instructions to execute this call will take longer
mjr 43:7a6364d82a41 134 // than that.
mjr 43:7a6364d82a41 135 ao1.start();
mjr 35:e959ffba78fd 136
mjr 43:7a6364d82a41 137 // take the clock low while we're waiting for the reading
mjr 43:7a6364d82a41 138 *clockPCOR = clockMask;
mjr 43:7a6364d82a41 139
mjr 43:7a6364d82a41 140 // Read the first half-sensor pixel from AO1
mjr 35:e959ffba78fd 141 pix[dst] = ao1.read_u16();
mjr 35:e959ffba78fd 142
mjr 43:7a6364d82a41 143 // Read the second half-sensor pixel from AO2, and store it
mjr 43:7a6364d82a41 144 // in the destination array at the current index PLUS 'n',
mjr 43:7a6364d82a41 145 // which you will recall contains half the output pixel count.
mjr 43:7a6364d82a41 146 // This second pixel is halfway up the sensor from the first
mjr 43:7a6364d82a41 147 // pixel, so it goes halfway up the output array from the
mjr 43:7a6364d82a41 148 // current output position.
mjr 43:7a6364d82a41 149 ao2.start();
mjr 43:7a6364d82a41 150 pix[dst + n] = ao2.read_u16();
mjr 35:e959ffba78fd 151
mjr 43:7a6364d82a41 152 // Clock through the skipped pixels
mjr 43:7a6364d82a41 153 for (int i = skip ; i > 0 ; --i)
mjr 35:e959ffba78fd 154 {
mjr 43:7a6364d82a41 155 *clockPSOR = clockMask;
mjr 43:7a6364d82a41 156 *clockPCOR = clockMask;
mjr 35:e959ffba78fd 157 }
mjr 35:e959ffba78fd 158 }
mjr 35:e959ffba78fd 159 }
mjr 35:e959ffba78fd 160 else
mjr 35:e959ffba78fd 161 {
mjr 35:e959ffba78fd 162 // serial mode - read all pixels in a single file
mjr 43:7a6364d82a41 163 for (dst = 0 ; dst < n ; ++dst)
mjr 35:e959ffba78fd 164 {
mjr 43:7a6364d82a41 165 // Clock the next pixel onto the sensor A0 line
mjr 43:7a6364d82a41 166 *clockPSOR = clockMask;
mjr 35:e959ffba78fd 167
mjr 43:7a6364d82a41 168 // start the ADC sampler
mjr 43:7a6364d82a41 169 ao1.start();
mjr 35:e959ffba78fd 170
mjr 43:7a6364d82a41 171 // take the clock low while we're waiting for the analog reading
mjr 43:7a6364d82a41 172 *clockPCOR = clockMask;
mjr 35:e959ffba78fd 173
mjr 43:7a6364d82a41 174 // wait for and read the ADC sample; plug it into the output
mjr 43:7a6364d82a41 175 // array, and increment the output pointer to the next position
mjr 43:7a6364d82a41 176 pix[dst] = ao1.read_u16();
mjr 43:7a6364d82a41 177
mjr 43:7a6364d82a41 178 // clock through the skipped pixels
mjr 43:7a6364d82a41 179 for (int i = skip ; i > 0 ; --i)
mjr 35:e959ffba78fd 180 {
mjr 43:7a6364d82a41 181 *clockPSOR = clockMask;
mjr 43:7a6364d82a41 182 *clockPCOR = clockMask;
mjr 35:e959ffba78fd 183 }
mjr 17:ab3cec0c8bf4 184 }
mjr 17:ab3cec0c8bf4 185 }
mjr 17:ab3cec0c8bf4 186
mjr 43:7a6364d82a41 187 //$$$
mjr 43:7a6364d82a41 188 if (done==1) printf(". done: dst=%d\r\n", dst);
mjr 43:7a6364d82a41 189
mjr 17:ab3cec0c8bf4 190 // clock out one extra pixel to leave A1 in the high-Z state
mjr 43:7a6364d82a41 191 clock = 1;
mjr 43:7a6364d82a41 192 clock = 0;
mjr 43:7a6364d82a41 193
mjr 43:7a6364d82a41 194 if (n >= 80) { totalTime += t.read(); nRuns += 1; } // $$$
mjr 17:ab3cec0c8bf4 195 }
mjr 2:c174f9ee414a 196
mjr 2:c174f9ee414a 197 // Clock through all pixels to clear the array. Pulses SI at the
mjr 2:c174f9ee414a 198 // beginning of the operation, which starts a new integration cycle.
mjr 2:c174f9ee414a 199 // The caller can thus immediately call read() to read the pixels
mjr 2:c174f9ee414a 200 // integrated while the clear() was taking place.
mjr 17:ab3cec0c8bf4 201 void clear()
mjr 17:ab3cec0c8bf4 202 {
mjr 35:e959ffba78fd 203 // get the clock pin pointers into local variables for fast access
mjr 35:e959ffba78fd 204 register FGPIO_Type *clockPort = this->clockPort;
mjr 35:e959ffba78fd 205 register uint32_t clockMask = this->clockMask;
mjr 35:e959ffba78fd 206
mjr 17:ab3cec0c8bf4 207 // clock in an SI pulse
mjr 17:ab3cec0c8bf4 208 si = 1;
mjr 43:7a6364d82a41 209 clockPort->PSOR = clockMask;
mjr 17:ab3cec0c8bf4 210 si = 0;
mjr 43:7a6364d82a41 211 clockPort->PCOR = clockMask;
mjr 17:ab3cec0c8bf4 212
mjr 40:cc0d9814522b 213 // if in serial mode, clock all pixels across both sensor halves;
mjr 40:cc0d9814522b 214 // in parallel mode, the pixels are clocked together
mjr 43:7a6364d82a41 215 int n = parallel ? nPixSensor/2 : nPixSensor;
mjr 40:cc0d9814522b 216
mjr 17:ab3cec0c8bf4 217 // clock out all pixels
mjr 40:cc0d9814522b 218 for (int i = 0 ; i < n + 1 ; ++i) {
mjr 43:7a6364d82a41 219 clock = 1; // $$$clockPort->PSOR = clockMask;
mjr 43:7a6364d82a41 220 clock = 0; // $$$clockPort->PCOR = clockMask;
mjr 17:ab3cec0c8bf4 221 }
mjr 17:ab3cec0c8bf4 222 }
mjr 2:c174f9ee414a 223
mjr 2:c174f9ee414a 224 private:
mjr 43:7a6364d82a41 225 int nPixSensor; // number of pixels in physical sensor array
mjr 40:cc0d9814522b 226 DigitalOut si; // GPIO pin for sensor SI (serial data)
mjr 40:cc0d9814522b 227 DigitalOut clock; // GPIO pin for sensor SCLK (serial clock)
mjr 40:cc0d9814522b 228 FGPIO_Type *clockPort; // IOPORT base address for clock pin - cached for fast writes
mjr 35:e959ffba78fd 229 uint32_t clockMask; // IOPORT register bit mask for clock pin
mjr 43:7a6364d82a41 230 AltAnalogIn ao1; // GPIO pin for sensor AO1 (analog output 1) - we read sensor data from this pin
mjr 43:7a6364d82a41 231 AltAnalogIn ao2; // GPIO pin for sensor AO2 (analog output 2) - 2nd sensor data pin, when in parallel mode
mjr 40:cc0d9814522b 232 bool parallel; // true -> running in parallel mode (we read AO1 and AO2 separately on each clock)
mjr 2:c174f9ee414a 233 };
mjr 2:c174f9ee414a 234
mjr 2:c174f9ee414a 235 #endif /* TSL1410R_H */