Добрый день, довольно простая и обыденная задача вызвала большие затруднения с ее решением. Надо от одного таймера запустить 3 других и получить результат, как на рисунке 1.
TIM4 просто циклично задает начало отсчета (зеленая линия) с постоянной частотой. Далее мне надо получить картину как на рисунке, где все параметры (T1, T2, T3, P1, P2, P3) динамически могу меняться путем задания их длительности с ПК.
Основная проблема в том, что я не могу добиться нужной мне точности срабатывания таймеров и установки логических уровней на пинах мк. Для этого попробовал разные подходы:
1. Изначально была идея сделать на прерываниях. Довольно банально, от TIM4 стартуем все таймеры и в их прерываниях выставляем логические уровни и делаем их перезапуск.
В таком виде это работает, но с ошибками. Если выставить тайминги довольно большими, например T7 = 29 мк сек, то в целом картина более менее стабильна (на логическом анализаторе он будет 31.75), т.е. все тайминги по факту будут больше на порядка 1.5 - 2 мк сек, полагаю из за задержки на время запуска таймеров. Хотя такая задержка вызывает вопросы, не много ли? Но когда я уменьшаю время срабатывания таймера допустим T7 до 0.1 мк сек от старта, то тут во-первых этот тайминг не выставится меньше 2.5 мк сек (Рисунок 2), во вторых почему-то начинает сильно ошибаться величина P7, может уменьшиться в 1.5 раза и тд, происходит какое-то влияние одной величины на другую. Такая не предсказуемость меня не сильно устроила, поэтому попробовал второй вариант.
2. Решил я переделать все на one pulse mode. В целом идея та же в коллбеке TIM4 стартуем 3 таймера, но уже настроенные в этом режиме. Для эксперимента взял TIM11 и TIM12 Спойлер
Запускаю я их вместе, времена у них заданы одинаковые, а срабатывают они в разное время. А именно таймер 12 опаздывает на 2.5 мк сек. Измерил я, ради интереса, этот участок кода:
По длительности он как раз занимает порядка 2.2 мк сек. Отсюда следует, если таким образом запускать 3 таймера подряд, то 3й будет отставать от первого на 5 мк сек. Это трындец будет. Ну и вопрос, опять, почему так много уходит времени на запуск таймера?
3. Третьей моей идеей является взять один таймер с 4мя каналами, запустить его в коллбеке TIM4 и в прерывании от каждого канала запускать еще по одному таймеру, чтобы выдержать необходимые длительности импульсов (P1, P2, P3). Берем пока TIM12 на 2 канала. Ставлю такие параметры: Для канала 1 - TIM_OC_InitStruct.CompareValue = 1; Для канала 2 - TIM_OC_InitStruct.CompareValue = 2500; Т.е. при запуске в том же самом коллбеке TIM4
Я должен получить, что первый канал сработает сразу же, а второй как отсчитает 2500 тиков, что равно 25 мксек. По факту первый стартует спустя 1.5 мк сек, а второй 25 + 1.5 мк сек. Т.е. опять задержка от времени старта единицы мк секунд.
Исходя из этого: 1) Почему такие большие задержки запуска таймеров? 2) Какой подход для решения данной задачи будет самым правильным? 3) Может просто я что-то делаю не так?
Буду благодарен за любые подсказки, ибо не понимаю причину такой работы мк.
Лирическое отступление: мк - stm32f746. Настройка в CubeMX (для таймеров LL), так как используется FreeRTOS, но приоритет таймеров выше чем у любой задачи ОС. Таймеры функции ОС не используют
Вложения:
Комментарий к файлу: Рисунок 3 3.png [74.25 KiB]
Скачиваний: 77
Комментарий к файлу: Рисунок 2 2.png [27.46 KiB]
Скачиваний: 81
Комментарий к файлу: Рисунок 1 1.png [9.92 KiB]
Скачиваний: 93
Посмотрите, например, на странице 794 документа RM0385 табличку с внутренними сигналами промежтаймерными. Можно ведомые таймеры настроить так, чтобы они запускались от события ведущего без участия ядра. Ну и в том же документе конечно написано как это сделать. Может быть придётся использовать не именно те таймеры, что у вас сейчас, но главное, что принцип организации аппаратного взаимодействия таймеров будет понятен.
>TEHb<, Благодарю, тоже подумал про настройку ведомых таймеров в режиме one pulse mode. В целом сделал, есть одна загвоздка. Динамически задаю тайминги:
Так как в этом режиме задаются 2 точки, меняю пока только первую - время срабатывания таймера. Если выставляю величину 250 тиков таймера (2500 нс) и более, то все нормально, тайминги хорошие, таймер, который запустили вторым, отстает от первого на 750 нс (Рис. 1). Если же поставить CCR1 и CCR2 меньше, например 100 (1000 нс), то сигнал искажается, как на рис. 2 Такое поведение не понятно. Либо что-то не так с настройками, либо все-таки есть минимальный предел, меньше которого таймер не может нормально функционировать, но думаю, что это не так.
У таймеров есть slave-mode с одновременным запуском по мастер-таймеру, либо с запуском по событиям триггеров. ARPE в CR1 буферизует только ARR регистр. Если надо буферизовать CCRx регистры, биты её разрешения находится в регистрах CCMRx. Буферизация - это загрузка записанных в регистры значений только после наступления события Update, то есть в начале нового цикла счета.
RTOS и HAL могут вносить значительные задержки в доступе непосредственно к регистрам таймера, просто по причине очень длинного кода. И даже если вы назначили высокий приоритет задаче работы с таймерами, она все равно будет на короткое время прерываться с интервалом каждого системного тика, но возвращаться назад, если более приоритетных нет. Системные события никуда не деваются ведь, планировщик не остановлен.
Последний раз редактировалось MLX90640 Чт сен 01, 2022 15:41:16, всего редактировалось 1 раз.
Если выкинуть калокуб, задержка будет меньше. Но все-таки, правильней сделать, как советовали: использовать связанные таймеры. Таймер-господин по определенному событию будет пинать своих рабов. P.S. DmitryR, а что за задача-то? Это случаем не генерирование трех синусоид со сдвигом в 120°?
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Мурик, если надо будет - будут. Пока мне F7 не нужен. Я вообще не понимаю, честно говоря, для каких целей такую жиробасину можно использовать. Да и дорого ужасно. Дешевле же сделать связку из orange pi + STM32F072 или F103. Но уж вляпываться в калокод — ну это совсем буээ.
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Кстати, F7 ничем особым не отличается от того же F4 или даже F0 в этом плане. Если писали "на регистрах" для F0, то для F7 точно напишите таймеры. Они не отличаются, за исключением двух дополнительных каналов. Разве что частота до 216 МГц и расширенный набор инструкций позволяют быстрее "проглатывать" портянки HAL. Нынче F746 очень дорог. Иной раз H743 может оказаться дешевле.
>TEHb<, MLX90640, никогда не пользовался буферизацией, надо будет попробовать, спасибо за совет, только я не совсем понял какой регистр за это отвечает.
Цитата:
OC1PE: Output Compare 1 preload enable Бит для управления буферизацией регистра TIMx_CCR1. 0: буферизация регистра TIMx_CCR1 не используется; запись в регистр TIMx_CCR1 может быть произведена в любой момент и новое значение начнёт использоваться немедленно. 1: используется буферизация регистра TIMx_CCR1; операции чтения/записи выполняются с буферным регистром, новое значение из буфера передаётся в активный регистр (который и управляет работой таймера) при каждом событии обновления.
Вот, вроде, подходит, или все-таки CCMRx?
Цитата:
RTOS и HAL могут вносить значительные задержки в доступе непосредственно к регистрам таймера, просто по причине очень длинного кода. И даже если вы назначили высокий приоритет задаче работы с таймерами, она все равно будет на короткое время прерываться с интервалом каждого системного тика, но возвращаться назад, если более приоритетных нет. Системные события никуда не деваются ведь, планировщик не остановлен.
Там у FreeRTOS максимальный приоритет 5, у всех этих таймеров задан приоритет 3, функции ОС они не используют, по идее ОС не должна влиять, но точно утверждать не могу...
Eddy_Em,
Цитата:
Если выкинуть калокуб, задержка будет меньше.
Ну про куб и HAL... Там ОС и Ethernet (LwIP), писать это на регистрах точно нет, поэтому какой выход я тут пытаюсь найти: настройка периферии на HAL или LL, далее все, что не имеет критическое значение и может работать медленно и не очень эффективно на HAL или том же LL, все, что критически важно на CMSIS. Ну как-то так... Благо ресурсы контроллера позволяют.
Цитата:
а что за задача-то? Это случаем не генерирование трех синусоид со сдвигом в 120°?
Не, по сути управление драйверами для транзисторов, надо их в нужное время открывать и с довольно критичной точностью по времени.
Цитата:
Я вообще не понимаю, честно говоря, для каких целей такую жиробасину можно использовать. Да и дорого ужасно.
Ну я привожу же не весь проект, а только его конкретную часть, где возникли проблемы, но на самом деле там можно обойтись более простым контроллером, не 103 конечно, но каким-нибудь 407. Просто у меня отладочная плата nucleo c ethernet, мне удобно пользоваться такой, а там уже как проект готов, можно думать какой мк взять. А стоимость, стоимость такой платы месяца 3-4 назад около 3-4 тыс, с алиэкспресс приехали абсолютно нормальные платы один в один как в чип и дипе
А стоимость, стоимость такой платы месяца 3-4 назад около 3-4 тыс, с алиэкспресс приехали абсолютно нормальные платы один в один как в чип и дипе
Ну вот. А в случае с orange pi + дешевый МК вышло бы 2.5-3.5тыр. И на нормальном линуксе писать, а не извращаться с говеным lwip в убогой RTOS! И можно спокойно будет по ssh работать с железом (чего нельзя в случае МК)...
P.S. Получается, нужно сгенерировать три импульса строго определенной длительности, идущие через строго определенные промежутки времени? А обязательно отсчитывать прямо от общего начала? Ведь можно отсчитывать от времени подачи первого импульса. Тогда нужно будет использовать один таймер в режиме господина и два таймера в режиме раба. У первого CC1 будет определять длительность импульса, а CC2 и CC3 - пинать подчиненные таймеры. У тех же CC1 будет определять длительность. Иначе придется задействовать четыре таймера: один господин и три раба.
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Там у FreeRTOS максимальный приоритет 5, у всех этих таймеров задан приоритет 3
Это всё внутри операционки, а ей самой ещё нужно с железом и задачами цацкаться. Systick, например, какой-нибудь может кааак сработать и всё, времена уплыли. Если временные интервалы и формировать на ядре, то нужно чертовски точно до такта понимать что и как там работает. Во всех смыслах ловчее получается таки аппаратными средствами периферии, благо таковые средства имеются. Конкретный бит конкретного регистра не подскажу, я больше по HRTIM, но направление задали куда надо. Читайте, пробуйте.
Eddy_Em писал(а):
orange pi + дешевый МК
Можно ещё ноутбук старый прикупить за такие деньги и не караться с этим одноплатником. Тут и экран, и клавиатура и всё такое. Лично я бы для точных временных интервалов и вовсе 334 контроллер бы взял.
А в случае с orange pi + дешевый МК вышло бы 2.5-3.5тыр
Ну это довольно сомнительная выгода, чтобы так заморачиваться) На счет LWIP согласен, с ним тяжко, особенно когда была задача разогнать максимальную скорость передачи данных, он явно не для этого (хотя на форуме st есть серия постов, где этот стек разогнали до 90-95 Мбит/сек). К ОС особо претензий нет, но если бы LWIP (HTTP) не требовало бы ее, то и смысла в ней тоже нет для этой задачи.
Цитата:
И на нормальном линуксе писать
Все эти инструменты дело вкуса, навыков и времени на их осваивание. Raspberry pi еще есть) Но если бы мк совсем не тянул задачу, лично я бы лучше взял связку мк + ПЛИС. Как правило самые критичные функции они же и являются самыми простыми по функционалу, типа как здесь таймеры, а самое объемное и замороченное, типа как передача данных по Ethernet, не столь требовательны к скорости выполнения.
Цитата:
P.S. Получается, нужно сгенерировать три импульса строго определенной длительности, идущие через строго определенные промежутки времени? А обязательно отсчитывать прямо от общего начала? Ведь можно отсчитывать от времени подачи первого импульса.
Нуу, в идеале да, строго определенной длительности и в строго определенное время. Строгость тут относительная, например я готов понять, если я запущу таймер так, чтобы он сработал через 20 мксек, а он сработает через 20.25 это одно дело, а если он сработает через 23 мк сек, это дикость для таймера, который тактируется частотой 100 МГц. Тут больше нюанс в том, что мне не нужны артефакты в работе кода, а именно ситуация как на приведенном выше скрине, когда я меняю время срабатывания таймера, а у меня появляются ложные срабатывания, либо была еще ситуация, когда мной изменялся только промежуток времени начала импульса, а его длительность сама изменилась в 1.5 раза, хотя этот параметр никто не трогал. Такое поведение наблюдается, когда он старта до момента срабатывания таймера требуется меньше 1-5 мк секунд. В этом диапазоне наблюдается хаотичное поведение не соответствующее требуемому.
К тому, что у меня задержка от запуска таймера до его максимально быстрого срабатывания 500 ns я уже, своего рода, привык, главное чтобы этот параметр был постоянным, чтобы импульсы каждый раз запускались в один и тот же момент.
Но от первого таймера отталкиваться нельзя, так как все параметры (время старта и длительность импульса) могут быть и будут динамически меняться, не исключена ситуация, когда второй импульс, в какой-то момент, станет первым и тд.
Поэтому суть в том, чтобы все 3 таймера были привязаны к одному моменту старта, были довольно точны по своему срабатыванию (ну в пределах 100 нс) и таймеры могли иметь возможность сработать как можно раньше от своего запуска. Ну и, соответственно, не было ошибок в работе.
Цитата:
Если временные интервалы и формировать на ядре, то нужно чертовски точно до такта понимать что и как там работает. Во всех смыслах ловчее получается таки аппаратными средствами периферии, благо таковые средства имеются.
Ну вот получается сейчас так реализовано, с ведущим и ведомыми таймерами. Только один момент, сейчас я в прерывании от ведущего таймера запускаю ведомые в режиме one pulse mode:
А могу я как-то один раз запустить ведомые и ведущий таймер вместе, чтобы мне не надо было ведомые каждый раз в прерывании от ведущего запускать? Тогда это будет работать без участия процессора.
Код:
Systick, например, какой-нибудь может кааак сработать и всё
Если я не ошибаюсь, то и Systick имеет приоритет не выше 5го, т.е. эти таймеры с приоритетом 3 перебью все процессы ОС, именно поэтому я и не могу использовать в них функционал ОС
Добавлено after 8 minutes 10 seconds: Я как-то даже не подумал попробовать запустить ведущие таймеры, а потом ведомый, интересно, как себя поведет мк
Добавлено after 11 minutes 1 second: MLX90640, где-нибудь перед запуском или в инициализации добавить TIM3->CCMR1 |= TIM_CCMR1_OC1PE; Правильно же понимаю?
Systick - это таймер системных тиков для RTOS, и он ну полюбасу будет вызываться вот как угодно, просто для того, чтобы сама операционка работала. Если его заблокировать, то операционка повиснет. Тут как бы не надо путать приоритеты задач внутри операционки и приоритеты прерываний микроконтроллера. Приоритеты задач - это очередность выполнения их и величина выделяемого на задачу времени. Щас как бы нет особо времени вникнуть в суть проблемы вашей, я просто временно отвлекаюсь на форум.
MLX90640, Мои познания в работе FreeRTOS не так значительны, чтобы спорить на счет ее работы) Я думал Systick нужен, чтобы в заданные промежутки времени пинать шедулер, который всех прерывает и передает управление, но может Вы и правы)
Ну в принципе то да, систик, работающий на прерывании микроконтроллера, вызывается через равные промежутки времени и вызывает функции планировщика (шедулера), который и определяет, какие задачи в какой очередности переключать. Да. И если есть активная задача с более высоким приоритетом чем остальные задачи, планировщик обратно передаст ей управление. Но выполение кода планировщика тоже занимает время. Как правило, приоритет прерывания систика довольно низкий в системе прерываний микроконтроллера. Другие прерывания с более высоким приоритетом не будут перебиты систиком и будут обработаны с минимальной задержкой. Однако, использование функций HAL дает ощутимую задержку из-за длинного кода этих функций, ориентированного на универсальность написания программистом, но не на скорость работы кода. Каждый лишний коллбек, каждое лишнее использование HAL будет добавлять задержку выполения. В сумме она может стать весьма значительной.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения