Embedded HandbookПриложения
Все разделы › XX. Элементы и типовые схемы вокруг МК
STM32G474, STM32F103 · уровень средний · 14 мин чтения
Открыть в интерактивном справочнике

173б. Li-ion на плате: заряд, защита и сколько осталось

Раздел 173 защищал вход платы, 173а считал миллисекунды после пропадания питания. Здесь питание носят с собой: одна литиевая ячейка. От неё плате нужно три вещи — зарядиться, не испортить ячейку и знать, сколько осталось. Первые две делают готовые микросхемы, третью — чаще всего микроконтроллер, и именно там больше всего ошибок: делитель, который врёт на сотни милливольт, опора АЦП, которая садится вместе с батареей, и счётчик тока, который за сутки уходит на проценты.

Опоры: модель ячейки — та же, что в разделе 121 (таблица холостого хода 3,00…4,20 В из 11 точек, R0 = 0,05 Ом, R1·C1 = 0,03 Ом · 1000 Ф, 2,5 А·ч); напряжение заряда 4,2 В — общеизвестная константа этой химии. Что должен знать контроллер заряда — привязки и драйверы зарядных микросхем в дереве Zephyr v4.4.2 (раздел 34а). Токи утечки выводов, VREFINT и предельные режимы — даташиты F103 (DocID13587) и G474 (DS12288) из паков Keil. Всё посчитано моделью на ПК в образе stm-lab:1, каталог _verify/liion173c; код пересчёта собран armclang для G474 и сверен с моделью на ПК. Даташиты конкретных зарядных микросхем и плат защиты здесь не используются — их пороги не приводятся.

Как это называется в документации

Оригинал Перевод
constant current / constant voltage (CC/CV) заряд постоянным током, затем постоянным напряжением
precharge, trickle charge предзаряд малым током
charge termination current ток окончания заряда
re-charge voltage напряжение, ниже которого заряд начинается снова
protection circuit (overcharge, overdischarge, overcurrent) защита ячейки: от перезаряда, переразряда, перегрузки
open-circuit voltage (OCV) напряжение холостого хода
state of charge (SoC) заряд: доля от полной ёмкости
coulomb counting, fuel gauge счёт кулонов, датчик заряда
input leakage current (Ilkg) ток утечки входа
dropout voltage перепад вход-выход стабилизатора

173б.1 Ячейка и что о ней известно заранее

Для прошивки ячейка — это схема из раздела 121: источник напряжения холостого хода, зависящего от заряда, последовательное сопротивление R0 и RC-цепочка. Под током напряжение на выводах отличается от холостого на I·R0 и на напряжение цепочки, которая успокаивается с постоянной R1·C1 = 30 с.

Из этой схемы сразу видны три числа, на которых держится весь раздел.

4,2 В — предел заряда (общеизвестная константа для этой химии; у других литиевых химий свой). Выше заряжать нельзя, и выдерживает этот предел зарядная микросхема, а не программа.

4,2 В выше абсолютного максимума питания. И у F103, и у G474 предел по VDD — 4,0 В (у G474 он включает VDDA, VBAT и VREF+). Ячейку на питание кристалла напрямую не вешают: между ними стабилизатор (173б.6).

Таблица холостого хода пологая. Между 30 и 50 % заряда напряжение растёт всего на 0,5 В на всю шкалу — 0,20 % заряда на милливольт; у нижнего края (0…10 %) — в девять раз круче, 4,5 В на шкалу. Всё, что вносит в измерение напряжения десяток милливольт, в середине шкалы — уже проценты заряда.


173б.2 Заряд CC/CV

Заряд идёт в два этапа. Сначала постоянный ток — пока напряжение на выводах не дойдёт до 4,2 В. Потом 4,2 В держат постоянными, и ток сам падает; когда он опустится до тока окончания, заряд выключают. Очень разряженную ячейку перед этим подтягивают малым током — предзаряд; в модели он не показан.

Заряд ячейки 2,5 А·ч током 0,5C: напряжение на выводах растёт от 3,06 до 4,2 В за 113 минут, заряд к этому моменту 94,1 процента; дальше напряжение держится 4,2 В, ток падает с 1,25 А до 0,125 А, заряд доходит до 99,4 процента на 129,4 минуте; при токе 1C 4,2 В достигается на 52,2 минуте при заряде 87 процентов

Модель — ячейка из 121, от нуля заряда:

Ток заряда 4,2 В на выводах Заряд в этот момент Конец при 0,1C Конец при 0,05C
0,5C = 1,25 А 113,0 мин 94,1 % 124,4 мин, 98,8 % 129,4 мин, 99,4 %
1C = 2,5 А 52,2 мин 87,0 % 69,5 мин, 98,8 % 74,5 мин, 99,4 %

