Как оценить загруженность микроконтроллера? С памятью все понятно размеры занимаемого кода и оперативной памяти показывает компилятор, а что делать с процессорным временем? Конечно, в линейной программе можно взять и посчитать время выполнения каждой процедуры и станет ясно успеет микроконтроллер выполнить все на него повешанное или слажает в каком-нибудь критичном месте.
Куда сложней оценивать время в кооперативной операционной системе реального времени. Тут задачка получается нетривиальной у нас куча процессов скачут через диспетчер. В ходе программирования задачи навешиваешь одну за другой, как бусинки на нить каждый процесс обработки чего либо составляет подобную цепочку, а всего их может быть просто тьма. Ядро же у контроллера всего одно, а значит выполнять можно всего одну задачу за раз и если у нас в диспетчере скопится много критичных ко времени процессов (вообще их лучше развешивать на прерывания, но бывает и прерываний на всех не напасешься), то возможно либо переполнение очереди диспетчера, либо превышение времени ожидания, что тоже не праздник.
Самое западло в том, что умозрительно отлаживать такие вещи довольно сложно. Единственный вариант рисовать временные диаграммы запуска каждой задачи и смотреть где у нас узкие места. Еще можно попробовать в 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 ЦАП.
Комментарии к статье:
Чтобы оставить комментарий, прокрутите в самый конец статьи Комментировать материал
Заманчивая идея Я тоже сначала думал как такую шнягу можно замутить, а потом дошло что нужно менять уровень на ноге))) А вот чтобы делать иголки разные по высоте не дошло. Хотя их смысл только на осциллографе есть, так как если выводить как аналоговый сигнал Будет портиться картина=)
Надо будет тоже летом замутить, но после того как сделаю свою ОС, так как только там она имеет смысл (Я даже не смотрел код Вашей ОС=) ). У Вас же все под ОС работает?
Да это под ОС все сварганено
У меня большинство программ выполнено в виде главного цикла, в котором последовательно проводится проверка и исполнение задач. Вертится он постоянно, время выполнения зависит от нагрузки. С самого начала я прикидываю критическое время, за которое должен пробегать цикл, чтобы все успеть и ничего не потерять. От того, насколько он крутится быстрее, можно судить о запасе производительности.
В начале главного цикла аналогично выставляю 1 на какой нибудь неиспользуемой ноге, в конце снимаю, но чаще, чтобы не ловить иголки, просто в начале цикла инвертирую состояние ноги. Получаю почти меандр, частоту или период которого смотрю осциллографом, если нужна точность частотомером. Часто для проверки выполнения какого-либо куска кода также делаю контрольный вывод. Отладочная информация великая вещь, никакой симулятор не заменит отладки в реальном времени, на реальном железе. Поэтому я обычно прекрасно обхожусь без симуляторов и отладочных плат, отлаживая программу сразу на плате устройства.
Ну так в твой главный цикл все равно в случайном порядке вклиниваются куски кода в зависимости от флагов. Или ты просчитваешь максимально худший вариант развития событий?
Я обычно определяю критичные возможные ситуации (к примеру, время обработки байта, поступающего с канала связи, и связанных с ним действий, до поступления следующего), и исходя из этого просчитываю максимально допустимые времена. Потом просчитываю время прогона цикла, исходя их худшей ситуации (одновременная обработка всех событий). Если не укладываюсь оптимизирую алгоритмы, ищу другие варианты, использую аппаратную поддержку некоторых функций. При отладке смотрю реальное время прогона, прикидывая, насколько велик запас. В общем, всегда исхожу из худшего из возможного, заранее избавляясь от кучи проблем в дальнейшем.
Кстати, в PIC очень удобно считать времена: все команды выполняются за один цикл (4 такта), переходы за 2 цикла. На I8080 было сложнее, там команды выполнялись от 3 тактов до 18, от 1 до 5 циклов, причем машинный цикл мог содержать от 3 до 5 тактов И ничего, считал.
Здравствуйте всем! Немного не в тему DI HALT, ты обещал написать о самодельном JTAG ICE.
И напишу, когда доделаю. Жду прихода Мега16. Собственно уже готов девайс.
Привет, DI HALT, я вот смотрю на картинку и непонимаю, а как ты смог записать 6 байт в EEPROM за 4,5 мс, у меня запись одного байта длится 8,5 мс, как по даташиту. Посмотрел твой код записи, всё вроде то же самое, поделись секретом.
Ну вот так само получается О_о
Шью побайтно, с тупым ожиданием флага готовности. На выходе бит устанавливается в момент ухода на процедуру записи и сбрасывается в момент ухода на диспетчер. Получилась вот такая картинка.
хехе, гениальненко однако:)
Это ж как мыслить-то надо творческИ, дабы намутогонить такой вариант, спасибо аз статью.
Я вот таким образом, дёргая ногой, отлаживал софтовый уарт на атмеге 168. Я не знал, когда действительно осуществляется считывание ноги RX при приёме байта, а принималось чёрти-что, т.е. явно что-то было с этим временем выборки не так. А потом догадался во время каждого считывания дёргать в единицу одну из свободных ножек, и на осциллографе, совместив график сигнала, поступающего на уарта, с осциллограммой напряжения на этой свободной ноге, всё увидел как на картинке и заставил наконец программу работать 🙂 Так что да, без осциллографа всё равно что без глаз что-то можно делать, но очень тяжело.