Тестирование встраиваемых систем — один аспект, о котором почему-то мало говорят

    К написанию статьи подтолкнуло прочтение статьи с похожим названием, последнее посещение Embedded World и опыт разработки в этой области.

    Почему-то, когда говорят о тестировании применительно к встраиваемым системам, почти всегда подразумевают под этим платформу, позволяющую «отрезать» эту самую встраиваемую систему, чтобы «независимо от аппаратной платформы» протестировать написанный код.

    Безусловно, подход имеет место быть, и с его помощью можно многое протестировать и найти, но…

    Вот в качестве примера простенькая система: микроконтроллер и подключенный к нему по I2C инфракрасный датчик температуры. Как будем тестировать?

    Что тут можно виртуализировать, чтоб тест не потерял всякий смысл? Если весь код по сути сводится к инициализации I2C периферии контроллера и реализации протокола коммуникации с самим датчиком? И еще блокировка доступа к ресурсу для случая многозадачного окружения.

    На мой взгляд, для нормального тестирования нужно иметь возможность прочитать с датчика значение температуры, и каким-либо образом извне получить данные о реальной температуре окружающей среды и/или объекта, на который указывает датчик. И сравнить их. Т.е. для нормального «end-to-end' тестирования без реальной платы с контроллером и датчиком, а также интерфейсом связи „наружу“, на мой взгляд, никак не обойтись… В самом крайнем случае можно считать, что температура в помещении, где работают люди, будет в диапазоне 18-30 градусов, и проверять полученное значение на попадание в этот интервал. Но если надо проверить точность, то — без термо-камеры, увы, не обойтись.

    Пример из жизни: пришлось нам как-то работать с чипом ADG2128 — матрица коммутации 8х12 с управлением по I2C. А чип, как оказалось, имел недокументированный глюк — его I2C часть „будила“ чип не только, когда получала его адрес в начале пакета, а при любом обнаружении его адреса на шине. Даже в середине передачи. I2C как бы предназначен для того, чтобы на нем несколько устройств висело. А теперь — идет коммуникация с другим устройством, висящим на той же шине, и в середине коммуникации проскакивает байт с адресом этого ADG, он просыпается и начинает выдавать свои данные в шину… В общем, интересный был баг, и его исправление-костыль тоже было весьма своеобразным, хоть и работающим в конце-концов.

    Так вот — каким образом такой или подобный глюк можно было бы „отловить“, используя подход тестирования без наличия самой встроенной системы с „живым“ чипом на ней?

    Еще пару примеров из жизни встраиваемых систем — после добавления очередной функции заканчивается память контроллера. Добавление новой функциональности приводит к „гонкам“ или взаимной блокировке. Как вариант, к аналогичным последствиям приводят неправильные, но все же возможные в реальности действия пользователя из серии „подключить к устройству не то/ не так/ не туда / не вовремя“. Или же послать неправильную конфигурацию на устройство. Или же само устройство при определенной конфигурации начнет потреблять тока больше, чем может обеспечить USB. Или при подключении устройства к ноуту, работающему от батареи, не возникнет соединения „земли“ с „землей“ в розетке — и измерение окажется поразительно неточным из-за бага в спроектированной схеме…

    На мой взгляд — нормальное, „полноценное“ тестирование будет возможно лишь в виде разработки еще одного устройства, реального, „железного“, которое будет эмулировать все необходимые воздействия на наше тестируемое устройство, плюс наш тестовый фреймворк должен иметь возможность управления самим нашим тестируемым устройством и устройством симуляции воздействий.

    Когда мы разрабатывали DSLAM (телекоммуникационное устройство, на одном конце которого — широкий Ethernet, а на другом 32/64/128 DSL модемов), тестовый стенд выглядел как-то так: 64 модема, подключенных к 64-портам генератора L2/L3 трафика, и Uplink, подключенный к еще одному порту. Тестовый скрипт конфигурировал DSLAM, генераторы трафика, запускал трафик и проверял результаты.

    Когда мы разрабатывали многоканальный прикладной осциллограф, устройство тестирования выглядело так: коробочка, имеющая 4 независимых выхода, подключенных ко входам тестируемого осциллографа, каждый выход мог симулировать все поддерживаемые осциллографом сенсоры (типа токовых клещей или датчика давления), а также выдавать значения, которые выдавал бы настоящий сенсор. Тестовый сценарий — задать на выходах комбинацию сенсоров и генерируемых значений, сконфигурировать тестируемое устройство (задать сенсор, диапазон и т.п.), измерить их тестируемым устройством, сравнить со сгенерированными.

    Все это интегрировалось в систему CI — текущий билд собирался и заливался на устройство, после чего начиналось описанное выше тестирование.

    Системы использовались как на этапе разработки для регрессионного тестирования, так и на этапе производства для проверки нового устройства перед отправкой его „в поле“.

    Несомненно, такой подход затратен — но при длительном и сложном многофункциональном проекте, мне кажется, альтернативы ему нет. А без него — прямая дорога к „смертельной петле тестирования“ (Росту необходимого количества „ручных“ тестов по мере добавления новых функций, как следствие — даже простейшее изменение в коде невозможно сделать быстро: 1 час на изменение/багфикс и неделя ручного регрессионного тестирования, ага. Про неделю — не шутка, увы.)

    Сейчас делаем саму систему тестирования в виде более-менее универсальной модульной системы, посмотрим, будет ли оно кому-нибудь еще нужно…
    • +12
    • 7,1k
    • 8
    Поделиться публикацией

    Комментарии 8

      0
      Существенный вопрос при тестировании на железе, но точного ответа не знаю. Надеюсь подскажите.
      Предпосылка следующая. Идет поиск ошибки приводящей к зависанию микроконтроллера. В код то там, то здесь делаются вставки, типа контрольных точек, которые выводят сообщения в дебажный порт. Таким образом проверяется, что в таком то месте программы контроллер еще бегал.
      Вопрос такой. Можно ли гарантировать, что если выполнялась команда вывода сообщения в порт (RS232/RS485), т.е. байты переданы в буфер приемопередатчика, а на следующем такте (или очень близко к этому моменту) происходит зависание контроллера ( к примеру аппаратное исключение «деление на ноль» или «закончился стек»), то приемопередатчик все-таки выдаст отладочные байты наружу? Т.е. насколько приемопередатчик работает независимо от микроконтроллера?
        0
        Зависит от контроллера.
        Реально может так «глюкать» что для примера отключает UART от питания или например на ходу меняет тактовые частоты. Тут все довольно железно специфично.
          0
          Выходит, что UART как правило «независим» от контроллера и будет выдавать данные из своего буфера при зависшем контроллере. Кроме тех случаев, когда в случае сбоя будет послана команда:
          1. на отключение UART;
          2. на настройку параметров UART;
          3. на изменение тактовой частоты.
          Думаю из всего множества возможных вариантов, данная тройка имеет существенно малую вероятность. Т.е. доверять отладке через вывод в дебажный порт в целом можно, но это не гарантия. Правильно?
            0
            В микроконтроллерах даже отладка через JTAG не дает полной гарантии, т.к. есть свои тараканы. Любая операция несет какие-либо побочные эффекты. Например, при остановке ядра JTAG-ом — таймеры могут продолжать тикать, обычно можно настроить останов периферии при останове ядра, но не всегда и не везде.

            Но если не заморачиваться сильно, то отладочный вывод в UART является простым и довольно надежным решением. Так самый удобный способ отловить причину аппаратного исключения — сделать обработчик с разбором стека и выдачей его в UART.
          0
          Вообще, по моему опыту, последовательный порт весьма надежно работает.

          Еще можно светодиод на GPIO повесить — там достаточно одной записи в регистр для изменения его состояния. При помощи осциллографа можно таким образом очень точно интервалы времени измерять
          0
          Вот интересно, как же Вы реализуете стенд тестирования? Тот же датчик температуры взять (какой нибудь DS1820) — время измерения 800-1000мс. За минуту можно сделать не более 60 измерений — правильно? Да и сама тестируемая система меняется довольно медленно. Похоже в любом случае тестирование будет долгим?

          Вот другой пример. Я разрабатывал устройство и одно из требований к нему — когда контроллер не активен, то раз в сутки включать насос на 5 секунд, чтоб не закисливался. Как проверить такую функцию?
            +1
            Суть в том, что бы тестирование было автоматическим. В этом случае длительность теста не имеет особого значения, хоть на час запустить, хоть на месяц.
              0
              Ну для датчика температуры, т.к. это не основная функция устройства, просто проверялось, что полученная с него температура в диапазоне комнатной (т.к. там относительно сложный алгоритм преобразования из raw данных в температуру, при любом сбое значение температуры будет неадекватным. Примеры стендов по основным функциям привел вроде в статье.

              А для включения раз в сутки на 5 секунд — сделать устройство, подключаемое вместо насоса, которое будет считать, сколько раз и на сколько времени было включение. И оставить на неделю.

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

            Самое читаемое