AVR. Учебный Курс. Оценка загрузки контроллера.

Как оценить загруженность микроконтроллера? С памятью все понятно — размеры занимаемого кода и оперативной памяти показывает компилятор, а что делать с процессорным временем? Конечно, в линейной программе можно взять и посчитать время выполнения каждой процедуры и станет ясно успеет микроконтроллер выполнить все на него повешанное или слажает в каком-нибудь критичном месте.
Куда сложней оценивать время в кооперативной операционной системе реального времени. Тут задачка получается нетривиальной — у нас куча процессов скачут через диспетчер. В ходе программирования задачи навешиваешь одну за другой, как бусинки на нить — каждый процесс обработки чего либо составляет подобную цепочку, а всего их может быть просто тьма. Ядро же у контроллера всего одно, а значит выполнять можно всего одну задачу за раз и если у нас в диспетчере скопится много критичных ко времени процессов (вообще их лучше развешивать на прерывания, но бывает и прерываний на всех не напасешься), то возможно либо переполнение очереди диспетчера, либо превышение времени ожидания, что тоже не праздник.
Самое западло в том, что умозрительно отлаживать такие вещи довольно сложно. Единственный вариант — рисовать временные диаграммы запуска каждой задачи и смотреть где у нас узкие места. Еще можно попробовать в AVR Studio поставить Break Point на переполнение диспетчера, но студия не сэмулирует всю ту прорву периферии, а в пошаговой отладке этого не увидеть — да и момент надо подобрать так, чтобы все навалилось.

В один момент мне пришла в голову одна идея — а почему бы не заставить рисовать временные диаграммы работы задач сам контроллер? Это же просто! Берем и в диспетчере, перед вызовом задачи выставляем бит порта в 1. А когда диспетчер задач опустошается полностью, то есть выполняется переход на Idle — сбрасываем бит в 0. В результате, у нас на выходе будет подобие ШИМ. Если постоянно крутится Idle — будут нули перманентно. Если же проц в поте лица гонит через себя непрерывно код, то будут высокий уровнь сплошняком. А если все прерывисто — что то ШИМообразное. Причем чем больше загрузка процессора тем выше заполнение. Можно поставить интегрирующую RC цепочку и получим аналоговый сигнал. Хоть на стрелочный индикатор заводи :). Сказано — сделано.

Получилось вот так:

Пока задача шлет раз в секунду байт по UART, а остальное время Idle, т.е. бездельничает.

А вот мы добавили опрос клавиатуры. Стало бодрей — иголки увеличились числом. Каждая иголка запуск процесса.

Вот одна иголка крупным планом.

Вызваю процедуру записи в EEPROM — во как, сразу же сожралось куча времени на выполнение. А записалось всего 6 байт. Обратите внимание на масштаб времени. Насколько запись в EEPROM дольше выполнения обычного кода.

Но одними иголками сыт не будешь. Не прикольно. Как бы задачки эти выделить. Чтобы можно было понять кто есть кто. Решение элементарное — выделить для отладочных целей не один бит, а поболее. У меня тут в запасе нашлось целых 8 ног. Соответственно я сразу же по заходу в задачу вывел в порт ее номер, а из порта загнал в R-2R ЦАП. Картина стала наглядней — теперь высота иголки у всех задач стала разной.

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

Вот что мы видим. Иголки номер 1 — это сканирование клавиатуры. Те что повыше, номер 2 — это пинг, отсыл одного байта по UART, а вот средние — отправка пачек данных через тот же UART.

Вообще применение осциллографа это могучее средство для реалтаймовой отладки. Не обязательно таким замудреным способом как у меня. Это я больше для прикола и наглядности всякие АЦП вешаю. Достаточно же просто бит выводить и смотреть на осциллографе. Еще можно добавлять программные ловушки. Например, переполнилась критическая переменная — выдали бит. А чтобы не ловить на экране осциллографа этих тараканов, проще этот бит завести на какую-либо следящую систему, да хоть на триггер. Взвел следилку и гоняй свою отлаживаемую программу в хвост и в гриву, нагружай пока не позеленеет от натуги. А если где то что то сорвет, то выскочит твой бит, триггер его запомнит и там хоть сирену включай — ахтунг! Error!!!

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

