An I/O controller for virtual pinball machines: accelerometer nudge sensing, analog plunger input, button input encoding, LedWiz compatible output controls, and more.
Dependencies: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
TSL14xx.h
00001 /* 00002 * AMS/TAOS TSL14xx series photodiode array interface class. 00003 * 00004 * This provides a high-level interface for the AMS/TAOS TSLxx series 00005 * of photodiode arrays. This class works with most of the sensors 00006 * in this series, which differ only in pixel array sizes. This code 00007 * has been tested with the following sensors from the series: 00008 * 00009 * TSL1410R - 1280 pixels, 400dpi 00010 * TSL1412S - 1536 pixels, 400dpi 00011 * TSL1401CL - 128 pixels, 400dpi 00012 * 00013 * All of these sensors have the same electrical interface, consisting 00014 * of a clock input (CLK), start pulse input (SI), and analog pixel 00015 * output (AO). The sensors are equipped with hold capacitors and 00016 * shift registers that allow simultaneous sampling of all pixels, and 00017 * serial access to the pixel values. 00018 * 00019 * (Note on the plunger sensor class hierarchy: this class is for the 00020 * sensor only, not for the plunger application. This class is meant 00021 * to be reusable in other contexts that just need to read raw pixel 00022 * data from the sensor. Plunger/tslxxSensor.h implements the 00023 * specializations of the plunger interface class for these sensors.) 00024 * 00025 * 00026 * *** Double buffering *** 00027 * 00028 * Our API is based on a double-buffered asynchronous read. The caller 00029 * can access a completed buffer, containing the pixels from the last image 00030 * frame, while the sensor is transferring data asynchronously (using the 00031 * microcontroller's DMA capability) into the other buffer. Each time a 00032 * new read is started, we swap buffers, making the last completed buffer 00033 * available to the client and handing the other buffer to the DMA 00034 * controller to fill asynchronously. 00035 * 00036 * In a way, there are actually THREE frames in our pipeline at any given 00037 * time: 00038 * 00039 * - a live image integrating light on the photo receptors on the sensor 00040 * - the prior image, held in the sensor's shift register and being 00041 * transferred via DMA into one of our buffers (the "DMA" buffer) 00042 * - the second prior image, in our other buffer (the "stable" buffer), 00043 * available for the client to process 00044 * 00045 * The integration process on the sensor starts when we begin the transfer 00046 * of an image via DMA. That frame's integration period ends when the next 00047 * transfer starts. So the minimum integration time is also the DMA pixel 00048 * transfer time. Longer integration times can be achieved by waiting 00049 * for an additional interval after a DMA transfer finishes, before starting 00050 * the next transfer. We make provision for this added time to allow for 00051 * longer exposure times to optimize image quality. 00052 * 00053 * 00054 * *** Optimizing pixel transfer speed *** 00055 * 00056 * For Pinscape purposes, we want the fastest possible frame rate, as we're 00057 * trying to accurately capture the motion of a fast-moving object (the 00058 * plunger). The TSL14xx sensors can achieve a frame rate up to about 00059 * 1000 frames per second, if everything is clocked at the limits in the 00060 * data sheet. The KL25Z, however, can't achieve that fast a rate. The 00061 * limiting factor is the KL25Z's ADC. We have to take an ADC sample for 00062 * every pixel, and the minimum sampling time for the ADC on the KL25Z is 00063 * about 2us. With the 1280-pixel TSL1410R, that gives us a minimum 00064 * pixel transfer time of about 2.6ms. And it's actually very difficult 00065 * to achieve that speed - my original, naive implementation took more 00066 * like 30ms (!!!) to transfer each frame. 00067 * 00068 * As a rule, I don't like tricky code, because it's hard to understand 00069 * and hard to debug. But in this case it's justified. For good plunger 00070 * tracking, it's critical to achieve a minimum frame rate of around 200 00071 * fps (5ms per frame). I'm pretty sure there's no way to even get close 00072 * to this rate without the complex setup described below. 00073 * 00074 * Here's our approach for fast data transfer: 00075 * 00076 * First, we put the analog input port (the ADC == Analog-to-Digital 00077 * Converter) in "continuous" mode, at the highest clock speed we can 00078 * program with the available clocks and the fastest read cycle 00079 * available in the ADC hardware. (The analog input port is the 00080 * GPIO pin attached to the sensor's AO == Analog Output pin, where 00081 * it outputs each pixel's value, one at a time, as an analog voltage 00082 * level.) In continuous mode, every time the ADC finishes taking a 00083 * sample, it stores the result value in its output register and then 00084 * immediately starts taking a new sample. This means that no MCU 00085 * (or even DMA) action is required to start each new sample. This 00086 * is where most of the speedup comes from, since it takes significant 00087 * time (multiple microseconds) to move data through the peripheral 00088 * registers, and it takes more time (also multiple microseconds) for 00089 * the ADC to spin up for each new sample when in single-sample mode. 00090 * We cut out about 7us this way and get the time per sample down to 00091 * about 2us. This is close to the documented maximum speed for the 00092 * ADC hardware. 00093 * 00094 * Second, we use the DMA controller to read the ADC result register 00095 * and store each sample in a memory array for processing. The ADC 00096 * hardware is designed to work with the DMA controller by signaling 00097 * the DMA controller when a new sample is ready; this allows DMA to 00098 * move each sample immediately when it's available without any CPU 00099 * involvement. 00100 * 00101 * Third - and this is where it really gets tricky - we use two 00102 * additional "linked" DMA channels to generate the clock signal 00103 * to the CCD sensor. The clock signal is how we tell the CCD when 00104 * to place the next pixel voltage on its AO pin, so the clock has 00105 * to be generated in lock step with the ADC sampling cycle. The 00106 * ADC timing isn't perfectly uniform or predictable, so we can't 00107 * just generate the pixel clock with a *real* clock. We have to 00108 * time the signal exactly with the ADC, which means that we have 00109 * to generate it from the ADC "sample is ready" signal. Fortunately, 00110 * there is just such a signal, and in fact we're already using it, 00111 * as described above, to tell the DMA when to move each result from 00112 * the ADC output register to our memory array. So how do we use this 00113 * to generate the CCD clock? The answer lies in the DMA controller's 00114 * channel linking feature. This allows one DMA channel to trigger a 00115 * second DMA channel each time the first channel completes one 00116 * transfer. And we can use DMA to control our clock GPIO pin by 00117 * using the pin's GPIO IPORT register as the DMA destination address. 00118 * Specifically, we can take the clock high by writing our pin's bit 00119 * pattern to the PSOR ("set output") register, and we can take the 00120 * clock low by writing to the PCOR ("clear output") register. We 00121 * use one DMA channel for each of these operations. 00122 * 00123 * Putting it all together, the cascade of linked DMA channels 00124 * works like this: 00125 * 00126 * - We kick off the first ADC sample. 00127 * 00128 * - When the ADC sample completes, the ADC DMA trigger fires, 00129 * which triggers channel 1, the "Clock Up" channel. This 00130 * performs one transfer of the clock GPIO bit to the clock 00131 * PSOR register, taking the clock high, which causes the CCD 00132 * to move the next pixel onto AO. 00133 * 00134 * - After the Clock Up channel does its transfer, it triggers 00135 * its link to channel 2, the ADC transfer channel. This 00136 * channel moves the ADC output register value to our memory 00137 * array. 00138 * 00139 * - After the ADC channel does its transfer, it triggers channel 00140 * 3, the "Clock Down" channel. This performs one transfer of 00141 * the clock GPIO bit to the clock PCOR register, taking the 00142 * clock low. 00143 * 00144 * Note that the order of the channels - Clock Up, ADC, Clock Down - 00145 * is important. It ensures that we don't toggle the clock line 00146 * too quickly. The CCD has a minimum pulse duration of 50ns for 00147 * the clock signal. The DMA controller is so fast that it might 00148 * toggle the clock faster than this limit if we did the Up and 00149 * Down transfers back-to-back. 00150 * 00151 * Note also that it's important for Clock Up to be the very first 00152 * operation after the DMA trigger. The ADC is in continuous mode, 00153 * meaning that it starts taking a new sample immediately upon 00154 * finishing the previous one. So when the ADC DMA signal fires, 00155 * the new sample is already starting. We therefore have to get 00156 * the next pixel onto the sampling pin immediately, or as close 00157 * to immediately as possible. The sensor's "analog output 00158 * settling time" is 120ns - this is the time for a new pixel 00159 * voltage to stabilize on AO after a clock rising edge. So 00160 * assuming that the ADC raises the DMA signal immediately on 00161 * sample completion, and the DMA controller responds within a 00162 * couple of MCU clock cycles, we should have the new pixel voltage 00163 * stable on the sampling pin by about 200ns after the new ADC 00164 * sample cycle starts. The sampling cycle with our current 00165 * parameters is about 2us, so the voltage level is stable for 00166 * 90% of the cycle. 00167 * 00168 * Also, note that it's okay that the ADC sample transfer doesn't 00169 * happen until after the Clock Up DMA transfer. The ADC output 00170 * register holds the last result until the next sample completes, 00171 * so we have about 2us to grab it. The first Clock Up DMA 00172 * transfer only takes a couple of clocks - order of 100ns - so 00173 * we get to it with time to spare. 00174 * 00175 * (Note that it would nicer to handle the clock with a single DMA 00176 * channel, since DMA channels are a limited resource. We could 00177 * conceivably consolidate the clock generator one DMA channel by 00178 * switching the DMA destination to the PTOR "toggle" register, and 00179 * writing *two* times per trigger - once to toggle the clock up, 00180 * and a second time to toggle it down. But I haven't found a way 00181 * to make this work. The obstacle is that the DMA controller can 00182 * only do one transfer per trigger in the fully autonomous mode 00183 * we're using, and to make this toggle scheme work, we'd have to do 00184 * two writes per trigger. Maybe even three or four: I think we'd 00185 * have to throw in one or two no-op writes (of all zeroes) between 00186 * the two toggles, to pad the timing to ensure that the clock pulse 00187 * width is over the sensor's 50ns minimum. But it's the same issue 00188 * whether it's two writes or four. The DMA controller does have a 00189 * "continuous" mode that does an entire transfer on a single trigger, 00190 * but it can't reset itself after such a transfer; CPU intervention 00191 * is required to do that, which means we'd have to service an 00192 * interrupt on every ADC cycle to set up the next clock write. 00193 * Given the 2us cycle time, an interrupt would create a ton of CPU 00194 * load, and I don't think the CPU is fast enough to reliably complete 00195 * the work we'd have to do on each 2us cycle. Fortunately, at 00196 * the moment we can afford to dedicate three channels to this 00197 * module. We only have one other module using the DMA at all 00198 * (the TLC5940 PWM controller interface), and it only needs one 00199 * channel. So the KL25Z's complement of four DMA channels is just 00200 * enough for all of our needs for the moment.) 00201 * 00202 * Note that some of the sensors in this series (TSL1410R, TSL1412S) 00203 * have a "parallel" readout mode that lets them physically deliver 00204 * two pixels at once the MCU, via separate physical connections. This 00205 * could provide a 2X speedup on an MCU equipped with two independent 00206 * ADC samplers. Unfortunately, the KL25Z is not so equipped; even 00207 * though it might appear at first glance to support multiple ADC 00208 * "channels", all of the channels internally multiplex into a single 00209 * converter unit, so the hardware can ultimately perform only one 00210 * conversion at a time. Paradoxically, using the sensor's parallel 00211 * mode is actually *slower* with a KL25Z than using its serial mode, 00212 * because we can only maintain the higher throughput of the KL25Z ADC's 00213 * continuous sampling mode by reading all samples thorugh a single 00214 * channel. Switching channels on alternating samples involves a 00215 * bunch of setup overhead within the ADC hardware that adds lots of 00216 * clocks compared to single-channel continuous mode. 00217 */ 00218 00219 #include "mbed.h" 00220 #include "config.h" 00221 #include "AltAnalogIn.h" 00222 #include "SimpleDMA.h" 00223 #include "DMAChannels.h" 00224 00225 #ifndef TSL14XX_H 00226 #define TSL14XX_H 00227 00228 00229 // To allow DMA access to the clock pin, we need to point the DMA 00230 // controller to the IOPORT registers that control the pin. PORT_BASE() 00231 // gives us the address of the register group for the 32 GPIO pins with 00232 // the same letter name as our target pin (e.g., PTA0 through PTA31), 00233 // and PINMASK gives us the bit pattern to write to those registers to 00234 // access our single GPIO pin. Each register group has three special 00235 // registers that update the pin in particular ways: PSOR ("set output 00236 // register") turns pins on, PCOR ("clear output register") turns pins 00237 // off, and PTOR ("toggle output register") toggle pins to the opposite 00238 // of their current values. These registers have special semantics: 00239 // writing a bit as 0 has no effect on the corresponding pin, while 00240 // writing a bit as 1 performs the register's action on the pin. This 00241 // allows a single GPIO pin to be set, cleared, or toggled with a 00242 // 32-bit write to one of these registers, without affecting any of the 00243 // other pins addressed by the register. (It also allows changing any 00244 // group of pins with a single write, although we don't use that 00245 // feature here.) 00246 // 00247 // - To turn a pin ON: PORT_BASE(pin)->PSOR = PINMASK(pin) 00248 // - To turn a pin OFF: PORT_BASE(pin)->PCOR = PINMASK(pin) 00249 // - To toggle a pin: PORT_BASE(pin)->PTOR = PINMASK(pin) 00250 // 00251 #define GPIO_PORT(pin) (((unsigned int)(pin)) >> PORT_SHIFT) 00252 #define GPIO_PORT_BASE(pin) ((GPIO_Type *)(PTA_BASE + GPIO_PORT(pin) * 0x40)) 00253 #define GPIO_PINMASK(pin) gpio_set(pin) 00254 00255 IF_DIAG( 00256 extern uint64_t mainLoopIterCheckpt[]; 00257 extern Timer mainLoopTimer;) 00258 00259 class TSL14xx 00260 { 00261 public: 00262 // Set up the interface. 00263 // 00264 // nPixSensor = native number of pixels on sensor 00265 // siPin = SI pin (GPIO, digital out) 00266 // clockPin = CLK pin (GPIO, digital out) 00267 // aoPin = AO pin (GPIO, analog in - must be ADC-capable) 00268 TSL14xx(int nPixSensor, PinName siPin, PinName clockPin, PinName aoPin) 00269 : adc_dma(DMAch_TSL_ADC), 00270 clkUp_dma(DMAch_TSL_CLKUP), 00271 clkDn_dma(DMAch_TSL_CLKDN), 00272 si(siPin), 00273 clock(clockPin), 00274 ao(aoPin, true, 0), // continuous sampling, fast sampling mode 00275 nPixSensor(nPixSensor) 00276 { 00277 // Calibrate the ADC for best accuracy 00278 ao.calibrate(); 00279 00280 // start the sample timer with an arbitrary zero point of 'now' 00281 t.start(); 00282 00283 // start with no minimum integration time 00284 tIntMin = 0; 00285 00286 // allocate our double pixel buffers 00287 pix1 = new uint8_t[nPixSensor*2]; 00288 pix2 = pix1 + nPixSensor; 00289 00290 // put the first DMA transfer into the first buffer (pix1) 00291 pixDMA = 0; 00292 00293 // DMA owns both buffers until the first transfer completes 00294 clientOwnsStablePix = true; 00295 00296 // remember the clock pin port base and pin mask for fast access 00297 clockPort = GPIO_PORT_BASE(clockPin); 00298 clockMask = GPIO_PINMASK(clockPin); 00299 00300 // clear out power-on random data by clocking through all pixels twice 00301 clear(); 00302 clear(); 00303 00304 // Set up the Clock Up DMA channel. This channel takes the 00305 // clock high by writing the clock bit to the PSOR (set output) 00306 // register for the clock pin. 00307 clkUp_dma.source(&clockMask, false, 32); 00308 clkUp_dma.destination(&clockPort->PSOR, false, 32); 00309 00310 // Set up the Clock Down DMA channel. This channel takes the 00311 // clock low by writing the clock bit to the PCOR (clear output) 00312 // register for the clock pin. 00313 clkDn_dma.source(&clockMask, false, 32); 00314 clkDn_dma.destination(&clockPort->PCOR, false, 32); 00315 00316 // Set up the ADC transfer DMA channel. This channel transfers 00317 // the current analog sampling result from the ADC output register 00318 // to our pixel array. 00319 ao.initDMA(&adc_dma); 00320 00321 // Set up our chain of linked DMA channel: 00322 // 00323 // ADC sample completion triggers Clock Up 00324 // ...which triggers the ADC transfer 00325 // ...which triggers Clock Down 00326 // 00327 // We operate the ADC in "continuous mode", meaning that it starts 00328 // a new sample immediately after the last one completes. This is 00329 // what keeps the cycle going after the Clock Down, since the Clock 00330 // Down transfer itself doesn't trigger another DMA operation. 00331 clkUp_dma.trigger(Trigger_ADC0); 00332 clkUp_dma.link(adc_dma); 00333 adc_dma.link(clkDn_dma, false); 00334 00335 // Set the trigger on the downstream links to NONE - these are 00336 // triggered by their upstream links, so they don't need separate 00337 // peripheral or software triggers. 00338 adc_dma.trigger(Trigger_NONE); 00339 clkDn_dma.trigger(Trigger_NONE); 00340 00341 // Register an interrupt callback so that we're notified when 00342 // the last transfer completes. 00343 clkDn_dma.attach(this, &TSL14xx::transferDone); 00344 00345 // clear the timing statistics 00346 totalTime = 0.0; 00347 nRuns = 0; 00348 00349 // start the first transfer 00350 startTransfer(); 00351 } 00352 00353 // Get the stable pixel array. This is the image array from the 00354 // previous capture. It remains valid until the next startCapture() 00355 // call, at which point this buffer will be reused for the new capture. 00356 void getPix(uint8_t * &pix, uint32_t &t) 00357 { 00358 // return the pixel array that ISN'T assigned to the DMA 00359 if (pixDMA) 00360 { 00361 // DMA owns pix2, so the stable array is pix1 00362 pix = pix1; 00363 t = t1; 00364 } 00365 else 00366 { 00367 // DMA owns pix1, so the stable array is pix2 00368 pix = pix2; 00369 t = t2; 00370 } 00371 } 00372 00373 // Wait for the current DMA transfer to finish, and retrieve its 00374 // pixel array buffer. This provides access to the latest image 00375 // without starting a new transfer. These pixels are valid throughout 00376 // the next transfer (started via startCapture()) and remain valid 00377 // until the next transfer after that. 00378 void waitPix(uint8_t * &pix, uint32_t &t) 00379 { 00380 // wait for stable buffer ownership to transfer to the client 00381 wait(); 00382 00383 // Return the pixel array that IS assigned to DMA, since this 00384 // is the latest buffer filled. This buffer is stable, even 00385 // though it's assigned to DMA, because the last transfer is 00386 // already finished and thus DMA is no longer accessing the 00387 // buffer. 00388 if (pixDMA) 00389 { 00390 // DMA owns pix2 00391 pix = pix2; 00392 t = t2; 00393 } 00394 else 00395 { 00396 // DMA owns pix1 00397 pix = pix1; 00398 t = t1; 00399 } 00400 } 00401 00402 // Set the requested minimum integration time. If this is less than the 00403 // sensor's physical minimum time, the physical minimum applies. 00404 virtual void setMinIntTime(uint32_t us) 00405 { 00406 tIntMin = us; 00407 } 00408 00409 // Wait for the stable buffer ownership to transfer to the client 00410 void wait() { while (!clientOwnsStablePix) ; } 00411 00412 // Is a buffer available? 00413 bool ready() const { return clientOwnsStablePix; } 00414 00415 // Release the client DMA buffer. The client must call this when it's 00416 // done with the current image frame to release the frame back to the 00417 // DMA subsystem, so that it can hand us the next frame. 00418 void releasePix() { clientOwnsStablePix = false; } 00419 00420 // get the timing statistics - sum of scan time for all scans so far 00421 // in microseconds, and total number of scans so far 00422 void getTimingStats(uint64_t &totalTime, uint32_t &nRuns) const 00423 { 00424 totalTime = this->totalTime; 00425 nRuns = this->nRuns; 00426 } 00427 00428 // get the average scan time in microseconds 00429 uint32_t getAvgScanTime() const 00430 { 00431 return uint32_t(totalTime / nRuns); 00432 } 00433 00434 private: 00435 // Start a new transfer. We call this at the end of each integration 00436 // cycle, in interrupt mode. This can be called directly by the interrupt 00437 // handler invoked when the DMA transfer completes, or by a timeout. In 00438 // either case, we're in interrupt mode. 00439 void startTransfer() 00440 { 00441 // If we own the stable buffer, swap buffers: hand ownership of the 00442 // old DMA buffer to the client, and take control of the old client 00443 // buffer (which the client must be done with if we own it) as our 00444 // new DMA buffer. 00445 // 00446 // If the client owns the stable buffer, we can't swap buffers, 00447 // because the client is still working on the stable one. So we 00448 // must start the new transfer using the existing DMA buffer. 00449 if (!clientOwnsStablePix) 00450 { 00451 // swap buffers 00452 pixDMA ^= 1; 00453 00454 // release the prior DMA buffer to the client 00455 clientOwnsStablePix = true; 00456 } 00457 00458 // Set up the active pixel array as the destination buffer for 00459 // the ADC DMA channel. 00460 adc_dma.destination(pixDMA ? pix2 : pix1, true); 00461 00462 // start the DMA transfers 00463 clkDn_dma.start(nPixSensor*4, true); 00464 adc_dma.start(nPixSensor, true); 00465 clkUp_dma.start(nPixSensor*4, true); 00466 00467 // note the start time of this transfer 00468 t0 = t.read_us(); 00469 00470 // start the next integration cycle by pulsing SI and one clock 00471 si = 1; 00472 clock = 1; 00473 si = 0; 00474 clock = 0; 00475 00476 // Set the timestamp for the current active buffer. The SI pulse 00477 // we just did performed the HOLD operation, which takes a snapshot 00478 // of the photo receptors and stores it in the sensor's shift 00479 // register. We noted the start of the current integration cycle 00480 // in tInt when we started it during the previous scan. The image 00481 // we're about to transfer therefore represents the light collected 00482 // between tInt and right now (actually, the SI pulse above, but 00483 // close enough). The image covers a time range rather than a 00484 // single point in time, but we still have to give it a single 00485 // timestamp. Use the midpoint of the integration period. 00486 uint32_t tmid = (t0 + tInt) >> 1; 00487 if (pixDMA) 00488 t2 = tmid; 00489 else 00490 t1 = tmid; 00491 00492 // Start the ADC sampler. The ADC will read samples continuously 00493 // until we tell it to stop. Each sample completion will trigger 00494 // our linked DMA channel, which will store the next sample in our 00495 // pixel array and pulse the CCD serial data clock to load the next 00496 // pixel onto the analog sampler pin. This will all happen without 00497 // any CPU involvement, so we can continue with other work. 00498 ao.start(); 00499 00500 // The new integration cycle starts with the 19th clock pulse 00501 // after the SI pulse. We offload all of the transfer work (including 00502 // the clock pulse generation) to the DMA controller, which doesn't 00503 // notify when that 19th pulse occurs, so we have to approximate. 00504 // Based on empirical measurements, each pixel transfer in our DMA 00505 // setup takes about 2us, so clocking 19 pixels takes about 38us. 00506 // In addition, the ADC takes about 4us extra for the first read. 00507 tInt = t.read_us() + 19*2 + 4; 00508 } 00509 00510 // End of transfer notification. This is called as an interrupt 00511 // handler when the DMA transfer completes. 00512 void transferDone() 00513 { 00514 // stop the ADC sampler 00515 ao.stop(); 00516 00517 // clock out one extra pixel to leave the analog out pin on 00518 // the sensor in the high-Z state 00519 clock = 1; 00520 clock = 0; 00521 00522 // add this sample to the timing statistics (for diagnostics and 00523 // performance measurement) 00524 uint32_t now = t.read_us(); 00525 totalTime += uint32_t(now - t0); 00526 nRuns += 1; 00527 00528 // note the ending time of the transfer 00529 tDone = now; 00530 00531 // Figure the time remaining to reach the minimum requested 00532 // integration time for the next cycle. The sensor is currently 00533 // working on an integration cycle that started at tInt, and that 00534 // cycle will end when we start the next cycle. We therefore want 00535 // to wait to start the next cycle until we've reached the desired 00536 // total integration time. 00537 uint32_t dt = now - tInt; 00538 00539 // Figure the time to the start of the next transfer. Wait for the 00540 // remainder of the current integration period if we haven't yet 00541 // reached the requested minimum, otherwise just start almost 00542 // immediately. (Not *actually* immediately: we don't want to start 00543 // the new transfer within this interrupt handler, because the DMA 00544 // IRQ doesn't reliably clear if we start a new transfer immediately.) 00545 uint32_t dtNext = dt < tIntMin ? tIntMin - dt : 1; 00546 00547 // Schedule the next transfer 00548 integrationTimeout.attach_us(this, &TSL14xx::startTransfer, dtNext); 00549 } 00550 00551 // Clear the sensor shift register. Clocks in all of the pixels from 00552 // the sensor without bothering to read them on the ADC. Pulses SI 00553 // at the beginning of the operation, which starts a new integration 00554 // cycle. 00555 void clear() 00556 { 00557 // get the clock toggle register 00558 volatile uint32_t *ptor = &clockPort->PTOR; 00559 00560 // make sure any DMA run is completed 00561 wait(); 00562 00563 // clock in an SI pulse 00564 si = 1; 00565 *ptor = clockMask; 00566 clockPort->PSOR = clockMask; 00567 si = 0; 00568 *ptor = clockMask; 00569 00570 // This starts a new integration period. Or more precisely, the 00571 // 19th clock pulse will start the new integration period. We're 00572 // going to blast the clock signal as fast as we can, at about 00573 // 100ns intervals (50ns up and 50ns down), so the 19th clock 00574 // will be about 2us from now. 00575 tInt = t.read_us() + 2; 00576 00577 // clock out all pixels, plus an extra one to clock past the last 00578 // pixel and reset the last pixel's internal sampling switch in 00579 // the sensor 00580 for (int i = 0 ; i < nPixSensor + 1 ; ) 00581 { 00582 // toggle the clock to take it high 00583 *ptor = clockMask; 00584 00585 // increment our loop variable here to pad the timing, to 00586 // keep our pulse width long enough for the sensor 00587 ++i; 00588 00589 // toggle the clock to take it low 00590 *ptor = clockMask; 00591 } 00592 } 00593 00594 // DMA controller interfaces 00595 SimpleDMA adc_dma; // DMA channel for reading the analog input 00596 SimpleDMA clkUp_dma; // "Clock Up" channel 00597 SimpleDMA clkDn_dma; // "Clock Down" channel 00598 00599 // Sensor interface pins 00600 DigitalOut si; // GPIO pin for sensor SI (serial data) 00601 DigitalOut clock; // GPIO pin for sensor SCLK (serial clock) 00602 GPIO_Type *clockPort; // IOPORT base address for clock pin - cached for DMA writes 00603 uint32_t clockMask; // IOPORT register bit mask for clock pin 00604 AltAnalogIn_8bit ao; // GPIO pin for sensor AO (analog output) 00605 00606 // number of pixels in the physical sensor array 00607 int nPixSensor; // number of pixels in physical sensor array 00608 00609 // pixel buffers - we keep two buffers so that we can transfer the 00610 // current sensor data into one buffer via DMA while we concurrently 00611 // process the last buffer 00612 uint8_t *pix1; // pixel array 1 00613 uint8_t *pix2; // pixel array 2 00614 00615 // Timestamps of pix1 and pix2 arrays, in microseconds, in terms of the 00616 // sample timer (this->t). 00617 uint32_t t1; 00618 uint32_t t2; 00619 00620 // DMA target buffer. This is the buffer for the next DMA transfer. 00621 // 0 means pix1, 1 means pix2. The other buffer contains the stable 00622 // data from the last transfer. 00623 uint8_t pixDMA; 00624 00625 // Stable buffer ownership. At any given time, the DMA subsystem owns 00626 // the buffer specified by pixDMA. The other buffer - the "stable" buffer, 00627 // which contains the most recent completed frame, can be owned by EITHER 00628 // the client or by the DMA subsystem. Each time a DMA transfer completes, 00629 // the DMA subsystem looks at the stable buffer owner flag to determine 00630 // what to do: 00631 // 00632 // - If the DMA subsystem owns the stable buffer, it swaps buffers. This 00633 // makes the newly completed DMA buffer the new stable buffer, and makes 00634 // the old stable buffer the new DMA buffer. At this time, the DMA 00635 // subsystem also changes the stable buffer ownership to CLIENT. 00636 // 00637 // - If the CLIENT owns the stable buffer, the DMA subsystem can't swap 00638 // buffers, because the client is still using the stable buffer. It 00639 // simply leaves things as they are. 00640 // 00641 // In either case, the DMA system starts a new transfer at this point. 00642 // 00643 // The client, meanwhile, is free to access the stable buffer when it has 00644 // ownership. If the client *doesn't* have ownership, it must wait for 00645 // the ownership to be transferred, which can only be done by the DMA 00646 // subsystem on completing a transfer. 00647 // 00648 // When the client is done with the stable buffer, it transfers ownership 00649 // back to the DMA subsystem. 00650 // 00651 // Transfers of ownership from DMA to CLIENT are done only by DMA. 00652 // Transfers from CLIENT to DMA are done only by CLIENT. So whoever has 00653 // ownership now is responsible for transferring ownership. 00654 // 00655 volatile bool clientOwnsStablePix; 00656 00657 // End-of-integration timeout handler. This lets us fire an interrupt 00658 // when the current integration cycle is done, so that we can start the 00659 // next cycle. 00660 Timeout integrationTimeout; 00661 00662 // Requested minimum integration time, in micoseconds. The client can use 00663 // this to control the exposure level, by increasing it for a longer 00664 // exposure and thus more light-gathering in low-light conditions. Note 00665 // that the physical limit on the minimum integration time is roughly equal 00666 // to the pixel file transfer time, because the integration cycle is 00667 // initiated and ended by transfer starts. It's thus impossible to make 00668 // the integration time less than the time for one full pixel file 00669 // transfer. 00670 uint32_t tIntMin; 00671 00672 // timing statistics 00673 Timer t; // sample timer 00674 uint32_t t0; // start time (us) of current sample 00675 uint32_t tInt; // start time (us) of current integration period 00676 uint32_t tDone; // end time of latest finished transfer 00677 uint64_t totalTime; // total time consumed by all reads so far 00678 uint32_t nRuns; // number of runs so far 00679 }; 00680 00681 #endif /* TSL14XX_H */
Generated on Wed Jul 13 2022 03:30:11 by 1.7.2