[Tinyos-8051wg] Re: [Tinyos-2.0wg] Aligning TEP 101 (ADC) with TEP 108 (Resource Arbitration) and 109 (Sensorboards)

David Gay dgay42 at gmail.com
Mon May 9 15:10:00 PDT 2005


[Long message follows...]

On 5/4/05, Jan Hauer <hauer at tkn.tu-berlin.de> wrote:
> 1. HPL and HAL
> [...]
> To align the HAL with TEP108 I would suggest to instead of platform
> dependent reserve commands provide the Resource interface introduced
> in TEP108. A successful call to an HAL's Resource.request() would
> reserve the ADC for the caller until he calls Resource.release(). For
> time critical sampling an additional platform dependent command e.g.
> MSP430ADC12Multiple.prepare(uint16_t *buf, uint16_t length, uint16_t
> jiffies) is provided that sets up ADC registers so that a subsequent
> MSP430ADC12Multiple.getData() will start the sampling process
> immediately with these settings.

Sounds good to me.

> 2. HIL
> 
> As far as I understand our last conclusion was that an HIL will
> provide one lean ADC interface with only a getData() command and the
> Resource interface (see TEP108). The idea was to have a HIL component
> (wrapper) per channel (sensor). On top of multiple HIL components a
> service like round robin could be built.
> 
> To align HIL with TEP109 I would like to provide the "Sensor" and
> "QSensor" as well as the "CalibrationData" interface by the HIL
> (wrapper) instead of providing a separate "ADC", "ADCSingle" or
> "ADCMultiple" interface. The Sensor interface already has the same
> commands as the suggested lean "ADCSingle" or "ADC" interface.
> "QSensor" is for async requests and "CalibrationData" to return
> calibration data, both should be provided optionally.

Actually QSensor isn't in tep 109, but after some discussion with Phil L.,
we came up with some thoughts about all this:

- first, both the names "Sensor" and "ADCxxx" are too specific: these
interfaces are really about data acquisition, and are offered by several
kinds of components: A/D converters, various sensors, etc.

- We do think there is a place for an "A/D converter" abstraction distinct
from the general concept of a sensor board (though it may well be just a
special case).

- There are some hardware-independent interfaces to sensors -- we propose
something along the lines of the following (note that we've removed
Sensor and ADC from the names, but I'm not 100% happy with all the new
names):

  1) Simple, non-async data acquisition. For low-rate, non-time-sensitive
     acquisition.

  interface AcquireData { // similar to previous Sensor proposal
    /** Start data acquisition
     *  @return SUCCESS if request accepted, EBUSY if it is refused
     *    'dataReady' or 'error' will be signaled if SUCCESS is returned
     */
    command error_t getData();

    /** Data has been acquired.
     * @param data Acquired value
     *   Values are "left-justified" within each 16-bit integer, i.e., if
     *   the data is acquired with n bits of precision, each value is 
     *   shifted left by 16-n bits.
     */
    event void dataReady(uint16_t data);

    /** Signal that the data acquisition failed
     * @param info error information
     */
    event void error(uint16_t info);
  }

  2) Async data acquisition. Low-overhead, low-latency (note that
     the error path is not async).

  interface AcquireDataNow {
    /** Start data acquisition. The data acquisition SHOULD start 
     *  immediately (within hardware constraints).
     *  @return SUCCESS if request accepted, EBUSY if it is refused
     *    'dataReady' or 'error' will be signaled if SUCCESS is returned.
     */
    async command error_t getData();

    /** Data has been acquired. This SHOULD be signaled as soon as
     * possible after the hardware has acquired the value.
     * @param data Acquired value
     *   Values are "left-justified" within each 16-bit integer, i.e., if
     *   the data is acquired with n bits of precision, each value is 
     *   shifted left by 16-n bits.
     */
    async event void dataReady(uint16_t data);

    /** Signal that the data acquisition failed
     * @param info error information
     */
    event void error(uint16_t info);
  }

  3) Repeated data acquisition, at a specified rate, to a RAM buffer.
