Mike R / Mbed 2 deprecated Pinscape_Controller_V2

Dependencies:   mbed FastIO FastPWM USBDevice

Fork of Pinscape_Controller by Mike R

Revision:
35:e959ffba78fd
Parent:
25:e22b88bd783a
Child:
40:cc0d9814522b
--- a/TSL1410R/tsl1410r.h	Thu Dec 03 07:34:57 2015 +0000
+++ b/TSL1410R/tsl1410r.h	Sat Dec 19 06:37:19 2015 +0000
@@ -4,25 +4,51 @@
  *  This provides a high-level interface for the Taos TSL1410R linear CCD array sensor.
  */
  
- #include "mbed.h"
- #include "config.h"
- #include "FastIO.h"
- #include "FastAnalogIn.h"
+#include "mbed.h"
+#include "config.h"
+#include "FastAnalogIn.h"
  
- #ifndef TSL1410R_H
- #define TSL1410R_H
+#ifndef TSL1410R_H
+#define TSL1410R_H
+
+// For faster GPIO on the clock pin, we write the IOPORT registers directly.
+// PORT_BASE gives us the memory mapped location of the IOPORT register set
+// for a pin; PINMASK gives us the bit pattern to write to the registers.
+//
+// - To turn a pin ON:  PORT_BASE(pin)->PSOR |= PINMASK(pin)
+// - To turn a pin OFF: PORT_BASE(pin)->PCOR |= PINMASK(pin)
+// - To toggle a pin:   PORT_BASE(pin)->PTOR |= PINMASK(pin)
+//
+// When used in a loop where the port address and pin mask are cached in
+// local variables, this runs at the same speed as the FastIO library - about 
+// 78ns per pin write on the KL25Z.  Not surprising since it's doing the same
+// thing, and the compiler should be able to reduce a pin write to a single ARM
+// instruction when the port address and mask are in local register variables.
+// The advantage over the FastIO library is that this approach allows for pins
+// to be assigned dynamically at run-time, which we prefer because it allows for
+// configuration changes to be made on the fly rather than having to recompile
+// the program.
+#define GPIO_PORT_BASE(pin)   ((FGPIO_Type *)(FPTA_BASE + ((unsigned int)pin >> PORT_SHIFT) * 0x40))
+#define GPIO_PINMASK(pin)     (1 << ((pin & 0x7F) >> 2))
  
