From 60959169f556ee3dc648a69f5c8fb1ed9cd887c7 Mon Sep 17 00:00:00 2001 From: janhauer Date: Mon, 7 Apr 2008 09:41:55 +0000 Subject: [PATCH] - bugfix: ReadStream did not work with a "usPeriod" parameter > 0xFFFF (the fix uses/adapts the atmel ReadStream code) - bugfix: overflow interrupts were not handled/signalled correctly from the HAL - fixed the wiring for DMA, which was not correct when used by more than one client - polished the HPL and added some comments - introduced a compile time warning when DMA/TimerA is accessed (will be removed once we decide how these components are arbitrated) --- apps/tests/msp430/Adc12/TestAdcMultiC.nc | 8 +- apps/tests/msp430/Adc12/TestAdcSingleC.nc | 6 +- tos/chips/msp430/adc12/AdcP.nc | 199 +---------- .../msp430/adc12/AdcReadStreamClientC.nc | 18 +- tos/chips/msp430/adc12/AdcStreamP.nc | 314 ++++++++++++++++++ tos/chips/msp430/adc12/HplAdc12P.nc | 27 +- .../msp430/adc12/Msp430Adc12ClientAutoDMAC.nc | 6 +- .../adc12/Msp430Adc12ClientAutoDMA_RVGC.nc | 8 +- .../msp430/adc12/Msp430Adc12ClientAutoRVGC.nc | 2 + tos/chips/msp430/adc12/Msp430Adc12DMAWireC.nc | 43 +++ tos/chips/msp430/adc12/Msp430Adc12ImplP.nc | 69 ++-- .../msp430/adc12/Msp430Adc12MultiChannel.nc | 9 +- tos/chips/msp430/adc12/README.txt | 4 +- tos/chips/msp430/adc12/WireAdcStreamP.nc | 40 +++ 14 files changed, 485 insertions(+), 268 deletions(-) create mode 100644 tos/chips/msp430/adc12/AdcStreamP.nc create mode 100644 tos/chips/msp430/adc12/Msp430Adc12DMAWireC.nc create mode 100644 tos/chips/msp430/adc12/WireAdcStreamP.nc diff --git a/apps/tests/msp430/Adc12/TestAdcMultiC.nc b/apps/tests/msp430/Adc12/TestAdcMultiC.nc index 26737838..53933342 100644 --- a/apps/tests/msp430/Adc12/TestAdcMultiC.nc +++ b/apps/tests/msp430/Adc12/TestAdcMultiC.nc @@ -68,7 +68,7 @@ implementation #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(); @@ -85,6 +85,8 @@ implementation bool assertData(uint16_t *data, uint16_t num) { uint16_t i; + if (num != BUFFER_SIZE) + post signalFailure(); for (i=0; i= 0xFFF){ post signalFailure(); @@ -117,8 +119,10 @@ implementation 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(); } diff --git a/apps/tests/msp430/Adc12/TestAdcSingleC.nc b/apps/tests/msp430/Adc12/TestAdcSingleC.nc index e1fe427c..809e4cac 100644 --- a/apps/tests/msp430/Adc12/TestAdcSingleC.nc +++ b/apps/tests/msp430/Adc12/TestAdcSingleC.nc @@ -64,6 +64,7 @@ implementation #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(); @@ -117,13 +118,15 @@ implementation 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(); @@ -133,6 +136,7 @@ implementation async event uint16_t* SingleChannel.multipleDataReady(uint16_t *buf, uint16_t length) { + numDone++; assertData(buf, length); call Resource.release(); post getData(); diff --git a/tos/chips/msp430/adc12/AdcP.nc b/tos/chips/msp430/adc12/AdcP.nc index 654807ad..7536a0a3 100644 --- a/tos/chips/msp430/adc12/AdcP.nc +++ b/tos/chips/msp430/adc12/AdcP.nc @@ -38,7 +38,6 @@ module AdcP { interface Read as Read[uint8_t client]; interface ReadNow as ReadNow[uint8_t client]; interface Resource as ResourceReadNow[uint8_t client]; - interface ReadStream as ReadStream[uint8_t streamClient]; } uses { // for Read only: @@ -48,11 +47,6 @@ module AdcP { // for Read and ReadNow: interface AdcConfigure as Config[uint8_t client]; interface Msp430Adc12SingleChannel as SingleChannel[uint8_t client]; - // for ReadStream only: - interface AdcConfigure as ConfigReadStream[uint8_t streamClient]; - interface Msp430Adc12SingleChannel as SingleChannelReadStream[uint8_t streamClient]; - interface Resource as ResourceReadStream[uint8_t streamClient]; - } } implementation @@ -61,28 +55,12 @@ 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) { @@ -96,8 +74,6 @@ implementation command error_t Read.read[uint8_t client]() { - if (call ResourceRead.isOwner[client]()) - return EBUSY; return call ResourceRead.request[client](); } @@ -108,8 +84,7 @@ implementation 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); } @@ -189,137 +164,6 @@ implementation // 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; } @@ -332,52 +176,19 @@ implementation 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; } - - -} - + +} diff --git a/tos/chips/msp430/adc12/AdcReadStreamClientC.nc b/tos/chips/msp430/adc12/AdcReadStreamClientC.nc index 94efef51..696bf71b 100644 --- a/tos/chips/msp430/adc12/AdcReadStreamClientC.nc +++ b/tos/chips/msp430/adc12/AdcReadStreamClientC.nc @@ -48,26 +48,24 @@ generic configuration AdcReadStreamClientC() { provides interface ReadStream; uses interface AdcConfigure; } 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; } diff --git a/tos/chips/msp430/adc12/AdcStreamP.nc b/tos/chips/msp430/adc12/AdcStreamP.nc new file mode 100644 index 00000000..af14a477 --- /dev/null +++ b/tos/chips/msp430/adc12/AdcStreamP.nc @@ -0,0 +1,314 @@ +/* $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 + */ +#include "Timer.h" + +module AdcStreamP { + provides { + interface Init @atleastonce(); + interface ReadStream[uint8_t client]; + } + uses { + interface Msp430Adc12SingleChannel as SingleChannel[uint8_t client]; + interface AdcConfigure[uint8_t client]; + interface Alarm; + } +} +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; } +} diff --git a/tos/chips/msp430/adc12/HplAdc12P.nc b/tos/chips/msp430/adc12/HplAdc12P.nc index 2423dba0..aaee9ce5 100644 --- a/tos/chips/msp430/adc12/HplAdc12P.nc +++ b/tos/chips/msp430/adc12/HplAdc12P.nc @@ -53,21 +53,25 @@ implementation 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){ @@ -92,15 +96,8 @@ implementation 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(){ @@ -108,7 +105,9 @@ implementation 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); } diff --git a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMAC.nc b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMAC.nc index 2f75f47d..74db72f9 100644 --- a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMAC.nc +++ b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMAC.nc @@ -48,19 +48,19 @@ generic configuration Msp430Adc12ClientAutoDMAC() provides { interface Resource; interface Msp430Adc12SingleChannel; + interface Msp430Adc12Overflow; } } implementation { - components Msp430DmaC, Msp430Adc12DMAP, Msp430Adc12P; + components Msp430DmaC, Msp430Adc12DMAP, Msp430Adc12P, Msp430Adc12DMAWireC; enum { ID = unique(MSP430ADC12_RESOURCE), }; Resource = Msp430Adc12P.Resource[ID]; Msp430Adc12SingleChannel = Msp430Adc12DMAP.SingleChannel[ID]; + Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID]; Msp430Adc12DMAP.SubSingleChannel[ID] -> Msp430Adc12P.SingleChannel[ID]; Msp430Adc12DMAP.AsyncAdcControl[ID] -> Msp430Adc12P.DMAExtension[ID]; - Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control; - Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel0; } diff --git a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMA_RVGC.nc b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMA_RVGC.nc index 7377496e..9d554ee9 100644 --- a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMA_RVGC.nc +++ b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoDMA_RVGC.nc @@ -47,15 +47,17 @@ generic configuration Msp430Adc12ClientAutoDMA_RVGC() provides { interface Resource; interface Msp430Adc12SingleChannel; + interface Msp430Adc12Overflow; } uses interface AdcConfigure; } implementation { - components Msp430Adc12P, Msp430RefVoltArbiterP; + components Msp430Adc12P, Msp430RefVoltArbiterP, Msp430Adc12DMAWireC; enum { ID = unique(MSP430ADC12_RESOURCE), }; Resource = Msp430RefVoltArbiterP.ClientResource[ID]; + Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID]; Msp430RefVoltArbiterP.AdcResource[ID] -> Msp430Adc12P.Resource[ID]; @@ -69,8 +71,4 @@ generic configuration Msp430Adc12ClientAutoDMA_RVGC() Msp430Adc12DMAP.SubSingleChannel[ID] -> Msp430Adc12P.SingleChannel[ID]; Msp430Adc12DMAP.AsyncAdcControl[ID] -> Msp430Adc12P.DMAExtension[ID]; - - Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control; - Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel0; - } diff --git a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoRVGC.nc b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoRVGC.nc index 246f5860..b7e5c6c5 100644 --- a/tos/chips/msp430/adc12/Msp430Adc12ClientAutoRVGC.nc +++ b/tos/chips/msp430/adc12/Msp430Adc12ClientAutoRVGC.nc @@ -46,6 +46,7 @@ generic configuration Msp430Adc12ClientAutoRVGC() interface Resource; interface Msp430Adc12SingleChannel; interface Msp430Adc12MultiChannel; + interface Msp430Adc12Overflow; } uses interface AdcConfigure; } implementation { @@ -57,6 +58,7 @@ generic configuration Msp430Adc12ClientAutoRVGC() Resource = Msp430RefVoltArbiterP.ClientResource[ID]; Msp430Adc12SingleChannel = Msp430Adc12P.SingleChannel[ID]; Msp430Adc12MultiChannel = Msp430Adc12P.MultiChannel[ID]; + Msp430Adc12Overflow = Msp430Adc12P.Overflow[ID]; Msp430RefVoltArbiterP.AdcResource[ID] -> Msp430Adc12P.Resource[ID]; diff --git a/tos/chips/msp430/adc12/Msp430Adc12DMAWireC.nc b/tos/chips/msp430/adc12/Msp430Adc12DMAWireC.nc new file mode 100644 index 00000000..2a1f8ba4 --- /dev/null +++ b/tos/chips/msp430/adc12/Msp430Adc12DMAWireC.nc @@ -0,0 +1,43 @@ +/* + * 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 + * ======================================================================== + */ + +configuration Msp430Adc12DMAWireC +{ +} implementation { + components Msp430DmaC, Msp430Adc12DMAP; + Msp430Adc12DMAP.DMAControl -> Msp430DmaC.Control; + Msp430Adc12DMAP.DMAChannel -> Msp430DmaC.Channel2; +#warning Accessing DMA.channel2 for ADC12 +} diff --git a/tos/chips/msp430/adc12/Msp430Adc12ImplP.nc b/tos/chips/msp430/adc12/Msp430Adc12ImplP.nc index 36c80b8f..e815ee61 100644 --- a/tos/chips/msp430/adc12/Msp430Adc12ImplP.nc +++ b/tos/chips/msp430/adc12/Msp430Adc12ImplP.nc @@ -63,6 +63,7 @@ module Msp430Adc12ImplP } implementation { +#warning Accessing TimerA for ADC12 enum { SINGLE_DATA = 1, SINGLE_DATA_REPEAT = 2, @@ -86,7 +87,12 @@ implementation 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; } @@ -325,7 +331,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, @@ -404,8 +410,7 @@ implementation 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, @@ -420,7 +425,7 @@ implementation }; 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; @@ -481,13 +486,14 @@ implementation #endif resetAdcPin( (call HplAdc12.getMCtl(0)).inch ); if (state & MULTI_CHANNEL){ - ADC12IV = 0; // clear any pending overflow for (i=1; i 16) length = 16; else @@ -567,18 +574,20 @@ 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; @@ -591,7 +600,7 @@ implementation resultBuffer = signal SingleChannel.multipleDataReady[clientID]( resultBuffer-resultBufferLength, - resultBufferLength); + overflow ? 0 : resultBufferLength); if (!resultBuffer) stopConversion(); break; diff --git a/tos/chips/msp430/adc12/Msp430Adc12MultiChannel.nc b/tos/chips/msp430/adc12/Msp430Adc12MultiChannel.nc index 0ded55e3..38ff00c7 100644 --- a/tos/chips/msp430/adc12/Msp430Adc12MultiChannel.nc +++ b/tos/chips/msp430/adc12/Msp430Adc12MultiChannel.nc @@ -74,13 +74,8 @@ interface Msp430Adc12MultiChannel * (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 jiffies 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 * getData() can be called to start the conversion. diff --git a/tos/chips/msp430/adc12/README.txt b/tos/chips/msp430/adc12/README.txt index 6a6ca684..3f0d589a 100644 --- a/tos/chips/msp430/adc12/README.txt +++ b/tos/chips/msp430/adc12/README.txt @@ -36,8 +36,8 @@ An application that is written for an MSP430-based platform like 'eyesIFX' or 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. diff --git a/tos/chips/msp430/adc12/WireAdcStreamP.nc b/tos/chips/msp430/adc12/WireAdcStreamP.nc new file mode 100644 index 00000000..7d9291d5 --- /dev/null +++ b/tos/chips/msp430/adc12/WireAdcStreamP.nc @@ -0,0 +1,40 @@ +/* $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[uint8_t client]; + uses { + interface AdcConfigure[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; +} -- 2.39.2