view doc/Deep-sleep-support @ 929:ab771ce34fac

rvinterf/lowlevel/format.c: get rid of static fmtbuf
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 23 May 2023 05:56:08 +0000
parents 19cabe7c8e08
children
line wrap: on
line source

All standard phones and modems based on the Calypso chipset from TI implement
several different power saving modes, called sleep modes, and one of these sleep
modes has a profound impact on the operation of the externally visible UART
interfaces provided by the device.  The power saving mode in question is called
deep sleep, and the phone or modem can only enter this deep sleep mode when it
is in the so-called idle state, meaning that it is camped on a cell and is ready
to receive incoming calls, messages or GPRS packets - deep sleep cannot be
entered while in an active call or in the middle of packet data transfer.  When
a Calypso GSM device is idle with deep sleep enabled, it will only wake up at
preprogrammed intervals to listen on the paging channel, and will stay in deep
sleep in between these paging windows.  Calypso GSM devices also enter deep
sleep when they are completely idle with no radio network connection.

When a Calypso GSM device enters deep sleep, the main VCXO or VCTCXO that runs
at 13 or 26 MHz and provides all other clocks in normal operation is completely
stopped (powered off), and the only clock that remains running is the 32.768 kHz
watch crystal oscillator.  The preprogrammed wakeup timing (waking up to listen
on the paging channel at the right time) is driven by this 32.768 kHz clock, but
the Calypso can also be woken up ahead of the programmed time by an external
interrupt such as a button press on the phone keypad.

This deep sleep mode provides a very important power saving measure (the
extremely low current draw that is achieved during deep sleep is not possible
without stopping the fast clock), but it presents a real challenge for the
external UART interfaces.  Consider what happens when an external host sends
some characters to one of Calypso's UARTs (either the AT command interface or
RVTMUX) while the GSM device is in deep sleep.  In normal operation a UART
requires a clock of 16x the baud rate (some vendors' UARTs can make do with
only 8x the baud rate) in order to receive asynchronous incoming characters,
and in the Calypso these UART clocks come from the 13 MHz master clock - but
that master clock is stopped during deep sleep!

Calypso UARTs have some special asynchronous (non-clock-dependent) logic that
causes a wakeup signal to be generated if some incoming traffic is detected at
a UART while in deep sleep, but the first character that triggers this wakeup
will be lost: the asynchronous logic can detect that there is "something
happening" on the UART RxD line, but it cannot catch the actual byte content
without a clock: the *only* clock available during deep sleep is 32.768 kHz,
and even at 9600 baud one would need a clock several times faster than this
rate in order to receive and register an incoming byte.  Furthermore, wakeup
from deep sleep takes a non-trivial length of time, thus if someone tries to
send lots of data to a Calypso UART while in deep sleep, quite a bit more than
just the first character will be lost: I did some experiments to characterize
the delay which needs to be inserted between the first "sacrificial" wakeup
character and the subsequent character which is expected to be received
correctly, and 40 ms wasn't enough, whereas 60 ms did the trick.

So how can one have reliable communication with a Calypso GSM device over a
UART if the GSM device goes into and out of deep sleep at times which are
unpredictable to the external host and if sending characters to the Calypso
during deep sleep causes those characters to be lost?  The solution involves a
special protocol:

1) On the Calypso side, TI's reference firmware implements a UART activity
timer: every time some characters are received at a UART, the timer is reset to
10 s, and until that timer expires, the GSM device is not allowed to go into
deep sleep.

2) Host systems sending command traffic to Calypso modems need to keep track of
how much time has elapsed since the last time they sent something to the modem,
and if enough time has elapsed that the modem is now allowed to enter deep
sleep, the host needs to perform a precautionary wakeup transmission before the
actual desired one.

What is a precautionary wakeup transmission?  The idea is to send something to
the modem can be either accepted or lost by the latter: if the modem happens to
be awake at the time, the transmission will be received normally, and if the
modem is in deep sleep, the transmission will be lost but will cause the modem
to wake up and start the 10 s UART activity timer.  Our FC host tools currently
use the following wakeup transmissions:

* On the AT command channel we send A-delay-T-delay-CR, i.e., AT and a carriage
return (3 characters total) with delays inserted in between; each of the two
delays is currently set to 30 ms based on empirical testing.  We expect the
response to be either AT<newline>OK<newline> (echo of command followed by OK
response) if the modem was awake or just <newline>OK<newline> if we woke it up:
if we are waking the modem from deep sleep, our initial characters will trigger
the wakeup sequence but will themselves be lost, and the modem is expected to
be awake with UARTs working by the time the CR comes in; we make use of a quirk
of TI's AT command interpreter implementation in that sending a CR by itself
produces a <newline>OK<newline> response.

* On the RVTMUX interface we send a string of 64 zero bytes followed by 100 ms
of delay; it is certainly overkill, but this approach was implemented back in
2013 (near the very beginning of FreeCalypso) and has worked without any
problems ever since, hence we are not changing it.

In the case of RVTMUX, our serial communication engine through which everything
funnels is rvinterf.  Rvinterf will do the "wakeup shot" the first time it sends
anything to the target, and for all subsequent transmissions it will consider
the time since the last transmission: if it is greater than a set threshold
(7 s by default), the wakeup shot is sent again.  Thus there will be no
extraneous wakeup shots and associated delays during reasonably continuous
back to back communication, but the wakeup shot delay will be incurred if
rvinterf is killed and restarted or if a non-trivial pause occurs in the
communication flow.

In the case of AT commands, our fcup-* tools described in the User-phone-tools
article go through a back-end program called fcup-atinterf which does the serial
talking, and the latter helper program is responsible for the wakeup logic.
However, fcup-atinterf is not a daemon like rvinterf, it is run anew for every
fcup-* user command, hence every fcup-* command currently involves the wakeup
delay step.  It is certainly inefficient, but the underlying philosophy values
reliability over efficiency.

The one remaining use case which has not been addressed at all yet is the GSM
07.10 MUX; the current plan is to investigate it after the fc-host-tools-r9
release and after we get FCDEV3B V2 boards which will hopefully be free from
the sleep mode bug that afflicts FCDEV3B V1.