Контроль напряжения в PalmOS
==== Введение ====
В статье обсуждается что в действительности означает вольтаж и процент зарядки аккумулятора.
==== Время работы устройства на одной зарядке ====
Можно уверенно сказать, что батарея является узким местом в современных карманных устройствах. Если старые монохромные КПК жили неделями на двух ААА батарейках, то современные устройства требуют подзарядки раз в 2-3 дня в зависимости от активности использования.
КПК потребляют электроэнергию во всех состояниях: и в включенном и в выключенном. Необходимость сохранения данных в выключенном виде тоже требует питания, поэтому пальма не пытается работать до полного опустошения аккумулятора, а выключается раньше, оставляя часть заряда на сохранение данных "до ближайшего кредла".
У пальм есть два важных порога разряженности батареи: предупреждающее и критическое. По достижению предупреждающего порога устройсво выдает сообщение пользователю. По достижению критического порога устройство выключается и продолжает сохранять данные.
Пороговые значения железно задаются в прошивке устройств. Как показывает следующее сообщение, http://palmz.4to.info/showpost.php?p=185918&postcount=5 , эти величины берутся с большим запасом, так что уменьшение порогов может продлить время работы устройства.
==== Что показывает пальм? ====
У любого устройства на PalmOS есть возможность показать пользователю текущее напряжение на аккумуляторе и степень его заряженности. Возникает вопрос - а откуда эти числа берутся? Насколько можно им доверять?
В API PalmOS существует функция, получающая информацию о состоянии батареи. Вот ее прототип:
UInt16 SysBatteryInfo(Boolean set, UInt16 *warnThresholdP, UInt16 *criticalThresholdP,
Int16 *maxTicksP, SysBatteryKind* kindP, Boolean *pluggedIn, UInt8 *percentP);
Функция позволяет получить следующие характеристики:
* текущее напряжение в сантивольтах
* зарядка аккумулятора в процентах
* напряжение в сантивольтах, при котором выдается сообщение о разрядке батареи
* напряжение в сантивольтах, при котором устройство отключается
* тип батареи (алкалиновая, Li-Ion, NiMH итд)
* факт подключения к внешней зарядке
* таймаут между последовательными показами сообщения о разрядке
Сразу возникают вопросы: насколько можно верить значени напряжения? Как рассчитывается разряженность батареи? Понятно, что где-то стоит ADC, который преобразовывает напряжение в некоторое число в диапазоне 0-255. А как из этого числа получить вольты с точностью до сотых долей? Понятно, что мини-вольтметру нужна калибрация.
==== Калибрационные поправки ====
В очень старые времена, когда пальмы были на батарейках AAA, никакой встроенной калибрации не было. Существовал хак, позволявший задать корректирующие значения вручную.
У моделей со встроенным аккумулятором погрешности измерений могли привести к порче батареи, поэтому проблему нужно было решать на уровне производителя. Разработчики PalmOS решили эту задачу следующим образом.
Большая часть системного ROM одинакова у всех экземпляров одной модели, но предусмотрена возможность прошивать индивидуальные данные. Эти данные прописываются в специальном формате и называются ROM Token. Каждый токен представляет из себя четырехбуквенное имя и блок данных. Самый известный токен имеет имя num. В него записывается FlashID устройства.
Для калибрации используется токен с именем adcc. В него записываются замеры двух пар (напряжение, значение ADC). Одно значение измеряется для маленького напряжения, а второе для большого. Из двух значений аппроксимацией можно получить значение напряжения с достаточной точностью.
typedef struct {
UInt16 lowCentivolts;
UInt16 lowAToDOutput;
UInt16 highCentivolts;
UInt16 highAToDOutput;
} SysAToDCalibrationTokenType;
Такой способ калибрации используется во всех устройствах от PalmOne у которых вместо ROM стоит перезаписываемая флешка.
==== Уровень разряженности ====
Процент разряда вычисляется как функция от напряжения. Поскольку зависимость разряда от напряжения нелинейная, то воспользоваться линейной аппроксимацией не получится. Поэтому используются предопределенные значения напряжения в 11 точках, соответствующих 0%, 10%, 20%... 100% заряда. Находится интервал, в который попадает текущее напряжение и уже внутри интервала используется линейная аппроксимация.
==== Тип батареи ====
Магическое значение "тип батареи" определяет характеристики батарее: предупреждающее и критическое напряжение, выборки кривой разряда итд. Желающие могут поглядеть на данные, которые определяются для каждого типа батарей и аккумуляторов.
typedef struct {
Word sysBattDataStructVersion; // rev level of the structure (this one is 1)
Word sysBattMildWrngVoltage; // in centivolts-- this is the voltage where the warning dialog appears
Word sysBattSevereWrngVoltage; // in cVolts-- this is the voltage where the critical warning dialog appears
Word sysBattMildWrngPercent; // Mild warning percentage for 3.2 and newer (rev 2)
Word sysBattSevereWrngPercent; // Severe warning percentage for 3.2 and newer (rev 2)
Word sysBattShutdownEnVoltage; // in cV-- This voltage causes us to do a software shutdown
Word sysBattShutdownDisVoltage; // in cV-- This voltage allows us to wakeup from shutdown
Word sysBattMinIRVoltage; // prevents IR from working if below this threshold
DWord sysBattMildWrngTimeout; // in ticks-- this is the number of ticks to wait between displaying warning dialogs
DWord sysBattSevereWrngTimeout; // in ticks-- this is the number of ticks to wait between displaying critical warning dialogs
Word sysBattCritWarnOffDays; // in days-- number of days between mild and severe warnings
DWord sysBattCritWarnOnTicks; // in ticks-- number of ticks between mild and severe warnings
Word sysBattStepsPerVolt; // for scaling A/D to Voltages
SWord sysBattVoltageStepOffset; // for scaling A/D to Voltages
DWord sysBattReserved1; // future use
DWord sysBattReserved2; // future use
Word sysBattVoltageCurve[11]; // in cV; this is the voltage at the specified percentage/10; i.e. if the voltage
// with 20% remaining is 2.5 volts, battVoltageCurve[2] = 250.
} SysBatteryDataStruct, *SysBatteryDataStructP;
==== Соберем вместе ====
Теперь посмотрим на функционирование системы в целом. При старте (и при смене типа батареи) PalmOS выбирает таблицу параметров батареи и калибровочные значения.
С некоторой периодичностью система считывает значение ADC и с помощью данных из параметров батареи и калибрационных поправок происходит вычисление напряжения. По таблице sysBattVoltageCurve вычисляется степень разряженности батареи.
Когда напряжение падает ниже уровня warning, на экран выдается предупреждение. Когда напряжение падает ниже уровня critical, устройство выключается.
Работа с батареей была в модуле, который писал производитель устройства, но функции и системные данные хранились в данных PalmOS 4, поэтому было можно написать универсальный хак, который позволял корректировать времена выключения вручную.
==== PalmOS5. Что нового? ====
В PalmOS5 были внесены изменения в идеологию работы с акумулятором. Что было сделано?
На самом верхнем уровне, уровне m68k API (который все программы и используют), никаких изменений не видно. Все также используется функция SysBatteryInfo.
Ниже идет уровень ARM API. Аналог старой функции SysBatteryInfo теперь называется SysBatteryInfoV40, а новая функция SysBatteryInfo вместо сантивольтов возвращает только проценты разрядки. SysBatteryInfoV40 вызывает SysBatteryInfo которая в свою очередь вызывает HALBatteryGetInfo.
Теперь вопрос - как SysBatteryInfoV40 вычисляет напряжение по процентам? Очень просто: cV = percents * 0.5 + 370. Всегда. То есть напряжение, возвращаемое в программы не имеет никакого отношения к реальному напряжению. Скорее это просто показания "идеального аккумулятора" в вакууме.
Функция HALBatteryGetInfo находится в модуле DAL. Этот модуль пишется разработчиками конкретного устройства. Реализация этой функции возвращает информацию в максимально абстрактном виде, в процентах разрядки батареи. Таким образом у ядра PalmOS (у модуля boot.prc) нет никакой возможности узнать реальное напряжение.
Err HALBatteryGetInfo(UInt16 *warnThresholdPercentP,
UInt16 *criticalThresholdPercentP,
UInt16 *shutdownThresholdPercentP,
UInt32 *warnMaxTicksP, SysBatteryKind *kindP,
Boolean *pluggedInP, SysBatteryState *stateP,
UInt8 *percentP);
Таким образом в PalmOS 5 нет возможности узнать реальное напряжение. Более того, модули DAL могут и не вычислять напряжение вообще, а сразу переводить его из чисел на выходе ADC в проценты. Это усложняет реализацию ручной поправки критических значений. Если раньше было достаточно подкорректировать системную переменную "критическое напряжение", то теперь такой переменной нет. Есть просто проценты зарядки при которых устройство отключается. А сам модуль DAL использует внутренние переменные для определения момента выключения и коррекция процентов ни к чему не приводит.
==== FullPower ====
Разработчики из Mobile Stream ( http://www.mobile-stream.com/ ) таки раскопали место хранения вольтажа. Программа FullPower позволяет изменять критический порог.
Эта программа залезает в переменные модуля DAL и изменяет пороговые напряжения. Поскольку DALы разных устройств работают по-разному, программа может не работать на некоторых устройствах.
==== Ссылки
http://palmz.4to.info/showthread.php?t=21156 - часть информации была заимствована из обсуждения