Class similar to AnalogIn that uses burst mode to run continious background conversions so when the input is read, the last value can immediatly be returned.

Fork of FastAnalogIn by Erik -

Obsolete!

Has been already merged with Erik's original repository => take the original!

  • Added support for LPC4088.
  • Fixed linker error (missing definition of static member "channel_usage")

Files at this revision

API Documentation at this revision

Comitter:
frankvnk
Date:
Sat Mar 08 15:44:57 2014 +0000
Parent:
1:575f4d2d6e9c
Child:
3:a9b753c25073
Commit message:
Added KLxx support

Changed in this revision

FastAnalogIn.cpp Show diff for this revision Revisions of this file
FastAnalogIn.h Show annotated file Show diff for this revision Revisions of this file
FastAnalogIn_KLXX.cpp Show annotated file Show diff for this revision Revisions of this file
FastAnalogIn_LPC1768.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/FastAnalogIn.cpp	Sat May 11 08:56:22 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-#include "FastAnalogIn.h"
-static inline int div_round_up(int x, int y)
-{
-    return (x + (y - 1)) / y;
-}
-
-const PinMap FastAnalogIn::PinMap_ADC[] = {
-    {P0_23, ADC0_0, 1},
-    {P0_24, ADC0_1, 1},
-    {P0_25, ADC0_2, 1},
-    {P0_26, ADC0_3, 1},
-    {P1_30, ADC0_4, 3},
-    {P1_31, ADC0_5, 3},
-    {P0_2,  ADC0_7, 2},
-    {P0_3,  ADC0_6, 2},
-    {NC,    NC,     0}
-};
-
-int FastAnalogIn::channel_usage[] = {0};
-
-
-FastAnalogIn::FastAnalogIn(PinName pin, bool enabled)
-{
-    ADCnumber = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
-    if (ADCnumber == (uint32_t)NC)
-        error("ADC pin mapping failed");
-    datareg = (uint32_t*) (&LPC_ADC->ADDR0 + ADCnumber);
-
-    // ensure power is turned on
-    LPC_SC->PCONP |= (1 << 12);
-    // set PCLK of ADC to /1
-    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
-    LPC_SC->PCLKSEL0 |= (0x1 << 24);
-    uint32_t PCLK = SystemCoreClock;
-
-    // calculate minimum clock divider
-    //  clkdiv = divider - 1
-    uint32_t MAX_ADC_CLK = 13000000;
-    uint32_t clkdiv = div_round_up(PCLK, MAX_ADC_CLK) - 1;
-    // Set the clkdiv
-    LPC_ADC->ADCR &= ~(255<<8);
-    LPC_ADC->ADCR |= clkdiv<<8;
-
-    //Enable ADC:
-    LPC_ADC->ADCR |= 1<<21;
-
-    //Enable burstmode, set start as zero
-    LPC_ADC->ADCR |= 1<<16;
-    LPC_ADC->ADCR &= ~(7<<24);
-
-    //Map pins
-    pinmap_pinout(pin, PinMap_ADC);
-
-    //Enable channel
-    running = false;
-    enable(enabled);
-
-};
-
-FastAnalogIn::~FastAnalogIn(void)
-{
-    disable();
-}
-
-
-void FastAnalogIn::enable(bool enabled)
-{
-    //If currently not running
-    if (!running) {
-        if (enabled) {
-            //Enable the ADC channel
-            channel_usage[ADCnumber]++;
-            LPC_ADC->ADCR |= (1<<ADCnumber);
-            running = true;
-        } else
-            disable();
-    }
-};
-
-void FastAnalogIn::disable( void )
-{
-    //If currently running
-    if (running) {
-        channel_usage[ADCnumber]--;
-        
-        if (channel_usage[ADCnumber]==0)
-            LPC_ADC->ADCR &= ~(1<<ADCnumber);
-    }
-    running = false;
-};
-
-unsigned short FastAnalogIn::read_u16( void )
-{
-    volatile unsigned int retval;
-    //If object is enabled return current value of datareg
-    if (running )
-        retval = *datareg;
- 
-    //If it isn't running, enable it and wait until new value is written to datareg
-    else {
-        //Force a read to clear done bit, enable the ADC channel
-        retval = *datareg;
-        enable();
-        //Wait until it is converted
-        while(1) {
-            wait_us(1);
-            retval = *datareg;
-            if ((retval>>31) == 1)
-                break;
-        }
-        
-        //Do a second conversion since first one always fails for some reason
-        while(1) {
-            wait_us(1);
-            retval = *datareg;
-            if ((retval>>31) == 1)
-                break;
-        }
-
-        //Disable again
-        disable();
-    }
-    
-    //Do same thing as standard mbed lib, unused bit 0-3, replicate 4-7 in it
-    retval &= ~0xFFFF000F;
-    retval |= (retval >> 8) & 0x000F;
-    return retval;
-
-};
-
-float FastAnalogIn::read( void )
-{
-    unsigned short value = read_u16();
-    return (float)value/65535;
-}
--- a/FastAnalogIn.h	Sat May 11 08:56:22 2013 +0000
+++ b/FastAnalogIn.h	Sat Mar 08 15:44:57 2014 +0000
@@ -7,20 +7,60 @@
 #include "mbed.h"
 #include "pinmap.h"
 
