Hello.
I've already created a ticket in costumer support center (CS0724274, ticsc.service-now.com/csm), but I was asked to move it here since it's more suitable for this kind of problem.
So I try to copy here all the information from the ticket ...
I have a problem with systick timing. At the beginning of the investigation we found out that there's a problem with periodical sending of Profinet cyclic data. The cyclic frames should be sent each 2 ms, but we measured that sometimes (once in a few minutes) one frame is sent just 1 ms after the previous one. And then continue again with correct 2 ms cycle.
I did a long investigation going deeper to find the source of the issue. As I finally find out and verified the problem is in timing of systick timer, which is set to 1 ms with highest priority. It's very strange but sometimes the systick interrupt is raised additionally in much shorter time.
I was going through the err data document but I haven't found there such an issue. Don't you know about similar problem which could appear on the controller? Or would you have any explanation for the behavior?
I checked out the systick registers when the interrupt is raised and it shows that sometimes it's really called too early since the timer value doesn't time out according to the actual timer value gained by MAP_SysTickValueGet function.
I'm adding a few screenshots from my measurements. To see the behavior there are cyclic buffers storing the last 10 values. There can be seen the time since last interrupt, the actual timer value and actual system state register (0xE000ED24).
I have additional information for the issue. I've recorded a few additional registers to see the actual state when the sys tick interrupt handler is called. I attached the screenshots of last 10 values of
- time from last sys tick interrupt (measured by another timer)
- System Handler Control and State (SYSHNDCTRL), offset 0xD24
- SysTick Control and Status Register (STCTRL), offset 0x010
- SysTick Reload Value Register (STRELOAD), offset 0x014
- SysTick Current Value Register (STCURRENT), offset 0x018
- Interrupt Control and State (INTCTRL), offset 0xD04
- System Handler Priority 3 (SYSPRI3), offset 0xD20 As can be seen from the pictures, something strange happened in the cycle 3, see the pictures.
I'm sending you the file with the systick handling.
The SysTick configuration ...
ABC_IRQ_DISABLE(ABC_INT_SCHEDULER);
/* Set the default priority level to be masked */
CPUbasepriSet(ABC_INT_PRIORITY_MASKED);
/* set the priority for the systems interrupts */
MAP_IntPrioritySet(ABC_INT_SYSTICK, ABC_INT_PRIORITY_0);
MAP_IntPrioritySet(ABC_INT_SCHEDULER,ABC_INT_PRIORITY_SCHEDULER);
MAP_IntPrioritySet(ABC_INT_SVCALL, ABC_INT_PRIORITY_3);
ABC_IRQ_ENABLE(ABC_INT_SCHEDULER);
...
// Configure SysTick for a periodic interrupt.
(void) MAP_SysTickPeriodSet( (uint32_t) cpuinfo_drv_get_frequency() / SYSTICKHZ);
(void) MAP_SysTickEnable();
(void) MAP_SysTickIntEnable();
Where ...
#define ABC_INT_SYSTICK FAULT_SYSTICK
#define ABC_INT_SCHEDULER FAULT_PENDSV
#define ABC_INT_SVCALL FAULT_SVCALL
...
#define ABC_INT_PRIORITY_0 (0x00 << 5)
#define ABC_INT_PRIORITY_1 (0x01 << 5)
#define ABC_INT_PRIORITY_2 (0x02 << 5)
#define ABC_INT_PRIORITY_3 (0x03 << 5)
#define ABC_INT_PRIORITY_4 (0x04 << 5)
#define ABC_INT_PRIORITY_5 (0x05 << 5)
#define ABC_INT_PRIORITY_6 (0x06 << 5)
#define ABC_INT_PRIORITY_7 (0x07 << 5)
// The default IRQ priority of scheduler
#define ABC_INT_PRIORITY_SCHEDULER ABC_INT_PRIORITY_6
// The IRQ priority which is by default masked
#define ABC_INT_PRIORITY_MASKED ABC_INT_PRIORITY_7
...
CPUbasepriSet(uint32_t ui32NewBasepri)
{
//
// Set the BASEPRI register
//
__asm(" msr BASEPRI, r0\n"
" bx lr\n");
}
...
// enable/disable all interrupts
#define ABC_IRQ_ENABLE_ALL (void) MAP_IntMasterEnable()
#define ABC_IRQ_DISABLE_ALL (void) MAP_IntMasterDisable()
// enable/disable specific interrupts
#define ABC_IRQ_ENABLE(IRQ_ID) abc_irq_enable(IRQ_ID)
#define ABC_IRQ_DISABLE(IRQ_ID) abc_irq_disable(IRQ_ID)
...
ABC_STATIC_INLINE void abc_irq_enable(unsigned int irq_id)
{
if (irq_id != ABC_INT_SCHEDULER)
{
MAP_IntEnable(irq_id);
}
else
{
MAP_IntPrioritySet(FAULT_PENDSV, ABC_INT_PRIORITY_SCHEDULER);
}
}
ABC_STATIC_INLINE void abc_irq_disable(unsigned int irq_id)
{
if (irq_id != ABC_INT_SCHEDULER)
{
MAP_IntDisable(irq_id);
}
else
{
MAP_IntPrioritySet(FAULT_PENDSV, ABC_INT_PRIORITY_MASKED);
}
}
And the Systick ISR handler ...
/***
* Process tick of the system timer.
***/
void SysTick_Handler(void)
{
ABC_IRQ_ACK(ABC_INT_SYSTICK);
// call the system tick handler
abc_sys_timer_tick();
// trigger clocks
abc_tmr_clock_trigger(CLOCK_REALTIME);
ABC_IRQ_EOI(ABC_INT_SYSTICK);
}
Where ...
/***
* Acknowledge interrupt
**/
#define ABC_IRQ_ACK(irq_nr) ABC_IRQ_DISABLE_ALL
/***
* End of interrupt
**/
#define ABC_IRQ_EOI(irq_id) if (0 == abc_spin_irq_count) { ABC_IRQ_ENABLE_ALL; }
It seems to me there's some problem between SysTick interrupt and PendSV interrupt used by the OS scheduler. The scheduler uses following functions ...
// Add scheduler interrupt request
ABC_IRQ_SET_REQUEST(ABC_INT_SCHEDULER);
// Remove scheduler interrupt request
ABC_IRQ_CLR_REQUEST(ABC_INT_SCHEDULER);
// set a specific interrupt request
#define ABC_IRQ_SET_REQUEST(IRQ_ID) MAP_IntPendSet(IRQ_ID)
#define ABC_IRQ_CLR_REQUEST(IRQ_ID) MAP_IntPendClear(IRQ_ID)
// IntPendSet from TivaWare driverlib
void IntPendSet(uint32_t ui32Interrupt)
{
...
//
// Pend the SysTick interrupt.
//
HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTSET;
...
}
Can't you see there any problem?