-template <PinName siPin, PinName clockPin> class TSL1410R
+class TSL1410R
 {
 public:
-    // set up the analog in port for reading the currently selected 
-    // pixel value
-    TSL1410R(PinName aoPin) : ao(aoPin)
+    TSL1410R(int nPix, PinName siPin, PinName clockPin, PinName ao1Pin, PinName ao2Pin) 
+        : nPix(nPix), si(siPin), clock(clockPin), ao1(ao1Pin), ao2(ao2Pin)
     {
+        // we're in parallel mode if ao2 is a valid pin
+        parallel = (ao2Pin != NC);
+        
+        // remember the clock pin port base and pin mask for fast access
+        clockPort = GPIO_PORT_BASE(clockPin);
+        clockMask = GPIO_PINMASK(clockPin);
+        
         // disable continuous conversion mode in FastAnalogIn - since we're
         // reading discrete pixel values, we want to control when the samples
         // are taken rather than continuously averaging over time
-        ao.disable();
+        ao1.disable();
+        if (parallel) ao2.disable();
 
         // clear out power-on noise by clocking through all pixels twice
         clear();
@@ -66,38 +92,84 @@
     // the current pixels and start a fresh integration cycle.
     void read(uint16_t *pix, int n)
     {
+        // get the clock pin pointers into local variables for fast access
+        register FGPIO_Type *clockPort = this->clockPort;
+        register uint32_t clockMask = this->clockMask;
+        
         // start the next integration cycle by pulsing SI and one clock
         si = 1;
-        clock = 1;
+        clockPort->PSOR |= clockMask;       // turn the clock pin on (clock = 1)
         si = 0;
-        clock = 0;
+        clockPort->PCOR |= clockMask;       // turn the clock pin off (clock = 0)
         
         // figure how many pixels to skip on each read
         int skip = nPix/n - 1;
         
         // read all of the pixels
-        for (int src = 0, dst = 0 ; src < nPix ; ++src)
+        if (parallel)
         {
-            // clock in and read the next pixel
-            clock = 1;
-            ao.enable();
-            wait_us(1);
-            clock = 0;
-            wait_us(11);
-            pix[dst++] = ao.read_u16();
-            ao.disable();
-            
-            // clock skipped pixels
-            for (int i = 0 ; i < skip ; ++i, ++src) 
+            // parallel mode - read pixels from each half sensor concurrently
+            int nPixHalf = nPix/2;
+            for (int src = 0, dst = 0 ; src < nPixHalf ; ++src)
             {
-                clock = 1;
-                clock = 0;
+                // pulse the clock and start the ADC sampling
+                clockPort->PSOR |= clockMask;
+                ao1.enable();
+                ao2.enable();
+                wait_us(1);
+                clockPort->PCOR |= clockMask;
+                
+                // wait for the ADCs to stabilize
+                wait_us(11);
+                
+                // read the pixels
+                pix[dst] = ao1.read_u16();
+                pix[dst+n/2] = ao2.read_u16();
+                
+                // turn off the ADC until the next pixel is ready
+                ao1.disable();
+                ao2.disable();
+                
+                // clock skipped pixels
+                for (int i = 0 ; i < skip ; ++i, ++src) 
+                {
+                    clockPort->PSOR |= clockMask;
+                    clockPort->PCOR |= clockMask;
+                }
+            }
+        }
+        else
+        {
+            // serial mode - read all pixels in a single file
+            for (int src = 0, dst = 0 ; src < nPix ; ++src)
+            {
+                // pulse the clock and start the ADC sampling
+                clockPort->PSOR |= clockMask;
+                ao1.enable();
+                wait_us(1);
+                clockPort->PCOR |= clockMask;
+                
+                // wait for the ADC sample to stabilize
+                wait_us(11);
+                
+                // read the ADC sample
+                pix[dst++] = ao1.read_u16();
+                
+                // turn off the ADC until the next pixel is ready
+                ao1.disable();
+                
+                // clock skipped pixels
+                for (int i = 0 ; i < skip ; ++i, ++src) 
+                {
+                    clockPort->PSOR |= clockMask;
+                    clockPort->PCOR |= clockMask;
+                }
             }
         }
         
         // clock out one extra pixel to leave A1 in the high-Z state
-        clock = 1;
-        clock = 0;
+        clockPort->PSOR |= clockMask;
+        clockPort->PCOR |= clockMask;
     }
 
     // Clock through all pixels to clear the array.  Pulses SI at the
@@ -106,27 +178,32 @@
     // integrated while the clear() was taking place.
     void clear()
     {
+        // get the clock pin pointers into local variables for fast access
+        register FGPIO_Type *clockPort = this->clockPort;
+        register uint32_t clockMask = this->clockMask;
+
         // clock in an SI pulse
         si = 1;
-        clock = 1;
-        clock = 0;
+        clockPort->PSOR |= clockMask;
         si = 0;
+        clockPort->PCOR |= clockMask;
         
         // clock out all pixels
         for (int i = 0 ; i < nPix + 1 ; ++i) {
-            clock = 1;
-            clock = 0;
+            clockPort->PSOR |= clockMask;
+            clockPort->PCOR |= clockMask;
         }
     }
 
-    // number of pixels in the array
-    static const int nPix = CCD_NPIXELS;
-    
-    
 private:
-    FastOut<siPin> si;
-    FastOut<clockPin> clock;
-    FastAnalogIn ao;
+    int nPix;                 // number of pixels in physical sensor array
+    DigitalOut si;
+    DigitalOut clock;
+    FGPIO_Type *clockPort;    // IOPORT base address for clock pin, for fast writes
+    uint32_t clockMask;       // IOPORT register bit mask for clock pin
+    FastAnalogIn ao1; 
+    FastAnalogIn ao2;         // valid iff running in parallel mode
+    bool parallel;            // true -> running in parallel mode
 };
  
 #endif /* TSL1410R_H */