Однобитные иголки

Нагрузили еще немного. Шлю по UART, видно как растет нагрузка на конвеер

Применили R-2R ЦАП.

12 thoughts on “AVR. Учебный Курс. Оценка загрузки контроллера.”

  1. Заманчивая идея… Я тоже сначала думал как такую шнягу можно замутить, а потом дошло что нужно менять уровень на ноге))) А вот чтобы делать иголки разные по высоте… не дошло. Хотя их смысл только на осциллографе есть, так как если выводить как аналоговый сигнал… Будет портиться картина=)

    Надо будет тоже летом замутить, но после того как сделаю свою ОС, так как только там она имеет смысл (Я даже не смотрел код Вашей ОС=) ). У Вас же все под ОС работает?

  2. У меня большинство программ выполнено в виде главного цикла, в котором последовательно проводится проверка и исполнение задач. Вертится он постоянно, время выполнения зависит от нагрузки. С самого начала я прикидываю критическое время, за которое должен пробегать цикл, чтобы все успеть и ничего не потерять. От того, насколько он крутится быстрее, можно судить о запасе производительности.
    В начале главного цикла аналогично выставляю 1 на какой — нибудь неиспользуемой ноге, в конце — снимаю, но чаще, чтобы не ловить «иголки», просто в начале цикла инвертирую состояние ноги. Получаю почти меандр, частоту или период которого смотрю осциллографом, если нужна точность — частотомером. Часто для проверки выполнения какого-либо куска кода также делаю контрольный вывод. Отладочная информация — великая вещь, никакой симулятор не заменит отладки в реальном времени, на реальном железе. Поэтому я обычно прекрасно обхожусь без симуляторов и отладочных плат, отлаживая программу сразу на плате устройства.

    1. Ну так в твой главный цикл все равно в случайном порядке вклиниваются куски кода в зависимости от флагов. Или ты просчитваешь максимально худший вариант развития событий?

      1. Я обычно определяю критичные возможные ситуации (к примеру, время обработки байта, поступающего с канала связи, и связанных с ним действий, до поступления следующего), и исходя из этого просчитываю максимально допустимые времена. Потом просчитываю время прогона цикла, исходя их худшей ситуации (одновременная обработка всех событий). Если не укладываюсь — оптимизирую алгоритмы, ищу другие варианты, использую аппаратную поддержку некоторых функций. При отладке смотрю реальное время прогона, прикидывая, насколько велик запас. В общем, всегда исхожу из худшего из возможного, заранее избавляясь от кучи проблем в дальнейшем.
        Кстати, в PIC очень удобно считать времена: все команды выполняются за один цикл (4 такта), переходы — за 2 цикла. На I8080 было сложнее, там команды выполнялись от 3 тактов до 18, от 1 до 5 циклов, причем машинный цикл мог содержать от 3 до 5 тактов… И ничего, считал.

  3. Привет, DI HALT, я вот смотрю на картинку и непонимаю, а как ты смог записать 6 байт в EEPROM за 4,5 мс, у меня запись одного байта длится 8,5 мс, как по даташиту. Посмотрел твой код записи, всё вроде то же самое, поделись секретом.

    1. Ну вот так само получается О_о

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

  4. Я вот таким образом, дёргая ногой, отлаживал софтовый уарт на атмеге 168. Я не знал, когда действительно осуществляется считывание ноги RX при приёме байта, а принималось чёрти-что, т.е. явно что-то было с этим временем выборки не так. А потом догадался во время каждого считывания дёргать в единицу одну из свободных ножек, и на осциллографе, совместив график сигнала, поступающего на уарта, с осциллограммой напряжения на этой свободной ноге, всё увидел как на картинке… и заставил наконец программу работать :) Так что да, без осциллографа всё равно что без глаз — что-то можно делать, но очень тяжело.

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha