Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Расчет и поиск делителя PSC и периода ARR для таймера STM32

Ср фев 05, 2020 19:02:08

Встречал данный вопрос на англоязычных сайтах, а так же и наших просторах, дельного к сожалению не нашел, но может что-то поменялось сейчас. В-общем суть по началу простая, хочу формировать с помощью режима PWM на таймерах STM32 последовательность импульсов на шаговики (как пример). Оставим в стороне формирование рампы разгона и торможения, это целая отдельная тема, пока мне не совсем понятен подход большинства кодеров, кто как формирует произвольную частоту?
Есть замечательная програмка Timer Calculator от mikroe.com, которая считает оптимальную пару в прескалер-регистр PSC и период таймера ARR на компе. НО!!! что если я хочу предоставить пользователю задавать частоту самому в диапазоне от 1 до 20 кГц, это значит я должен в программе контроллера просчитать эту пару. Тогда возникает ряд неудобств, для получения частоты 1 Гц я должен тактирующую частоту 72МГц поделить на 72000000, а это никак не влезает в 16 битные регистры и необходимо разбивать 72000000 на пары, например, 60000 и 1200, и так далее для каждой частоты. Для некоторых частот пары могут давать разную погрешность, если деление не происходит нацело: например для получения 7 это 29138 и 353, а пара 65535 и 183 даст гораздо большую погрешность 0,0591599783% против 0,0000027778% как было у первой пары. Но ведь эту пару надо еще найти. Другой пример: для 23Гц пара 56917 и 55 с погрешностью 0,0000069444%. Общий принцип, который советуют - это факторизация или разложение на множители путем перебора одного из множителей начиная от минимального числа (72МГц/("необходимая частота")*65535) и до корня квадратного из (72МГц/("необходимая частота")), а затем выбор пары с наименьшей погрешностью получения нужной частоты (просто попаданию в коридор разрешенной погрешности). Кто-то советует использовать для этого только простые числа (вель это сократит количество циклов) и даже рекомендует ознакомиться с решетом Сундарама для их поиска, но тут есть проблемки, некоторые пары, как например для 23Гц имеет малый множитель, которые не относится к простым числам, а ближайшее простое число 173 у которого пара с 18095 дает такую же погрешность, требует перебора уже большого числа циклов (для 23Гц перебираем от 48 до 55 - это 8 числе, а в случае с простыми числами 25 чисел), в нагрузке которых деление итп. Еще одна из проблем - пары могут дать разные по величине множители и если использовать период по назначению, то будет меняться глубина регулирования, не знаю на сколько это страшно, но возможно где-то это прям камень преткновения.

В итоге прошу у сообщества советов по данному вопросу.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Ср фев 05, 2020 19:35:45

А если заранее вычислить и хранить таблицу?

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Ср фев 05, 2020 19:44:30

Можно и таблицу, можно взять мк с 32-х битным таймером, можно и тупо перебрать несколько десятков тысяч вариантов, думаю в максимум 10ms можно списаться.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Ср фев 05, 2020 21:08:41

Напрямую таймером может не получится. Можно воспользоваться алгоритмом DDS для прямоугольного сигнала. Там легко получить частоту с точностью 0,1Гц. Но вам нужно считать колличество импульсов? и соотносить с другими шаговиками?

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Ср фев 05, 2020 21:16:44

Напрямую таймером может не получится. Можно воспользоваться алгоритмом DDS для прямоугольного сигнала. Там легко получить частоту с точностью 0,1Гц. Но вам нужно считать колличество импульсов? и соотносить с другими шаговиками?

точность 0,1 Гц это без проблем, такое совпадение пар можно получить порой даже без перебора. По поводу интерполяций итп с другими осями для этой задачи не предусмотрено. Импульсы считать хочется, пока не знаю что лучше использовать, хотел DMA или регистр таймера для этих целей использовать (название не упомню сразу, но который количество повторений загрузок ограничивает).

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Ср фев 05, 2020 21:25:04

Про 0,1Гц это для частоты 10КГц. На 23 Гц будет пропорционально точнее.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 08:36:03

А, по-простому, подобрать "на лету" ? Как я понимаю, есть два числа, X и Y, из диапазона 1-65536, произведение которых должно быть как можно ближе к точному значению, допустим, Div32 ? Так задаем X = 65535, затем в цикле делаем Y = Div32 / X, проверяем, какая получилась точность, если лучше предыдущей итерации запоминаем эту, затем уменьшаем X на единичку и повторяем цикл. Заканчиваем, когда Y окажется больше X, Ну, или в любой момент, если вдруг ошибка окажется равной нулю (существует точное представление). При тактовой 72 МГц это должно быть довольно быстро...

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 11:48:27

Как я понимаю, есть два числа, X и Y, из диапазона 1-65536, произведение которых должно быть как можно ближе к точному значению, допустим, Div32 ? Так задаем X = 65535, затем в цикле делаем Y = Div32 / X, проверяем, какая получилась точность, если лучше предыдущей итерации запоминаем эту, затем уменьшаем X на единичку и повторяем цикл. Заканчиваем, когда Y окажется больше X, Ну, или в любой момент, если вдруг ошибка окажется равной нулю (существует точное представление). При тактовой 72 МГц это должно быть довольно быстро...

