tinyos / tinyos-main

Main development repository for TinyOS (an OS for embedded, wireless devices).
1.41k stars 519 forks source link

Question about RadioAlarm and LocalTimeRadio timer source #323

Closed ucolesanti closed 9 years ago

ucolesanti commented 9 years ago

I'm porting Atmel's SamR21 on TinyOS and right now I'm starting to work on the integrated rf233 transceiver. For several reasons it's better for me not to use the RTC timer (that I use for timemilli) as RadioAlarm and LocalTimeRadio. The timer that I want to use instead, consumes up to 50uA hence, I need to stop it as soon as the mcusleep component calls the sleep function. This, however, brings me to think that, at least, the LocalTimeRadio component won't work correctly since the counter will be intermittently stopped. Probably this does not happen for the RadioAlarm component since I can keep the timer active when the compare/match interrupt is enabled. I had a look to the Iris platform and noticed that the timerMilli is clocked from the async timer 2 while the RadioAlarm and LocalTimerRadio are wired to AlarmOne16C and CounterOne16C respectively that are sourced from timer1, which is synchronous and (I think) it is stopped during sleep. This should be exactly my same situation, so, how does it work?

For example, let assume that I receive a packet, the timestamp will be taken from LocalTimeRadio and then converted in TMilli by the timestamping layer following the formula:

int32_t offset = call PacketTimeStampRadio.timestamp(msg) - call LocalTimeRadio.get(); return (offset >> RADIO_ALARM_MILLI_EXP) + call LocalTimeMilli.get();

If the application reads the timestamp (in milliseconds) immediately after the reception, the timestamp value should be correct since the LocalTimeRadio never stopped in the meanwhile, but if I store the message somewhere and then read the timestamp in a second moment, I suppose the conversion will be no longer valid since "call LocalTimeRadio.get()" will no longer be coherent with the timestamp stored in the message. What am I missing?

Best regards,

Ugo

p.s. I posted the question here since I cannot access to tinyos-help mailing list during these days.

sallai commented 9 years ago

Your assessment is correct. The counter that feeds RadioAlarm and LocalTimeRadio stops when the MCU goes to sleep.

This is not an issue for RadioAlam, because McuSleepC prevents the MCU from going to sleep when an alarm (i.e. output compare) is set, and the radio stack only uses RadioAlarm for delays/timeouts, never for scheduling an alarm to fire at some concrete local time instance.

Reading the timestamps has caveats, though. Everything is fine if the MCU hasn't gone to sleep since the message was received/sent. If it has, the timestamp goes stale.

If you want to convert the timestamp to TMilli (or T32Khz, whatever your RTC timer's resolution is), you must do it immediately after reception/transmission, in the receive()/sendDone() events. If you want to forward a received message, you must do that as soon as possible.

Posting a task from the receive() event will make sure that the scheduler's queue is not empty, so the MCU will not go to sleep, and, in turn, the radio timer will not stop. This would prevent the timestamp from going stale.

ucolesanti commented 9 years ago

Thanks for your reply, I wasn't aware of that. Btw if the Iris platform works fine with that configuration, it should be ok for the R21 too. I'm quite surprised that there is no documentation on that, it might produce several headaches to those that work on time synchronization. In addition it is platform dependent, since as an example, the same issue does not appear on RFA1 based motes. I'm wondering whether there might be some issues when activating some optional layers in the rfxlink stack. I checked the LPL and it seems fine, but for the CSMA layer I'm not so sure since after a CCA request, the cpu waits for an interrupt from the radio...

sallai commented 9 years ago

It works with CCA, because the driver uses alarms to actively poll the channel state, rather than relying on an interrupt from the radio hardware. This keeps the MCU awake. I haven't tested it with PacketLink though. That would probably fail if packets are being resent.

If you're implementing a new driver, I suggest that you use McuPowerOverride.lowestState() to keep the MCU from sleeping if the packet needs to be timestamped, and allow it to go to sleep if no timestamping is requested.

ucolesanti commented 9 years ago

Ahah! now I understand why there is the alarm also in the turnOn command. I was rewriting the rf233 as interrupt based, I will restore the original implementation immediately. Thanks! I don't use McuPowerOverride at all: the samr21 has clock generators that can set an OnDemand bit to force the clock source to stay active even when the sleep function __WFI() is called in McuSleep... very comfortable :) Ugo

cire831 commented 9 years ago

any other issues/questions with this question thread?

ucolesanti commented 9 years ago

Not for me, everything is clear now. Thank you.

Ugo