Наша компания разрабатывает и производит оборудование для автоматизации и у нас есть флагманский продукт — контроллер Wiren Board на ОС Linux. Его ставят почти в каждую инсталляцию, поэтому мы стараемся его постоянно улучшать: используем более производительные процессоры, добавляем больше оперативной и постоянной памяти, даём пользователям новые возможности по подключению сторонних устройств.

Осенью 2023 года вышел новый Wiren Board 7.4, который почти ничем не отличается от предшественника Wiren Board 7.3, но стал важным шагом на пути к Wiren Board 8 — в нём появился Embedded Controller (EC).

Мы уже рассказывали о том, как приручили робота-пайщика, как делаем устройства и тестируем их. Теперь хотим поделиться опытом разработки полноценного Embedded Controller — какие задачи решает, как устроен и что у него под капотом в прошивке.

Плата контроллера Wiren Board 7.4
Плата контроллера Wiren Board 7.4

Задачи

Конечно, часть задач можно решить без микроконтроллера и программирования на отдельных дискретных и логических элементах, но это усложняет проектирование и отладку, а также увеличивает себестоимость BOM (Bill of Materials, список компонентов).

Поэтому, как только нам понадобилось гибкое управление питанием и кнопка включения, мы добавили в контроллер специальную микросхему, которая по пути сделала много других полезных дел.

Задачи, которые решает EC:

  • Power Sequencer или управление питанием;

  • сторожевой таймер Watchdog:

  • RTC и будильник:

  • кнопка ON/OFF:

  • измерение температуры базовой платы:

  • управление выходом Vout:

  • АЦП на A1-A4:

  • отладочный вывод до включения процессора.

Ниже мы подробно рассмотрим каждую из них.

Слева контроллер Wiren Board 7.3.4 в который был вживлен Embedded Controller (EC), использовался в начале разработки прошивки. Справа — новый Wiren Board 7.4 с EC на плате
Слева контроллер Wiren Board 7.3.4 в который был вживлен Embedded Controller (EC), использовался в начале разработки прошивки. Справа — новый Wiren Board 7.4 с EC на плате

Power Sequencer

Основной задачей, которая сложно решалась дискретными компонентами, было управление питанием. Wiren Board 7 может питаться от разных источников: внешнее питание, PoE, два USB-C, встроенный источник резервного питания WBMZ, — и каждый из них имеет свои особенности:

  • Внешний источник поддерживает диапазон от 9 до 48 В, однако на клеммник Vout для питания Modbus-устройств нельзя выдавать более 28 В — многие из них не выдерживают напряжения больше.

  • На USB-C приходит напряжение 5 В. Этого достаточно для питания контроллера, но недостаточно для питания Vout и зарядки модулей WBMZ-*.

  • Модуль WBMZ4-BATTERY имеет встроенный повышающий преобразователь и выдаёт 12 В. Из-за необходимости сохранять совместимость с предыдущими версиями мы не могли изменить это, поэтому пришлось ввести правило: зарядка WBMZ включается только при наличии внешнего питания выше 12 В.

Теперь у нас EС следит за тем, где какое напряжение есть и самостоятельно выбирает оптимальный источник питания контроллера.

Схемы управления питанием в версиях 7.3 и 7.4
Схемы управления питанием в версиях 7.3 и 7.4
Фрагмент кода EC. Проверка наличия внешнего питания
// Проверяем, что питание есть
if (vcc_5v_ok) {
    // Питание есть - включаемся в обычном режиме
    // (просто идём дальше)
    // WBMZ включится отдельным алторитмом, если Vin будет более 11.5 В
} else {
    // Питания нет - включаем WBMZ
    linux_cpu_pwr_seq_enable_wbmz();
}

// Если дошли до этого места, надо включиться в обычном режиме
rtc_disable_periodic_wakeup();
new_state(WBEC_STATE_WAIT_STARTUP);

Так как EC может следить за всеми рейками питания контроллера, то мы реагируем на проблемы с ними. Например, если контроллер питается от отладочного порта через плохой USB-C кабель, то может проседать напряжение 3.3 В. В этом случае пробуем перезапустить питание контроллера, а если такое происходит очень часто, то выключаемся совсем.

Фрагмент кода EC. Проверка наличия 3.3 В
// Если пропало 3.3В - пробуем перезапустить питание, но не более N раз за M минут
// Если питание пропадает слишком часто - выключаемся
// Это происходит, например, при питании через плохой USB кабель.
// В результате PMIC выключается, но питание на линии 5В остаётся.
// Ограничение по числу попыток нужно, чтобы избежать циклического перезапуска.
if (!vmon_get_ch_status(VMON_CHANNEL_V33)) {
    if (!vmon_get_ch_status(VMON_CHANNEL_V50)) {
        // Если при этом нет напряжения на линии 5В - это означает, что выдернули питание
        // и не надо пытаться включиться заново
        linux_cpu_pwr_seq_hard_off();
        new_state(WBEC_STATE_POWER_OFF_SEQUENCE_WAIT);
    } else {
        if (systick_get_time_since_timestamp(wbec_ctx.power_loss_timestamp) < (WBEC_POWER_LOSS_TIMEOUT_MIN * 60 * 1000)) {
            wbec_ctx.power_loss_cnt++;
        } else {
            wbec_ctx.power_loss_cnt = 0;
        }
        wbec_ctx.power_loss_timestamp = systick_get_system_time_ms();
        if (wbec_ctx.power_loss_cnt > WBEC_POWER_LOSS_ATTEMPTS) {
            console_print_w_prefix("Reaching power loss limit, power off and go to standby now\r\n");
            // Чтобы включиться - нужно нажать кнопку или сбросить внешнее питание
            linux_cpu_pwr_seq_hard_off();
            new_state(WBEC_STATE_POWER_OFF_SEQUENCE_WAIT);
        } else {
            console_print_w_prefix("3.3V is lost, try to reset power\r\n");
            console_print_w_prefix("Enable WBMZ to prevent power loss under load\r\n");
            wbec_info.poweron_reason = REASON_PMIC_OFF;
            linux_cpu_pwr_seq_enable_wbmz();
            linux_cpu_pwr_seq_hard_reset();
            new_state(WBEC_STATE_POWER_ON_SEQUENCE_WAIT);
        }
    }
}
break;