Конечно вместо целочисленного умножения за такт и сравнения целых чисел можно делить и сравнивать числа с плавающей точкой на мк без FPU, но зачем? :) В худшем случае придется перебрать практически весь диапазон 65К, это уже будет не 10ms, а хорошо если 100...

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 16:02:14

В-общем суть по началу простая, хочу формировать с помощью режима PWM на таймерах STM32 последовательность импульсов на шаговики (как пример).

Это не так делается. Полностью аппаратный шим для шаговиков - изначально неверный путь. Дело в том что новый шаг должен определяться не частотой, а временем события этого шага. В этом случае становится доступным плавный разгон, и торможение, а так-же режим стоп - чего на таймере сделать просто нереально.
Событие нужно проверять через фиксированные промежутки времени, вот тут таймер сгодится - например проверка каждые 1мс.
Для того чтобы вращать двигатель с разной скоростью - понадобятся дробные делители, в программном виде это выглядит очень просто: целое число со знаком, например int32_t. Используется половина этого числа - 2147483647, что с таймингом в 1мс даёт дробное время 46,56612.. пикосекунд - более чем достаточно.
Например нам для вращения двигателя нужна частота 201Гц, дробный делитель при этом будет 201*2/1000*2147483647 = 1075889307. Вот это число нужно прибавлять к счётчику в прерывании таймера. Если результат будет больше нуля - то отнять 2147483647 и инвентировать пин программного шима.
А теперь разгон/торможение - для этого полученное число необходимо умножать на вторую переменную, которая будет плавно меняться от нуля до единицы. Эту переменную нужно увеличивать/уменьшать в прерывании, с контролем нуля и единицы.

Программная частота будет иметь небольшой джиттер, но механика мотора его прекрасно компенсирует.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 18:33:25

AVI-crak писал(а):целое число со знаком, например int32_t.
AVI-crak писал(а):201*2/1000*2147483647 = 1075889307
Может я чего не понял, но при целочисленных вычислениях получим другой результат. 201*2/1000 даст 0, который умножив на 2147483647 получим 0. :dont_know: :facepalm:

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 19:17:29

Reflector писал(а):можно делить и сравнивать числа с плавающей точкой на мк без FPU, но зачем?
Причем здесь плавучка? Целые числа, 32-разрядная арифметика, может быть, потребуется одна-две 64-битных операции, и то вряд ли. Тут, правда, коллега AVI-crak высказал более серьезное замечание, что в этой задаче надо мыслить не в частотной, а во временнОй области, но и тут, в принципе, все спокойно должно считаться в целых числах, только аккуратно надо.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 19:46:49

Причем здесь плавучка? Целые числа, 32-разрядная арифметика, может быть, потребуется одна-две 64-битных операции, и то вряд ли.

Например, для 19'992 Гц нужно искать числа произведение которых максимально близко к 72M / 19'992 = 3601.44. Даже если отбросить дробную часть, то 3601 при делении на 100, 99 или 98 дает 36.01, 36.37 и 36.75, возможно первое из этих значений нам и нужно, но ведь при целочисленном делении будет просто 36/36/36, что с ними делать дальше?

ps. Не самый удачный пример, т.к. 3601 влазит в 16 бит, но тем не менее :)

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 21:44:54

Тут бы определиться с частотными границами. Для примера примем самый обычный шаговик на 200 шагов.Например ограничим максимальную частоту вращения 1200 об/мин или 20 об/сек. С полным шагом частота сигнала Step будет 4000 Гц, с дроблением на 4 соответственно 16 кГц или время одного Step - 62,5 мкс. Вопрос - с какой точностью вы хотите выдерживать такое время? Я так понимаю это будет зависеть от задания разгона/торможения? Для таймера с входной частотой 72 Мгц делитель получится 4500 и ошибка установки 1/4500 -> 0.022% Этого не достаточно?

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 23:19:17

Если нужно вычислить что-то по формуле Y=A*X/B, то наилучшим способом вычисления A и B является приближение A/B цепной дробью.
В Octave для этого есть функция rat. Скажем, надо нам найти с точностью 0.001 приближение числа 0.178:
Код:
[N D]=rat(0.178, 0.001)
N =  8
D =  45

Все, это - 8/45!
И так далее.. Понятно, что при таких вычислениях нужно следить, чтобы умножение не вышло за пределы используемого целочисленного типа.

// храню всякие разные настройки АЦП именно в виде numerator/denominator, а требуемые значения функцией rat вычисляю.
Аналогично можно и множитель/делитель для настройки таймера вычислять.

Добавлено after 4 minutes 15 seconds:
Re: Расчет и поиск делителя PSC и периода ARR для таймера STM32
P.S. На самом деле, для шаговика нафиг не нужно вычислять скорость. Задавайте период и не парьтесь... Я обычно в зависимости от микрошагов так настраиваю таймер, чтобы минимальный шаг был 1мс. Разгон/торможение тоже легко реализуются инкрементом/декрементом CCR и ARR.
Вот так просто у меня в одной (уже полтора года работающей) железяке реализовано управление двумя шаговиками (каждому ШД свой таймер для полной независимости).
Последний раз редактировалось Eddy_Em Чт фев 06, 2020 23:22:57, всего редактировалось 1 раз.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Чт фев 06, 2020 23:19:40

