sadr0b0t / stepper_h

Stepper motor control library for ChipKIT/Arduino
GNU Lesser General Public License v3.0
3 stars 1 forks source link

Замерить/посчитать рабочие частоты таймера для одновременного вращения моторов на разных контроллерах #25

Closed sadr0b0t closed 7 years ago

sadr0b0t commented 7 years ago

Замерить/посчитать рабочие частоты таймера для одновременного вращения моторов на разных контроллерах.

Тестовые чипы

Истотия такая.

Понятно, что чем выше частота таймера, тем быстрее мы можем крутить моторами (и достигать их предельных значений). Но просто выставить максимальную частоту мы не можем, т.к. на определенных скоростях обработчик прерыванию перестанет умещаться в отведенный ему промежуток времени, тем более, если нужно вращать сразу несколько моторов. Поэтому нужно искать некий компромисс, подобрать частоту так, чтобы и весь необходимый код выполнялся во-время, и моторы крутились максимально быстро.

Таким образом, задача - произвести замеры производительности чипов и зафиксировать максимальные рабочие частоты для линейного перемещения моторов в ситуациях:

Предварительно начало работы (для PIC32MX/ChipKIT) положено здесь: Добавить вызов max_cycle_time https://github.com/sadr0b0t/stepper_h/issues/17 Рабочие частоты для моторов с разными делителями здесь: Посчитать разные граничные значения для драйверов, моторов и логики https://github.com/sadr0b0t/stepper_h/issues/23

sadr0b0t commented 7 years ago

И вот они, замеры

    // 
    // для периода 1 микросекунда (1млн вызовов в секунду == 1МГц):
    // 
    // - PIC32MX/ChipKIT (вообще не ок)
    // 1 мотор:
    //   timer handler takes longer than timer period: cycle time=3us, timer period=1us
    // 
    // - AVR/Arduino (вообще не ок):
    // 2 мотора: cycle time=4294966284us (снос крыши)

    _timer_period_us = stepper_configure_timer_1MHz(TIMER_DEFAULT);
    // 
    // для периода 5 микросекунд (200тыс вызовов в секунду == 200КГц):
    // 
    // - PIC32MX/ChipKIT (вообще не ок)
    // 1 мотор:
    //   timer handler takes longer than timer period: cycle time=5us, timer period=5us
    // 2 мотора:
    //   timer handler takes longer than timer period: cycle time=5us, timer period=5us

    _timer_period_us = stepper_configure_timer_200KHz(TIMER_DEFAULT);
    // 
    // для периода 10 микросекунд (100тыс вызовов в секунду == 100КГц):
    // 
    // - PIC32MX/ChipKIT (наименьший период для 3х моторов)
    // 1 мотор (ок):
    //   Finished cycle, max time=4
    // 2 мотора (ок):
    //   Finished cycle, max time=7
    // 3 мотора (не ок):
    //   timer handler takes longer than timer period: cycle time=10us, timer period=10us
    //
    // - AVR/Arduino (вообще не ок):
    // 1 мотор (не ок: снос крыши):
    //   timer handler takes longer than timer period: cycle time=4294966284us, timer period=10us
    // 2 мотора (не ок: снос крыши):
    //   timer handler takes longer than timer period: cycle time=4294966284us, timer period=10us

    _timer_period_us = stepper_configure_timer_100KHz(TIMER_DEFAULT);
    // 
    // для периода 20 микросекунд (50тыс вызовов в секунду == 50КГц):
    //
    // - PIC32MX/ChipKIT (наименьший период для 3х моторов)
    // 2 мотора (тем более ок):
    //   Finished cycle, max time=9
    // 3 мотора (ок):
    //   Finished cycle, max time=11
    // дуга-2 мотора (не ок)
    //   совсем не ок для движения по дуге (по 90мкс на acos/asin)
    //
    // - AVR/Arduino (вообще не ок):
    // 1 мотор (не ок: снос крыши)
    //   timer handler takes longer than timer period: cycle time=4294966284us, timer period=20us
    // 2 мотора (не ок: снос крыши):
    //   timer handler takes longer than timer period: cycle time=4294966284us, timer period=20us
    //   cycle time=4294966284us - это почти 2^32(=4294967296-4294966284=1012 - разница 1 миллисекунда).
    // Довольно странное значение (по времени это 72 минуты), в stepper_timer.cpp это переменная _cycle_max_time,
    // по коду не очень понятно, как в нее могло попасть это число. 
    // Двоичное представление: b11111111_11111111_11111100_00001100
    // Пока что проще всего списать на некий глюк, который будет происходить на контроллере,
    // если обработчик прерывания не укладывается в период между тиками таймера.
    // Если присваивать _cycle_max_time константу, то мусор в переменной не появляется,
    // значит проблема возникает где-то вот в этих 3х строках:
    // 
    //   unsigned long cycle_start = micros();
    //   ...
    //   unsigned long cycle_finish = micros();
    //   unsigned long cycle_time = cycle_finish - cycle_start;
    // после небольшого дебага получили максимальные значения замеров:
    // cycle_start(max) = 5003256
    // cycle_finish(max) = 5003256
    // Возможно, в один из моментов получается, что значение start как-то получется
    // даже больше, чем финиш, в _cycle_max_time появляется отрицательное значение,
    // которое из-за unsigned, превращается в большое положительное.

    _timer_period_us = stepper_configure_timer_50KHz(TIMER_DEFAULT);
    // 
    // для периода 50 микросекунд (20тыс вызовов в секунду == 20КГц):
    // 
    // - AVR/Arduino (наименьший период для 1 мотора):
    // 1 мотор (ок):
    //   Finished cycle, max time=40
    // 2 мотора (не ок):
    //   timer handler takes longer than timer period: cycle time=60us, timer period=50us
    //   (хотя в цикл не умещается, но уже по крайней мере значение корректно)

    _timer_period_us = stepper_configure_timer_20KHz(TIMER_DEFAULT);
    // 
    // для периода 100 микросекунд (10тыс вызовов в секунду == 10КГц):
    // 
    // - AVR/Arduino (наименьший период для 2х моторов):
    // 2 мотора (ок)
    //   Finished cycle, max time=72
    // 3 мотора (не ок)
    //   timer handler takes longer than timer period: cycle time=100us, timer period=100us 

    _timer_period_us = stepper_configure_timer_10KHz(TIMER_DEFAULT);
    // 
    // для периода 200 микросекунд (5тыс вызовов в секунду == 5КГц):
    // 
    // - PIC32MX/ChipKIT 
    //   ок для движения по дуге (по 90мкс на acos/asin)
    // 
    // - AVR/Arduino (наименьший период для 3х моторов):
    // 2 мотора (ок)
    //   Finished cycle, max time=72
    // 3 мотора (ок)
    //   Finished cycle, max time=104

    _timer_period_us = stepper_configure_timer_5KHz(TIMER_DEFAULT);