Ещё один интересный сценарий: при питании контроллера от USB-C EC задерживает подачу питания на процессор на пять секунд. Это нужно, чтобы на компьютере, к которому подключен контроллер, успели загрузиться драйверы USB-Serial и пользователь увидел в консоли первые строчки логов U-Boot.

Пауза перед стартом контроллера при питании от USB-C, чтобы вывод U-Boot не пропадал
Пауза перед стартом контроллера при питании от USB-C, чтобы вывод U-Boot не пропадал

Watchdog

Другой задачей для EC стал сторожевой таймер Watchdog, который следит за тем, чтобы ПО контроллера не зависало. У нас два сторожевых таймера:

  • аппаратный — отсчитывает заданное время и, если никто его не сбросит, то он перегружает контроллер по питанию;

  • программный — следит за сервисами ОС и сбрасывает аппаратный таймер, чтобы тот не перезапускал контроллер.

Две схемы: сторожевой таймер на компараторе и на EC
Две схемы: сторожевой таймер на компараторе и на EC

Программный реализован на стандартном сервисе watchdog, а вот аппаратный раньше реализовывался на компараторе, и иногда такая простота приносила проблемы. Например, в одной из ревизий контроллера сторожевой таймер мог из-за утечек не сработать во влажной среде, если плата контроллера была загрязнена пылью (ERRWB600011). Мы это починили улучшением схемотехники в новых ревизиях, но осадочек остался.

Теперь аппаратный сторожевой таймер реализован на EC, который перезагружает контроллер по питанию в случае отсутствия сигнала от программного сервиса или загрузчика.

Фрагмент кода EC. Перезагрузка контроллера по питанию
// Если сработал WDT - перезагружаемся по питанию
if (wdt_handle_timed_out()) {
    wbec_info.poweron_reason = REASON_WATCHDOG;
    console_print("\r\n\n");
    console_print_w_prefix("Watchdog is timed out, reset power.\r\n");
    linux_cpu_pwr_seq_hard_reset();
    new_state(WBEC_STATE_POWER_ON_SEQUENCE_WAIT);
}

Если какой-то из отслеживаемых программным сторожевым таймером сервисов будет работать нестабильно, то контроллер невозможно будет загрузить из-за постоянных срабатываний аппаратного сторожевого таймера. Чтобы пользователь смог загрузить контроллер и устранить неполадку, предусмотрен специальный сигнал WD_OFF. В первую очередь он отключает сторожевой таймер, поэтому мы повесили его на EC_RESET для 100% железной работы — весь ЕС отключается, пины переходят в HiZ, а схемотехника сделана так, что питание на процессор в этом случае продолжает поступать. Как побочный эффект — отключается и всё остальное, сделанное на ЕС, но это не очень критично, так как сторожевой таймер отключается только при поиске неисправностей.

Индикатор работы EC и кнопка отключения аппаратного сторожевого таймера
Индикатор работы EC и кнопка отключения аппаратного сторожевого таймера

Чтобы при отключенном EC контроллер Wiren Board всё равно мог включиться, мы сделали специальную схему задержки подачи питания на процессор. За это отвечает RC-цепочка R38-C32, которая и даёт задержку при включении питания: когда подается питание на клеммник, то питание на процессор не поступает в течение примерно 1 секунды. За это время ЕС решает что делать: перехватить питание и держать отключенным или включить. В то же время, если в ЕС нет прошивки или он ещё как-то не работает, контроллер всё равно включится сам.

Схема формирования задержки подачи питания на процессор
Схема формирования задержки подачи питания на процессор
Найдите отличия в разных версиях сторожевого таймера

На картинке мы собрали выдержки из схем базовых плат контроллера, где мы периодически улучшали аппаратный сторожевой таймер. Описывать изменения не будем, что-то можно почерпнуть из комментариев в схемах, а что-то — заметить самому. Картинка в высоком разрешении.

RTC и будильник

У нас обычный Debian Linux, поэтому при работе контроллера он синхронизирует время по NTP, если тот доступен. Но когда контроллер выключен, время отсчитывает аппаратный RTC. Раньше мы делали его на специальной микросхеме, теперь этим занимается EC-контроллер. Это позволило нам предложить пользователю новую фичу — пробуждение по будильнику. 

Контроллеры Wiren Board нередко используют на удалённых объектах: стабильная работа, аппаратный сторожевой таймер, много интерфейсов в одном корпусе и возможность установить 3G/4G-модем для отправки данных в систему верхнего уровня.

Представьте себе кучу метеостанций, которые стоят вдоль реки и питаются от автомобильных АКБ. Раз в несколько месяцев на станции приезжает машина и меняет АКБ на заряженные, поэтому заряд АКБ нужно экономить. Вот на таком объекте теперь тоже можно установить наш контроллер и он будет несколько раз в день просыпаться, делать замеры, отправлять данные на сервер и снова засыпать.

Другой сценарий — работа на удаленном объекте со стационарным питанием. В контроллер можно установить модуль бесперебойного питания WBMZ, от которого он может проработать несколько часов. При пропадании питания на объекте можно сообщить об этом в систему верхнего уровня, передать какую-то телеметрию и заснуть на часок. Потом проснуться, снова сообщить телеметрию и уснуть, — и так до тех пор, пока не появится внешнее питание или пока не сядет встроенный АКБ контроллера. Всё это время оператор будет получать телеметрию с объекта и точный статус внешнего питания.

Будильник работает через стандартный rtcwake. Например, следующая команда выключит контроллер и включит его через 60 секунд:

