Заряжаем ноутбук Dell XPS от любого адаптера питания
Не так давно я решил произвести обновление своего ноутбука и приобрёл на Ebay Dell XPS 13 9350. Цена вышла очень приятная (в 2 раза дешевле, чем в отечественных магазинах, отлично проходило в лимит 1000 евро, при этом комплектация максимальная, а состояние «New»). Ноутбук мне очень понравился (стоит ли говорить — туда отлично встал Linux без каких-либо танцев с бубном кроме перевода SSD из режима RAID в режим AHCI одной галкой в UEFI). И я даже отлично попользовался им 2 недели, а потом…, а потом блок питания ноутбука перестал работать.
Конечно, я немного огорчился, но блок питания вещь не такая уж дорогая (как относительно стоимости ноутбука, так и относительно выгоды от заказа на ebay), а пытаться что-то выяснять с продавцом из-за такого пустяка — лишняя трата времени, так что я отправился в местный компьютерный магазин. Тут меня ждало первое разочарование — с подходящим штекером БП не нашлось. Я отправился в следующий магазин, но и там меня постигла неудача. В таком случае я рассудил, что можно позаимствовать штекер и кусочек провода от неисправного БП и сделать переходник, поэтому приобрёл произвольный БП с подходящей мощностью и выходным напряжением, а также совместимый с ним штекер (не резать же провод у нового БП).
Однако всё было не так просто…
Когда я вернулся домой, меня ждало второе разочарование — после разреза провода оригинального БП оказалось, что там целых 3 жилы (2 «экрана» и центральный провод). У меня не осталось выбора — я распилил оригинальный БП (его конструкция такова, что альтернатив не особо то было). Исходя из обозначений на его печатной плате выяснилось, что внешний «экран» это GND, внутренний «экран» это VOUT (то есть 19 вольт), а центральный провод — ID.
Для начала я подключил GND и VOUT кабеля соответствующим образом к новому БП, а ID пин остался висеть в воздухе. Ноутбук увидел блок питания и перешёл на внешнее питание, однако при загрузке выдал предупреждение, что адаптер питания какой-то непонятный и батарея «может не заряжаться». Обычно на практике такая фраза означает, что она не «может», а обязательно не будет заряжаться. Так и вышло.
Разумеется, мириться с подобной ситуацией я не собирался. Самый очевидный вариант — купить оригинальный адаптер Dell. Однако, во-первых, это ожидание доставки (в моём городе таких нет), во-вторых, дополнительные финансовые затраты (я уже купил один блок питания, а оригинальный стоит ещё и дороже в 2 раза), в-третьих, приобретённого адаптера вполне достаточно для полноценной работы ноутбука (он даже немного мощнее), зачем его менять. В то же время можно освежить свои знания микроконтроллеров и получить полезный опыт.
Первое куда я отправился — был Google. По запросу «dell power adapter id» я нашёл статью. В принципе, на этом можно было остановиться, однако, во-первых, мой ноутбук более новый и даже другой линейки, так что потенциально Dell мог что-то изменить, а, во-вторых, автор использовал MSP430, которого опять же нет в моём городе и надо заказывать и ждать.
Для начал я произвёл первый эксперимент — соединил GND и ID пины старого адаптера с соответствующими линиями кабеля (при этом питание по-прежнему поступало от нового), а затем подключил его к ноутбуку. Эксперимент удался — ноутбук распознал адаптер как совместимый и начал заряжаться. Таким образом я получил возможность заряжать аккумулятор, пока не найду более оптимальное решение. При этом определение параметров адаптера происходит лишь в момент подключения, после этого плату старого адаптера можно отключить.
Из статьи следует, что в адаптере питания установлена микросхема с интерфейсом 1wire, что отлично соотносится с количеством линий, используемых для идентификации. К счастью, у меня имеется Bus Pirate, который позволяет удобно общаться с устройствами в том числе по этому протоколу. Поскольку, земли USB и адаптера питания соединены, когда последний подключен, мне осталось лишь подключить линию ID к пину MOSI BusPirate (именно он используется в режиме 1wire). Кстати, ещё я приметил, что ноутбук подтягивает линию ID к 3.3В, что потом повлияло на выбор напряжения питания микроконтроллера-эмулятора.
Открываем любую программу для работы с последовательным портом (BusPirate отображается в системе именно как он) и вводим команду «m 2» для переключения в режим 1wire, а затем выполняем команду »[ 0×33 r:8». Данная команда реализует сброс шины, отправляет байт 0×33 (считать адрес единственного устройства на шине), а затем принимает 8 байт.
В результате я получил: 0×09 0×52 0×8D 0xED 0×65 0×00 0×00 0xEF, что соответствует 1wire EEPROM на 1024 бит (128 байт), исходя из первого байта адреса, который определяет семейство. Это может быть, например, DS2502 (такое же предположение сделал и автор статьи выше, что показывает, что мы на верном пути).
Открываем даташит (или читаем англоязычную статью внимательнее) и узнаём, что для чтения используется команда 0xF0, за которой следует 2 байта смещения (сначала младший байт, затем старший). Пробуем эту команду на нашем подопытном:»[ 0xCC 0xF0 0×00 x00 r:130». 0xCC перед командой означает «игнорировать адрес» и позволяет не указывать адрес устройства (тогда бы надо было отправить байт 0×55 и за ним 8 байт адреса), если оно одно на шине. Ответом является последовательность из 130 байт:
0x8D
0x44 0x45 0x4C 0x4C 0x30 0x30 0x41 0x43 0x30 0x34 0x35 0x31 0x39 0x35 0x30 0x32
0x33 0x43 0x4E 0x30 0x43 0x44 0x46 0x35 0x37 0x37 0x32 0x34 0x33 0x38 0x36 0x35
0x51 0x32 0x37 0x46 0x32 0x41 0x30 0x35 0x3D 0x94 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xCA
Первый байт — CRC-8 от 3 байт команды, затем следует 128 байт данных из EEPROM, последний байт — CRC-8 от данных EEPROM. Можно воспользоваться любой утилитой проверки CRC-8, чтобы убедиться, что она верная. Это окончательно доказывает, что мы верно определили требуемый способ взаимодействия с адаптером питания.
Этот массив байт станет гораздо понятнее, если трактовать байты в нём как ASCII коды (кроме байт 0×94 и последующих 0xFF — значение байта 0×94 мне не известно, это может быть какая-нибудь контрольная сумма, 0xFF — свободное место в EEPROM).
DELL00AC045195023CN0CDF577243865Q27F2A05=
Последовательность DELL подтверждает, что это именно строка идентификации адаптера данного производителя, последовательность AC, вероятно, указывает тип адаптера (Dell также имеет в своём ассортименте портативные зарядные устройства). 045 — максимальная мощность в ваттах, 195 — напряжение в десятых долях вольта (19.5В), 023 — максимальная сила тока в десятых долях ампера (2.3А). Возможен вариант, что напряжение задаётся в сотых долях (1950), а ток не имеет ведущего нуля. Остальные байты похожи на что-то вроде серийного номера (при этом CN — код страны производителя). В статье на hackaday указано, что ноутбук считывает лишь байты, содержащие данные о мощности, напряжении и токе, однако на всякий случай лучше скопировать всё содержимое EEPROM (ведь поведение может отличаться от модели к модели).
Теперь у нас имеется 2 варианта действий. Можно купить готовую микросхему 1wire eeprom (ту же самую DS2502), либо выпаять имеющуюся из адаптера питания. На самом деле это предпочтительный вариант, ибо он гарантированно сработает, к тому же обладает минимальной трудоёмкостью и максимальной компактностью (можно легко уместить всё в штекер питания). Однако я пошёл по более сложному пути. Выпаивать микросхему из БП мне не хотелось, потому что я боялся её повредить и вообще лишиться возможности заряжать аккумулятор. Приобретать новую — опять же ждать доставки, пусть даже несколько дней.
Поэтому я пошёл по тому же пути, что и автор статьи с hackaday — я реализовал 1wire slave на базе микроконтроллера. Правда, взял более распространённый и компактный ATTINY85. Заработала моя прошивка не сразу, пришлось потратить какое-то время на отладку (BusPirate очень помог тем, что я мог эмулировать запросы ноутбука с его помощью), но в результате получилось как-то так — github.com/KivApple/dell-charger-emulator. Объём кода вышел небольшой — 1660 байт ПЗУ и 22 байта ОЗУ, поэтому можно использовать другие МК той же серии — ATTINY45 или ATTIN25, только подредактировать параметр -mmcu в Makefile. Использование других микроконтроллеров может потребовать модификации исходного кода.
При прошивке следует настроить фьюзы на использование внутреннего RC-генератора на 8 МГц без делителя. При желании можно также подключить внешний кварцевый резонатор на 8 МГц (потребуется изменить фьюзы соответствующим образом), но лично у меня всё работает и без него.
ID линию штекера следует подключить к пину PB2 (именно он обладает функционалом внешних прерываний на ATTINY85), земли соединить. Сначала я попробовал использовать паразитное питание, но несмотря на применение режима энергосбережения, его недостаточно, поэтому нужно внешнее. 19В явно многовато для AVR, поэтому его нужно понизить (до 3.3В, потому что ноутбук ожидает именно такие уровни). Поскольку энергопотребление очень мало (1 мА большую часть времени, 3 мА в течении нескольких миллисекунд в моменты запроса, оценка очень грубая по даташиту на МК, в реальности скорее всего ещё меньше), можно ограничиться линейный стабилизатором. Я применил 78L33. При этом я не ставил стабилизирующие конденсаторы на питание для увеличения компактности, однако в случае проблем рекомендую их поставить.
К сожалению, результат так и не поместился в корпус штекера, поэтому получился не очень презентабельный (но за счёт большого количества слоёв синей изоленты достаточно жёсткий, чтобы минимизировать вероятность выхода из строя из-за механических повреждений).
Ноутбук подвоха не заметил и радостно начал заряжаться, рапортуя о 45 ваттном источнике питания (каковым был стандартный). Я попытался изменить отдаваемые параметры на 65 ватт, 3.5 ампера, исходя из реальных параметров нового БП, но мне это не удалось — ноутбук перестал определять зарядник как оригинальный. То ли имеется какой-то белый список параметров питания, то ли я не подправил какую-то дополнительную контрольную сумму. Впрочем, моя задача в любом случае была решена.
При разработке прошивки я активно использовал вот эту статью про 1wire. На мой взгляд, в ней всё описано достаточно просто и подробно.
И напоследок пара предупреждений:
1. Чисто теоретически подобные манипуляции могут привести к выходу ноутбука из строя или хотя бы лишению гарантии (с другой стороны, откуда производитель узнает о новом БП, если не писать статью об этом на гиктаймс и отдать им старый?). На практике я по собственной глупости подал 19В на линию ID. Ничего не произошло. Совсем ничего (ноутбук даже не выключился аварийно, как бывает при КЗ на USB). Но вам лучше не повторять моих ошибок и быть более аккуратными.
2. Я бы не советовал подключать адаптер питания с меньшей мощностью, чем указано в содержимом EEPROM. Вероятность повредить ноутбук мала, но вот адаптер, если превышения мощности не хватит для срабатывания защиты сразу, будет медленно перегреваться, пока не выйдет из строя (а тут уже всякое может быть). Адаптер должен быть такой же по характеристикам, либо мощнее (выходное напряжение же ОБЯЗАТЕЛЬНО должно совпадать с оригинальным, либо отличаться не более, чем на 0.5В, причём лучше в меньшую сторону, чем в большую).
Также было бы интересно услышать рекомендации по оптимизации моего кода и идеи, что же могут означать остальные байты в EEPROM. Сам я подумываю о том, чтобы когда-нибудь переделать всю схему на маленькой печатной плате и SMD-компонентах, чтобы она таки умещалась внутри штекера.