[Tinyos-devel] TEP 101 - the proposal for ADC interfaces
yuvalpeduel at digitalsun.com
Mon Feb 14 13:33:26 PST 2005
I first heard about this proposal at Friday's TinyOS Technology Exchange
and was disappointed
at what was outlined there. I then read the TEP and became even more
My concerns fall into two areas:
1. As someone who does not know anything about the external ADCs or the
MSP 430, I am very concerned that any Hardware Independent Layer spec be
written in such a way that I as an ignorant user can safely write
platform-independent code and that I as a developer on a new platform
can write a compatible implementation.
2. As someone who has spent a good bit of time using the Atmel Atmega
128 and its ADC unit, I'm very concerned about the fundamental approach
this proposal is taking as it seems to be extending the TinyOS 1.1.x
interface and implementation rather than looking forward to the HAA model.
Let's start with the HIL. This is supposed to be a hardware independent
interface, yet understanding it seems to require detailed understanding
of the MSP 430. Looking at this spec, I haven't the foggiest notion of
how I would go about writing an application. Under what circumstances
would I use reserve(), reserveContinuous(), and unreserve()? Under what
circumstances would I use ADCMultiple as opposed to ADCSingle? What
error conditions might I encounter and what error returns correspond?
Note also that as a developer of a compatible implementation, I would
have to understand all of these issues thoroughly. I could not just play
safe by using ADCSingle and ignore the "reserve" issues. This means that
any HIL interface must be extremely well documented.
On to the Atmel Atmega 128, its ADC, your interfaces, and the current
We've been using TinyOS since before the 1.1.0 release. In the first
version we used, a getData call would check to see if the ADC was free
and start the conversion if it was, but return FAIL if it wasn't. Very
simple and very close to the hardware.
When we upgraded to a 1.1.x version of TinyOS, we found a new
implementation with the same interface. This implementation tried to
queue requests. Therefore, it introduced two problems:
1. There was no way of knowing whether a "successful" request was, in
fact, currently being executed. This made it impossible to know whether
the results were actually timely (an important issue in such
applications as using the ADC to control radio transmission in the
context of squelch).
2. When switching from a single-ended to a differential channel, the
Atmel spec suggests waiting 125usec or throwing away a sample or two.
With the original interface, if we wanted to read a differential
channel, we could start a read at the task level and then at the
dataReady signal throw that result away and start another, secure in the
knowledge that no other code could get in to start a sample on a
different channel. With the new implementation, another channel may have
been requested before the dataReady, so even with the second request at
the dataReady level, there was no guarantee that the two samples on the
differential channel would be adjacent and hence result in a usable value.
As a result, we do not use the standard 1.1.x ADCM but have ported the
old one (and cleaned it up). (Note the implications for relying on the
code to understand the interface, a point related to the need for
thorough documentation of HIL interfaces.)
Another concern with the current implementation is the handling of ADC
Enable. The 1.1.x HPLADCC code keeps ADC Enable off by default. It turns
it on at each getData, and then turns it off again at each dataReady.
The result is that each ADC sample takes about twice as many cycles as
it should, again an issue in such applications as CC1000 radio squelch
Then there is the issue of "binding". Different hardware platforms use
different voltage references. Some, like the mica, use external
references; others use one of the two internal references. When one
switches between one reference and another, a settling period is
required (as when switching from a single ended to a differential
input), though one might also argue that this generally makes no sense.
More to the point, when the current code loads the hardware, it uses the
value in the "binding" to specify the voltage reference. And when an
application specifies the binding, it must, therefore, also specify the
voltage reference. While this may be suitable at the HPL interface
level, it clearly is not at the ADCControl level.
You note that the HPL interface should give access to the registers. The
current HPLADC interface does not. For example, there is no way to reset
the ADC in the middle of a conversion (important when going to sleep, as
well as a safety net in case of errors); there is no interface to check
if it is busy; etc. Similarly, there is no way to get around the ADC
Enable problem other than by writing a replacement for HPLADCC.
In summary, none of the existing Atmel Atmega 128 ADC interfaces are
well defined, and none of them are really suited as either an HPL or as
an HAL interface. And even if the interfaces were adequately defined,
their implementations would have to be changed enough so that much
existing code would have to be rethought, if not rewritten.
Thus from what I can see, the idea that you want "To maintain
compatibility with the existing code" makes no sense at all if you are
serious about "aligning the ADC abstraction with the three-layer
Hardware Abstraction Architecture (HAA)".
I think the HAA is a good idea and I'm glad to see it as your goal. ADCs
are idiosyncratic enough that it is going to be very difficult, if not
impossible, to actually integrate every possible, or even every
reasonable ADC hardware and usage mode into such a model. But surely we
can do much better if we do not tie ourselves to legacy code, and,
instead, start with what we have learned about how ADC code should be
written? If that requires throwing out the existing implementations, or
at least letting them continue running only on TinyOS 1.x rather than
2.x too, so be it.
More information about the Tinyos-devel