This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Question about clock ratio with the Tiva C Series

Hi,

I'm using the Tiva C Series to drive step motors and I try to figure out how to control my step motors step by step. I would like to be able to count the number of steps my motors are doing.

To do it, I use a timer set to the PWM period in clock ticks (not sure if this is the right way to do it). My sysclock is configured to 80Mhz:

ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

And I use a 4 div PWM clock:

ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_4);

Unfortunatelly, the PWM clock is isn't 20Mhz at all. If I display in the UART the value from ROM_SysCtlPWMClockGet() I get 1,17MMHz instead. What's wrong wit ROM_SysCtlPWMClockSet() ?

If I understand, I should set my timer in sysclock period. So to set my timer to the period of sysclock, I should do:

TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_SYSTEM);
ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 1); // should set to sysclock?

But I also set the period of the PWM from ROM_PWMGenPeriodSet() to change the speed of rotation. The period of the PWM is set in PWM clock ticks, rights? So if I set the PWM period like:

ROM_PWMGenPeriodSet(..., 1000);

It should be 1000 PWM clock ticks => 4000 timer ticks.

So to set my step counter, I do:

clockRatio = ROM_SysCtlClockGet() / ROM_SysCtlPWMClockGet();
microStepCount = microStepsToDo * pwmPeriod * clockRatio;