Что из неё видно.

До 4,2 В на выводах ячейка не полная. Под током 1,25 А выводы выше холостого на I·R0 и на RC-цепочку, и 4,2 В приходит при 94,1 % заряда; при 2,5 А — уже при 87,0 %. Остальное добирает этап постоянного напряжения.

Вдвое больший ток — не вдвое быстрее. Этап постоянного тока короче вдвое с лишним (113,0 → 52,2 мин), но этап постоянного напряжения длиннее: 11,4 → 17,3 мин до 0,1C.

Конечный заряд задаёт ток окончания, а не ток заряда. При 0,1C оба заряда кончаются на 98,8 %, при 0,05C — на 99,4 %: в конце ток мал, и выводы выше холостого только на этот ток, умноженный на R0 + R1.

Токи 0,5C и 1C и ток окончания здесь — примеры для модели. Настоящие пределы для ячейки — в её паспорте, а в зарядной микросхеме они задаются резисторами или регистрами.


173б.3 Зарядная микросхема и защита ячейки

Что должен знать о ячейке контроллер заряда, хорошо видно по описанию батареи в Zephyr (dts/bindings/battery/battery.yaml): ток предзаряда, ток окончания заряда, наибольший ток постоянного тока, наибольшее напряжение постоянного напряжения, напряжение повторного заряда, ёмкость и таблица холостого хода из 11 точек — от 0 до 100 % через 10 %, ровно как в модели 121. А что микросхема сообщает о себе — по программному интерфейсу зарядных устройств Zephyr (include/zephyr/drivers/charger.h):

Что Состояния в charger.h
идёт ли заряд заряжается, не заряжает, полная
каким током предзаряд (TRICKLE), быстрый (FAST), обычный, щадящий (LONGLIFE)
исправность перегрев, холодно, прохладно, тепло, горячо, перенапряжение, истёк таймер безопасности, нет батареи

Отсюда всё, что делает хорошая зарядная микросхема: предзаряд глубоко разряженной ячейки, CC/CV с точным пределом напряжения, окончание по току, таймер безопасности на случай, если ток так и не упал, заряд только в разрешённом диапазоне температур по датчику ячейки, повторный заряд после саморазряда. Программе остаётся читать состояние — по выводам «идёт заряд» и «есть вход» у простых микросхем или по I²C у тех, что с регистрами, — и не мешать.

Защита ячейки — отдельная плата или микросхема прямо на ячейке с двумя ключами в минусовом проводе. Она размыкает цепь при перезаряде, при переразряде, при перегрузке по току и при коротком замыкании. Это последняя линия, а не рабочий режим: зарядная микросхема должна закончить заряд раньше, чем сработает защита от перезаряда, а прошивка — выключить нагрузку раньше, чем сработает защита от переразряда. Пороги у каждой микросхемы защиты свои и берутся из её даташита; здесь они не приводятся.

Почему не заряжать «сам» — ШИМ, ключ и АЦП микроконтроллера? Предел 4,2 В должен держаться, даже когда прошивка зависла или перезагружается. Сторожевой таймер (раздел 12) перезапустит программу, но ключ в это время может остаться открытым. Зарядная микросхема держит предел сама.


173б.4 Напряжение ячейки: делитель, утечка и опора

4,2 В на вход АЦП не подать — питание 3,3 В, значит делитель. Раздел 166.5 разобрал, сколько такой делитель тратит и как его отключать ключом. Здесь — сколько он врёт. Ток утечки входа течёт через сопротивление делителя; приведённая к ячейке ошибка — ток утечки, умноженный на верхний резистор. Предельные токи утечки из даташитов: у F103 ±1 мкА (обычные выводы), у G474 ±100 нА (выводы FT) и ±150 нА (TT):

Делитель Ток делителя при 4,2 В F103, ±1 мкА G474, ±150 нА
1 МОм / 1 МОм 2,1 мкА ±1000,0 мВ — больше всей шкалы ±150,0 мВ, 30,0 % заряда
100 кОм / 100 кОм 21,0 мкА ±100,0 мВ, 20,0 % заряда ±15,0 мВ, 3,0 % заряда
10 кОм / 10 кОм 210,0 мкА ±10,0 мВ, 2,0 % заряда ±1,5 мВ, 0,3 % заряда

Проценты — в самом пологом месте таблицы, 0,20 % на милливольт. Это предельные значения, на конкретном кристалле утечка обычно меньше, но закладываться приходится на них. Делитель 1 МОм, который 166.5 брал за малый ток, на F103 годится только для грубого «жив/сел»; для оценки заряда нужны сотни килоом с ключом и конденсатором у входа (50.6) — или меньше.

