#performance #algorithm #testing #arduino #attiny
#Производительность #алгоритм #тестирование #arduino #attiny
Вопрос:
Я заинтересован в использовании контроллеров atmel avr для считывания данных с шины LIN. К сожалению, сообщения на такой шине не имеют индикатора начала или конца, и единственным разумным решением, по-видимому, является синтаксический анализ методом перебора. Доступные данные из шины загружаются в циклический буфер, и метод грубой силы находит допустимые сообщения в буфере.
Работая с 64-байтовым буфером и attiny с частотой 20 МГц, как я могу проверить производительность своего кода, чтобы определить, может ли произойти переполнение буфера? Добавлено: меня беспокоит то, что алгоритм будет работать медленно, что приведет к буферизации еще большего количества данных.
Немного об алгоритме грубой силы. Предполагается, что вторым элементом в буфере является размер сообщения. Например, если предполагаемая длина равна 22, то первые 21 байт преобразуются в XOR и проверяются на соответствие 22-му байту в буфере. Если контрольная сумма проходит, код проверяет, соответствуют ли первый (SRC) и третий (DST) байты тому, какими они должны быть.
Ответ №1:
AVR — один из самых простых микроконтроллеров для анализа производительности, потому что это RISC-машина с простым набором инструкций и хорошо известным временем выполнения команд для каждой команды.
Итак, базовая процедура заключается в том, что вы берете код сборки и начинаете вычислять различные сценарии. Основные операции с регистрами занимают один такт, ветвления обычно два цикла, а доступ к памяти осуществляется три цикла. Цикл XORing может занимать 5-10 циклов на байт, поэтому он относительно дешевый. То, как вы получаете доступ к ассемблерному коду, зависит от компилятора, но все компиляторы, как правило, дают вам конечный результат в разумной разборчивой форме.
Обычно, не видя алгоритма и ничего не зная о требованиях к срокам, совершенно невозможно дать однозначный ответ на такого рода вопросы. Однако, поскольку скорость шины LIN ограничена 20 кбит / с, у вас будет около 10 000 тактов на каждый байт. Этого достаточно практически для чего угодно.
Более сложный вопрос заключается в том, что делать с кадрированием линии, которое зависит от времени. Это не очень приятная привычка, так как она действительно требует от микроконтроллера дополнительных временных усилий. (Что, черт возьми, не так с использованием 9-го бита?)
Фрейм LIN состоит из
- перерыв (не менее 13 бит)
- разделитель синхронизации (0x55)
- идентификатор сообщения (8 бит)
- сообщение (0..8 x 8 бит)
- контрольная сумма (8 бит)
Существует по крайней мере четыре возможных подхода со своими взлетами и падениями:
- (Ваше приложение.) Начните со всех возможных начальных позиций и попытайтесь выяснить, где находится сообщение с контрольной суммой. После синхронизации это не требуется. (Легко, но возвращает сообщения-призраки с вероятностью 1/256. Не забудьте удалить поле синхронизации.)
- Используйте внутренний UART и найдите поле синхронизации; попытайтесь выяснить, имеют ли смысл данные после разделителя. (Это имеет меньшую вероятность ошибок, чем указано выше, но требует, чтобы разделитель синхронизации проходил без сбоев и, следовательно, мог пропускать сообщения.)
- Ищите разрыв. Самый простой способ сделать это — проставить временную метку на все поступающие байты. Вероятно, не требуется каким-либо образом буферизировать входящие данные, поскольку скорость передачи данных очень низкая (максимум 2000 байт / с). Номинально расстояние между концом последнего символа кадра и началом первого символа следующего кадра составляет не менее 13 бит. Поскольку получение символа занимает 10 бит, задержка между получением конца последнего символа в предыдущем сообщении и конца первого символа следующего сообщения номинально составляет не менее 23 бит. Чтобы обеспечить некоторый допуск для синхронизации битов, предел может быть установлен, например, на 17 бит. Если расстояние во времени между прерываниями «принят символ» превышает этот предел, символы принадлежат другому кадру. Как только вы обнаружите сбой, вы можете начать собирать новое сообщение. (Это работает почти в соответствии с официальной спецификацией.)
- Сделай сам по крупицам. Если у вас нет хорошей синхронизации между ведомым и ведущим устройством, вам придется определять тактовые частоты главного устройства с помощью этого метода. Реализация не очень проста, но один пример: http://www.atmel.com/images/doc1637.pdf (Я не утверждаю, что этот метод надежен, он довольно упрощен.)
Я бы выбрал # 3. Создайте прерывание для входящих данных, и всякий раз, когда поступают данные, вы сравниваете текущую временную метку (для которой вам нужен счетчик) с временной меткой предыдущего прерывания. Если межсимвольное время слишком велико, вы запускаете новое сообщение, в противном случае добавляете к старому сообщению. Тогда вам может потребоваться двойная буферизация для сообщений (одно вы собираете, другое анализируете), чтобы избежать очень длительных процедур прерывания.
Фактическая реализация зависит от другой структуры вашего кода. Это не должно занять много времени.
И если вы не можете убедиться, что ваши часы достаточно хорошо синхронизированы ( — 4%) с тактовыми часами moster, тогда вам придется взглянуть на # 4, который, вероятно, гораздо более поучителен, но довольно утомителен.
Комментарии:
1. Я не совсем знаком с фреймингом шины LIN, но я предполагаю, что это связано с управлением синхронизацией для отправки и получения данных. ATmel предлагает комплексное решение для автомобильных приложений, которое включает микроконтроллер, линейный контроллер и регулятор напряжения. Можно было бы предположить, что контроллер lin будет обрабатывать все необходимые синхронизации и обеспечивать уровень RX / TX cmos для микроконтроллера. Несмотря на это, спасибо за информацию и ваш ответ.
2. Смотрите мой отредактированный ответ. Более полное описание см., например, vr.ncue.edu.tw/esa/a1014/LIN.pdf . Самый сложный вопрос заключается в том, нужно ли вам синхронизировать часы или вы достаточно хорошо знаете частоту передачи.
3. Под «частотой» вы подразумеваете скорость, с которой работает шина? Если да, то в моем случае это будет 9600 бит / с. При такой скорости один бит составляет примерно 104 микросекунды (1/9600), поэтому в моем коде метода прерывания будут искать задержки более 2,2 миллисекунды. Это кажется правильным?
4. @jM2.me : Почти… Извините за ошибку в тексте, я ее исправлю. Длина одного символа составляет 10 символов, поэтому номинальная минимальная задержка между последним символом предыдущего кадра и первым символом следующего кадра должна составлять 10 13 = 23 бита, т.е. 23/9600 = 2,40 мс. Обычно ваши прерывания будут поступать с интервалом 10/9600 = 1,04 мс. Вам нужно будет выбрать значение между ними, чтобы определить межкадровую задержку. Я бы использовал 2,0 мс, но это не очень критично (если оно не слишком близко к 2,4 мс).
5. Это имеет смысл, но мне, вероятно, нужно будет больше узнать о последовательной связи. В любом случае, спасибо за информацию.
Ответ №2:
Ваш основной вопрос заключается в следующем (как я его вижу):
как я могу проверить производительность своего кода, чтобы определить, возможно ли переполнение буфера?
Установите высокий пин-код в начале алгоритма, а низкий — в конце. Посмотрите на это на осциллографе (я предполагаю, что у вас есть один из них — без него очень сложно разрабатывать встроенные приложения.) Вы сможете измерить максимальное время, затрачиваемое алгоритмом, а также получить некоторое представление об изменчивости.