]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/msp430/adc12/Msp430Adc12ImplP.nc
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / tos / chips / msp430 / adc12 / Msp430Adc12ImplP.nc
index 4b5c3ff8ccae1fae06053f497ee40225b528755b..e9e7f68e869dd8f07bee73dbd5bb08d86d407252 100644 (file)
  */
 
 #include <Msp430Adc12.h>
-module Msp430Adc12ImplP 
+module Msp430Adc12ImplP @safe()
 {
   provides {
     interface Init;
     interface Msp430Adc12SingleChannel as SingleChannel[uint8_t id];
+    interface Msp430Adc12MultiChannel as MultiChannel[uint8_t id];
+    interface Msp430Adc12Overflow as Overflow[uint8_t id];
     interface AsyncStdControl as DMAExtension[uint8_t id];
-       }
-       uses {
+  }
+  uses {
     interface ArbiterInfo as ADCArbiterInfo;
-         interface HplAdc12;
+    interface HplAdc12;
     interface Msp430Timer as TimerA;;
     interface Msp430TimerControl as ControlA0;
     interface Msp430TimerControl as ControlA1;
@@ -57,36 +59,50 @@ module Msp430Adc12ImplP
     interface HplMsp430GeneralIO as Port65;
     interface HplMsp430GeneralIO as Port66;
     interface HplMsp430GeneralIO as Port67;
-       }
+  }
 }
 implementation
 { 
+
+#ifdef ADC12_TIMERA_ENABLED
+  #warning Accessing TimerA for ADC12 
+#endif
+
   enum {
     SINGLE_DATA = 1,
     SINGLE_DATA_REPEAT = 2,
     MULTIPLE_DATA = 4,
     MULTIPLE_DATA_REPEAT = 8,
-    CONVERSION_MODE_MASK = 0x0F,
+    MULTI_CHANNEL = 16,
+    CONVERSION_MODE_MASK = 0x1F,
 
-    ADC_BUSY = 16,                /* request pending */
-    USE_TIMERA = 32,              /* TimerA used for SAMPCON signal */
+    ADC_BUSY = 32,                /* request pending */
+    USE_TIMERA = 64,              /* TimerA used for SAMPCON signal */
+    ADC_OVERFLOW = 128,
   };
 
   uint8_t state;                  /* see enum above */
   
-  uint16_t *resultBuffer;  /* conversion results */
   uint16_t resultBufferLength;    /* length of buffer */
+  uint16_t *COUNT_NOK(resultBufferLength) resultBufferStart;
   uint16_t resultBufferIndex;     /* offset into buffer */
+  uint8_t numChannels;            /* number of channels (multi-channel conversion) */
   uint8_t clientID;               /* ID of client that called getData() */
 
   command error_t Init.init()
   {
+    adc12ctl0_t ctl0;
     call HplAdc12.stopConversion();
+    ctl0 = call HplAdc12.getCtl0();
+    ctl0.adc12tovie = 1;
+    ctl0.adc12ovie = 1;
+    call HplAdc12.setCtl0(ctl0);
     return SUCCESS;
   }
 
   void prepareTimerA(uint16_t interval, uint16_t csSAMPCON, uint16_t cdSAMPCON)
   {
+#ifdef ADC12_TIMERA_ENABLED
     msp430_compare_control_t ccResetSHI = {
       ccifg : 0, cov : 0, out : 0, cci : 0, ccie : 0,
       outmod : 0, cap : 0, clld : 0, scs : 0, ccis : 0, cm : 0 };
@@ -99,10 +115,12 @@ implementation
     call ControlA0.setControl(ccResetSHI);
     call CompareA0.setEvent(interval-1);
     call CompareA1.setEvent((interval-1)/2);
+#endif
   }
     
   void startTimerA()
   {
+#ifdef ADC12_TIMERA_ENABLED
     msp430_compare_control_t ccSetSHI = {
       ccifg : 0, cov : 0, out : 1, cci : 0, ccie : 0,
       outmod : 0, cap : 0, clld : 0, scs : 0, ccis : 0, cm : 0 };
@@ -118,11 +136,12 @@ implementation
     //call ControlA1.setControl(ccResetSHI); 
     call ControlA1.setControl(ccRSOutmod);
     call TimerA.setMode(MSP430TIMER_UP_MODE); // go!
+#endif
   }   
   
   void configureAdcPin( uint8_t inch )
   {
-#ifdef P6PIN_AUTO_CONFIGURE
+#ifdef ADC12_P6PIN_AUTO_CONFIGURE
     switch (inch)
     {
       case 0: call Port60.selectModuleFunc(); call Port60.makeInput(); break;
@@ -139,7 +158,7 @@ implementation
   
   void resetAdcPin( uint8_t inch )
   {
-#ifdef P6PIN_AUTO_CONFIGURE
+#ifdef ADC12_P6PIN_AUTO_CONFIGURE
     switch (inch)
     {
       case 0: call Port60.selectIOFunc(); break;
@@ -158,7 +177,7 @@ implementation
       const msp430adc12_channel_config_t *config)
   {
     error_t result = ERESERVE;
-#ifdef CHECK_ARGS
+#ifdef ADC12_CHECK_ARGS
     if (!config)
       return EINVAL;
 #endif
@@ -202,7 +221,11 @@ implementation
       uint16_t jiffies)
   {
     error_t result = ERESERVE;
-#ifdef CHECK_ARGS
+#ifdef ADC12_CHECK_ARGS
+#ifndef ADC12_TIMERA_ENABLED
+    if (jiffies>0) 
+      return EINVAL;
+#endif
     if (!config || jiffies == 1 || jiffies == 2)
       return EINVAL;
 #endif
@@ -250,7 +273,11 @@ implementation
       uint16_t *buf, uint16_t length, uint16_t jiffies)
   {
     error_t result = ERESERVE;
-#ifdef CHECK_ARGS
+#ifdef ADC12_CHECK_ARGS
+#ifndef ADC12_TIMERA_ENABLED
+    if (jiffies>0) 
+      return EINVAL;
+#endif
     if (!config || !buf || !length || jiffies == 1 || jiffies == 2)
       return EINVAL;
 #endif
@@ -280,8 +307,9 @@ implementation
         ctl0.sht1 = config->sht;
 
         state = MULTIPLE_DATA;
-        resultBuffer = buf;
+       resultBufferStart = NULL;
         resultBufferLength = length;
+        resultBufferStart = buf;
         resultBufferIndex = 0;
         call HplAdc12.setCtl0(ctl0);
         call HplAdc12.setCtl1(ctl1);
@@ -306,7 +334,11 @@ implementation
       uint16_t *buf, uint8_t length, uint16_t jiffies)
   {
     error_t result = ERESERVE;
-#ifdef CHECK_ARGS
+#ifdef ADC12_CHECK_ARGS
+#ifndef ADC12_TIMERA_ENABLED
+    if (jiffies>0) 
+      return EINVAL;
+#endif
     if (!config || !buf || !length || length > 16 || jiffies == 1 || jiffies == 2)
       return EINVAL;
 #endif
@@ -316,7 +348,7 @@ implementation
       if (call ADCArbiterInfo.userId() == id){
         adc12ctl1_t ctl1 = {
           adc12busy: 0,
-          ctl1.conseq = 3,
+          conseq: 3,
           adc12ssel: config->adc12ssel,
           adc12div: config->adc12div,
           issh: 0,
@@ -336,8 +368,9 @@ implementation
         ctl0.sht1 = config->sht;
 
         state = MULTIPLE_DATA_REPEAT;
-        resultBuffer = buf;
+       resultBufferStart = NULL;
         resultBufferLength = length;
+        resultBufferStart = buf;
         resultBufferIndex = 0;            
         
         call HplAdc12.setCtl0(ctl0);
@@ -362,7 +395,7 @@ implementation
   {
     atomic {
       if (call ADCArbiterInfo.userId() == id){
-        if (state & MULTIPLE_DATA_REPEAT && !resultBuffer)
+        if ((state & MULTIPLE_DATA_REPEAT) && !resultBufferStart)
           return EINVAL;
         if (state & ADC_BUSY)
           return EBUSY;
@@ -378,15 +411,112 @@ implementation
     return FAIL;
   }
 
+  async command error_t MultiChannel.configure[uint8_t id](
+      const msp430adc12_channel_config_t *config,
+      adc12memctl_t *memctl, uint8_t numMemctl, uint16_t *buf, 
+      uint16_t numSamples, uint16_t jiffies)
+  {
+    error_t result = ERESERVE;
+#ifdef ADC12_CHECK_ARGS
+#ifndef ADC12_TIMERA_ENABLED
+    if (jiffies>0) 
+      return EINVAL;
+#endif
+    if (!config || !memctl || !numMemctl || numMemctl > 15 || !numSamples || 
+        !buf || jiffies == 1 || jiffies == 2 || numSamples % (numMemctl+1) != 0)
+      return EINVAL;
+#endif
+    atomic {
+      if (state & ADC_BUSY)
+        return EBUSY;
+      if (call ADCArbiterInfo.userId() == id){
+        adc12ctl1_t ctl1 = {
+          adc12busy: 0,
+          conseq: (numSamples > numMemctl+1) ? 3 : 1, 
+          adc12ssel: config->adc12ssel,
+          adc12div: config->adc12div,
+          issh: 0,
+          shp: 1,
+          shs: (jiffies == 0) ? 0 : 1,
+          cstartadd: 0
+        };
+        adc12memctl_t firstMemctl = {
+          inch: config->inch,
+          sref: config->sref,
+          eos: 0
+        };     
+        uint16_t i, mask = 1;
+        adc12ctl0_t ctl0 = call HplAdc12.getCtl0();
+        ctl0.msc = (jiffies == 0) ? 1 : 0;
+        ctl0.sht0 = config->sht;
+        ctl0.sht1 = config->sht;
+
+        state = MULTI_CHANNEL;
+       resultBufferStart = NULL;
+        resultBufferLength = numSamples;
+        resultBufferStart = buf;
+        resultBufferIndex = 0;
+        numChannels = numMemctl+1;
+        call HplAdc12.setCtl0(ctl0);
+        call HplAdc12.setCtl1(ctl1);
+        call HplAdc12.setMCtl(0, firstMemctl);
+        for (i=0; i<(numMemctl-1) && i < 14; i++){
+          memctl[i].eos = 0;
+          call HplAdc12.setMCtl(i+1, memctl[i]);
+        }
+        memctl[i].eos = 1;
+        call HplAdc12.setMCtl(i+1, memctl[i]);
+        call HplAdc12.setIEFlags(mask << (i+1));        
+        
+        if (jiffies){
+          state |= USE_TIMERA;
+          prepareTimerA(jiffies, config->sampcon_ssel, config->sampcon_id);
+        }
+        result = SUCCESS;
+      }      
+    }
+    return result;
+  }
+
+  async command error_t MultiChannel.getData[uint8_t id]()
+  {
+    uint8_t i;
+    atomic {
+      if (call ADCArbiterInfo.userId() == id){
+        if (!resultBufferStart)
+          return EINVAL;
+        if (state & ADC_BUSY)
+          return EBUSY;
+        state |= ADC_BUSY;
+        clientID = id;
+        for (i=0; i<numChannels; i++)
+          configureAdcPin((call HplAdc12.getMCtl(i)).inch);
+        call HplAdc12.startConversion();
+        if (state & USE_TIMERA)
+          startTimerA(); 
+        return SUCCESS;
+      }
+    }
+    return FAIL;
+  }
+  
   void stopConversion()
   {
-    adc12memctl_t memctl = call HplAdc12.getMCtl(0);
+    uint8_t i;
+#ifdef ADC12_TIMERA_ENABLED
     if (state & USE_TIMERA)
       call TimerA.setMode(MSP430TIMER_STOP_MODE);
-    resetAdcPin( memctl.inch );
-    call HplAdc12.stopConversion();
-    call HplAdc12.resetIFGs(); 
-    state &= ~ADC_BUSY;
+#endif
+    resetAdcPin( (call HplAdc12.getMCtl(0)).inch );
+    if (state & MULTI_CHANNEL){
+      for (i=1; i<numChannels; i++)
+        resetAdcPin( (call HplAdc12.getMCtl(i)).inch );
+    }
+    atomic {
+      call HplAdc12.stopConversion();
+      call HplAdc12.resetIFGs(); 
+      state &= ~ADC_BUSY;
+    }
   }
 
   async command error_t DMAExtension.start[uint8_t id]()
@@ -403,13 +533,8 @@ implementation
   
   async command error_t DMAExtension.stop[uint8_t id]()
   {
-    atomic {
-      if (call ADCArbiterInfo.userId() == id){
-        stopConversion();
-        return SUCCESS;
-      }
-    }
-    return FAIL;
+    stopConversion();
+    return SUCCESS;
   }
   
   async event void TimerA.overflow(){}
@@ -418,6 +543,18 @@ implementation
 
   async event void HplAdc12.conversionDone(uint16_t iv)
   {
+    bool overflow = FALSE;
+    uint16_t *resultBuffer;
+
+    if (iv <= 4){ // check for overflow
+      if (iv == 2)
+        signal Overflow.memOverflow[clientID]();
+      else
+        signal Overflow.conversionTimeOverflow[clientID]();
+      // only if the client didn't ask for data as fast as possible (jiffies was not zero)
+      if (!(call HplAdc12.getCtl0()).msc)
+        overflow = TRUE;
+    }
     switch (state & CONVERSION_MODE_MASK) 
     { 
       case SINGLE_DATA:
@@ -429,13 +566,33 @@ implementation
           error_t repeatContinue;
           repeatContinue = signal SingleChannel.singleDataReady[clientID](
                 call HplAdc12.getMem(0));
-          if (repeatContinue == FAIL)
+          if (repeatContinue != SUCCESS)
             stopConversion();
           break;
         }
+#ifndef ADC12_ONLY_WITH_DMA
+      case MULTI_CHANNEL:
+        {
+          uint16_t i = 0, k;
+          resultBuffer = resultBufferStart + resultBufferIndex;
+          do {
+            *resultBuffer++ = call HplAdc12.getMem(i);
+          } while (++i < numChannels);
+          resultBufferIndex += numChannels;
+          if (overflow || resultBufferLength == resultBufferIndex){
+            stopConversion();
+            resultBuffer -= resultBufferIndex;
+            k = resultBufferIndex - numChannels;
+            resultBufferIndex = 0;
+            signal MultiChannel.dataReady[clientID](resultBuffer, 
+                overflow ? k : resultBufferLength);
+          }
+        }
+        break;
       case MULTIPLE_DATA:
         {
-          uint16_t i = 0, length;
+          uint16_t i = 0, length, k;
+          resultBuffer = resultBufferStart + resultBufferIndex;
           if (resultBufferLength - resultBufferIndex > 16) 
             length = 16;
           else
@@ -444,35 +601,39 @@ implementation
             *resultBuffer++ = call HplAdc12.getMem(i);
           } while (++i < length);
           resultBufferIndex += length;
-              
-          if (resultBufferLength - resultBufferIndex > 15)
+          if (overflow || resultBufferLength == resultBufferIndex){
+            stopConversion();
+            resultBuffer -= resultBufferIndex;
+            k = resultBufferIndex - length;
+            resultBufferIndex = 0;
+            signal SingleChannel.multipleDataReady[clientID](resultBuffer,
+               overflow ? k : resultBufferLength);
+          } else if (resultBufferLength - resultBufferIndex > 15)
             return;
-          else if (resultBufferLength - resultBufferIndex > 0){
+          else {
+            // last sequence < 16 samples
             adc12memctl_t memctl = call HplAdc12.getMCtl(0);
             memctl.eos = 1;
             call HplAdc12.setMCtl(resultBufferLength - resultBufferIndex, memctl);
-          } else {
-            stopConversion();
-            resultBuffer -= resultBufferLength;
-            resultBufferIndex = 0;
-            signal SingleChannel.multipleDataReady[clientID](resultBuffer, resultBufferLength);
           }
         }
         break;
       case MULTIPLE_DATA_REPEAT:
         {
           uint8_t i = 0;
+          resultBuffer = resultBufferStart;
           do {
             *resultBuffer++ = call HplAdc12.getMem(i);
           } while (++i < resultBufferLength);
           
-          resultBuffer = signal SingleChannel.multipleDataReady[clientID](
+          resultBufferStart = signal SingleChannel.multipleDataReady[clientID](
               resultBuffer-resultBufferLength,
-                    resultBufferLength);
-          if (!resultBuffer)  
+              overflow ? 0 : resultBufferLength);
+          if (!resultBufferStart)  
             stopConversion();
           break;
         }
+#endif
       } // switch
   }
 
@@ -482,13 +643,15 @@ implementation
   }
    
   default async event uint16_t* SingleChannel.multipleDataReady[uint8_t id](
-      uint16_t *buf, uint16_t length)
+      uint16_t *buf, uint16_t numSamples)
   {
     return 0;
   }
+   
+  default async event void MultiChannel.dataReady[uint8_t id](uint16_t *buffer, uint16_t numSamples) {};
   
-  async event void HplAdc12.memOverflow(){}
-  async event void HplAdc12.conversionTimeOverflow(){}
+  default async event void Overflow.memOverflow[uint8_t id](){}
+  default async event void Overflow.conversionTimeOverflow[uint8_t id](){}
 
 }