The getRate command allows you to enforce whatever error logic you
want (e.g., sampling rate must be within 10%).

  interface AcquireDataBuffered {
    /** Prepare to acquire 'count' samples into 'buffer', with
     *  'rate' microseconds between each sample.
     *  There must be a call to 'prepare' before every call to 'getData'
     *  @param buffer Buffer in which to store samples
     *  @param count Number of samples to acquire
     *  @param rate Interval in microseconds between each sample. The
     *    actual rate may be (very) different from this value, use
     *    the getRate command to find out what value will be used.
     *  @return SUCCESS if request accepted, EBUSY if it is refused,
     *    EINVAL if the parameters are invalid.
     *    'dataReady' or 'error' will be signaled if SUCCESS is returned
    command error_t prepare(uint16_t *buffer, uint16_t count, 
			     uint32_t rate);

    /** Return the sampling rate for the next acquisition
     *  @return Sampling interval in microseconds that will be used by the
     *    next call to getData.
     */
    command uint32_t getRate();

    /** Request data. A call to 'getData' must be preceded by a call to
     *  'prepare' to set up the data acquisition parameters.
     *  @return SUCCESS if request accepted, EBUSY if it is refused
     *    'dataReady' or 'error' will be signaled if SUCCESS is returned.
     *    The data acquisition SHOULD start immediately (within 
     *    hardware constraints).
     */
    async command result_t getData();

    /** Data has been acquired.
     * @param buffer Buffer containing the data.
     *   Samples are "left-justified" within each 16-bit integer, i.e., if
     *   the data is acquired with n bits of precision, each value is 
     *   shifted left by 16-n bits.
     * @param count Number of samples acquired.
     */
    event void dataReady(uint16_t *buffer, uint16_t count);

    /** Signal that the data acquisition failed
     *  @param info error information
     */
    event void error(uint16_t info);
  }


- tep109 would be rephrased to say that all sensors provide AcquireData
interfaces, and that those sensors needing high-frequency sampling will
provide AcquireDataNow and/or AcquireDataBuffered.

- It makes sense to me (i.e., I'm quite possibly wrong) to present the
onboard A/D converter of the msps and atmegas as a component providing
parameterised  AcquireData, AcquireDataNow and AcquireDataBuffered (maybe
this last one optional?) interfaces, along with a tep107 style Resource
interface (sensor board implementations using the onboard A/D will
want this anyway).

- This brings up a hole in tep109 (sensor boards): it doesn't talk about
resource reservation (oops!). Thoughts? (I'm tempted to say that sensors
are generally not shared, and we could annotate their interfaces with
@atmostonce() to enforce that...)


Summary: I think this is similar to your thoughts, with the addition of the
AcquireDataBuffered interface.

> 3. "Services"
> 
> Services are built on top of the wrappers that represent a Sensor. A
> service component wires to a single or multiple wrappers and extends
> or combines the functionality of these wrappers. Examples are a round
> robin service or a service returning multiple samples taken at precise
> points in time. Services are (mostly) platform independent. Example
> configuration:
> 
>     configuration ADCRoundRobinServiceC
>     {
>       provides interface StdControl;
>       provides interface Sensor as RoundRobinSensor[uint8_t id];
>       uses interface Sensor as SimpleSensor[uint8_t id];
>     }
>     implementation
>     {
>       components ADCRoundRobinServiceM;
> 
>       StdControl = ADCRoundRobinServiceM;
>       RoundRobinSensor = ADCRoundRobinServiceM;
>       SimpleSensor =  ADCRoundRobinServiceM;
>     }
> 
> and a client configuration:
> 
>   configuration RoundRobinClientC
>   {
>   }
>   implementation
>   {
>     enum {
>       TEMP_SENSOR = unique("ADCRoundRobinService")
>     };
>     components ADCRoundRobinServiceC, RoundRobinClientM,
>     InternalTempC, Main;
> 
>     Main.StdControl -> ADCRoundRobinServiceC;
>     Main.StdControl -> RoundRobinClientM;
>     RoundRobinClientM.TempSensor -> ADCRoundRobinServiceC.RoundRobinSensor[TEMP_SENSOR];
> 
>     ADCRoundRobinServiceC.SimpleSensor[TEMP_SENSOR] -> InternalTempC;
>   }

I like this. We can save clients a bit of typing with:

  generic configuration ADCRRClient() {
    provides interface Sensor as In;
    uses interface Sensor as Out;
  } implementation {
     enum {
       SENSOR = unique("ADCRoundRobinService")
     };
     components ADCRoundRobinServiceC;
 
     In = ADCRoundRobinServiceC.RoundRobinSensor[SENSOR];
     Out = ADCRoundRobinServiceC.SimpleSensor[SENSOR];
  }

making the client shorter:

  configuration RoundRobinClientC {}
  implementation {
    components new ADCRRClient() as MyClient, RoundRobinClientM,
    InternalTempC, Main;

    Main.StdControl -> RoundRobinClientM;
    RoundRobinClientM.TempSensor -> MyClient;
    MyClient -> InternalTempC;
  }

(I'm assuming the Main.StdControl -> ADCRoundRobinServiceC line is moved into
ADCRoundRobinServiceC)

This would argue for mentioning the ADCRoundRobinServiceC in the tep (as 
most clients will access the A/D chip that way?).

David

_______________________________________________
Tinyos-2.0wg mailing list
Tinyos-2.0wg at Mail.Millennium.Berkeley.EDU
http://Mail.Millennium.Berkeley.EDU/mailman/listinfo/tinyos-2.0wg


More information about the Tinyos-8051wg mailing list