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.

TM4C123GH6PM: Resetting or setting systick remaning counter

Part Number: TM4C123GH6PM

Tool/software:

Hello,

I have systick running with period of 80000000 / 1024 to get 1024 ticks per second and my SysTickIntHandler does:

void SysTickIntHandler(void) {
    g_ui32SysTickCount++;
    if(g_ui32SysTickCount % 1024 == 0) { g_ui32PosixTime++; g_ui32SysTickCount = 0; }
}

So posix_time is seconds, and sys tick count is between 0 and 1023

I am also using usb serial to send posix time packets with nanoseconds, and I would like to syncronize the time with the microcontroller.

Is there any way to reset the systick counter remeaning time, or even better to set it to a given value?

In page 536 of the peripheral reference it says:

"Calling this function does not cause the SysTick counter to reload immediately. If an immediate
reload is required, the NVIC_ST_CURRENT register must be written. Any write to this register
clears the SysTick counter to 0 and causes a reload with the ui32Period supplied here on the
next clock after SysTick is enabled."

So I wonder if there is any way to set the  timer to given value.

Best Regards,

Can

  • Hi Can,

    So I wonder if there is any way to set the  timer to given value.

      You are already on the right API. Calling SysTickPeriodSet will load the systick counter to your specified value. The Reload Value Register (STRELOAD) value is loaded to the Current Value Register (STCURRENT) when Current Value Register reaches 0. If you want the specified value to take effect then you can directly write to the  Current Value Register (STCURRENT) using HWREG. 

  • Well I made a test case where:

    uint8_t systick_counter = SysTickValueGet();
    HWREG(NVIC_ST_RELOAD) = dt_period - 1;
    HWREG(NVIC_ST_CURRENT) = dt_period - 1;
    uint8_t systick_counter2 = SysTickValueGet();

    uint8_t len = sprintf(loginfo_buffer, "%lu\n", systick_counter);
    UARTprintf(loginfo_buffer, len);
    len = sprintf(loginfo_buffer, "%lu\n", systick_counter2);
    UARTprintf(loginfo_buffer, len);

    Where dt_period is 80000000 / 1024. On the serial debug port I always get low numbers like

    "

    175

    37

    "

    How can I check that my systick is counting down from the period?

    Best Regards,

    Can

  • Hi Can,

      I gave you a misinformation earlier. When you write to HWREG(NVIC_ST_CURRENT), you will clear the register no matter what value you write. You should just comment out the HWREG(NVIC_ST_CURRENT) = dt_period - 1. With this, NVIC_ST_CURRENT will be loaded by the value stored in the NVIC_ST_RELOAD and start counting assume you also enable SysTick in the STCTRL register. 

  • Hello Charles,

    Kind of confused right now. The reason I am doing this is time syncronization. I would like to change the period of systick counter, arbitarily, just for one time, when the sync packet arrives, the nanoseconds obtained from host computer is parsed, calculated, and the remaining systick counter is set, either increased or reduced between 0 to dt_period.

    Is this even possible?

    Best Regards,

    Can

  • Hi Can,

    Let me use an example. Let's say you first load a value of 1000 to the STRELOAD register. The systick counter will then decrement from 1000 to 0 and then reload with 1000 when the counter value becomes 0. This process repeats. Suppose in the middle of the counting and the current counter value is 300, you write a value of 600 to the STRELOAD register. What will happen?  In this case, the counter (which can be read from the STCURRENT register) is not loaded with 600 until the counter becomes 0. The counter is currently at 300, it will have to count 300 more cycles until it reaches 0 before the new value 600 will take effect. If you want the new value 600 take effect as quickly as possible, you will first write to STRELOAD with your new reload value followed by another write to STCURRENT register. Writing to STCURRENT will clear the counter to 0 and then reload with the new value. However, it takes some cycles to complete writing to these two registers. 

    The timer consists of three registers:
    ■ SysTick Control and Status (STCTRL): A control and status counter to configure its clock,
    enable the counter, enable the SysTick interrupt, and determine counter status.
    ■ SysTick Reload Value (STRELOAD): The reload value for the counter, used to provide the
    counter's wrap value.
    ■ SysTick Current Value (STCURRENT): The current value of the counter.
    When enabled, the timer counts down on each clock from the reload value to zero, reloads (wraps)
    to the value in the STRELOAD register on the next clock edge, then decrements on subsequent
    clocks. Clearing the STRELOAD register disables the counter on the next wrap. When the counter
    reaches zero, the COUNT status bit is set. The COUNT bit clears on reads.
    Writing to the STCURRENT register clears the register and the COUNT status bit. The write does
    not trigger the SysTick exception logic. On a read, the current value is the value of the register at
    the time the register is accessed

  • and in this case where I write 600 to STRELOAD, and then to STCURRENT, the next cycle will also start from 600?

    I need it so what it changes the countdown value, but next time it starts from original period_value.

    Does the value we write on STCURRENT matter, or just writing anything to it resets the counter.

    Best Regards,

    Can

  • and in this case where I write 600 to STRELOAD, and then to STCURRENT, the next cycle will also start from 600?

    After the STCURRENT is cleared by writing any value to it, it will be reloaded with the new reload value which is 600.

    I need it so what it changes the countdown value, but next time it starts from original period_value.

    I'm not clear here. You want to it to reload with 600 or 1000? 600 is the new reload value and 1000 is the original value. Here you said you want to start from original period_set. I suppose you meant the new reload value which is 600. 

    Does the value we write on STCURRENT matter, or just writing anything to it resets the counter.

    Correct, writing any value to STCURRENT will reset the counter. 

  • Ok, the original period is 78125, which is 1/1024 of 80M.

    I want to for example set the counter to arbitary value, let it count down from this arbitary value, and when it hits 0, the next counter value should be the original period of 78125.

    I could potentially:

    HWREG(NVIC_ST_RELOAD) = dt_period - p_st_current;

    HWREG(NVIC_ST_CURRENT) = 0x1;

    HWREG(NVIC_ST_RELOAD) = dt_period;

    So load the wanted value, set counter to 0 by writing to STCURRENT, and then set the reload value to original. I wonder if that would work, because you said it would take few clock cycles.

    Alternatively, I could use the SysTickIntHandler to see if the counter value has been modified, and if so set it to original, but either case has some over head.

    Best Regards,

    Can

  • well I have been experimenting, and one question arises.

    When I:

    // reload systick counter with value

    HWREG(NVIC_ST_RELOAD) = new period;

    HWREG(NVIC_ST_CURRENT) = 0x01;

    Will this immediately trigger a SysTick Interrupt? It causes the counter to reset up, but also this reset can trigger a systick interrupt and if so, how can we get around it?

    Best Regards,

    Can

  • // reload systick counter with value

    HWREG(NVIC_ST_RELOAD) = new period;

    HWREG(NVIC_ST_CURRENT) = 0x01;

    Will this immediately trigger a SysTick Interrupt? It causes the counter to reset up, but also this reset can trigger a systick interrupt and if so, how can we get around it?

    Writing any value to NVIC_ST_CURRENT causes the counter to reset to zero. A zero in the counter also triggers an interrupt if enabled. There are two methods I can think of. First, write to NVIC_ST_CURRENT to reset the counter and in the ISR, load NVIC_ST_RELOAD with your new value. Second method would be to keep your above code but disable interrupt before you write to NVIC_ST_CURRENT.