-#ifndef TARGET_LPC1768
+#if !defined TARGET_LPC1768 && !defined TARGET_KL25Z && !defined TARGET_KL46Z && !defined TARGET_KL05Z
     #error "Target not supported"
 #endif
 
-/** A class that is similar to AnalogIn, only faster
-*
-* AnalogIn does a single conversion when you read a value (actually several conversions and it takes the median of that).
-* This library has all used ADC channels running automatically in the background, and if you read a value it will immediatly return the last converted value.
-*
-* You can use several FastAnalogIn objects per ADC pin, and several ADC pins at the same time. Using more ADC pins will decrease the conversion rate.
-* If you need to generally convert one pin very fast, but sometimes also need to do AD conversions on another pin, you can disable the ADC channel and still read its value.
-* Only now it will block until conversion is complete, so more like the regular AnalogIn library. Of course you can also disable an ADC channel and enable it later.
-*
-* It does not play nicely with regular AnalogIn objects, so use only this library or only AnalogIn. Also currently only LPC1768 is supported.
+ /** A class similar to AnalogIn, only faster, for LPC1768 and KLxx
+ *
+ * AnalogIn does a single conversion when you read a value (actually several conversions and it takes the median of that).
+ * This library runns the ADC conversion automatically in the background.
+ * When read is called, it immediatly returns the last sampled value.
+ * Using more ADC pins in continuous mode will decrease the conversion rate.
+ * If you need to sample one pin very fast and sometimes also need to do AD conversions on another pin,
+ * you can disable the continuous conversion on that ADC channel and still read its value.
+ * When continuous conversion is disabled, a read will block until the conversion is complete (much like the regular AnalogIn library does).
+ * Each ADC channel can be enabled/disabled separately.
+ *
+ * IMPORTANT NOTES
+ * ---------------
+ * - When used with KLxx processors, this library can coexist with the regular AnalogIn library.
+ * - When used with the LPC1768 processor, it does not play nicely with regular AnalogIn objects,
+ *   so either use this library or AnalogIn, not both at the same time!!
+ *
+ * Example for the KLxx processors:
+ * @code
+ * // Print messages when the AnalogIn is greater than 50%
+ *
+ * #include "mbed.h"
+ *
+ * FastAnalogIn temperature(PTC2); //Fast sampling on PTC2
+ * AnalogIn speed(PTB3);           //Normal sampling on PTB3
+ *
+ * int main() {
+ *     while(1) {
+ *         if(temperature > 0.5) {
+ *             printf("Too hot! (%f) at speed %f", temperature.read(), speed.read());
+ *         }
+ *     }
+ * }
+ * @endcode
+ * Example for the LPC1768 processor:
+ * @code
+ * // Print messages when the AnalogIn is greater than 50%
+ *
+ * #include "mbed.h"
+ *
+ * AnalogIn temperature(p20);
+ *
+ * int main() {
+ *     while(1) {
+ *         if(temperature > 0.5) {
+ *             printf("Too hot! (%f)", temperature.read());
+ *         }
+ *     }
+ * }
+ * @endcode
 */
 class FastAnalogIn {
 
@@ -32,7 +72,10 @@
      */
     FastAnalogIn( PinName pin, bool enabled = true );
     
-    ~FastAnalogIn( void );
+    ~FastAnalogIn( void )
+    {
+        disable();
+    }
     
     /** Enable the ADC channel
     *
@@ -58,7 +101,11 @@
     *
     * @param return Float with scaled converted value to 0.0-1.0
     */
-    float read( void );
+    float read( void )
+    {
+        unsigned short value = read_u16();
+        return (float)value/65535;
+    }
     
     /** An operator shorthand for read()
     */
@@ -68,16 +115,10 @@
 
     
 private:
-    static const PinMap PinMap_ADC[9];
     static int channel_usage[8];
-    
     bool running;    
     char ADCnumber;
     uint32_t *datareg;
-    
-    
-
-
 };
 