Опора садится вместе с батареей. Опора АЦП — VDDA, то есть выход стабилизатора 3,3 В. Пока ячейка выше 3,35 В (стабилизатор с перепадом 50 мВ), всё честно. Ниже стабилизатор выходит из режима, VDDA идёт за батареей, и пересчёт «код × 3,3 В / 4095» начинает врать — ровно тогда, когда знать напряжение важнее всего:

Ячейка VDDA Код делителя «× 3,3 В» Ошибка Через VREFINT
4,00 В 3,30 В 2482 4,000 В 0 мВ 3,999 В
3,50 В 3,30 В 2172 3,501 В +1 мВ 3,500 В
3,30 В 3,25 В 2079 3,351 В +51 мВ 3,300 В
3,20 В 3,15 В 2080 3,352 В +152 мВ 3,198 В
3,00 В 2,95 В 2082 3,356 В +356 мВ 3,000 В

Код делителя почти не меняется: ячейка и опора падают вместе. Прибор показывает «3,35 В» до самого выключения. Лечится как в 14.9: в том же опросе мерить VREFINT и пересчитывать опору по заводскому коду. У G474 он лежит по адресу 0x1FFF 75AA и снят при VDDA = 3,0 В (DS12288, таблица 6):

uint32_t vbat_mv(uint16_t bat_code, uint16_t vref_code, uint16_t cal)
{
    uint64_t num = (uint64_t)DIV_NUM * bat_code * CAL_MV * cal;
    return (uint32_t)((num + (uint64_t)vref_code * 4095u / 2u) / ((uint64_t)vref_code * 4095u));
}

Функция собрана armclang для G474 и gcc для ПК; на кодах из модели она даёт те же 3999, 3500, 3300, 3198 и 3000 мВ. У F103 заводского кода нет (14.9) — только номинал VREFINT с его разбросом.


173б.5 Сколько осталось: по напряжению и счётом кулонов

По напряжению — таблица холостого хода наоборот:

uint32_t soc_permille(uint32_t mv)
{
    if (mv <= ocv_mv[0])
        return 0;
    for (unsigned k = 0; k < 10; k++)
        if (mv <= ocv_mv[k + 1])
            return 100u * k + 100u * (mv - ocv_mv[k]) / (uint32_t)(ocv_mv[k + 1] - ocv_mv[k]);
    return 1000;
}

3700 мВ — 460 промилле, 3710 мВ — уже 480: 10 мВ дают 2 % заряда. Годится это только после покоя: под током выводы ниже холостого на I·R0 и на цепочку, и в 121.2 ошибка таблицы под нагрузкой доходила до десятков процентов. Так её и используют — утром, после ночи без нагрузки.

Счётом кулонов — интеграл тока через шунт. Пример: шунт 50 мОм, ОУ ×16 (раздел 44), АЦП 12 бит — 1,007 мА на код. Ошибки этого счётчика — не в шаге, а в том, что копится:

Что Ошибка тока За сутки, от 2,5 А·ч
смещение ОУ ±1,5 мВ (44.2), без калибровки 30,0 мА 28,8 %
после калибровки нуля: дрейф ±10 мкВ/°C × 40 °C = 400 мкВ 8,0 мА 7,7 %
сон 20 мкА — меньше шага, счётчик его не видит 0,02 мА 0,48 мА·ч

Счётчик на встроенном ОУ хорош для тока в сотни миллиампер и коротких отрезков, но за сутки уходит на проценты. Для малых токов берут шунт больше или усилитель с малым смещением.

Выборка и импульсы. Нагрузка 5 мА с радиоимпульсом 200 мА на 3 мс раз в секунду — в среднем 5,600 мА. Счётчик с выборкой 10 раз в секунду:

Выборка Насчитал Ошибка
в такт с импульсами, мимо них 5,000 мА −11 %
в такт с импульсами, в них 25,000 мА +346 %
в случайные моменты, 36 000 за час 5,583 мА −0,3 %

Если таймер выборки и расписание радио идут от одного такта, счётчик может годами не видеть импульсов или видеть только их. Выборка должна быть несвязанной с нагрузкой — или непрерывной с усреднением.

Старение. Ёмкость ячейки со временем падает; в 121 постаревшая ячейка имела на 12 % меньше паспортной. Счётчик с паспортной ёмкостью в момент настоящей пустоты покажет 12 %.

Отсюда рецепт, который 121.8 собрал в фильтр Калмана, а в простом виде выглядит так: счёт кулонов между опорными точками, таблица по напряжению после покоя, 100 % — по окончании заряда по току (173б.2: при 0,05C это 99,4 %), ёмкость — по полным циклам.


173б.6 Питание МК от 3,0–4,2 В

