#define BUFFER_SIZE 100
const msp430adc12_channel_config_t config = {inch, sref, ref2_5v, adc12ssel, adc12div, sht, sampcon_ssel, sampcon_id};
adc12memctl_t memCtl = {inch2, sref2};
- uint8_t state;
+ norace uint8_t state;
uint16_t buffer[BUFFER_SIZE];
void task getData();
bool assertData(uint16_t *data, uint16_t num)
{
uint16_t i;
+ if (num != BUFFER_SIZE)
+ post signalFailure();
for (i=0; i<num; i++)
if (!data[i] || data[i] >= 0xFFF){
post signalFailure();
async event void MultiChannel.dataReady(uint16_t *buf, uint16_t numSamples)
{
- if (assertData(buf, numSamples))
+ if (assertData(buf, numSamples) && state++ == 0)
post signalSuccess();
+ else
+ post signalFailure();
call Resource.release();
}
#define BUFFER_SIZE 100
const msp430adc12_channel_config_t config = {inch, sref, ref2_5v, adc12ssel, adc12div, sht, sampcon_ssel, sampcon_id};
uint8_t state;
+ norace uint8_t numDone;
uint16_t buffer[BUFFER_SIZE];
void task getData();
call SingleChannel.getData();
break;
default: call Resource.release();
- signal Notify.notify(TRUE);
+ if (numDone == state)
+ signal Notify.notify(TRUE);
break;
}
}
async event error_t SingleChannel.singleDataReady(uint16_t data)
{
+ numDone++;
assertData(&data, 1);
call Resource.release();
post getData();
async event uint16_t* SingleChannel.multipleDataReady(uint16_t *buf, uint16_t length)
{
+ numDone++;
assertData(buf, length);
call Resource.release();
post getData();
interface Read<uint16_t> as Read[uint8_t client];
interface ReadNow<uint16_t> as ReadNow[uint8_t client];
interface Resource as ResourceReadNow[uint8_t client];
- interface ReadStream<uint16_t> as ReadStream[uint8_t streamClient];
}
uses {
// for Read only:
// for Read and ReadNow:
interface AdcConfigure<const msp430adc12_channel_config_t*> as Config[uint8_t client];
interface Msp430Adc12SingleChannel as SingleChannel[uint8_t client];
- // for ReadStream only:
- interface AdcConfigure<const msp430adc12_channel_config_t*> as ConfigReadStream[uint8_t streamClient];
- interface Msp430Adc12SingleChannel as SingleChannelReadStream[uint8_t streamClient];
- interface Resource as ResourceReadStream[uint8_t streamClient];
-
}
}
implementation
STATE_READ,
STATE_READNOW,
STATE_READNOW_INVALID_CONFIG,
- STATE_READSTREAM,
- };
-
- struct stream_entry_t {
- uint16_t count;
- struct stream_entry_t *next;
};
// Resource interface / arbiter makes norace declaration safe
norace uint8_t state;
norace uint8_t owner;
norace uint16_t value;
- norace uint16_t *resultBuf;
-
- // atomic section in postBuffer() makes norace safe
- norace struct stream_entry_t *streamBuf[uniqueCount(ADCC_READ_STREAM_SERVICE)];
- norace uint32_t usPeriod[uniqueCount(ADCC_READ_STREAM_SERVICE)];
- msp430adc12_channel_config_t streamConfig;
-
- void task finishStreamRequest();
- void task signalBufferDone();
- void nextReadStreamRequest(uint8_t streamClient);
error_t configure(uint8_t client)
{
command error_t Read.read[uint8_t client]()
{
- if (call ResourceRead.isOwner[client]())
- return EBUSY;
return call ResourceRead.request[client]();
}
if (result == SUCCESS){
state = STATE_READ;
result = call SingleChannel.getData[client]();
- }
- if (result != SUCCESS){
+ } else {
call ResourceRead.release[client]();
signal Read.readDone[client](result, 0);
}
// error !
return 0;
}
-
- command error_t ReadStream.postBuffer[uint8_t streamClient]( uint16_t* buf, uint16_t count )
- {
- struct stream_entry_t *newEntry = (struct stream_entry_t *) buf;
-
- newEntry->count = count;
- newEntry->next = 0;
- atomic {
- if (!streamBuf[streamClient])
- streamBuf[streamClient] = newEntry;
- else {
- struct stream_entry_t *tmp = streamBuf[streamClient];
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = newEntry;
- }
- }
- return SUCCESS;
- }
-
- command error_t ReadStream.read[uint8_t streamClient]( uint32_t _usPeriod )
- {
- if (!streamBuf[streamClient])
- return EINVAL;
- if (call ResourceReadStream.isOwner[streamClient]())
- return EBUSY;
- usPeriod[streamClient] = _usPeriod;
- return call ResourceReadStream.request[streamClient]();
- }
-
- void task finishStreamRequest()
- {
- call ResourceReadStream.release[owner]();
- if (!streamBuf[owner])
- // all posted buffers were filled
- signal ReadStream.readDone[owner]( SUCCESS, usPeriod[owner] );
- else {
- // the commented code below makes gcc throw
- // "internal error: unsupported relocation error" !?!
- /*
- do {
- signal ReadStream.bufferDone[owner]( FAIL, (uint16_t *) streamBuf[owner], 0);
- streamBuf[owner] = streamBuf[owner]->next;
- } while (streamBuf[owner]);
- */
- signal ReadStream.readDone[owner]( FAIL, 0 );
- }
- }
-
- event void ResourceReadStream.granted[uint8_t streamClient]()
- {
- error_t result;
- const msp430adc12_channel_config_t *config;
- struct stream_entry_t *entry = streamBuf[streamClient];
-
- if (!entry)
- result = EINVAL;
- else {
- config = call ConfigReadStream.getConfiguration[streamClient]();
- if (config->inch == INPUT_CHANNEL_NONE)
- result = EINVAL;
- else {
- owner = streamClient;
- streamConfig = *config;
- streamConfig.sampcon_ssel = SAMPCON_SOURCE_SMCLK; // assumption: SMCLK runs at 1 MHz
- streamConfig.sampcon_id = SAMPCON_CLOCK_DIV_1;
- streamBuf[streamClient] = entry->next;
- result = call SingleChannelReadStream.configureMultiple[streamClient](
- &streamConfig, (uint16_t *) entry, entry->count, usPeriod[streamClient]);
- if (result == SUCCESS)
- result = call SingleChannelReadStream.getData[streamClient]();
- else {
- streamBuf[streamClient] = entry;
- post finishStreamRequest();
- return;
- }
- }
- }
- if (result != SUCCESS){
- call ResourceReadStream.release[streamClient]();
- signal ReadStream.readDone[streamClient]( FAIL, 0 );
- }
- return;
- }
-
-
- async event uint16_t* SingleChannelReadStream.multipleDataReady[uint8_t streamClient](
- uint16_t *buf, uint16_t length)
- {
- error_t nextRequest;
-
- if (!resultBuf){
- value = length;
- resultBuf = buf;
- post signalBufferDone();
- if (!streamBuf[streamClient])
- post finishStreamRequest();
- else {
- // fill next buffer (this is the only async code dealing with buffers)
- struct stream_entry_t *entry = streamBuf[streamClient];
- streamBuf[streamClient] = streamBuf[streamClient]->next;
- nextRequest = call SingleChannelReadStream.configureMultiple[streamClient](
- &streamConfig, (uint16_t *) entry, entry->count, usPeriod[streamClient]);
- if (nextRequest == SUCCESS)
- nextRequest = call SingleChannelReadStream.getData[streamClient]();
- if (nextRequest != SUCCESS){
- streamBuf[owner] = entry;
- post finishStreamRequest();
- }
- }
- } else {
- // overflow: can't signal data fast enough
- struct stream_entry_t *entry = (struct stream_entry_t *) buf;
- entry->next = streamBuf[streamClient];
- streamBuf[streamClient] = entry; // what a waste
- post finishStreamRequest();
- }
- return 0;
- }
-
- void task signalBufferDone()
- {
- signal ReadStream.bufferDone[owner]( SUCCESS, resultBuf, value);
- resultBuf = 0;
- }
-
- async event error_t SingleChannelReadStream.singleDataReady[uint8_t streamClient](uint16_t data)
- {
- // won't happen
- return SUCCESS;
- }
default async command error_t ResourceRead.request[uint8_t client]() { return FAIL; }
default async command error_t ResourceRead.immediateRequest[uint8_t client]() { return FAIL; }
default async command bool SubResourceReadNow.isOwner[uint8_t client]() { return FALSE; }
default event void ResourceReadNow.granted[uint8_t nowClient](){}
default async event void ReadNow.readDone[uint8_t client]( error_t result, uint16_t val ){}
- default async command error_t SubResourceReadNow.immediateRequest[uint8_t nowClient]()
- {
- return FAIL;
- }
-
- default async command error_t ResourceReadStream.request[uint8_t streamClient]() { return FAIL; }
- default async command error_t ResourceReadStream.release[uint8_t streamClient]() { return FAIL; }
- default async command bool ResourceReadStream.isOwner[uint8_t streamClient]() { return FALSE; }
- default event void ReadStream.bufferDone[uint8_t streamClient]( error_t result,
- uint16_t* buf, uint16_t count ){}
- default event void ReadStream.readDone[uint8_t streamClient]( error_t result, uint32_t actualPeriod ){ }
-
+ default async command error_t SubResourceReadNow.immediateRequest[uint8_t nowClient]() { return FAIL; }
default async command error_t SingleChannel.getData[uint8_t client]()
{
return EINVAL;
}
- // will be placed in flash
const msp430adc12_channel_config_t defaultConfig = {INPUT_CHANNEL_NONE,0,0,0,0,0,0,0};
default async command const msp430adc12_channel_config_t*
Config.getConfiguration[uint8_t client]()
{
return &defaultConfig;
- }
-
- default async command const msp430adc12_channel_config_t*
- ConfigReadStream.getConfiguration[uint8_t client]()
- {
- return &defaultConfig;
- }
-
- default async command error_t SingleChannelReadStream.configureMultiple[uint8_t client](
- const msp430adc12_channel_config_t *config, uint16_t buffer[],
- uint16_t numSamples, uint16_t jiffies)
- {
- return FAIL;
- }
-
- default async command error_t SingleChannelReadStream.getData[uint8_t client]()
- {
- return FAIL;
- }
-
+ }
default async command error_t SingleChannel.configureSingle[uint8_t client](
const msp430adc12_channel_config_t *config){ return FAIL; }
-
-
-}
-
+
+}
provides interface ReadStream<uint16_t>;
uses interface AdcConfigure<const msp430adc12_channel_config_t*>;
} implementation {
- components AdcP,
+ components WireAdcStreamP,
#ifdef REF_VOLT_AUTO_CONFIGURE
// if the client configuration requires a stable
// reference voltage, the reference voltage generator
// is automatically enabled
- new Msp430Adc12ClientAutoRVGC() as Msp430AdcPlient;
+ new Msp430Adc12ClientAutoRVGC() as Msp430AdcClient;
+ AdcConfigure = Msp430AdcClient.AdcConfigure;
#else
- new Msp430Adc12ClientC() as Msp430AdcPlient;
+ new Msp430Adc12ClientC() as Msp430AdcClient;
#endif
enum {
RSCLIENT = unique(ADCC_READ_STREAM_SERVICE),
};
- ReadStream = AdcP.ReadStream[RSCLIENT];
- AdcConfigure = AdcP.ConfigReadStream[RSCLIENT];
- AdcP.SingleChannelReadStream[RSCLIENT] -> Msp430AdcPlient.Msp430Adc12SingleChannel;
- AdcP.ResourceReadStream[RSCLIENT] -> Msp430AdcPlient.Resource;
-#ifdef REF_VOLT_AUTO_CONFIGURE
- AdcConfigure = Msp430AdcPlient.AdcConfigure;
-#endif
+ ReadStream = WireAdcStreamP.ReadStream[RSCLIENT];
+ AdcConfigure = WireAdcStreamP.AdcConfigure[RSCLIENT];
+ WireAdcStreamP.Resource[RSCLIENT] -> Msp430AdcClient.Resource;
+ WireAdcStreamP.Msp430Adc12SingleChannel[RSCLIENT] -> Msp430AdcClient.Msp430Adc12SingleChannel;
}
--- /dev/null
+/* $Id$
+ * Copyright (c) 2005 Intel Corporation
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached INTEL-LICENSE
+ * file. If you do not find these files, copies can be found by writing to
+ * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA,
+ * 94704. Attention: Intel License Inquiry.
+ *
+ * Copyright (c) 2004, Technische Universitaet Berlin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of the Technische Universitaet Berlin nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * Convert MSP430 HAL A/D interface to the HIL interfaces (adapted atmega code).
+ * @author David Gay
+ * @author Jan Hauer <hauer@tkn.tu-berlin.de>
+ */
+#include "Timer.h"
+
+module AdcStreamP {
+ provides {
+ interface Init @atleastonce();
+ interface ReadStream<uint16_t>[uint8_t client];
+ }
+ uses {
+ interface Msp430Adc12SingleChannel as SingleChannel[uint8_t client];
+ interface AdcConfigure<const msp430adc12_channel_config_t*>[uint8_t client];
+ interface Alarm<TMilli, uint32_t>;
+ }
+}
+implementation {
+ enum {
+ NSTREAM = uniqueCount(ADCC_READ_STREAM_SERVICE)
+ };
+
+ /* Resource reservation is required, and it's incorrect to call getData
+ again before dataReady is signaled, so there are no races in correct
+ programs */
+ norace uint8_t client = NSTREAM;
+
+ /* Stream data */
+ struct list_entry_t {
+ uint16_t count;
+ struct list_entry_t *next;
+ };
+ struct list_entry_t *bufferQueue[NSTREAM];
+ struct list_entry_t **bufferQueueEnd[NSTREAM];
+ uint16_t *lastBuffer, lastCount;
+
+ norace uint16_t *buffer, *pos, count;
+ norace uint32_t now, period;
+ norace bool periodModified;
+
+
+ command error_t Init.init() {
+ uint8_t i;
+
+ for (i = 0; i != NSTREAM; i++)
+ bufferQueueEnd[i] = &bufferQueue[i];
+
+ return SUCCESS;
+ }
+
+ void sampleSingle() {
+ call SingleChannel.getData[client]();
+ }
+
+ command error_t ReadStream.postBuffer[uint8_t c](uint16_t *buf, uint16_t n) {
+ if (n < sizeof(struct list_entry_t))
+ return ESIZE;
+ atomic
+ {
+ struct list_entry_t *newEntry = (struct list_entry_t *)buf;
+
+ if (!bufferQueueEnd[c]) // Can't post right now.
+ return FAIL;
+
+ newEntry->count = n;
+ newEntry->next = NULL;
+ *bufferQueueEnd[c] = newEntry;
+ bufferQueueEnd[c] = &newEntry->next;
+ }
+ return SUCCESS;
+ }
+
+ task void readStreamDone() {
+ uint8_t c = client;
+ uint32_t actualPeriod = period;
+ if (periodModified)
+ actualPeriod = period - (period % 1000);
+
+ atomic
+ {
+ bufferQueue[c] = NULL;
+ bufferQueueEnd[c] = &bufferQueue[c];
+ }
+
+ client = NSTREAM;
+ signal ReadStream.readDone[c](SUCCESS, actualPeriod);
+ }
+
+ task void readStreamFail() {
+ /* By now, the pending bufferDone has been signaled (see readStream). */
+ struct list_entry_t *entry;
+ uint8_t c = client;
+
+ atomic entry = bufferQueue[c];
+ for (; entry; entry = entry->next)
+ signal ReadStream.bufferDone[c](FAIL, (uint16_t *)entry, entry->count);
+
+ atomic
+ {
+ bufferQueue[c] = NULL;
+ bufferQueueEnd[c] = &bufferQueue[c];
+ }
+
+ client = NSTREAM;
+ signal ReadStream.readDone[c](FAIL, 0);
+ }
+
+ task void bufferDone() {
+ uint16_t *b, c;
+ atomic
+ {
+ b = lastBuffer;
+ c = lastCount;
+ lastBuffer = NULL;
+ }
+
+ signal ReadStream.bufferDone[client](SUCCESS, b, c);
+ }
+
+ void nextAlarm() {
+ call Alarm.startAt(now, period);
+ now += period;
+ }
+
+ async event void Alarm.fired() {
+ sampleSingle();
+ }
+
+ error_t nextBuffer(bool startNextAlarm) {
+ atomic
+ {
+ struct list_entry_t *entry = bufferQueue[client];
+
+ if (!entry)
+ {
+ // all done
+ bufferQueueEnd[client] = NULL; // prevent post
+ post readStreamDone();
+ return FAIL;
+ }
+ else
+ {
+ bufferQueue[client] = entry->next;
+ if (!bufferQueue[client])
+ bufferQueueEnd[client] = &bufferQueue[client];
+ pos = buffer = (uint16_t *)entry;
+ count = entry->count;
+ if (startNextAlarm)
+ nextAlarm();
+ return SUCCESS;
+ }
+ }
+ }
+
+ void nextMultiple(uint8_t c)
+ {
+ if (nextBuffer(FALSE) == SUCCESS){
+ msp430adc12_channel_config_t config = *call AdcConfigure.getConfiguration[c]();
+ config.sampcon_ssel = SAMPCON_SOURCE_SMCLK; // assumption: SMCLK runs at 1 MHz
+ config.sampcon_id = SAMPCON_CLOCK_DIV_1;
+ call SingleChannel.configureMultiple[c]( &config, pos, count, period);
+ call SingleChannel.getData[c]();
+ }
+ }
+
+ command error_t ReadStream.read[uint8_t c](uint32_t usPeriod)
+ {
+ if (usPeriod & 0xFFFF0000){
+ // "manual" sampling
+ period = usPeriod / 1000;
+ periodModified = TRUE;
+ client = c;
+ now = call Alarm.getNow();
+ call SingleChannel.configureSingle[c](call AdcConfigure.getConfiguration[c]());
+ if (nextBuffer(FALSE) == SUCCESS)
+ sampleSingle();
+ } else {
+ period = usPeriod;
+ periodModified = FALSE;
+ client = c;
+ nextMultiple(c);
+ }
+ return SUCCESS;
+ }
+
+
+ async event error_t SingleChannel.singleDataReady[uint8_t streamClient](uint16_t data)
+ {
+ if (client == NSTREAM)
+ return FAIL;
+
+ if (count == 0)
+ {
+ now = call Alarm.getNow();
+ nextBuffer(TRUE);
+ }
+ else
+ {
+ *pos++ = data;
+ if (!--count)
+ {
+ atomic
+ {
+ if (lastBuffer)
+ {
+ /* We failed to signal bufferDone in time. Fail. */
+ bufferQueueEnd[client] = NULL; // prevent post
+ post readStreamFail();
+ return FAIL;
+ }
+ else
+ {
+ lastBuffer = buffer;
+ lastCount = pos - buffer;
+ }
+ }
+ post bufferDone();
+ nextBuffer(TRUE);
+ }
+ else
+ nextAlarm();
+ }
+ return FAIL;
+ }
+
+ async event uint16_t* SingleChannel.multipleDataReady[uint8_t streamClient](
+ uint16_t *buf, uint16_t length)
+ {
+ atomic
+ {
+ if (lastBuffer)
+ {
+ /* We failed to signal bufferDone in time. Fail. */
+ bufferQueueEnd[client] = NULL; // prevent post
+ post readStreamFail();
+ return 0;
+ }
+ else
+ {
+ lastBuffer = buffer;
+ lastCount = pos - buffer;
+ }
+ }
+ post bufferDone();
+ nextMultiple(streamClient);
+ return 0;
+ }
+
+ const msp430adc12_channel_config_t defaultConfig = {
+ inch: SUPPLY_VOLTAGE_HALF_CHANNEL,
+ sref: REFERENCE_VREFplus_AVss,
+ ref2_5v: REFVOLT_LEVEL_1_5,
+ adc12ssel: SHT_SOURCE_ACLK,
+ adc12div: SHT_CLOCK_DIV_1,
+ sht: SAMPLE_HOLD_4_CYCLES,
+ sampcon_ssel: SAMPCON_SOURCE_SMCLK,
+ sampcon_id: SAMPCON_CLOCK_DIV_1
+ };
+ default async command const msp430adc12_channel_config_t* AdcConfigure.getConfiguration[uint8_t c]()
+ {
+ return &defaultConfig;
+ }
+ default async command error_t SingleChannel.configureMultiple[uint8_t c](
+ const msp430adc12_channel_config_t *config, uint16_t b[],
+ uint16_t numSamples, uint16_t jiffies)
+ {
+ return FAIL;
+ }
+ default async command error_t SingleChannel.getData[uint8_t c]()
+ {
+ return FAIL;
+ }
+ default async command error_t SingleChannel.configureSingle[uint8_t c](
+ const msp430adc12_channel_config_t *config){ return FAIL; }
+}
MSP430REG_NORACE(ADC12IFG);
MSP430REG_NORACE(ADC12IE);
MSP430REG_NORACE(ADC12IV);
+
+ // SFRs are accessed directly or cast to a pointer, both works fine
+ // (we don't access all SFRs directly, because that would result in
+ // much higher memory footprint)
async command void HplAdc12.setCtl0(adc12ctl0_t control0){
- ADC12CTL0 = *(uint16_t*)&control0;
+ ADC12CTL0 = *((uint16_t*) &control0);
}
async command void HplAdc12.setCtl1(adc12ctl1_t control1){
- ADC12CTL1 = *(uint16_t*)&control1;
+ ADC12CTL1 = *((uint16_t*) &control1);
}
async command adc12ctl0_t HplAdc12.getCtl0(){
- return *(adc12ctl0_t*) &ADC12CTL0;
+ return *((adc12ctl0_t*) &ADC12CTL0);
}
async command adc12ctl1_t HplAdc12.getCtl1(){
- return *(adc12ctl1_t*) &ADC12CTL1;
+ return *((adc12ctl1_t*) &ADC12CTL1);
}
async command void HplAdc12.setMCtl(uint8_t i, adc12memctl_t memControl){
async command uint16_t HplAdc12.getIEFlags(){ return (uint16_t) ADC12IE; }
async command void HplAdc12.resetIFGs(){
- if (!ADC12IFG)
- return;
- else {
- // workaround, because ADC12IFG is not writable
- uint8_t i;
- volatile uint16_t tmp;
- for (i=0; i<16; i++)
- tmp = call HplAdc12.getMem(i);
- }
+ ADC12IV = 0;
+ ADC12IFG = 0;
}
async command void HplAdc12.startConversion(){
ADC12CTL0 |= (ADC12SC + ENC);
}
- async command void HplAdc12.stopConversion(){
+ async command void HplAdc12.stopConversion(){
+ // stop conversion mode immediately, conversion data is unreliable
+ ADC12CTL1 &= ~(CONSEQ0 | CONSEQ1);
ADC12CTL0 &= ~(ADC12SC + ENC);
ADC12CTL0 &= ~(ADC12ON);
}
provides {\r
interface Resource;\r
interface Msp430Adc12SingleChannel;\r
+ interface Msp430Adc12Overflow;\r
}\r
} implementation {\r
- components Msp430DmaC, Msp430Adc12DMAP, Msp430Adc12P;\r
+ components Msp430DmaC, Msp430Adc12DMAP, Msp430Adc12P, Msp430Adc12DMAWireC;\r
\r
enum {\r
ID = unique(MSP430ADC12_RESOURCE),\r
};\r
Resource = Msp430Adc12P.Resource[ID];\r
Msp430Adc12SingleChannel = Msp430Adc12DMAP.SingleChannel[ID];\r
+ Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID];\r
\r
Msp430Adc12DMAP.SubSingleChannel[ID] -> Msp430Adc12P.SingleChannel[ID];\r
Msp430Adc12DMAP.AsyncAdcControl[ID] -> Msp430Adc12P.DMAExtension[ID];\r
\r
- Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control;\r
- Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel0;\r
}\r
provides {\r
interface Resource;\r
interface Msp430Adc12SingleChannel;\r
+ interface Msp430Adc12Overflow;\r
}\r
uses interface AdcConfigure<const msp430adc12_channel_config_t*>;\r
} implementation {\r
- components Msp430Adc12P, Msp430RefVoltArbiterP;\r
+ components Msp430Adc12P, Msp430RefVoltArbiterP, Msp430Adc12DMAWireC;\r
\r
enum {\r
ID = unique(MSP430ADC12_RESOURCE),\r
};\r
Resource = Msp430RefVoltArbiterP.ClientResource[ID];\r
+ Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID];\r
\r
Msp430RefVoltArbiterP.AdcResource[ID] -> Msp430Adc12P.Resource[ID];\r
\r
\r
Msp430Adc12DMAP.SubSingleChannel[ID] -> Msp430Adc12P.SingleChannel[ID];\r
Msp430Adc12DMAP.AsyncAdcControl[ID] -> Msp430Adc12P.DMAExtension[ID];\r
-\r
- Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control;\r
- Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel0;\r
- \r
}\r
interface Resource;\r
interface Msp430Adc12SingleChannel;\r
interface Msp430Adc12MultiChannel;\r
+ interface Msp430Adc12Overflow;\r
}\r
uses interface AdcConfigure<const msp430adc12_channel_config_t*>;\r
} implementation {\r
Resource = Msp430RefVoltArbiterP.ClientResource[ID];\r
Msp430Adc12SingleChannel = Msp430Adc12P.SingleChannel[ID];\r
Msp430Adc12MultiChannel = Msp430Adc12P.MultiChannel[ID];\r
+ Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID];\r
\r
Msp430RefVoltArbiterP.AdcResource[ID] -> Msp430Adc12P.Resource[ID];\r
\r
--- /dev/null
+/*
+ * Copyright (c) 2006, Technische Universitaet Berlin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of the Technische Universitaet Berlin nor the names
+ * of its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * - Revision -------------------------------------------------------------
+ * $Revision$
+ * $Date$
+ * @author: Jan Hauer <hauer@tkn.tu-berlin.de>
+ * ========================================================================
+ */
+
+configuration Msp430Adc12DMAWireC
+{
+} implementation {
+ components Msp430DmaC, Msp430Adc12DMAP;
+ Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control;
+ Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel2;
+#warning Accessing DMA.channel2 for ADC12
+}
}
implementation
{
+#warning Accessing TimerA for ADC12
enum {
SINGLE_DATA = 1,
SINGLE_DATA_REPEAT = 2,
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;
}
if (call ADCArbiterInfo.userId() == id){
adc12ctl1_t ctl1 = {
adc12busy: 0,
- ctl1.conseq = 3,
+ conseq: 3,
adc12ssel: config->adc12ssel,
adc12div: config->adc12div,
issh: 0,
if (call ADCArbiterInfo.userId() == id){
adc12ctl1_t ctl1 = {
adc12busy: 0,
- // use seq. of channels (rep.seq. channel does not work with TimerA + MSC ?)
- conseq: (jiffies == 0) ? 3 : 1,
+ conseq: (numSamples > numMemctl+1) ? 3 : 1,
adc12ssel: config->adc12ssel,
adc12div: config->adc12div,
issh: 0,
};
uint16_t i, mask = 1;
adc12ctl0_t ctl0 = call HplAdc12.getCtl0();
- ctl0.msc = 1;
+ ctl0.msc = (jiffies == 0) ? 1 : 0;
ctl0.sht0 = config->sht;
ctl0.sht1 = config->sht;
#endif
resetAdcPin( (call HplAdc12.getMCtl(0)).inch );
if (state & MULTI_CHANNEL){
- ADC12IV = 0; // clear any pending overflow
for (i=1; i<numChannels; i++)
resetAdcPin( (call HplAdc12.getMCtl(i)).inch );
}
- call HplAdc12.stopConversion();
- call HplAdc12.resetIFGs();
- state &= ~ADC_BUSY;
+ 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;
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)
{
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;
+ uint16_t i = 0, k;
do {
*resultBuffer++ = call HplAdc12.getMem(i);
} while (++i < numChannels);
resultBufferIndex += numChannels;
- if (resultBufferLength == resultBufferIndex){
+ if (overflow || resultBufferLength == resultBufferIndex){
stopConversion();
- resultBuffer -= resultBufferLength;
+ resultBuffer -= resultBufferIndex;
+ k = resultBufferIndex - numChannels;
resultBufferIndex = 0;
- signal MultiChannel.dataReady[clientID](resultBuffer, resultBufferLength);
+ signal MultiChannel.dataReady[clientID](resultBuffer,
+ overflow ? k : resultBufferLength);
} else call HplAdc12.enableConversion();
}
break;
case MULTIPLE_DATA:
{
- uint16_t i = 0, length;
+ uint16_t i = 0, length, k;
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;
resultBuffer = signal SingleChannel.multipleDataReady[clientID](
resultBuffer-resultBufferLength,
- resultBufferLength);
+ overflow ? 0 : resultBufferLength);
if (!resultBuffer)
stopConversion();
break;
* (numMemctl+1) must be zero. For example, to sample every channel twice use
* numSamples = (numMemctl+1) * 2
*
- * @param jiffies Sampling period per sequence in terms of clock ticks of
- * "sampcon_ssel" and input divider "sampcon_id". A sequence of (numMemctl+1)
- * is always sampled as fast as possible and <code>jiffies</code> specifies
- * the time between those sequences. For example, if numSamples =
- * (numMemctl+1) * 5, then dataReady() will be signalled after (approx.)
- * 5*jiffies clock ticks after the call to getData() and each set of
- * numMemctl+1 channels was sampled at (almost) the same time.
+ * @param jiffies Sampling period in terms of clock ticks of "sampcon_ssel"
+ * and input divider "sampcon_id".
*
* @return SUCCESS means that the ADC was configured successfully and
* <code>getData()</code> can be called to start the conversion.
the Msp430Adc12SingleChannel allows to perform one or more ADC conversions on a
single channel with a specified sampling frequency and (2) the
Msp430Adc12MultiChannel allows to sample a group of up to 16 different ADC
-channels "at once" (with minimum latency) and in addition define a sampling
-frequency for the whole group (useful for multi-channel accelerometers, etc.).
+channels.
+
On the MSP430 two additional hardware modules may play a role when the ADC12 is
used: the internal reference voltage generator and the DMA controller.
--- /dev/null
+/* $Id$
+ * Copyright (c) 2005 Intel Corporation
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached INTEL-LICENSE
+ * file. If you do not find these files, copies can be found by writing to
+ * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA,
+ * 94704. Attention: Intel License Inquiry.
+ */
+/**
+ * Support component for AdcReadStreamClientC.
+ *
+ * @author David Gay
+ * @author Jan Hauer
+ */
+
+#include "Msp430Adc12.h"
+
+configuration WireAdcStreamP {
+ provides interface ReadStream<uint16_t>[uint8_t client];
+ uses {
+ interface AdcConfigure<const msp430adc12_channel_config_t*>[uint8_t client];
+ interface Msp430Adc12SingleChannel[uint8_t client];
+ interface Resource[uint8_t client];
+ }
+}
+implementation {
+ components AdcStreamP, MainC, new AlarmMilli32C() as Alarm,
+ new ArbitratedReadStreamC(uniqueCount(ADCC_READ_STREAM_SERVICE), uint16_t) as ArbitrateReadStream;
+
+ ReadStream = ArbitrateReadStream;
+ AdcConfigure = AdcStreamP;
+ Resource = ArbitrateReadStream;
+
+ ArbitrateReadStream.Service -> AdcStreamP;
+
+ AdcStreamP.Init <- MainC;
+ Msp430Adc12SingleChannel = AdcStreamP.SingleChannel;
+ AdcStreamP.Alarm -> Alarm;
+}