On Dec 9, 2008, at 2:16 PM, Jeff Chen wrote:
> Hey All,
>
> I'm using TinyOS 2.0.2 and the MicaZ motes (ATmega 128s) to interact
> with the ADCs. I'm trying to connect 3 ultrasound sensors with ADC
> output to the MicaZ through the 51 pin header (pin 36-43 are the 8
> ADC pins from the ATmega128).
>
> After going through the tutorials, code and TEPs, I'm still not
> quite sure how TinyOS abstracts from the physical ADC pin on the
> Atmega all the way to the "Read" function in the HAL. After diving
> into the code, the abstraction seems to go on and on... Also,
> "Read" so far seems only to read a single generic ADC device input
>
> From a project standpoint:
> Where is the "missing link" where the physical ADC pins is connected
> to some higher level of abstraction?
> What elements in the provided code do I need to change (if any
> changes are needed), to make sure i'm hooking up to the right pins
> and can call a separate "Read" on each one?
Sorry for the slow reply.
The low-level micaz ADC implementation only allows a single
outstanding read at any time. When you call Read.read on multiple ADC
clients, then these requests are queued and serviced in order (the ADC
is virtualized).
When you issue a Read, the underlying ADC implementation figures out
which ADC pin you want to sample with the Atm128AdcConfig interface.
When it's ready to handle the request from a given client, it calls
Atm128AdcConfig.getChannel. It also calls Atm128GetRefVoltage, etc.
The logic for doing this is in the file "tos/chips/atm128/AdcP.nc".
This means that ADC-based sensor drivers (as opposed to digital
sensors over a bus) typically instantiate an ADC client
(AdcReadClientC) and wire in a provider of Atm128AdcConfig that will
properly configure the ADC. For example, look at "tos/sensorboards/
mts300/AccelXC.nc":
generic configuration AccelXC()
{
provides interface Read<uint16_t>;
}
implementation {
enum {
ID = unique(UQ_ACCEL_RESOURCE)
};
components AccelReadP,AccelConfigP, new AdcReadClientC() as AdcX;
Read = AccelReadP.ReadX[ID];
AccelReadP.ActualX[ID] -> AdcX;
AdcX.Atm128AdcConfig -> AccelConfigP.ConfigX;
}
This instantiates an AdcReadClientC and wires in AccelConfigP.ConfigX
as the implementation of Atm128AdcConfig.
AccelConfigP is a configuration; its implementation of ConfigX is that
of AccelP:
ConfigX = AccelP.ConfigX;
AccelP, however, is implemented such that it is independent of what
ADC pins the accelerometers are actually on. This is defined by
wiring. So AccelConfigP has another wiring:
AccelP.AccelAdcX -> MicaBusC.Adc3;
AccelP, when one calls ConfigX.getChannel, returns
async command uint8_t ConfigX.getChannel() {
return call AccelAdcX.getChannel();
}
Which is
async command uint8_t Adc3.getChannel() { return 3; }
So, the call chain goes like this:
1) Sensor driver calls Read.read.
2) Read request is enqueued until the ADC is ready (warmed up,
finished outstanding operation. etc.)
3) AdcP calls Atm128AdcConfig to get configuration parameters (AdcP.nc:
83)
4) These calls on AccelXC go to AccelP.
5) AccelP calls AccelAdcX.getChannel (AccelP.nc:31)
6) AccelAdcX.getChannel calls MicaBusC.Adc3.getChannel
7) MicaBusC.Adc3.getChannel returns 3.
Code in the tree typically has several layers of indirection like this
in order to make components more reusable. One issue we ran into with
TinyOS 1.x was that you'd find shadowed copies of modules in order to
modify a few configuration constants. For example, while the
implementation above goes through a few components, the upside is that
one could change the ADC pins yet still reuse all of the modules
unchanged. There's a real tension in the code base between
reusability and simplicity; because lots of folks use TinyOS for all
kinds of new hardware, low-level code tends to favor reusability.
Hope this helps,
_______________________________________________
Tinyos-help mailing list
[email protected]
https://www.millennium.berkeley.edu/cgi-bin/mailman/listinfo/tinyos-help