sadr0b0t commented 7 years ago

В итоге, имеем

Для PIC32MX/ChipKIT 80МГц

время выполнения одного цикла (может плавать плюс-минус в разных ситуациях, но, обычно, не радикально)

Вспомним максимальные рабочие частоты моторов с разными делителями шага https://github.com/sadr0b0t/stepper_h/issues/23)

один шаг мотора должен включать минимум 3 цикла таймера, поэтому минимальная задержка между шагами мотора step_delay будет:

Видим, что критическую роль частота таймера начитает играть только при делителе шага 1/32: 1 и 2 мотора можно вращать с максимальной скоростью на пределе рабочей частоты, 3 мотора можно вращать только в половину скорости. Для остальных делителей частота таймера оставляет запас на понижение с сохранением максимальной скорости вращения.

Сделаем частоту 50КГц (период=20мкс - достаточно для вращения одновременно 3х моторов) частотой по умолчанию на платформе PIC32MX/ChipKIT. Рекомендуемые значения минимальной задержки step_delay для разных делителей в таком случае с учетом кратности будут:

Для AVR/Arduino 16МГц

время выполнения одного цикла (может плавать плюс-минус в разных ситуациях, но, обычно, не радикально)

Вспомним максимальные рабочие частоты моторов с разными делителями шага https://github.com/sadr0b0t/stepper_h/issues/23)

один шаг мотора должен включать минимум 3 цикла таймера, поэтому минимальная задержка между шагами мотора step_delay будет:

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

Видим, что на чипах AVR+Arduino частота таймера уже начинает нагладывать существенные ограничения на скорость вращения моторов, особенно, при больших делителях шага. Относительно комфортно с минимальными потерями скорости можно работать с делителями 1/4, 1/2. На больших делителях работоспособноть, конечно, сохранится, но придется жертвовать максимальной скоростью.

Сделаем частоту 5КГц (период=200мкс - достаточно для вращения одновременно 3х моторов) частотой по умолчанию на платформе AVR/Arduino. Рекомендуемые значения минимальной задержки step_delay для разных делителей в таком случае с учетом кратности будут:

sadr0b0t commented 7 years ago

Добавил результаты в ридми и поправил тестовый скетч заодно вместе с портом на AVR/Arduino https://github.com/sadr0b0t/stepper_h/commit/906d1e5974f10c8c5250c782594ba47c4fa8961b https://github.com/sadr0b0t/stepper_h/issues/4