Может я чего не понял, но при целочисленных вычислениях получим другой результат.

Извиняюсь, у меня там мысль потерялась.
F*2*2147483647 / 1000 = 863288426
При умножении int32_t - в промежуточных вычислениях автоматически получается int64_t, куда всё гарантированно влезет.(наверное)

Sergi - при выходной частоте 16КГц, частота таймера должна быть минимум в 4 раза выше. Та самая теорема Котельникова.
И да, джиттер уже будет слышно. Мотор будет сопротивляться дрожанию фазы, и излучать звук.
Но с другой стороны - от нуля до 1200 об/мин, без регистрации и смс.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Пт фев 07, 2020 06:24:50

Это я писал в отношении скорости и да период 62,5, там и фронт и спад. Как правило шаговики применяют для позиционирования. К задающему таймеру привязать slave 32бит и в регистре CNT будем иметь шаги. С такой разрядностью это +-130тысяч оборотов двигателя вперед-назад с точностью 1/4 шага. И разгон легко посчитать как функцию разности текущего CNT и необходимого. Естественно с пределами задания скорости.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Сб фев 08, 2020 12:03:30

Прикольно :) А школьную математику уже забыли? PSC и ARR - это два множителя при подсчете коэфф.деления. C = (PSC - 1) * (ARR - 1). Причем, они равноправны. Что 2 * 5, что 5 * 2, полюбасу = 10. Ну а от коэфф.деления перейти к периоду, а оттудава к частоте - тоже несложно.

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Вс фев 09, 2020 11:17:33

Спрошу здесь же, чет не пойму...если использовать режим TIM_OCMode_PWM1 и настроить запрос к DMA путем команы TIM_DMACmd(TIM2,TIM_DMA_CC1,ENABLE); запросы к DMA проходят успешно, считаем в DMA_Setting.DMA_BufferSize = Num_Pulses; (или DMA1_Channel5->CNDTR) получаем один импульс при текущих настройках + (Num_Pulses -1) последующих импульсов путем загрузки их по DMA, все здорово, затем прерывание DMA1_Channel5_IRQHandler по биту TC (весь буфер передан), там остановка таймера.
НО!!! стоит только использовать TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE); для запросов DMA, как все перестает работать как надо, прерывание DMA1_Channel5_IRQHandler не поступает, хотя явно вижу в SR регистре UIF флаг в 1. TIM_UpdateDisableConfig(TIM2, DISABLE); и TIM_UpdateRequestConfig(TIM2, ENABLE); особой разницы не вносят...что я делаю не так?
Может просто в режиме TIM_OCMode_PWM1 не предусмотрена работа с TIM_DMA_Update ?

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Вс фев 09, 2020 12:01:58

Связка двух таймеров позволяет отделить программный счет. Второй таймер посчитает шаги в любом случае, хоть при обработке любого прерывания, хоть во время задержки (программный Delay).На него не тратится процессорное время. Только указать направление счета согласно Dir. Если нет 32битного, можно и 16битный применить. Только учитывать переполнения во внешней переменной.
В вашем случае может лучше отслеживать флаг переполнения вместо флага совпадения?

Re: Расчет и поиск делителя PSC и периода ARR для таймера ST

Вс фев 09, 2020 13:24:42

Связка двух таймеров позволяет отделить программный счет. Второй таймер посчитает шаги в любом случае, хоть при обработке любого прерывания, хоть во время задержки (программный Delay).На него не тратится процессорное время. Только указать направление счета согласно Dir. Если нет 32битного, можно и 16битный применить. Только учитывать переполнения во внешней переменной.
В вашем случае может лучше отслеживать флаг переполнения вместо флага совпадения?

Честно говоря, не понял о чем речь. У меня нет связки двух таймером и так не хочу делать. У меня задача на обычном таймере (TIM2-TIM5) сделать определенное число импульсов ШИМ (в том числе 50%/50% для шаговиков/сервы), тк нет регистра счетчика (да и в продвинутых он 8 битный, а мне бы вообще в идеале 32 битный) пользуюсь возможностями привязать импульсы к запросам на DMA (тем более потом буду ШИМ делать не простой, а с возможностью выдать просчитанный буфер для разгона). У меня была мысль привязать запрос DMA на событие Update, но оно почему-то не вызывало прерывания в отличие от CCR1.
ПыСы: По основному вопросу пришел к выводу, что устраивающий по точности и быстрый по исполнению результат получается, когда необходимую частоту 72000000/Pulse_fr (которая кстати не влезает в 16 бит только, если частота Pulse_fr менее 1099) делим на число 65536. Так получаем прескалер (округляем вверх), делим 72000000/Pulse_fr на прескалер, получаем период таймера, округляем. А если еще заморочиться с проверкой остатка от деления на полезные числа типа 60000 вместо 65536, то кое-где вообще можно получить погрешность 0 :shock: :)) .
Ответить