Раздел 55.3 посчитал, до какого заряда стабилизатор 3,3 В держит выход: с перепадом 0,2 В — до 85 % израсходованной ёмкости, с 50 мВ — до 92 %. Модель под током 50 мА даёт то же: 84,6 % и 92,1 %. Дальше выход идёт за ячейкой минус перепад, и микроконтроллер работает до своего порога сброса (173а.3) — у F103 спад питания 1,88 В, намного ниже конца разряда ячейки.

Сколько теряет линейный стабилизатор? Его КПД — выход, делённый на вход: у полной ячейки 3,3 / 4,2 = 78,6 %. Но большая часть ёмкости отдаётся на полке 3,6–3,8 В, и за весь разряд при 50 мА выходит 88,4 % (перепад 50 мВ) и 88,0 % (0,2 В). Импульсный понижающе-повышающий (58.8) берут, когда нужны не эти 12 %, а 3,3 В до самого конца разряда или ток больше сотен миллиампер.

Если прибор питается и от USB, и от ячейки через два диода — перепад диодов и обратный ток в ячейку разобраны в 169.6: ячейкой должен управлять контроллер заряда, а не утечка диода.


173б.7 Грабли

Заряд оборвали на 4,2 В. Этап постоянного тока закончился, а ячейка заряжена на 94,1 % (при 1C — на 87,0 %). Окончание — по току, а не по напряжению.

Прошивка сама заряжает ячейку ключом. Зависла — и ключ остался открытым. Предел 4,2 В держит зарядная микросхема.

Ячейка на VDD напрямую. 4,2 В — выше предела 4,0 В у F103 и G474.

Делитель 1 МОм на F103. Утечка ±1 мкА — ±1 В на ячейке. Сотни килоом с ключом или десятки килоом.

Прибор показывает 3,35 В до самого выключения. Опора АЦП — выход стабилизатора, который уже вышел из режима. Мерить VREFINT в том же опросе.

Заряд по напряжению под нагрузкой. Выводы ниже холостого на I·R0 и цепочку. Таблица — только после покоя.

Счётчик тока уходит на проценты в сутки. Смещение и дрейф ОУ: 30 мА без калибровки нуля, 8 мА после неё. Опорные точки — конец заряда и покой.

Счётчик не видит радиоимпульсов. Выборка в такт с нагрузкой. Брать отсчёты несвязанно или непрерывно с усреднением.

Через год батарея «садится на 12 %». Ёмкость постарела, а счётчик делит на паспортную. Уточнять ёмкость по полным циклам.


173б.8 Итоги

Полные исходники

bat173c.c — напряжение ячейки и заряд по таблице целыми числами.

/* 173б: напряжение ячейки и заряд по таблице — целыми числами, для STM32G474.
   Делитель пополам; опора АЦП — VDDA после стабилизатора, поэтому её узнаём по VREFINT
   и заводскому коду, снятому при 3,0 В (DS12288, табл. 6). Таблица — модель ячейки из раздела 121. */
#include <stdint.h>

#define VREFINT_CAL_ADDR ((const volatile uint16_t *)0x1FFF75AAu)
#define CAL_MV           3000u     /* заводской код снят при VDDA = VREF+ = 3,0 В */
#define DIV_NUM          2u        /* делитель 100 кОм / 100 кОм */

static const uint16_t ocv_mv[11] = { 3000, 3450, 3550, 3620, 3670, 3720, 3780, 3850, 3930, 4030, 4200 };

/* Напряжение ячейки, мВ: код делителя и код VREFINT из одного опроса АЦП. */
uint32_t vbat_mv(uint16_t bat_code, uint16_t vref_code, uint16_t cal)
{
    uint64_t num = (uint64_t)DIV_NUM * bat_code * CAL_MV * cal;
    return (uint32_t)((num + (uint64_t)vref_code * 4095u / 2u) / ((uint64_t)vref_code * 4095u));
}

/* Заряд, промилле, по напряжению холостого хода: верно только после покоя (раздел 121.2). */
uint32_t soc_permille(uint32_t mv)
{
    if (mv <= ocv_mv[0])
        return 0;
    for (unsigned k = 0; k < 10; k++)
        if (mv <= ocv_mv[k + 1])
            return 100u * k + 100u * (mv - ocv_mv[k]) / (uint32_t)(ocv_mv[k + 1] - ocv_mv[k]);
    return 1000;
}

uint32_t vbat_now_mv(uint16_t bat_code, uint16_t vref_code)
{
    return vbat_mv(bat_code, vref_code, *VREFINT_CAL_ADDR);
}

Дальше: раздел 173в «Открытая BMS на STM32: разбор Libre Solar — измерение ячеек, балансировка, защита и SOC».

Открыть в интерактивном справочнике