-#endif
\ No newline at end of file
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastAnalogIn_KLXX.cpp	Sat Mar 08 15:44:57 2014 +0000
@@ -0,0 +1,106 @@
+#ifdef TARGET_KLXX
+
+#include "FastAnalogIn.h"
+#include "clk_freqs.h"
+
+#define MAX_FADC            6000000
+#define CHANNELS_A_SHIFT    5
+
+/*typedef struct analogin_s fanalogin_t;
+
+void     fanalogin_init    (fanalogin_t *obj, PinName pin);
+float    fanalogin_read    (fanalogin_t *obj);
+uint16_t fanalogin_read_u16(fanalogin_t *obj);
+
+fanalogin_t _adc;*/
+
+FastAnalogIn::FastAnalogIn(PinName pin, bool enabled)
+{
+    ADCnumber = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
+    if (ADCnumber == (ADCName)NC) {
+        error("ADC pin mapping failed");
+    }
+
+    SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK;
+
+    uint32_t port = (uint32_t)pin >> PORT_SHIFT;
+    SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
+
+    uint32_t cfg2_muxsel = ADC_CFG2_MUXSEL_MASK;
+    if (ADCnumber & (1 << CHANNELS_A_SHIFT)) {
+        cfg2_muxsel = 0;
+    }
+    
+    // bus clk
+    uint32_t PCLK = bus_frequency();
+    uint32_t clkdiv;
+    for (clkdiv = 0; clkdiv < 4; clkdiv++) {
+        if ((PCLK >> clkdiv) <= MAX_FADC)
+            break;
+    }
+    if (clkdiv == 4)                    //Set max div
+        clkdiv = 0x7;
+
+    ADC0->SC1[1] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));
+
+    ADC0->CFG1 = ADC_CFG1_ADIV(clkdiv & 0x3)    // Clock Divide Select: (Input Clock)/8
+               | ADC_CFG1_MODE(3)               // (16)bits Resolution
+               | ADC_CFG1_ADICLK(clkdiv >> 2);  // Input Clock: (Bus Clock)/2
+
+    ADC0->CFG2 = cfg2_muxsel            // ADxxb or ADxxa channels
+               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
+               | ADC_CFG2_ADHSC_MASK;   // High-Speed Configuration
+
+    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference
+
+    pinmap_pinout(pin, PinMap_ADC);
+
+    //Enable channel
+    running = false;
+    enable(enabled);
+}
+
+void FastAnalogIn::enable(bool enabled)
+{
+    //If currently not running
+    if (!running) {
+        if (enabled) {
+            //Enable the ADC channel
+            ADC0->SC3 |= ADC_SC3_ADCO_MASK;       // Enable continuous conversion
+            ADC0->SC1[0] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));  //Start conversion
+            running = true;
+        } else
+            disable();
+    }
+}
+ 
+void FastAnalogIn::disable( void )
+{
+    //If currently running
+    if (running) {
+        ADC0->SC3 &= ~ADC_SC3_ADCO_MASK;      // Disable continuous conversion
+    }
+    running = false;
+}
+
+uint16_t FastAnalogIn::read_u16()
+{
+    if (!running)
+    {
+        // start conversion
+        ADC0->SC1[0] = ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT));
+        // Wait Conversion Complete
+        while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);
+    }
+    if(running && ((ADC0->SC1[0]&ADC_SC1_ADCH_MASK) != (ADC_SC1_ADCH(ADCnumber & ~(1 << CHANNELS_A_SHIFT)))))
+    {
+        running = false;
+        enable();
+        while ((ADC0->SC1[0] & ADC_SC1_COCO_MASK) != ADC_SC1_COCO_MASK);
+    }
+    // Return value
+    return (uint16_t)ADC0->R[0];
+}
+
+#endif //defined TARGET_KLXX
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastAnalogIn_LPC1768.cpp	Sat Mar 08 15:44:57 2014 +0000
@@ -0,0 +1,123 @@
+#ifdef TARGET_LPC1768
+
+#include "FastAnalogIn.h"
+static inline int div_round_up(int x, int y)
+{
+    return (x + (y - 1)) / y;
+}
+
+static const PinMap PinMap_ADC[] = {
+    P0_23, ADC0_0, 1,
+    P0_24, ADC0_1, 1,
+    P0_25, ADC0_2, 1,
+    P0_26, ADC0_3, 1,
+    P1_30, ADC0_4, 3,
+    P1_31, ADC0_5, 3,
+    P0_2,  ADC0_7, 2,
+    P0_3,  ADC0_6, 2,
+    NC,    NC,     0
+};
+
+FastAnalogIn::FastAnalogIn(PinName pin, bool enabled)
+{
+    ADCnumber = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
+    if (ADCnumber == (uint32_t)NC)
+        error("ADC pin mapping failed");
+    datareg = (uint32_t*) (&LPC_ADC->ADDR0 + ADCnumber);
+
+    // ensure power is turned on
+    LPC_SC->PCONP |= (1 << 12);
+    // set PCLK of ADC to /1
+    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
+    LPC_SC->PCLKSEL0 |= (0x1 << 24);
+    uint32_t PCLK = SystemCoreClock;
+
+    // calculate minimum clock divider
+    //  clkdiv = divider - 1
+    uint32_t MAX_ADC_CLK = 13000000;
+    uint32_t clkdiv = div_round_up(PCLK, MAX_ADC_CLK) - 1;
+    // Set the clkdiv
+    LPC_ADC->ADCR &= ~(255<<8);
+    LPC_ADC->ADCR |= clkdiv<<8;
+
+    //Enable ADC:
+    LPC_ADC->ADCR |= 1<<21;
+
+    //Enable burstmode, set start as zero
+    LPC_ADC->ADCR |= 1<<16;
+    LPC_ADC->ADCR &= ~(7<<24);
+
+    //Map pins
+    pinmap_pinout(pin, PinMap_ADC);
+
+    //Enable channel
+    running = false;
+    enable(enabled);
+
+}
+
+void FastAnalogIn::enable(bool enabled)
+{
+    //If currently not running
+    if (!running) {
+        if (enabled) {
+            //Enable the ADC channel
+            channel_usage[ADCnumber]++;
+            LPC_ADC->ADCR |= (1<<ADCnumber);
+            running = true;
+        } else
+            disable();
+    }
+}
+
+void FastAnalogIn::disable( void )
+{
+    //If currently running
+    if (running) {
+        channel_usage[ADCnumber]--;
+        
+        if (channel_usage[ADCnumber]==0)
+            LPC_ADC->ADCR &= ~(1<<ADCnumber);
+    }
+    running = false;
+}
+
+unsigned short FastAnalogIn::read_u16( void )
+{
+    volatile unsigned int retval;
+    //If object is enabled return current value of datareg
+    if (running )
+        retval = *datareg;
+ 
+    //If it isn't running, enable it and wait until new value is written to datareg
+    else {
+        //Force a read to clear done bit, enable the ADC channel
+        retval = *datareg;
+        enable();
+        //Wait until it is converted
+        while(1) {
+            wait_us(1);
+            retval = *datareg;
+            if ((retval>>31) == 1)
+                break;
+        }
+        
+        //Do a second conversion since first one always fails for some reason
+        while(1) {
+            wait_us(1);
+            retval = *datareg;
+            if ((retval>>31) == 1)
+                break;
+        }
+
+        //Disable again
+        disable();
+    }
+    
+    //Do same thing as standard mbed lib, unused bit 0-3, replicate 4-7 in it
+    retval &= ~0xFFFF000F;
+    retval |= (retval >> 8) & 0x000F;
+    return retval;
+
+}
+#endif //defined TARGET_LPC1768