Привет! На связи Геннадий «Крэйл» Круглов из команды, которая разрабатывает аппаратную часть Яндекс Станций. С кем-то из читателей Хабра мы уже могли познакомиться в рамках мероприятий Я.Железа, где делимся опытом разработки устройств.
Последние несколько лет мы с командой вынашивали идею публичного рассказа об устройстве отдельной взятой части наших умных колонок — кнопки Mute. Эта тема вызывает живой интерес, поскольку напрямую касается приватности. Мы часто говорили о том, что Mute отключает микрофоны физически, но как именно это происходит — не рассказывали. В итоге вопросы копились, но руки, как это обычно бывает, до статьи не доходили. Пожалуй, вернём сегодня этот должок.
В этом посте мы расскажем о нашем основном решении для кнопки Mute. Вы увидите, что у процессора устройства нет физической возможности управлять питанием микрофонов, а значит, обойти кнопку программным способом невозможно. Мы опубликуем схемы и расскажем, как они работают. Сначала на языке, который поймут коллеги-инженеры. В конце — резюмируем простыми словами для всех. Надеюсь, будет интересно и полезно.
Начнём с простого. Почему кнопка, а не хардкорный рубильник, размыкающий цепь питания? Ответ на поверхности. Кнопка в среднем надёжнее механически и лучше защищена от грязи и пыли. Кроме того, на большинстве наших Станций кнопка Mute выполняет ещё одну дополнительную функцию: если зажать её дольше пяти секунд, то настройки Станции сбрасываются. Ну и в дизайн устройства кнопка вписывается, конечно же, легче.
Идём дальше. Кнопка — это механический компонент. Главный вопрос: что делать с её сигналом? Проще и удобнее завести этот сигнал на процессор или микроконтроллер: он сможет отслеживать длительность нажатия, по короткому переключать состояние Mute, а по длинному — сбрасывать настройки. Но тогда поведение колонки в смысле отключения микрофонов будет зависеть от прошивки. Чтобы доказать, что у нас нет возможности менять поведение кнопки Mute, управление микрофонами реализовано без использования процессора/контроллера, на примитивных компонентах. Поэтому схема работы кнопки такая сложная. Если бы не эта необходимость, схема была бы проще в десятки раз, микрофоны всегда работали, а процессор просто не использовал их сигнал в режиме Mute.
Чтобы наш рассказ был более предметным, рассмотрим логику работы кнопки на примере наиболее популярных современных моделей Яндекс Станций.
Станция Миди (2023)
Начнём с одной из самых популярных новинок прошлого года. Схема обвязки кнопки Mute на Станции Миди выглядит так:
Кстати, эта схема была опробована ещё в обновлённой Станции Мини (2021).
Прежде чем двигаться дальше, давайте вспомним таблицу истинности триггера:
Это скриншот из даташита. Строки первая и третья у нас не сработают, поскольку вход #PRE безальтернативно подтянут к питанию.
При включении питания конденсатор C249 разряжен, на затворах VT6, VT7, VT8 — ноль, поэтому:
-
VT6 закрыт, на линии MUTE_BUTTON логическая 1.
-
VT7 открыт, VT8 закрыт, так что заряжается батарея конденсаторов C250, C252, C254.
Далее через резистор R125 заряжается конденсатор C249. Он зарядится за время T = RC = 100к × 0,22 мкФ = 22 мс. После этого:
-
Открывается транзистор VT6 и подаёт 0 на линию MUTE_BUTTON.
-
Закрывается транзистор VT7, прекращается зарядка батареи конденсаторов.
-
Открывается транзистор VT8 и разряжает батарею конденсаторов.
-
После разрядки батареи конденсаторов закрывается транзистор VT9, через R130 начинает заряжаться конденсатор C253.
Таким образом, на входе #CLR-триггера какое-то время присутствует 0, и триггер сбрасывается: на выходе Q появляется 0 (поскольку #PRE всегда 1), на выходе #Q — 1. На входе D через 10 мс (R131 = 100k, C255 = 0,1 мкФ => T = RC = 10 мс) появится 1. Но вход CLK остаётся в 0, поэтому триггер не переключится. Чуть ниже по тексту для наглядности приведён график переключений.
На линии MICENR (выход Q) присутствует 0, поэтому MUTE_STATE будет 1, а на MLED — 0.
При нажатии кнопки Mute заряд перераспределяется между заряженным C249 и разряженным C251: поскольку ёмкость первого больше, на линии CLK появляется логическая 1. Она там ненадолго: конденсаторы разряжаются через R129 и разрядятся примерно за 0,3 мс.
Таким образом, на вход CLK будет подан короткий единичный импульс. Поскольку на входе D логическая 1, то триггер переключится: на Q появится 1, а на #Q — 0. Через 10 мс 0 с выхода #Q окажется на входе D, но это ничего не изменит, поскольку опять же нет фронта на входе CLK. На линии MIC_EN_R появится 1, на MUTE_STATE — 0, а на MLED — 1.
Вернёмся к левой части схемы. После того как конденсаторы C249+C251 будут разряжены:
-
Закрывается транзистор VT6, на линию MUTE_BUTTON подаётся 1.
-
Закрывается транзистор VT8, прекращается разрядка батареи конденсаторов.
-
Открывается транзистор VT7, начинается зарядка батареи конденсаторов.
Если кнопку держать дольше, то за это время успеет зарядиться батарея конденсаторов. Расчётное время зарядки до напряжения 0,7 от напряжения питания — 15 с (T = RC = (1 М + 100 к) × (4,7 мкФ × 3)). Однако в реальности транзистор откроется при меньшем напряжении, поэтому задержка тоже будет меньше — порядка 5 с.
Транзистор VT9 откроется, на входе #CLR появится 0, и триггер сбросится в исходное состояние с Q = 0 и #Q = 1. Соответствующие выходные цепи тоже вернутся в начало. Если же кнопку отпустить раньше, то батарея конденсаторов не успеет зарядиться. Через 22 мс после отпускания кнопки зарядится конденсатор C249, и тогда:
-
На линии MUTE_BUTTON снова окажется 0.
-
Батарея конденсаторов снова будет разряжена.
-
Состояние линий MUTE_STATE и MLED не изменится.
При следующем нажатии кнопки на входе CLK снова появится единичный импульс, но на этот раз на входе D будет уже 0. Таким образом, триггер снова переключится: на Q появится 0, а на #Q — 1. Линии MUTE_STATE и MLED изменят своё состояние соответственно.
Покажем переключения на графике:
Очевидно, что процессор не участвует в переключении состояния MUTE и никак не может повлиять на работу кнопки.
Давайте посмотрим, куда идут выходные линии. MUTE_BUTTON и MUTE_STATE идут на GPIO процессора. Это подключение нужно, чтобы софт мог понять, в каком состоянии находится кнопка, и в каком — подсистема микрофонов. Это нужно, например, чтобы при долгом нажатии начать процесс возврата к заводским настройкам.
Посмотрим на верхнеуровневую схему:
Ныряем глубже, внутрь квадратика справа внизу:
И ещё глубже:
GPIO процессора подключены к стокам транзисторов. Даже если эти GPIO переключить в режим выхода, подача логических сигналов на линии MUTE_BUTTON и MUTE_STATE не в состоянии переключить схему.
Теперь проследим путь линии MLED. Нырнём в верхний правый квадратик верхнеуровневой схемы:
Разъём X5 соединяет основную плату и плату микрофонов.
Вот плата микрофонов:
Сначала заглянем в квадратик Connector:
При 0 на MUTE_EN транзистор VT2 будет открыт, подавая питание +VDD_MIC, а при 1 — закрыт, и питание будет выключено. На верхнеуровневой схеме видно, что питание микрофонов идёт именно по цепи +VDD_MIC / +3V3_MIC.
Заглянем в квадратик Mics.SchDoc, просто чтобы не оставлять белых пятен:
А теперь — в квадратик LED_Driver_Alice.SchDoc:
Тут видно, что при 1 на MUTE_EN транзистор открыт и включены красные каналы светодиодов.
Станция 2 (2022)
Схема обвязки кнопки в Станции 2 повторяет схему из Станции Миди, так что не будем на ней останавливаться:
Линии MHWEN и MSWDET подключены к GPIO процессора (опять же, процессор не в состоянии повлиять ими на схему переключения). А управляющий сигнал MLED поступает на плату микрофонов через шлейф.
Посмотрим на схему подсистемы микрофонов. Сначала общий вид:
Теперь схема подключения разъёма:
Посмотрим на схемы микрофона и светодиодов:
В правой части расположен транзистор VT1, который включает красные каналы светодиодов при логической 1 на затворе.
Как и написано: при логической 1 на MLED светодиоды светятся, а питание микрофонов отключено. И наоборот.
Станция Макс (2020)
Тут схема триггера проще, поскольку у Станции Макс есть две кнопки и нет необходимости использовать кнопку MUTE для сброса к заводским настройкам.
При включении питания:
-
Конденсатор C18 заряжается через R16.
-
Конденсатор C17 заряжается через R20 за T = RC = 1 мкФ × 100 к = 100 мс. Триггер сбрасывается: на выходе Q появляется 0, а на #Q — 1.
-
Конденсатор C28 заряжается через R15 за T = RC = 0,1 мкФ × 100 к = 10 мс, и на входе D появляется логическая 1.
При нажатии на кнопку конденсатор C18 разряжается через R2 за T = RC = 0,1 мкФ × 1 к = 0,1 мс. На вход CLK подаётся единичный импульс. Поскольку на входе D — логическая 1, триггер переключается: на выходе Q появляется 1, а на #Q — 0. Через 10 мс на входе D появляется логический 0 с выхода #Q.
При отпускании кнопки конденсатор C18 зарядится через 10 мс, так что повторно кнопку следует нажимать не раньше:)
При повторном нажатии триггер снова переключится и сигналы MIC_EN и #MIC_EN поменяют свой уровень.
Заметим, что светодиоды VD1 и VD2 горят, когда на #MIC_EN присутствует высокий уровень, а на MIC_EN — низкий.
Сигнал MIC_EN подведён к разъёму, откуда далее идёт на GPIO процессора. Больше он нигде не используется. Процессор, даже переведя GPIO в режим выхода, не может никак переключить схему: триггер переключается только по CLK, а на него сигнал может подать только кнопка.
Для управления микрофонами используется сигнал #MIC_EN:
Здесь при логической 1 на #MIC_EN (микрофоны выключены) выключено питание микрофонов, а также запрещена работа буферов DD1 и DD2, которые подают тактирование на микрофоны:
Так что тут отключены и питание, и тактирование.
Итоги — простыми словами
Итак, нажатие кнопки Mute отключает микрофоны без участия процессора и программного обеспечения: у них отключается питание, они перестают работать. Включить микрофоны обратно можно либо по кнопке Mute, либо через сброс питания всего устройства (грубо говоря, если выдернуть БП из розетки и воткнуть обратно). У процессора нет физической возможности управлять питанием микрофонов. Мы осознанно пошли на создание такой сложной схемы, чтобы добиться этого эффекта.
Описанные в статье решения применяются в наших колонках уже несколько лет, ими пользуются миллионы пользователей. Мы считаем такие масштабы хорошим бенчмарком. Тем не менее понимаем, что идеальных решений не бывает. И поэтому хотим напомнить, что Яндекс Станции участвуют в «Охоте за ошибками». Недавно мы подняли максимальную сумму вознаграждения за найденные в устройствах уязвимости до миллиона рублей. Верим, что это поможет проверить устройства с Алисой на прочность и сделать их ещё надёжнее.