But with the wrong ratio it won't work. Any idea?

  • Hello Cyril

    SysCtlPWMClockSet function is for the PWM Peripheral. The Timer peripheral's PWM mode is not controlled by this API. The Timer still works at System clock

    Regards
    Amit
  • Hi Amit,

    Yes I know the timer uses the System Clock, that's why I set it to 1 System Clock period (12.5ns). But I cannot figure out what's the PWM clock to know how many steps I did for 1 timer tick. If I know the PWM clock is 4 times slower than the System Clock, I can do numSteps * pwmPeriod * 4 to know how many counts I have to do in the timer to do numSteps steps with my motor. 

    Regards.

  • Hello Cyril

    That would be the divider on the PWM clock. If the divider is set to 4 then it will take 4 timer clocks for 1 PWM clock

    By the way there is a stepper motor reference design with TM4C12x devices which I would suggest,

    Regards
    Amit
  • Hi Amit,

    I use a pololu stepper motor driver on a home made shield. It works like a charm.

    If this is the divider, why ROM_SysCtlClockGet() isn't 4 times (not even close, 68 times!) ROM_SysCtlPWMClockGet() ?

    Regards

  • Hello Cyril

    Which TivaWare version are you using? I hope this is a TM4C123x device

    Also a simplified code to exhibit the same would be much appreciated so that we can check what the issue is?

    Regards
    Amit
  • Hi Amit,

    I use TivaWare v2.1.1.71. Yes this is a TM4C123x device.

    I program my Tiva in C++ so I won't be able to give you a simple code as it has multiple dependencies. 

    The idea is to do so:

    uint8_t usingTimer = 0; // number of motors using the timer
    uint16_t microStepsFreq = 63535; // frequency of the PWM
    uint32_t microStepsCount = 0; // number of steps
    
    void init()
    {
        ROM_FPUEnable();
        ROM_FPULazyStackingEnable();
    
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
        ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_4);
    
        ROM_IntMasterEnable();
    }
    
    void stepsCallback()
    {
        // count the steps by calling countMicroSteps() for each motor
    countMicroSteps(); } void startTimer() { if (usingTimer == 0) { ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); TimerClockSourceSet(TIMER1_BASE, TIMER_CLOCK_SYSTEM); ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC); ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 4); // the PWM clock is 4 times slower than the System clock TimerIntRegister(TIMER1_BASE, TIMER_A, stepsCallback); ROM_IntEnable(INT_TIMER1A); ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); ROM_TimerEnable(TIMER1_BASE, TIMER_A); ROM_IntPrioritySet(INT_TIMER1A, 3); } usingTimer++; } void stopTimer() { usingTimer--; if (usingTimer == 0) { ROM_TimerDisable(TIMER1_BASE, TIMER_A); ROM_TimerIntDisable(TIMER1_BASE, TIMER_TIMA_TIMEOUT); ROM_IntDisable(INT_TIMER1A); TimerIntUnregister(TIMER1_BASE, TIMER_A); } } void setFrequency(uint16_t freq) { uint16_t period = UINT26_MAX - freq; ROM_PWMOutputState(..., true); ROM_PWMGenPeriodSet(..., period); ROM_PWMPulseWidthSet(..., period / 2); } void idle() { microStepsFreq = 0; microStepsCount = 0; ROM_PWMGenPeriodSet(..., 0); ROM_PWMPulseWidthSet(..., 0); ROM_PWMOutputState(..., false); } void turn(uint16_t microSteps) { microStepsCount = microSteps * (UINT16_MAX - microStepsFreq); enableMotor(); // just set the enable GPIO startTimer(); } bool countMicroSteps() { if (microStepsCount != 0) { setFrequency(microStepsFreq); microStepsCount--; if (microStepsCount == 0) { idle(); disableMotor(); stopTimer(); return false; } } return true; } int main(int argc, char *argv[]) { init(); turn(200); while (1); return 0; }
  • Hello Cyril

    The ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, 4); will cause an interrupt every 4 system clock cycles. The Cortex M4F takes almost 10-12 system clock cycles to go to an interrupt handler. So before the interrupt handler gets invoked multiple interrupts have already happened

    Regards
    Amit
  • So If I do:

    ROM_SysCtlPWMClockSet(SYSCTL_PWMDIV_32);

    I should be able to count the steps of my motors?

  • Hello Cyril

    No. The interrupt is coming from timer and not PWM peripheral. The Timer has to run slower if interrupt processing overhead is taken into account. Try with a larger granule size, e.g. a count of 1000 instead of 4.

    Regards
    Amit
  • Hi Amit,

    Well if the timer is slower than the PWM, I won't be able to count the steps or?

    Regards.

  • Hello Cyril,

    How many microsteps are you counting for every turn and what is time period of each PWM pulse?

    Regards
    Amit
  • Hi

    Today I set the PWM clock to be 4 times slower than the System Clock (80MHz). The PWM period can change depending on the speed I want (I even should implement a trapezoid for acceleration). For the speed I decided to use a percentage. 0% is off and 100% is fullspeed. The percentage is set between 65535 (off) and 1 (full speed) ticks for for the PWM period (as it is a 16bits period).

    A step motor takes 3200 microsteps (200 steps) to do a complete turn. It takes about 9000 PWM pulse so I use a conversion factor I want to avoid.

    I also should be able to do acceleration and deceleration that make the counting not accurate as the timer doen't sync with PWM period variation.

    Regards.

  • Hello Cyril,

    It doesn't look like we have a solution for the requirements where a timer interrupt can be processed that fast.

    Regards
    Amit
  • Hi,

    Actually this isn't 4 times slower but 68 times because SysCtlPWMClockGet() doesn't return 20.000.000 but ~1.170.000.

    Regards.

  • Today I set the PWM clock to be 4 times slower than the System Clock (80MHz).

    You cannot process an interrupt of this frequency on a Cortex M.

    Interrupt entry and exit take already 12 cycles each. So, 80MHz / 24 wold give you the saturation point - with an interrupt of that frequency, the MCU is 100% busy with entering and exiting the interrupt, without yet doing anything useful. Beyond this point, it doesn't even leave the interrupt - they arrive faster than you can process it.

    You need to consider alternatives, most probably utilizing peripheral hardware. There is no Cortex M around that can manage this efficiently with core performance.

  • Yes this is what I said.
  • Hello Cyril,

    Only way I see this to happen is by using an external FPGA/CPLD

    Regards
    Amit