rtcwake -m off -s 60

Кнопка ON/OFF

Изначально выключатель контроллера появился в виде переключателя в 4-й версии контроллера, но к 5-й стал опцией. В 6-й версии он стал маленьким и аккуратным, но клиенты хотели обычную кнопку. В первых ревизиях 7.4 кнопка была отделена от индикатора и пряталась под наклейкой, сейчас мы используем кнопку с двухцветным индикатором.

Эволюция кнопки включения в контроллерах Wiren Board
Эволюция кнопки включения в контроллерах Wiren Board
Схема сигналов переключателя ON/OFF в Wiren Board 6
Схема сигналов переключателя ON/OFF в Wiren Board 6

Переключатель в старых версиях отключал одновременно модуль резервного питания WBMZ, входной Step-Down преобразователь и блокировал работу сторожевого таймера (Watchdog)

Это решение было простым, но имело недостатки:

  1. При питании от отладочного USB-C контроллер включался независимо от положения переключателя, но в это время не работал сторожевой таймер.

  2. Нельзя было выключить контроллер по команде poweroff: Linux выключался, программный сторожевой таймер переставал дергать аппаратный, и тот перезапускал контроллер. 

С появлением EC мы смогли заменить тумблер на аккуратную кнопку и обрабатывать её как хочется нам или заказчикам OEM-версий контроллера.

Обработка принудительного отключения по кнопке и командам poweroff / rtcwake
// Если флаг нажатой кнопки висит слишком долго (линукс по каким-то причинам не отреагировал)
// Нужно его сбросить, т.к. он влияет на решение для выключения по poweroff
if (wbec_ctx.pwrkey_pressed) {
    if (systick_get_time_since_timestamp(wbec_ctx.pwrkey_pressed_timestamp) > WBEC_LINUX_POWER_OFF_DELAY_MS) {
        wbec_ctx.pwrkey_pressed = false;
    }
}

