*/
#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;
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 };
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 };
//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;
void resetAdcPin( uint8_t inch )
{
-#ifdef P6PIN_AUTO_CONFIGURE
+#ifdef ADC12_P6PIN_AUTO_CONFIGURE
switch (inch)
{
case 0: call Port60.selectIOFunc(); break;
const msp430adc12_channel_config_t *config)
{
error_t result = ERESERVE;
-#ifdef CHECK_ARGS
+#ifdef ADC12_CHECK_ARGS
if (!config)
return EINVAL;
#endif
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
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
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);
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
if (call ADCArbiterInfo.userId() == id){
adc12ctl1_t ctl1 = {
adc12busy: 0,
- ctl1.conseq = 3,
+ conseq: 3,
adc12ssel: config->adc12ssel,
adc12div: config->adc12div,
issh: 0,
ctl0.sht1 = config->sht;
state = MULTIPLE_DATA_REPEAT;
- resultBuffer = buf;
+ resultBufferStart = NULL;
resultBufferLength = length;
+ resultBufferStart = buf;
resultBufferIndex = 0;
call HplAdc12.setCtl0(ctl0);
{
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;
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]()
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(){}
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:
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
*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
}
}
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](){}
}