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
TCD1103.h
00001 // Toshiba TCD1103 linear CCD image sensor, 1x1500 pixels. 00002 // 00003 // This sensor is conceptually similar to the TAOS TSL1410R (the original 00004 // Pinscape sensor!). Like the TSL1410R, it has a linear array of optical 00005 // sensor pixels that convert incident photons into electrical charge, an 00006 // internal shift register connected to the pixel file that acts as an 00007 // electronic shutter, and a serial interface that clocks the pixels out 00008 // to the host in analog voltage level format. 00009 // 00010 // The big physical difference between this sensor and the old TAOS sensors 00011 // is the size. The TAOS sensors were (by some miracle) approximately the 00012 // same size as the plunger travel range, so we were able to take "contact" 00013 // images without any optics, by placing the plunger close to the sensor, 00014 // back-lighting it, and essentially taking a picture of its shadow. The 00015 // Toshiba sensor, in contrast, has a pixel window that's only 8mm long, so 00016 // the contact image approach won't work. Instead, we have to use a lens 00017 // to focus a reduced image (about 1:10 scale) on the sensor. That makes 00018 // the physical setup more complex, but it has the great advantage that we 00019 // get a focused image. The shadow was always fuzzy in the old contact 00020 // image approach, which reduced the effective resolution when determining 00021 // the plunger position. With a focused image, we can get single-pixel 00022 // resolution. With this Toshiba sensor's 1500 pixels, that's about 500 00023 // dpi, which beats every other sensor we've come up with. 00024 // 00025 // The electronic interface to this sensor is similar to the TAOS, but it 00026 // has enough differences that we can't share the same code base. 00027 // 00028 // As with the 1410R, we have to use DMA for the ADC transfers in order 00029 // to keep up with the high data rate without overloading the KL25Z CPU. 00030 // With the 1410R, we're able to use the ADC itself as the clock source, 00031 // by running the ADC in continous mode and using its "sample ready" signal 00032 // to trigger the DMA transfer. We used this to generate the external clock 00033 // signal for the sensor by "linking" the ADC's DMA channel to another pair 00034 // of DMA channels that generated the clock up/down signal each time an ADC 00035 // sample completed. This strategy won't work with the Toshiba sensor, 00036 // though, because the Toshiba sensor's timing sequence requires *two* clock 00037 // pulses per pixel. I can't come up with a way to accomplish that with the 00038 // linked-DMA approach. Instead, we'll have to generate a true clock signal 00039 // for the sensor, and drive the DMA conversions off of that clock. 00040 // 00041 // The obvious (and, as far as I can tell, only) way to generate the clock 00042 // signal with the KL25Z at the high frequency required is to use a TPM - 00043 // the KL25Z module that drives PWM outputs. TPM channels are designed 00044 // precisely for this kind of work, so this is the right approach in terms of 00045 // suitability, but it has the downside that TPM units are an extremely scarce 00046 // resource on the KL25Z. We only have three of them to work with. Luckily, 00047 // the rest of the Pinscape software only requires two of them: one for the 00048 // IR transmitter (which uses a TPM channel to generate the 41-48 kHz carrier 00049 // wave used by nearly all consumer IR remotes), and one for the TLC5940 00050 // driver (which uses it to generate the grayscale clock signal). Note that 00051 // we also use PWM channels for feedback device output ports, but those don't 00052 // have any dependency on the TPM period - they'll work with whatever period 00053 // the underlying TPM is set to use. So the feedback output ports can all 00054 // happily use free channels on TPM units claimed by any of the dedicated 00055 // users (IR, TLC5940, and us). 00056 // 00057 // But what do we do about the 2:1 ratio between master clock pulses and ADC 00058 // samples? The "right" way would be to allocate a second TPM unit to 00059 // generate a second clock signal at half the frequency of the master clock, 00060 // and use that as the ADC trigger. But as we just said, we only have three 00061 // TPM units in the whole system, and two of them are already claimed for 00062 // other uses, so we only have one unit available for our use here. 00063 // 00064 // Fortunately, we can make do with one TPM unit, by taking advantage of a 00065 // feature/quirk of the KL25Z ADC. The quirk lets us take ADC samples at 00066 // exactly half of the master clock rate, in perfect sync. The trick is to 00067 // pick a combination of master clock rate and ADC sample mode such that the 00068 // ADC conversion time is *almost but not quite* twice as long as the master 00069 // clock rate. With that combination of timings, we can trigger the ADC 00070 // from the TPM, and we'll get an ADC sample on exactly every other tick of 00071 // the master clock. The reason this works is that the KL25Z ADC ignores 00072 // hardware triggers (the TPM trigger is a hardware trigger) that occur when 00073 // a conversion is already in progress. So if the ADC sampling time is more 00074 // than one master clock period, the ADC will always be busy one clock tick 00075 // after a sample starts, so it'll ignore that first clock tick. But as 00076 // long as the sampling time is less than *two* master clock periods, the 00077 // ADC will always be ready again on the second tick. So we'll get one ADC 00078 // sample for every two master clock ticks, exactly as we need. 00079 // 00080 // This is all possible because the ADC timing is deterministic, and runs on 00081 // the same clock as the TPM. The KL25Z Subfamily Reference Manual explains 00082 // how to calculate the ADC conversion time for a given combination of mode 00083 // bits. So we just have to pick an ADC mode, calculate its conversion time, 00084 // and then select a TPM period that's slightly more than 1/2 of the ADC 00085 // conversion time. 00086 // 00087 // I know this sounds like it should be prone to unpredictable timing bugs, 00088 // but it's actually 100% deterministic! It's truly deterministic because 00089 // the underlying clock for the TPM and ADC is shared. Intuitively, we 00090 // think of time-based processes as inherently stochastic because clocks 00091 // are never perfect, so if you have two time-based processes based on 00092 // separate clocks, the two processes are never perfectly in sync because 00093 // their separate clocks will drift slightly relative to one another. But 00094 // that's not what's going on here. The time-based processes we're talking 00095 // about are tied to the same underlying clock, so there's absolutely no 00096 // possibility of clock drift or phase shift or anything else that feeds 00097 // into that intuition about stochasticness in time-based processes. In 00098 // addition, the key ADC feature we're exploiting for the clock doubling - 00099 // that the ADC ignores hardware triggers during an active cycle - isn't 00100 // some accidental behavior we observed empirically. It's by design and 00101 // it's documented. We can count on it always being the case with this 00102 // ADC. Between those two factors (synchronous clock, designed and 00103 // documented ADC behavior), we can count on the timing being EXACTLY the 00104 // same on EVERY sample. We're not counting on being "lucky". 00105 // 00106 // Note that there are several other, similar Toshiba sensors with the same 00107 // electrical interface and almost the same signal timing, but with a 4:1 00108 // ratio between the master clock ticks and the pixel outputs. This code 00109 // could be adapted to those sensors using the same "trick" we use for the 00110 // 2:1 timing ratio, by choosing an ADC mode with a sampling rate that's 00111 // between 3*fM and 4*fM. That will make the ADC ignore the first three 00112 // master clocks in each cycle, triggering a new sample reading on every 00113 // fourth master clock tick, achieving the desired 4:1 ratio. We don't 00114 // provide an option for that because there are no such Toshiba sensors in 00115 // production that are of interest to us as plunger sensors, and because 00116 // the selection of a suitable fM timing and ADC mode are both dependent 00117 // on the constraints of your application, so it's not feasible to automate 00118 // the selection of either based on simple numeric parameters. If you want 00119 // to adapt the code, start by figuring out the range of fM timing you can 00120 // accept, then look at the KL25Z manual to work out the ADC cycle timing 00121 // for various modes with the properties you want. You can then adjust 00122 // either or both the fM timing and ADC settings until you find a suitable 00123 // balance in the timing. The Toshiba sensors can generally accept a wide 00124 // range of fM rates, so you can count both the clock rate and ADC modes as 00125 // free variables, within the constraints of your application in terms of 00126 // required frame rate and ADC sampling quality. 00127 // 00128 // 00129 // Pixel output signal 00130 // 00131 // The pixel output signal from this sensor is an analog voltage level. It's 00132 // inverted from the brightness: higher brightness is represented by lower 00133 // voltage. The dynamic range is only about 1V, with a 1V floor. So dark 00134 // pixels read at about 2V, and saturated pixels read at about 1V. 00135 // 00136 // The output pin from the sensor connects to what is essentially a very 00137 // small capacitor containing a tiny amount of charge. This isn't a good 00138 // source for the ADC to sample, so some additional circuitry is required 00139 // to convert the charge to a low-impedance voltage source suitable for 00140 // connecting to an ADC. The driver circuit recommended in the Toshiba 00141 // data sheet consists of a high-gain PNP transistor and a few resistors. 00142 // See "How to connect to the KL25Z" below for the component types and 00143 // values we've tested successfully. 00144 // 00145 // 00146 // Inverted logic signals 00147 // 00148 // The Toshiba data sheet recommends buffering the logic signal inputs from 00149 // an MCU through a 74HC04 inverter, because the sensor's logic gates have 00150 // relatively high input capacitance that an MCU might not be able to drive 00151 // fast enough directly to keep up with the sensor's timing requirements. 00152 // SH in particular might be a problem because of its 150pF capacitance, 00153 // which implies about a 2us rise/fall time if driven directly by KL25Z 00154 // GPIOs, which is too slow. 00155 // 00156 // The software will work with or without the logic inversion, in case anyone 00157 // wants to try implementing it with direct GPIO drive (not recommended) or 00158 // with a non-inverting buffer in place of the 74HC04. Simply instantiate the 00159 // class with the 'invertedLogicGates' template parameter set to false to use 00160 // non-inverted logic. 00161 // 00162 // 00163 // How to connect to the KL25Z 00164 // 00165 // Follow the "typical drive circuit" presented in the Toshiba data sheet. 00166 // They leave some of the parts unspecified, so here are the specific values 00167 // we used for our reference implementation: 00168 // 00169 // - 3.3V power supply 00170 // - 74HC04N hex inverter for the logic gate inputs (fM, SH, ICG) 00171 // - 0.1uF ceramic + 10uF electrolytic decoupling capacitors (GND to Vcc)) 00172 // - BC212A PNP transistor for the output drive (OS), with: 00173 // - 150 ohm resistor on the base 00174 // - 150 ohm resistor between collector and GND 00175 // - 2.2K ohm resistor between emitter and Vcc 00176 // 00177 00178 #include "config.h" 00179 #include "NewPwm.h" 00180 #include "AltAnalogIn.h" 00181 #include "SimpleDMA.h" 00182 #include "DMAChannels.h" 00183 00184 00185 template<bool invertedLogicGates> class TCD1103 00186 { 00187 public: 00188 TCD1103(PinName fmPin, PinName osPin, PinName icgPin, PinName shPin) : 00189 fm(fmPin, invertedLogicGates), 00190 os(osPin, false, 6, 1), // single sample, 6-cycle long sampling mode, no averaging 00191 icg(icgPin), 00192 sh(shPin), 00193 os_dma(DMAch_TDC_ADC) 00194 { 00195 // Idle conditions: SH low, ICG high. 00196 sh = logicLow; 00197 icg = logicHigh; 00198 00199 // Set a zero minimum integration time by default. Note that tIntMin 00200 // has no effect when it's less than the absolute minimum, which is 00201 // the pixel transfer time for one frame (around 3ms). tIntMin only 00202 // kicks in when it goes above that absolute minimum, at which point 00203 // we'll wait for any additional time needed to reach tIntMin before 00204 // starting the next integration cycle. 00205 tIntMin = 0; 00206 00207 // Calibrate the ADC for best accuracy 00208 os.calibrate(); 00209 00210 // ADC sample conversion time. This must be calculated based on the 00211 // combination of parameters selected for the os() initializer above. 00212 // See the KL25 Sub-Family Reference Manual, section 28.4.4.5, for the 00213 // formula. We operate in single-sample mode, so when you read the 00214 // Reference Manual tables, the sample time value to use is the 00215 // "First or Single" value. 00216 const float ADC_TIME = 2.1041667e-6f; // 6-cycle long sampling, no averaging 00217 00218 // Set the TPM cycle time to satisfy our timing constraints: 00219 // 00220 // Tm + epsilon1 < A < 2*Tm - epsilon2 00221 // 00222 // where A is the ADC conversion time and Tm is the master clock 00223 // period, and the epsilons provide a margin of safety for any 00224 // non-deterministic component to the timing of A and Tm. The 00225 // epsilons could be zero if the timing of the ADC is perfectly 00226 // deterministic; this must be determined empirically. 00227 // 00228 // The most conservative solution would be to make epsilon as large 00229 // as possible, which means bisecting the time window by making 00230 // A = 1.5*T, or, equivalently, T = A/1.5 (the latter form being more 00231 // useful because T is the free variable here, as we can only control 00232 // A to the extent that we can choose the ADC parameters). 00233 // 00234 // But we'd also like to make T as short as possible while maintaining 00235 // reliable operation. Shorter T yields a higher frame rate, and we 00236 // want the frame rate to be as high as possible so that we can track 00237 // fast plunger motion accurately. Empirically, we can get reliable 00238 // results by using half of the ADC time plus a small buffer time. 00239 // 00240 fm.getUnit()->period(masterClockPeriod = ADC_TIME/2 + 0.25e-6f); 00241 00242 // Start the master clock running with a 50% duty cycle 00243 fm.write(0.5f); 00244 00245 // Allocate our double pixel buffers. 00246 pix1 = new uint8_t[nPixAlo * 2]; 00247 pix2 = pix1 + nPixAlo; 00248 00249 // put the first DMA transfer into the first buffer (pix1) 00250 pixDMA = 0; 00251 clientOwnsStablePix = false; 00252 00253 // start the sample timer with an arbitrary epoch of "now" 00254 t.start(); 00255 00256 // Set up the ADC transfer DMA channel. This channel transfers 00257 // the current analog sampling result from the ADC output register 00258 // to our pixel array. 00259 os.initDMA(&os_dma); 00260 00261 // Register an interrupt callback so that we're notified when 00262 // the last ADC transfer completes. 00263 os_dma.attach(this, &TCD1103::transferDone); 00264 00265 // Set up the ADC to trigger on the master clock's TPM channel 00266 os.setTriggerTPM(fm.getUnitNum()); 00267 00268 // clear the timing statistics 00269 totalXferTime = 0.0; 00270 maxXferTime = 0; 00271 minXferTime = 0xffffffff; 00272 nRuns = 0; 00273 00274 // start the first transfer 00275 startTransfer(); 00276 } 00277 00278 // logic gate levels, based on whether or not the logic gate connections 00279 // in the hardware are buffered through inverters 00280 static const int logicLow = invertedLogicGates ? 1 : 0; 00281 static const bool logicHigh = invertedLogicGates ? 0 : 1; 00282 00283 // ready to read 00284 bool ready() { return clientOwnsStablePix; } 00285 00286 // Get the stable pixel array. This is the image array from the 00287 // previous capture. It remains valid until the next startCapture() 00288 // call, at which point this buffer will be reused for the new capture. 00289 void getPix(uint8_t * &pix, uint32_t &t) 00290 { 00291 // Return the pixel array that ISN'T assigned to the DMA. 00292 if (pixDMA) 00293 { 00294 // DMA owns pix2, so the stable array is pix1 00295 pix = pix1; 00296 t = t1; 00297 } 00298 else 00299 { 00300 // DMA owns pix1, so the stable array is pix2 00301 pix = pix2; 00302 t = t2; 00303 } 00304 } 00305 00306 // release the client's pixel buffer 00307 void releasePix() { clientOwnsStablePix = false; } 00308 00309 // figure the average scan time from the running totals 00310 uint32_t getAvgScanTime() { return static_cast<uint32_t>(totalXferTime / nRuns);} 00311 00312 // Set the requested minimum integration time. If this is less than the 00313 // sensor's physical minimum time, the physical minimum applies. 00314 virtual void setMinIntTime(uint32_t us) 00315 { 00316 tIntMin = us; 00317 } 00318 00319 protected: 00320 // Start an image capture from the sensor. Waits the previous 00321 // capture to finish if it's still running, then starts a new one 00322 // and returns immediately. The new capture proceeds asynchronously 00323 // via DMA hardware transfer, so the client can continue with other 00324 // processing during the capture. 00325 void startTransfer() 00326 { 00327 // if we own the stable buffer, swap buffers 00328 if (!clientOwnsStablePix) 00329 { 00330 // swap buffers 00331 pixDMA ^= 1; 00332 00333 // release the prior DMA buffer to the client 00334 clientOwnsStablePix = true; 00335 } 00336 00337 // figure our destination buffer 00338 uint8_t *dst = pixDMA ? pix2 : pix1; 00339 00340 // Set up the active pixel array as the destination buffer for 00341 // the ADC DMA channel. 00342 os_dma.destination(dst, true); 00343 00344 // Start the read cycle by sending the ICG/SH pulse sequence 00345 uint32_t tNewInt = gen_SH_ICG_pulse(true); 00346 00347 // Set the timestamp for the current active buffer. The ICG/SH 00348 // gymnastics we just did transferred the CCD pixels into the sensor's 00349 // internal shift register and reset the pixels, starting a new 00350 // integration cycle. So the pixels we just shifted started 00351 // integrating the *last* time we did that, which we recorded as 00352 // tInt at the time. The image we're about to transfer therefore 00353 // represents the light collected between tInt and the SH pulse we 00354 // just did. The image covers a time range rather than a single 00355 // point in time, but we still have to give it a single timestamp. 00356 // Use the midpoint of the integration period. 00357 uint32_t tmid = (tNewInt + tInt) >> 1; 00358 if (pixDMA) 00359 t2 = tmid; 00360 else 00361 t1 = tmid; 00362 00363 // Record the start time of the currently active integration period 00364 tInt = tNewInt; 00365 } 00366 00367 // End of transfer notification. This runs as an interrupt handler when 00368 // the DMA transfer completes. 00369 void transferDone() 00370 { 00371 // stop the ADC triggering 00372 os.stop(); 00373 00374 // add this sample to the timing statistics (for diagnostics and 00375 // performance measurement) 00376 uint32_t now = t.read_us(); 00377 uint32_t dt = dtPixXfer = static_cast<uint32_t>(now - tXfer); 00378 totalXferTime += dt; 00379 nRuns += 1; 00380 00381 // collect debug statistics 00382 if (dt < minXferTime) minXferTime = dt; 00383 if (dt > maxXferTime) maxXferTime = dt; 00384 00385 // figure how long we've been integrating so far on this cycle 00386 uint32_t dtInt = now - tInt; 00387 00388 // Figure the time to the start of the next transfer. Wait for the 00389 // remainder of the current integration period if we haven't yet 00390 // reached the requested minimum, otherwise just start almost 00391 // immediately. (Not *actually* immediately: we don't want to start 00392 // the new transfer within this interrupt handler, because the DMA 00393 // IRQ doesn't reliably clear if we start a new transfer immediately.) 00394 uint32_t dtNext = dtInt < tIntMin ? tIntMin - dtInt : 1; 00395 00396 // Schedule the next transfer 00397 integrationTimeout.attach_us(this, &TCD1103::startTransfer, dtNext); 00398 } 00399 00400 // Generate an SH/ICG pulse. This transfers the pixel data from the live 00401 // sensor photoreceptors into the sensor's internal shift register, clears 00402 // the live pixels, and starts a new integration cycle. 00403 // 00404 // If start_dma_xfer is true, we'll start the DMA transfer for the ADC 00405 // pixel data. We handle this here because the sensor starts clocking 00406 // out pixels precisely at the end of the ICG pulse, so we have to be 00407 // be very careful about the timing. 00408 // 00409 // Returns the timestamp (relative to our image timer 't') of the end 00410 // of the SH pulse, which is the moment the new integration cycle starts. 00411 // 00412 // Note that we send these pulses synchronously - that is, this routine 00413 // blocks until the pulses have been sent. The overall sequence takes 00414 // about 2.5us to 3us, so it's not a significant interruption of the 00415 // main loop. 00416 // 00417 uint32_t gen_SH_ICG_pulse(bool start_dma_xfer) 00418 { 00419 // Make sure the ADC is stopped 00420 os.stop(); 00421 00422 // If desired, prepare to start the DMA transfer for the ADC data. 00423 // (Set up a dummy location to write in lieu of the DMA register if 00424 // DMA initiation isn't required, so that we don't have to take the 00425 // time for a conditional when we're ready to start the DMA transfer. 00426 // The timing there will be extremely tight, and we can't afford the 00427 // extra instructions to test a condition.) 00428 uint8_t dma_chcfg_dummy = 0; 00429 volatile uint8_t *dma_chcfg = start_dma_xfer ? os_dma.prepare(nPixSensor, true) : &dma_chcfg_dummy; 00430 00431 // The basic idea is to take ICG low, and while holding ICG low, 00432 // pulse SH. The coincidence of the two pulses transfers the charge 00433 // from the live pixels into the shift register, which effectively 00434 // discharges the live pixels and thereby starts a new integration 00435 // cycle. 00436 // 00437 // The timing of the pulse sequence is rather tightly constrained 00438 // per the data sheet, so we have to take some care in executing it: 00439 // 00440 // ICG -> LOW 00441 // 100-1000 ns delay (*) 00442 // SH -> HIGH 00443 // >1000ns delay 00444 // SH -> LOW 00445 // >1000ns delay 00446 // ICG -> high (**) 00447 // 00448 // There are two steps here that are tricky: 00449 // 00450 // (*) is a narrow window that we can't achieve with an mbed 00451 // microsecond timer. Instead, we'll do a couple of extra writes 00452 // to the ICG register, which take about 60ns each. 00453 // 00454 // (**) has the rather severe constraint that the transition must 00455 // occur AND complete while the master clock is high. Other people 00456 // working with similar Toshiba chips in MCU projects have suggested 00457 // that this constraint can safely be ignored, so maybe the data 00458 // sheet's insistence about it is obsolete advice from past Toshiba 00459 // sensors that the doc writers carried forward by copy-and-paste. 00460 // Toshiba has been making these sorts of chips for a very long time, 00461 // and the data sheets for many of them are obvious copy-and-paste 00462 // jobs. But let's take the data sheet at its word and assume that 00463 // this is important for proper operation. Our best hope of 00464 // satisfying this constraint is to synchronize the start of the 00465 // ICG->high transition with the start of a TPM cycle on the master 00466 // clock. That guarantees that the ICG transition starts when the 00467 // clock signal is high (as each TPM cycle starts out high), and 00468 // gives us the longest possible runway for the transition to 00469 // complete while the clock is still high, as we get the full 00470 // length of the high part of the cycle to work with. To quantify, 00471 // it gives us about 600ns. The register write takes about 60ns, 00472 // and waitEndCycle() adds several instructions of overhead, perhaps 00473 // 200ns, so we get around 300ns for the transition to finish. That 00474 // should be a gracious plenty assuming that the hardware is set up 00475 // with an inverter to buffer the clock signals. The inverter should 00476 // be able to pull up the 35pF on ICG in a "typical" 30ns (rise time 00477 // plus propagation delay, per the 74HC04 data sheet) and max 150ns. 00478 // This seems to be one place where the inverter might really be 00479 // necessary to meet the timing requirements, as the KL25Z GPIO 00480 // might need more like 2us to pull that load up. 00481 // 00482 // There's an additional constraint on the timing at the end of the 00483 // ICG pulse. The sensor starts clocking out pixels on the rising 00484 // edge of the ICG pulse. So we need the ICG pulse end to align 00485 // with the start of an ADC cycle. If we get that wrong, all of our 00486 // ADC samples will be off by half a clock, so every sample will be 00487 // the average of two adjacent pixels instead of one pixel. That 00488 // would have the effect of shifting the image by half a pixel, 00489 // which could make our edge detection jitter by one pixel from one 00490 // frame to the next. So we definitely want to avoid this. 00491 // 00492 // The end of the SH pulse triggers the start of a new integration 00493 // cycle, so note the time of that pulse for image timestamping 00494 // purposes. That will be the start time of the NEXT image we 00495 // transfer after we shift out the current sensor pixels, which 00496 // represent the pixels from the last time we pulsed SH. 00497 // 00498 icg = logicLow; 00499 icg = logicLow; // for timing, adds about 150ns > min 100ns 00500 00501 sh = logicHigh; // take SH high 00502 00503 wait_us(1); // >1000ns delay 00504 sh = logicHigh; // a little more padding to be sure we're over the minimum 00505 00506 sh = logicLow; // take SH low 00507 00508 uint32_t t_sh = t.read_us(); // this is the start time of the NEXT integration 00509 00510 wait_us(3); // >1000ns delay, 5000ns typical; 3us should get us most 00511 // of the way there, considering that we have some more 00512 // work to do before we end the ICG pulse 00513 00514 // Now the tricky part! We have to end the ICG pulse (take ICG high) 00515 // at the start of a master clock cycle, AND at the start of an ADC 00516 // sampling cycle. The sensor will start clocking out pixels the 00517 // instance ICG goes high, so we have to align our ADC cycle so that 00518 // we start a sample at almost exactly the same time we take ICG 00519 // high. 00520 // 00521 // Now, every ADC sampling cycle always starts at a rising edge of 00522 // the master clock, since the master clock is the ADC trigger. BUT, 00523 // the converse is NOT true: every rising edge of the master clock 00524 // is NOT an ADC sample start. Recall that we've contrived the timing 00525 // so that every OTHER master clock rising edge starts an ADC sample. 00526 // 00527 // So how do we detect which part of the clock cycle we're in? We 00528 // could conceivably use the COCO bit in the ADC status register to 00529 // detect the little window between the end of one sample and the 00530 // start of the next. Unfortunately, this doesn't work: the COCO 00531 // bit is never actually set for the duration of even a single CPU 00532 // instruction in our setup, no matter how loose we make the timing 00533 // between the ADC and the fM cycle. I think the reason is the DMA 00534 // setup: the COCO bit triggers the DMA, and the DMA controller 00535 // reads the ADC result register (the DMA source in our setup), 00536 // which has the side effect of clearing COCO. I've experimented 00537 // with this using different timing parameters, and the result is 00538 // always the same: the CPU *never* sees the COCO bit set. The DMA 00539 // trigger timing is evidently deterministic such that the DMA unit 00540 // invariably gets its shot at reading ADC0->R before the CPU does. 00541 // 00542 // The COCO approach would be a little iffy anyway, since we want the 00543 // ADC idle time to be as short as possible, which wouldn't give us 00544 // much time to do all we have to do in the COCO period, even if 00545 // there were one. What we can do instead is seize control of the 00546 // ADC cycle timing: rather than trying to detect when the cycle 00547 // ends, we can specify when it begins. We can do this by canceling 00548 // the TPM->ADC trigger and aborting any conversion in progress, then 00549 // reprogramming the TPM->ADC trigger at our leisure. What we *can* 00550 // detect reliably is the start of a TPM cycle. So here's our 00551 // strategy: 00552 // 00553 // - Turn off the TPM->ADC trigger and abort the current conversion 00554 // - Wait until a new TPM cycle starts 00555 // - Reset the TPM->ADC trigger. The first new conversion will 00556 // start on the next TPM cycle, so we have the remainder of 00557 // the current TPM cycle to make this happen (about 1us, enough 00558 // for 16 CPU instructions - plenty for this step) 00559 // - Wait for the new TPM cycle 00560 // - End the ICG pulse 00561 // 00562 00563 // Enable the DMA controller for the new transfer from the ADC. 00564 // The sensor will start clocking out new samples at the ICG rising 00565 // edge, so the next ADC sample to complete will represent the first 00566 // pixel in the new frame. So we need the DMA ready to go at the 00567 // very next sample. Recall that the DMA is triggered by ADC 00568 // completion, and ADC is stopped right now, so enabling the DMA 00569 // won't have any immediate effect - it just spools it up so that 00570 // it's ready to move samples as soon as we resume the ADC. 00571 *dma_chcfg |= DMAMUX_CHCFG_ENBL_MASK; 00572 00573 // wait for the start of a new master clock cycle 00574 fm.waitEndCycle(); 00575 00576 // Wait one more cycle to be sure the DMA is ready. Empirically, 00577 // this extra wait is actually required; evidently DMA startup has 00578 // some non-deterministic timing element or perhaps an asynchronous 00579 // external dependency. In any case, *without* this extra wait, 00580 // the DMA transfer sporadically (about 20% probability) misses the 00581 // very first pixel that the sensor clocks out, so the entire image 00582 // is shifted "left" by one pixel. That makes the position sensing 00583 // jitter by a pixel from one frame to the next according to whether 00584 // or not we had that one-pixel delay in the DMA startup. Happily, 00585 // padding the timing by an fM cycle seems to make the DMA startup 00586 // perfectly reliable. 00587 fm.waitEndCycle(); 00588 00589 // Okay, a master clock cycle just started, so we have about 1us 00590 // (about 16 CPU instructions) before the next one begins. Resume 00591 // ADC sampling. The first new sample will start with the next 00592 // TPM cycle 1us from now. This step itself takes about 3 machine 00593 // instructions for 180ns, so we have about 820ns left to go. 00594 os.resume(); 00595 00596 // Eerything is queued up! We just have to fire the starting gun 00597 // on the sensor at the right moment. And that right moment is the 00598 // start of the next TPM cycle. Wait for it... 00599 fm.waitEndCycle(); 00600 00601 // And go! 00602 icg = logicHigh; 00603 00604 // note the start time of the transfer 00605 tXfer = t.read_us(); 00606 00607 // return the timestamp of the end of the SH pulse - this is the start 00608 // of the new integration period that we just initiated 00609 return t_sh; 00610 } 00611 00612 // master clock 00613 NewPwmOut fm; 00614 00615 // analog input for reading the pixel voltage level 00616 AltAnalogIn_8bit os; 00617 00618 // Integration Clear Gate output 00619 DigitalOut icg; 00620 00621 // Shift Gate output 00622 DigitalOut sh; 00623 00624 // DMA channel for the analog input 00625 SimpleDMA os_dma; 00626 00627 // Master clock period, in seconds, calculated based on the ADC timing 00628 float masterClockPeriod; 00629 00630 // Number of pixels. The TCD1103 has 1500 image pixels, plus 32 dummy 00631 // pixels at the front end (before the first image pixel) and another 14 00632 // dummy pixels at the back end. The sensor always transfers the full 00633 // file on each read cycle, including the dummies, so we have to make 00634 // room for the dummy pixels during each read. 00635 static const int nPixSensor = 1546; 00636 00637 // Figure the number of pixels to allocate per pixel buffer. Round 00638 // up to the next 4-byte boundary, so that the buffers are both DWORD- 00639 // aligned. (This allows using DWORD pointers into the buffer to 00640 // operate on buffer pixels four at a time, such as in the negative 00641 // image inversion code in the generic PlungerSensorImage base class.) 00642 static const int nPixAlo = (nPixSensor + 3) & ~3; 00643 00644 // pixel buffers - we keep two buffers so that we can transfer the 00645 // current sensor data into one buffer via DMA while we concurrently 00646 // process the last buffer 00647 uint8_t *pix1; // pixel array 1 00648 uint8_t *pix2; // pixel array 2 00649 00650 // Timestamps of pix1 and pix2 arrays, in microseconds, in terms of the 00651 // sample timer (this->t). 00652 uint32_t t1; 00653 uint32_t t2; 00654 00655 // DMA target buffer. This is the buffer for the next DMA transfer. 00656 // 0 means pix1, 1 means pix2. The other buffer contains the stable 00657 // data from the last transfer. 00658 uint8_t pixDMA; 00659 00660 // Stable buffer ownership. At any given time, the DMA subsystem owns 00661 // the buffer specified by pixDMA. The other buffer - the "stable" buffer, 00662 // which contains the most recent completed frame, can be owned by EITHER 00663 // the client or by the DMA subsystem. Each time a DMA transfer completes, 00664 // the DMA subsystem looks at the stable buffer owner flag to determine 00665 // what to do: 00666 // 00667 // - If the DMA subsystem owns the stable buffer, it swaps buffers. This 00668 // makes the newly completed DMA buffer the new stable buffer, and makes 00669 // the old stable buffer the new DMA buffer. At this time, the DMA 00670 // subsystem also changes the stable buffer ownership to CLIENT. 00671 // 00672 // - If the CLIENT owns the stable buffer, the DMA subsystem can't swap 00673 // buffers, because the client is still using the stable buffer. It 00674 // simply leaves things as they are. 00675 // 00676 // In either case, the DMA system starts a new transfer at this point. 00677 // 00678 // The client, meanwhile, is free to access the stable buffer when it has 00679 // ownership. If the client *doesn't* have ownership, it must wait for 00680 // the ownership to be transferred, which can only be done by the DMA 00681 // subsystem on completing a transfer. 00682 // 00683 // When the client is done with the stable buffer, it transfers ownership 00684 // back to the DMA subsystem. 00685 // 00686 // Transfers of ownership from DMA to CLIENT are done only by DMA. 00687 // Transfers from CLIENT to DMA are done only by CLIENT. So whoever has 00688 // ownership now is responsible for transferring ownership. 00689 // 00690 volatile bool clientOwnsStablePix; 00691 00692 // Minimum requested integration time, in microseconds 00693 uint32_t tIntMin; 00694 00695 // Timeout for generating an interrupt at the end of the integration period 00696 Timeout integrationTimeout; 00697 00698 // timing statistics 00699 Timer t; // sample timer 00700 uint32_t tInt; // start time (us) of current integration period 00701 uint32_t tXfer; // start time (us) of current pixel transfer 00702 uint32_t dtPixXfer; // pixel transfer time of last frame 00703 uint64_t totalXferTime; // total time consumed by all reads so far 00704 uint32_t nRuns; // number of runs so far 00705 00706 // debugging - min/max transfer time statistics 00707 uint32_t minXferTime; 00708 uint32_t maxXferTime; 00709 };
Generated on Wed Jul 13 2022 03:30:11 by 1.7.2