if (linux_powerctrl_req == LINUX_POWERCTRL_OFF) {
    // Если прилетел запрос из линукса на выключение
    // Это была выполнена команда `poweroff` или `rtcwake -m off`
    console_print("\r\n\n");
    console_print_w_prefix("Power off request from Linux.\r\n");
    bool wbmz = linux_cpu_pwr_seq_is_powered_from_wbmz();
    bool alarm = rtc_alarm_is_alarm_enabled();
    bool btn = wbec_ctx.pwrkey_pressed;

    if (alarm) {
        struct rtc_alarm rtc_alarm;
        rtc_get_alarm(&rtc_alarm);

        console_print_w_prefix("Time now is: ");
        console_print_time_now();
        console_print("\r\n");
        console_print_w_prefix("Alarm set to XXXX-XX-");
        console_print_dec_pad(BCD_TO_BIN(rtc_alarm.days), 2, '0');
        console_print(" ");
        console_print_dec_pad(BCD_TO_BIN(rtc_alarm.hours), 2, '0');
        console_print(":");
        console_print_dec_pad(BCD_TO_BIN(rtc_alarm.minutes), 2, '0');
        console_print(":");
        console_print_dec_pad(BCD_TO_BIN(rtc_alarm.seconds), 2, '0');
        console_print("\r\n");
    } else {
        console_print_w_prefix("Alarm: not set\r\n");
    }

    console_print_w_prefix("Power status: ");
    if (wbmz) {
        console_print("powered from WBMZ\r\n");
    } else {
        console_print("powered from external supply\r\n");
    }

Также мы обрабатываем потенциально опасную ситуацию, когда пользователь мог выключить удалённый контроллер командой poweroff и потерять к нему доступ. Одним из условий для выключения по этой команде — наличие будильника на пробуждение, если его нет, то перезагружаем контроллер.

Запрет выключения контроллера без АКБ по команде poweroff
            // Не должно быть возможности программно выключить контроллер так, чтобы
            // нужно было ехать нажимать кнопку чтобы его включить обратно
            // Поэтому здесь нужно проверить наличие будильника и если он есть - выключиться
            // иначе - перезагрузиться
            // Также разрешено выключаться по poweroff, если питаемся от WBMZ или если
            // выключились по кнопке
            if (wbmz || alarm || btn) {
                console_print_w_prefix("Powering off\r\n");
                linux_cpu_pwr_seq_hard_off();
                new_state(WBEC_STATE_POWER_OFF_SEQUENCE_WAIT);
            } else {
                console_print_w_prefix("Alarm not set, reboot system instead of power off.\r\n\n");
                wbec_info.poweron_reason = REASON_REBOOT_NO_ALARM;
                linux_cpu_pwr_seq_hard_reset();
                new_state(WBEC_STATE_POWER_ON_SEQUENCE_WAIT);
            }

Измерение температуры базовой платы

Раньше стоял датчик LM75, данные с которого считывал процессор контроллера. Теперь используем NTC-термистор с помощью которого EC измеряет температуру, а затем передаёт её в ОС Linux и использует в различных сценариях сам.

Датчик температуры LM75AD в ревизиях 7.2 и 7.3, в ревизии 7.4 используется NTC-термистор 10k. Пользователю доступно значение датчика в MQTT и веб-интерфейсе
Датчик температуры LM75AD в ревизиях 7.2 и 7.3, в ревизии 7.4 используется NTC-термистор 10k. Пользователю доступно значение датчика в MQTT и веб-интерфейсе

С внедрением EC поменялась и логика работы контроллера, завязанная на температуру базовой платы. Например, для защиты eMMC от поломок мы должны запретить старт контроллера при температурах ниже −40 °С. Раньше это делал загрузчик, но для его работы надо было запитать контроллер и eMMC, и только после этого он мог блокировать дальнейший старт. Сейчас EC сразу смотрит текущую температуру базовой платы, и если она ниже −40 °С, то не запитывает процессор и eMMC совсем. 

Блокировка старта контроллера при температуре ниже −40°С
case WBEC_STATE_TEMP_CHECK_LOOP:
    // В этом состоянии линукс выключен, проверяем температуру
    // Сидим тут до тех пор, пока температура не станет выше -40
    if (in_state_time_ms() > 5000) {
        if (adc.temp < WBEC_MINIMUM_WORKING_TEMPERATURE_C_X100) {
            console_print_w_prefix("Board temperature is below -40°C! Rechecking in 5 seconds\r\n");
            new_state(WBEC_STATE_TEMP_CHECK_LOOP);
        } else {
            console_print_w_prefix("Temperature is OK!\r\n");
            console_print_w_prefix("Turning on the main CPU; all future debug messages will originate from the CPU\r\n\n\n");
            linux_cpu_pwr_seq_on();
            new_state(WBEC_STATE_POWER_ON_SEQUENCE_WAIT);
        }
    }
    break;

В новом Wiren Board 8 мы добавим нагреватель, который будет греть плату контроллера при низких температурах, что позволит нам сделать версию, работающую от −55 °С.

Некоторые модели индустриальных eMMC выходят из строя, если попытаться с ними работать при температуре ниже −40 °С, поэтому сейчас мы с помощью EC запрещаем старт контроллера при низких температурах, а в будущем сделаем подогрев
Некоторые модели индустриальных eMMC выходят из строя, если попытаться с ними работать при температуре ниже −40 °С, поэтому сейчас мы с помощью EC запрещаем старт контроллера при низких температурах, а в будущем сделаем подогрев

Управление выходом Vout

В контроллерах Wiren Board есть два встроенных порта RS-485 и ещё три можно добавить модулями расширения.

Возле клемм встроенных портов есть выходы Vout с максимальным током до 1 А на оба, программным отключением и защитой от короткого замыкания. Их удобно использовать в небольших инсталляциях для питания устройств.

Клеммы RS-485 и выходы Vout в контроллерах Wiren Board
Клеммы RS-485 и выходы Vout в контроллерах Wiren Board

Внутри нет никаких преобразователей и питание на выход Vout подается напрямую с клемм V+ контроллера, но в этом кроется опасность: максимальное напряжение питание устройств 28 В постоянного тока, а контроллера — 48 В.

Так как в большинстве инсталляций напряжение питания не превышает 24 В, то у пользователей этот нюанс не вызывал дискомфорта. Но иногда пользователи запитывали контроллеры от блоков питания, которые удавалось найти в щите, и у тех, кто невнимательно читал документацию, это могло «выстрелить» и сжечь устройства на шине. Поэтому при внедрении EC мы сделали защиту, которая отключит выход при питании от напряжения, выше 28 В.

Также внедрение EC в ревизии 7.4 позволило нам упростить схему управления выходом Vout. В контроллерах Wiren Board 6.3…6.8 выход Vout управлялся программно сигналом с процессора, поэтому при перезагрузке ОС контроллера питание на нём пропадало. Чтобы этого избежать, с ревизии 6.9 мы добавили в схему два транзистора и конденсатор, которые удерживали ключ открытым, пока контроллер перезагружается и GPIO находятся в состоянии Hi-Z. Эта схема перекочевала и в ревизии 7.2…7.3. С версии 7.4 там просто мосфет, которым управляет EC.

Управление выходом Vout в старых ревизиях, а справа в новых
Управление выходом Vout в старых ревизиях, а справа в новых

АЦП на A1-A4

У контроллера есть универсальные входы/выходы Ax, которые в режиме аналогового входа измеряют напряжение. 

В Wiren Board 6 у нас стоял процессор NXP i.MX 6ULL и измерение напряжений на этих входах делалось его встроенным АЦП. В процессоре нового Wiren Board 7 свободных АЦП-входов оказалось всего три, а разрабатывался он в период дефицита компонентов, поэтому мы решили не ставить отдельную микросхему для измерения напряжения. Так выход A4 остался без измерения напряжения и был переименован в D1.

Универсальные входы контроллера Ax в ревизии 7.4, вернулся выход A4
Универсальные входы контроллера Ax в ревизии 7.4, вернулся выход A4
Схемотехника универсальных входов контроллера Ax и D1 в ревизиях 7.2…7.3
Схемотехника универсальных входов контроллера Ax и D1 в ревизиях 7.2…7.3

Но 12-битный АЦП в процессоре Allwinner A40i оказался с сюрпризом. В документации мы нашли, что у него есть специальный настроечный регистр RTP reg с адресом 0x01C25000, где по смещению 0x001C (Common Data Reg offset) лежит число 0x800 — оно вычитается из измеренного значения, что позволяет калибровать АЦП.

Например, замкнули мы вход на GND и получили на входе 0 В, при записанном в регистре значении 0x800 получили измеренное 0 В. Если записать туда, например 0x600, то в теории мы сместим точку отсчёта в минус.

Разобравшись с алгоритмом калибровки, сделали на производстве процедуру:

  1. Замыкаем вход Ax на GND.

  2. Пишем в регистр отклонение вниз 0x600 и получаем нужный оффсет по формуле offset= U_измеренное - (0x800 - 0x600) = U_измеренное - 0x200.

  3. Запись 0x800 + offset в регистр устанавливает 0 в АЦП.

Но при калибровке серийных экземпляров неожиданную обнаружили проблему: АЦП не отдает отрицательные значения. Например, если чип занижает на условные 200 мВ и мы впишем поправку в +200 мВ, то при подтяжке к GND (0 В на входе АЦП) чип будет показывать 200мВ. Поэтому точность АЦП на универсальных выходах в ревизиях 7.2…7.3 ниже, чем нам хотелось бы, но достаточная для прикладных задач.

С внедрением EC мы вернули четвертый аналоговый вход, а так как точности встроенного в STM32 АЦП для нас достаточно, то вместо калибровки мы просто проверяем, что измеренное значение попадает в заданные границы.

Гистограммы
Распределение отклонения встроенного в процессор АЦП на WB7.3.4 и старше, данные из БД проверок устройств
Распределение отклонения встроенного в процессор АЦП на WB7.3.4 и старше, данные из БД проверок устройств
Примеры гистограмм с распределением напряжений для WB 7.4.3, данные из БД проверок устройств. Напряжение подаётся от внутренних источников питания контроллера, поэтому в гистограмму попала их точность
Примеры гистограмм с распределением напряжений для WB 7.4.3, данные из БД проверок устройств. Напряжение подаётся от внутренних источников питания контроллера, поэтому в гистограмму попала их точность

Ожидание и реальность от калибровки АЦП Allwinner A40i
Ожидание и реальность от калибровки АЦП Allwinner A40i

Отладочный вывод до включения процессора

В контроллере есть отладочный порт Debug Console, куда выводится отладочная информация о процессах отключения/включения контроллера, а после загрузки ОС Linux можно получить доступ к её консоли.

Отладочный порт в контроллерах Wiren Board
Отладочный порт в контроллерах Wiren Board

Раньше в Debug Console писали сперва загрузчик, а потом Linux. Теперь мы можем узнать и о том, что происходило на этапе инициализации платформы и до подачи питания на процессор:

  • узнать причину отключения и включения — пришла команда из Linux, нажали на кнопку, сработал сторожевой таймер, внезапно пропало питание процессора и т. п.;

  • увидеть статус будильника — пользователь мог поставить и забыть о нём;

  • при включении узнать текущее напряжение питания, что поможет отловить неисправность преобразователей питания, из-за которых контроллер может не запуститься;

  • узнать температуру платы, что расскажет нам о неудачной попытке запуска при очень низких температурах;

  • другую служебную информацию, вроде версий прошивки EC и U-Boot.

Фрагмент отладочного вывода в Debug Console
Фрагмент отладочного вывода в Debug Console

Как устроен Embedded Controller

EC построен на микроконтроллере STM32G030C8 — с его помощью мы реализуем любые задуманные фичи программно.

Мы пока не используем операционную систему, поэтому весь код выполняется в основном цикле программы. Такому подходу есть исторические причины: изначально на EC-контроллере предполагалось выполнять мало задач, а значит исходный код без ОС получался компактным и исключал дополнительную точку отказа в виде самой ОС. Однако в процессе разработки аппетиты росли, функций стало больше, но внедрять ОС и переписывать весь код на конечном этапе разработке мы не стали. Возможно, переедем на ОС в будущем при добавлении новых функций.

Embedded Controller в контроллере Wiren Board 7.4
Embedded Controller в контроллере Wiren Board 7.4

Драйверы для Linux

Центральный процессор контроллера Wiren Board общается с EC-контроллером по шине SPI через запись и чтение регистров. SPI использовали, потому что он обеспечивает более высокую скорость передачи данных, чем I2C. Высокая скорость нам понадобится в новом Wiren Board 8, так как на используемом там процессоре не хватает UART-ов и мы планируем реализовать мост SPI <-> 2xUART на EC. То есть использование SPI — задел на будущее.

Чтобы управлять EC-контроллером и забирать с него данные из Linux, мы написали для ядра mfd драйвер (Multi Function Device Driver), который реализует интерфейс regmap для доступа к регистрам EC. Также в ядро добавлены драйверы для RTC, watchdog и остальных подсистем EC. В итоге в userspace ничего не изменилось и доступ к подсистемам ЕС осуществляется стандартными для Linux способами. Описание и исходный код драйверов можно найти в нашем репозитории.

Блок-схема доступа к EC из Linux
Блок-схема доступа к EC из Linux

Обновление прошивки пользователем

Мы любим, чтобы прошивки всех наших устройств пользователи могли обновлять без программатора, поэтому в EC используется встроенный загрузчик микроконтроллера. Сама прошивка загружается через интерфейс I2C, так как наш STM32G0 грузиться по SPI не умеет. Для запуска процесса обновления в Linux сначала необходимо применить device tree overlay, который настраивает I2C и GPIO для работы с загрузчиком. После этого можно обновить прошивку с помощью утилиты stm32flash. Для пользователей мы написали скрипт wb-ec-firmware-update, который обновляет прошивку автоматически.

Прошивка поставляется в deb-пакете wb-ec-firmware, исходный код вы найдёте в репозитории wb-embedded-controller.

Процесс обновления прошивки EC в контроллере Wiren Board
Процесс обновления прошивки EC в контроллере Wiren Board

Заключение

В статье мы рассказали, как сделали Embedded Controller с нуля без использования специализированных микросхем: таким образом, мы улучшили флагманский продукт и по пути сэкономили на некоторых дискретных компонентах, что в масштабе десятков тысяч штук весьма ощутимо.

Надеемся, что наш опыт будет полезен сообществу. Исходный код открыт и лежит на Гитхабе — там можно подсмотреть идеи реализации для своего проекта или собрать собственную прошивку, которая изменит поведение EC в контроллерах Wiren Board.

Если вы разработчик и хотите делать устройства, которыми пользуются десятки компаний и сотни тысяч людей, приходите к нам работать. Мы ищем Linux-программистов, Embedded-программистов, инженеров по внедрению, инженеров техподдержки и продакт оунеров. Присылайте резюме на info@wirenboard.com с пометкой в теме «Я с Хабра, хочу работать».

Приходите 25 и 26 апреля к нам на ежегодную выставку и конференцию WBCE. Там можно пообщаться с разработчиками оборудования Wiren Board, посетить производство с экскурсией, пощупать устройства и посмотреть готовые решения партнеров из самых разных отраслей.

Фотографии с прошлой выставки
Фотографии с прошлой выставки

Комментарии (34)


  1. rukhi7
    21.03.2024 07:17
    +1

    я так понимаю от Расбери-пиАй отличается тем что штатное подключение к монитору не предусмотрено, HDMI-я нет.

    Я думаю многих бы заинтересовал результат такого сравнения, еще до того как вы прилепили туда STM-контроллер. Я думаю это бы послужило хорошей рекламой. По моему нет ничего плохого залезть на плечи раскрученному названию.

    С наилучшими пожеланиями и успехов вам!


    1. wofs Автор
      21.03.2024 07:17
      +7

      я так понимаю от Расбери-пиАй отличается тем что штатное подключение к монитору не предусмотрено, HDMI-я нет.

      HDMI будет в 8й версии.

      Я думаю многих бы заинтересовал результат такого сравнения, еще до того как вы прилепили туда STM-контроллер. Я думаю это бы послужило хорошей рекламой. По моему нет ничего плохого залезть на плечи раскрученному названию.

      На вскидку отличия, важны они для вас лично или нет — решать вам:

      1. Мы используем память, процессор и eMMC, изготовленные по индустриальному техпроцессу, что сильно повышает надёжность.

      2. Выходной контроль 100 % устройств на производстве, о нём мы писали тут.

      3. У нас готовое устройство в корпусе с кучей интерфейсов и предустановленным софтом собственной разработки, который позволяет решить почти любую задачу автоматизации.

      4. Экосистема периферийных устройств, которая благодаря софту контроллера удобно настраивается и быстро работает. Например, драйвер из коробки умеет наше расширение Быстрый Modbus, а для сторонних устройств есть десятки готовых шаблонов: шторы, конционеры, частотники и т.п.

      5. Мы сами разрабатываем и производим устройства, но его вид и возможности продиктованы потребностями пользователей. Многие из них перешли на наши контроллеры в том числе и с малинок.

      6. Наш софт открыт, его можно дорабатывать под свои нужны. Этим иногда пользуются компании, которые заказывают OEM-версии контроллеров, чтобы потом сделать своё собственное нишевое решение. Также мы помогаем собрать преднастроенный образ софта для контроллера, что уменьшает стоимость развёртывания системы в разы.

      7. С недавних пор у нас появился сервис удалённого администрирования Wiren Board Cloud, который можно использовать «как есть» и установить к себе на сервер.

      У нас нет цели конкурировать с малинками, более того, наша периферия отлично с ними работает. Мы просто делаем то, что хорошо умеем и чего ждут от нас пользователи.

      Приходите к нам в гости в апреле и сами всё увидите, пообщаетесь с пользователями и разработчиками устройств, посмотрите на решения на базе нашего оборудования и оборудование некоторых конкурентов по рынку.


      1. almaz1c
        21.03.2024 07:17

        А что за процессор, на котором крутится Линукс?


        1. wofs Автор
          21.03.2024 07:17
          +4

          А что за процессор,

          Сейчас у нас Allwinner A40i 4 ядра 1.2 ГГц Industrial Grade, в новом Wiren Board 8 будет Allwinner T507 4 ядра 1.5 ГГц 64 бита Automotive Grade.

          Мы стараемся выбирать процессоры по доступности на рынке, а также по балансу производительности, качества и стоимости.


          1. almaz1c
            21.03.2024 07:17
            +2

            Всегда думал, что Allwinner не достать. Процессоры сами по себе. А эти оба есть на стоках. Спасибо. Процессорный модуль готовый используете, если не секрет, или с нуля плату под проц разводите?


            1. evgeny_boger
              21.03.2024 07:17
              +3

              Более того, в РФ есть целый дистрибьютор со складом, отладками и документацией.

              Процессорные модули свои, но готовые тоже существуют, у Стартеркита, например, их много.


              1. almaz1c
                21.03.2024 07:17
                +1

                Не знал. Спасибо. Обязательно обращусь.


      1. AlexHighTower
        21.03.2024 07:17
        +1

        Так же интересно сравнение с JetHome D1+


    1. NutsUnderline
      21.03.2024 07:17
      +2

       подключение к монитору не предусмотрено, HDMI-я нет

      это удобно начинающим для первого старта без "дополнительного" оборудования, но с учетом применения Wiren где нибуть на щите это довольно излишне.

      У малин софт наработан заметно более широко и полно всяких шляп на все случаи жизни, и кстати коробочка на din рейку тоже есть, карточки micrro sd бывают industrial grade. У малин много софта так или иначе связанного с именно типовой промышленной автоматизацией (там все так сказать, немного по другому)

      Т.е. в целом на любой вкус, прекрасно можно пользоваться малинками, пользоваться очень-очень гибко... но наступает момент когда колхоз из платок и релюшек начинает надоедать.. или вот недавно же в топике были уже разговоры про одноплатник "без всяких наворотов"

      Wiren - вещь достаточно промежуточная между классическими промышленными контроллерами со довольно специфичными языками программирования и, так сказать,компьютерами общего применения, с "традиционными" языками, чтобы не переучиваться. И ниша не очень четкая, но востребованная, есть другие ПЛК заточенные под эти самые традиционные языки. А есть, например, JetHome который хоть и на din рейку, но по сути такой же одноплатник для home assistant


  1. hooperer
    21.03.2024 07:17
    +1

    Мне почему то кажется в статье что то не так с форматированием:

    сначала идёт заголовок "Задачи", который состоит из одного абзаца,

    потом на этом же уровне по тексту размазаны -видимо- сами задачи.

    Из за чем сложно понять о чём идёт речь.

    Бодрого дня, да)


    1. wofs Автор
      21.03.2024 07:17

      сначала идёт заголовок "Задачи", который состоит из одного абзаца,
      потом на этом же уровне по тексту размазаны -видимо- сами задачи.

      К сожалению, таковы стили Хабра :( Задачи сделаны h2 заголовком, а Power Sequencer и далее до самого «Как устроен» h3.


      1. hooperer
        21.03.2024 07:17

        Приветствую)

        Может тогда стоило перечислением указать - какие именно функции покрываются?

        Тогда возможно было бы лучше понять, почему был выбран именно такой микроконтроллер?


        1. wofs Автор
          21.03.2024 07:17
          +1

          Может тогда стоило перечислением указать - какие именно функции покрываются?

          Спасибо за идею добавил перечень задач и правда стало лучше.


          1. hooperer
            21.03.2024 07:17

            Боброго дня,

            немного ещё побуду " душнилой" который не видел контроллера и не сильно понимает о чём речь :

            Задачи, которые решает EC:

            • Power Sequencer или управление входным питанием;

            • Реализация сторожевого таймера Watchdog;

            • RTC и будильник:

            • обслуживание кнопки ON/OFF:

            • Измерение температуры базовой платы:

            • Управление аналоговым выходом Vout:

            • Измерение показаний АЦП на аналоговых входах A1-A4:

            • Отладочный вывод до включения процессора.


            1. wofs Автор
              21.03.2024 07:17

              Так ниже каждый пункт разобран по кусочкам. Добавил про это в заголовок списка.


  1. syrus_the_virus
    21.03.2024 07:17
    +1

    Слежу за вашим контроллером давно, не сказать чтобы пристально, но стараюсь быть вкурсе. Внедрение в архитектуру ПЛК "супервайзера" на базе stm32 - очень годное и разумное решение. Но что насчёт входов и надёжности? Насколько я помню, гальваническую развязку входов/выходов и сетевых интерфейсов не завезли? Это очень важный аспект для того, чтобы ваш продукт занимал разные ниши в автоматизации. Ещё хочу спросить, думаете ли в сторону архитектуры ПЛК с использованием внешнего домена ОЗУ с питанием от литиевой батареи, в котором хранится текущий образ "пользовательской" или рабочей программы, вместе с трендами и конфигурационными данными? Очень хорошее решение, используемое не скажу где)), позволяет сильно повысить надёжность ПЛК не как собственно устройства , а как функционального оборудования на нижнем уровне автоматизации в составе АСУ ТП. Лучше иметь на борту три контроллера: cortex-a + 2 cortex-m: первый отвечает за работу с сетевыми интерфейсами, за работу с сетью и долговременным хранением данных(тренды, журналы), а также за реализацию верхнего уровня автоматизации(web-сервер, БД, и прочий верхний уровень), а два младших кортекса отвечают за функции "супервизора" для периферии, и второй cortex-m отвечает за реализацию"plc-core": он взаимодействует с энергонезависимым доменом ОЗУ, в котором хранится пользовательская программа, он выполняет арбитраж доступа к ней со стороны cortex-a процессора, постоянно считает CRC образа процесса, лежащего в этом ОЗУ, а также собственно управляет входами/выходами, осуществляя реализацию безопасного состояния выходов. Даже если cortex-a зависает, падает Linux, что угодно, супервизор перезагружает cortex-a без прерывания выполнения основной программы. Сценариев много, на самом деле, но рынок требует отказоустойчивых, надёжных и функциональных ПЛК.


    1. PA3JlUBHOE
      21.03.2024 07:17
      +4

      В ПЛК Panasonic как раз используется ОЗУ с батарейкой. Всегда поражался этому бреду. Иногда пользователи не видят сигнал о необходимости заменить батарейку - память стирается и дорогостоящее оборудование превращается в кирпич. Исходников программы производитель при поставке оборудования не дал, а к моменту факапа их уже и физически нет.

      Из вашего рассказа, про это чудо инженерной мысли, не понятно, как оно надежность-то повышает. Можете по подробнее пояснить?


      1. syrus_the_virus
        21.03.2024 07:17

        Литиевая батарея для сохранения образа программы используется почти во всех серьезных ПЛК, почти у всех вендоров. Это не бред уважаемый, а обычная практика. У ПЛК никаких пользователей не бывает: на верхнем уровне есть операторы и диспетчера, которые точно узнают о низком напряжении такой батареи с помощью аларма, который сначала нужно будет подтвердить, потом сбросить. Образ программы загружается из ПЗУ в эту энергонезависимую ОЗУ, и потеря питания не гарантирует потери работоспособности ПЛК и программы - просто он будет работать с ошибкой, без возможности сохранять журналы и тренды. А это чудо инженерной мысли повышает надёжность не ПЛК, а именно устройства как компонента нижнего уровня автоматизации таким образом: при пропадании питания CPU или понижении его ниже некоторого уровня супервайзер питания выключает питание или перезагружает систему, при этом образ работающей программы остаётся в nvram. Если это предусмотрено логикой работы программы, то в таких случаях либо выполнение программы приостанавливается (замораживается) для не критичной автоматики, либо задаётся безопасное состояние входов, в случае критической инфраструктуры. После того, как питание восстановится, загружается ядро ОС ПЛК и проверяется состояние образа программы в nvram: проверяется контрольная сумма образа, журнал ошибок и тренды сохраняются в ПЗУ, если было прервано выполнение не критичной программы - выполнение продолжается, что верно даже для больших систем с ответственной инфраструктурой, остановка одного ПЛК может быть убыточным для всей технологической линии.Подробно?


        1. PA3JlUBHOE
          21.03.2024 07:17
          +6

          ПЛК используются, например, в станках. Да и на линиях панель HMI это, часто, самый верхний уровень, куда аларм о батарейке может и не выводиться. Лампочка внутри шкафа автоматики под станком, например, куда редко кто заглядывает. А уж если станок выключен длительное время, обесточен, так и не проверить состояние батарейки. Батарейка, конечно, долго живет, может и 10 лет продержаться и это притупляет бдительность. ПЗУ - опция, дополнительная плата, которая далеко не всегда ставится. Розовые единороги это прекрасно, но я сталкивался с суровой реальностью, которую описал. Программа хранящаяся в ОЗУ с батарейкой это жизнь на измене)

          А что мешает сохранять тренды и параметры на флеш память? Не обязательно же каждую секунду туда писать. При пропадании питания есть время, чтобы переписать состояние из ОЗУ во флеш.


          1. Gryphon88
            21.03.2024 07:17
            +1

            Я б даже посоветовал ставить энергонезависимую память в dip'е, если высокие требования к времени простоя: поставил новый плк, переткнул память с уже подобранными коэффициентами.


        1. NutsUnderline
          21.03.2024 07:17
          +1

          немножко спутано тут все получается, сложно понять мысль. я вот вообще не понял: почему вообще пропадет возможность сохранять журналы - это выглядит как искусственное ограничение. Если потеря питания краткосрочная (бросок) то эффективнее оставлять питание всей системы - не сколько батареи, сколь аккумуляторы или даже просто ионисторы хорошие - просто работать дальше. В случае долговременного сбоя - определяем, сохраняемся во флеш нужное, культурно выключаемся. Хранить программу в батарейной оперативке вообще смысла нет, тем более ее там верифицировать - поступило питание, загрузили, восстановили состояние, пользуемся.. В общем скорее гибернация, а не спящий режим (а с линуксами это еще и вопрос, так то она инициализуирует память при старте, надо допиливать под такой режим)

          Батарейка нужна в первую очередь для часов, но поскольку в RTC есть еще память то какие то настройки довольно удобно хранить там. Для данных ее применяют не от хорошей жизни, когда с флешем те или иные проблемы. И это архитектурное решение


  1. Gryphon88
    21.03.2024 07:17
    +1

    Спасибо, интересно. Не подскажете

    • что висит на РА4?

    • откуда берете опорное напряжение для Vref+? встроенного опорника не хватает?

    • Не думали взять более многоногий мк, чтобы дать ему и Vref-, и внутренний опорник наружу вывести?


    1. pgasheev
      21.03.2024 07:17
      +3

      1) на PA4 выводится сигнал 1 Гц с RTC. Включается через карту регистров и используется в стенде тестирования для калибровки часового кварца. Калибровочное значение сохраняется в EMMC и применяется при загрузке линукса

      2) Vref+ соединён с Vdd МК через LC-фильтр. Для измерения напряжений как раз используется встроенный опорник, точности его оказалось достаточно

      3) а зачем внутренний опорник наружу? Не понял вашу мысль


      1. Gryphon88
        21.03.2024 07:17

        1Гц выводится через МСО или просто через таймер с прямым тактированием?

        Опорник иногда имеет смысл вывести для внешнего оу, хотя Goron_Dekar прав, помех можно наловить щедро.


        1. pgasheev
          21.03.2024 07:17

          Там прямо из RTC можно вывести, используется RTC_OUT2 на PA4


    1. Goron_Dekar
      21.03.2024 07:17

      Не надо внутренний опорник наружу!

      Помех по Vref наловите.


  1. ailcat
    21.03.2024 07:17

    Несколько озадачило использование STM32 в качестве аппаратного WDT.
    Да и вообще 32-битника вместо 8-битного MCU (хотя... найти даже 8-битник на технологии 65/90 нм и выше в современном мире, наверное, крайне сложно. Тогда вынужденно соглашусь).
    Но вообще - перечисленные задачи гораздо правильнее решать на FPGA, реализуя жесткую логику. Да, не так изящно - зато действительно надёжно, в индустриальном стиле.


    1. NutsUnderline
      21.03.2024 07:17

      Для перепрошивки придется чуть больше нагородить, плюс уровень вхождения выше, вопрос цены - интересен


      1. ailcat
        21.03.2024 07:17

        Да, в части цены - согласен, погорячился (простые FPGA стоят соизмеримо с STM32, а сколь-нибудь серьезные значительно дороже даже с учетом 24 года и китайского происхождения). А более высокий уровень вхождения в ПЛИС компенсируется однозначностью их поведения и более высокой надежности функционала.
        P.S.
        Но ваш EC заставил задуматься "а нафига нужен Padauc и прочие Attiny" :)


        1. NutsUnderline
          21.03.2024 07:17

          задуматься "а нафига нужен Padauc и прочие Attiny"

          Кому - что. STM32 применяют в подобном качестве в некоторых открытых проектах: ноут вроде был такой, или одноплатник...


          1. ailcat
            21.03.2024 07:17

            А еще круче вкорячить отечественный 32-битник для контроля питания монитора, и использовать у него буквально 1 ножку... (пардон за оффтоп).
            Вообще в эпоху MCU по тенологиям 90/130 нм это было весьма оправдано - они стойки к наводкам от пром.помех. А вот с переходом производителей на 28 нм (не помню, были ли микроконтроллеры на 45 нм, пропустил эту эпоху) началась "развлекуха" и гарантийные возвраты: столь тонкие нанометры ударно зависали, будучи установлены в общем цеху с импульсным или ВЧ оборудованием (лазерная резка, индукционный нагрев, ВЧ-сварка и т.п.), невзирая на качественно заземлённые металлические шкафы и экранированные кабели.
            От вашего контроллера работы в таких условиях ожидать, конечно, глупо (ARM сдуется от куда меньших воздействий, в пластиковом-то корпусе)... Но все же хочется, чтоб монитор питания превосходил по стойкости к помехам основной камень хотя бы на порядок.


            1. NutsUnderline
              21.03.2024 07:17

              Если что я к этому контроллеру и Wiren в целом- ни сном, ни духом ;)


            1. Gryphon88
              21.03.2024 07:17
              +1

              Какой мк сейчас делается по 28нм? Самый "тонкий", какой я знаю - 40 нм.


              1. ailcat
                21.03.2024 07:17
                +1

                Да, вы правы. Это меня переглючило. И АТмега-хххР, и любимые самодельщиками есп32 - это 40 нм (возможно, кругом пишут про 28 нм - вот меня и занесло).

                Ну хоть с 90/130 и более не перепутал. Хоть что-то в моё оправдание.