Slice Timers unusual behavior for MCF5485

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Slice Timers unusual behavior for MCF5485

1,932 Views
preetuabraham
Contributor III

I am working on a legacy project where in we use Slice Timers to generate 5 ms interrrupt. After around three hours run, the SLT1 timer is unable to trigger the interrupt.
I checked all the Slice timer registers using a debugger and the values are as expected:

The register values are validated as:
SLT Terminal Count Register (STCNTn) => 0x0008BD36 (5 msecs count)
SLT Control Register (SCRn) => 0x03000000 (IEN = 1, TEN = 1)
SLT Timer Count Register (SCNTn) => 0x00000000 (Timer expired)
SLT Status Register (SSRn) => 0x01000000 (ST = 1)

The above register values are properly defined to trigger the interrupt, but failed to triggered. I would really appreciate if you provide your answers why the slice timer is not generated for every 5 msecs even the register values are properly set to trigger the interrupt.

Software does perform 2 tasks, one is the Slice timer ISR for every 5 msecs and the other one is background task. As I mentioned above the software ran for 3 to 4 hours as expected to execute the tasks, but then only the background task was running but not the 5 msec slice timer task where as the SLT registers are verified and the values are configured as expected.

Tags (1)
0 Kudos
Reply
5 Replies

1,928 Views
TomE
Specialist II

First, you haven't programmed those timers for a 5ms interrupt period. They will interrupt 5ms after the PREVIOUS interrupt has been acked. If you actually need a real 5ms period, then you need the "RUN" bit set as well. But "5ms plus a random bit" might be what you actually want.

Once the interrupt triggers, the interrupt service routine has to reliably write a one to the "ST" bit in SSR0. This clears the interrupt and starts the timer running again. Are you doing this with a direct write or a read-modify-write? The latter is unnecessary and slow. Are you sure the memory regions are set up properly to make sure the cache isn't interfering?

Check the Interrupt Controller to make sure it is still properly programmed for this interrupt. Something may have turned it off there. Check the IPRH and IPRL Registers to see if the request is pending there. Check the IMRH and IMRL registers to make sure the interrupt is enabled.

Are you sure the background isn't accidentally changing the CPU IPL Level? It might be running at a high IPL and blocking the slice timer interrupt. Your background loop should check the IPL every time through and throw an error if it ever isn't zero.

The next thing that EVERYONE gets wrong the first time is that they miss the bit in the Reference Manual that says:

13.2.1.6 Interrupt Control Registers 1–63 (ICRn)
Each ICRn specifies the interrupt level (1–7) and the priority within the
level (0–7). All ICRn registers can be read, but only ICR8 to ICR63 can
be written. It is software’s responsibility to program the ICRn registers
with unique and non-overlapping level and priority definitions. Failure
to program the ICRn registers in this matter can result in undefined
behavior. If a specific interrupt request is completely unused,
the ICRn value can remain in its reset (and disabled) state.

That's really hard to do if the interrupts are set up "all over the place", so each driver sets its own interrupt. You need to have a common set of definitions for every interrupt in the system so that code (or a fixed table) can ensure that you never have two interrupts with the same level and priority. "Undefined behavior" can mean anything from failing immediately to failing once a week (or once every 3 hours).

The next thing everyone gets wrong is messing with any interrupt control registers while CPU interrupts are enabled. If you are enabling and disabling interrupts "on the fly" by changing bits in IMRL or IMRH then it is essential to set the CPU IPL to 7 around all those accesses. The same applies to any interrupt enables in peripheral registers. The worst thing is to be doing this in the mainline code and in interrupt service routines as then you've got a classic "shared data interrupt hazard" situation.

Tom

 

0 Kudos
Reply

1,921 Views
preetuabraham
Contributor III

Hi Tom,

    Thanks for the update. I will be replying to the queries along with some more clarfications that will be marked in red font. I am really looking forward to the queries asked below which is needed for better understanding of the Slice Timers Interrupt generation.

First, you haven't programmed those timers for a 5ms interrupt period. They will interrupt 5ms after the PREVIOUS interrupt has been acked. If you actually need a real 5ms period, then you need the "RUN" bit set as well. But "5ms plus a random bit" might be what you actually want.

I understand that the RUN bit will automatically load the counter and starts counting down which will generate the interrupt exactly at 5 msecs everytime upon counter expiration. But without RUN bit, the interrupt will be generated but the counter will be loaded only after the ST bit is status register is cleared (writing '1' to it). Software does clear the ST bit inside the ISR routine and I believe there will be little bit latency in generating the next 5 msecs interrupt, but shouldn't stop generating the interrupt every 5 msecs + latency.

Once the interrupt triggers, the interrupt service routine has to reliably write a one to the "ST" bit in SSR0. This clears the interrupt and starts the timer running again.Are you doing this with a direct write or a read-modify-write?

I am doing the direct write in my software to clear the interrupt inside the ISR routine and that will resume the countdown.

The latter is unnecessary and slow. Are you sure the memory regions are set up properly to make sure the cache isn't interfering?

Yes the memory regions are set up properly to make sure the cache isn't referring

Check the Interrupt Controller to make sure it is still properly programmed for this interrupt. Something may have turned it off there. Check the IPRH and IPRL Registers to see if the request is pending there. Check the IMRH and IMRL registers to make sure the interrupt is enabled.

Yes the registers are setup in my software as below

The register values for slice timer are validated as:
SLT Terminal Count Register (STCNTn) => 0x0008BD36 (5 msecs count)
SLT Control Register (SCRn) => 0x03000000 (IEN = 1, TEN = 1)
SLT Timer Count Register (SCNTn) => 0x00000000 (Timer expired)
SLT Status Register (SSRn) => 0x01000000 (ST = 1)

Are you sure the background isn't accidentally changing the CPU IPL Level? It might be running at a high IPL and blocking the slice timer interrupt. Your background loop should check the IPL every time through and throw an error if it ever isn't zero.

The background is not changing the CPU Level. The background function is run in a while(1) loop and does not depend on IPL to block the slice timer interrupt. Also verified the registers for correctness when the interrupt is not generated and everything looks fine.

The next thing that EVERYONE gets wrong the first time is that they miss the bit in the Reference Manual that says:

That's really hard to do if the interrupts are set up "all over the place", so each driver sets its own interrupt. You need to have a common set of definitions for every interrupt in the system so that code (or a fixed table) can ensure that you never have two interrupts with the same level and priority. "Undefined behavior" can mean anything from failing immediately to failing once a week (or once every 3 hours).

The next thing everyone gets wrong is messing with any interrupt control registers while CPU interrupts are enabled. If you are enabling and disabling interrupts "on the fly" by changing bits in IMRL or IMRH then it is essential to set the CPU IPL to 7 around all those accesses. The same applies to any interrupt enables in peripheral registers. The worst thing is to be doing this in the mainline code and in interrupt service routines as then you've got a classic "shared data interrupt hazard" situation.

The interrupt Control Registers are set below for different priorities with Interrupt Level 7

MCF_INTC_ICR29 = MCF_INTC_ICRn_IP(7) | MCF_INTC_ICRn_IL(7) ; /* DSPI */
MCF_INTC_ICR40 = MCF_INTC_ICRn_IP(6) | MCF_INTC_ICRn_IL(7) ; /* I2C */
MCF_INTC_ICR53 = MCF_INTC_ICRn_IP(5) | MCF_INTC_ICRn_IL(7) ; /* ST1 */
MCF_INTC_ICR54 = MCF_INTC_ICRn_IP(4) | MCF_INTC_ICRn_IL(7) ; /* ST0 */
MCF_INTC_ICR35 = MCF_INTC_ICRn_IP(1) | MCF_INTC_ICRn_IL(7) ; /* PSC0 */

/* The interrupt will not be masked if the bit is set to 0 */
MCF_INTC_IMRL &= ~( MCF_INTC_IMRL_INT_MASK29 ); /* DSPI TCF */
MCF_INTC_IMRH &= ~( MCF_INTC_IMRH_INT_MASK35 | /* PSC0 */
MCF_INTC_IMRH_INT_MASK40 | /* I2C Bus */
MCF_INTC_IMRH_INT_MASK53 | /* Slice Timer 1 */
MCF_INTC_IMRH_INT_MASK54 ); /* Slice Timer 0 */

Slice Timer 0 is not intialized as part of system initialization becasue it is not required for our software, only Slice Timer 1 is used to generate 5msec interrupt.

So next is I have two queries for my understanding w.r.t manual as listed below:

  • First one is a scenario. I setup all the control registers and mask registers, SLT Terminal Count Register  for 5 msec ,Slicer Timer SLT Control Register with only the timer enabled(TEN bit),then run a for loop for more than 5 msec (for eg:1 sec), the status register is set to 1 in the for loop and the timer will be expired before the for loop exists. Next, I will enable the interrupt bit in SLT Control Register, so my query here is whether the interrupt will be generated in this scenario?

Code Snippet:

//All the Interrupt related registers are configured before this.

SLT1_SCR->TEN = 1;

for(i=0i<500000;i++); // Approximately 1 secs (>5msec)

SLT1_SCR->IEN = 1; //whether the interrupt will be generated ?

  • Whether the interrupt will be generated for timer counter expiry or status bit getting set?

 

0 Kudos
Reply

1,907 Views
preetuabraham
Contributor III

Hi Tom,

I agree that the Reference Manual is really bad. Regarding the clock, I will inform to the team here about it.


I just gave the for loop as an exaMple just to check with NXP whether interrupt will be generated since information about the depedndecy with ST bit or timer count getting expired is not present is not present in manual.

Instead of for loop, consider this example and let know whether interrupt will be generated.

SLT1_SCR->TEN = 1;

while(SLT1_SSR->ST == 0);

SLT1_SCR->IEN = 1;

 

0 Kudos
Reply

1,904 Views
TomE
Specialist II

> Instead of for loop, consider this example and let know whether interrupt will be generated.

I don't see why NXP should bother to try and answer that question. Unless you give them a good reason why you need to know this, I can't see the point. You haven't answered my query on this.

The only way to answer that question is to load that code and run the test. I don't have the hardware. You do. So load that and run it and tell us what happens. You should put breakpoints in (if you have a debug pod) or single-step that code. Or better, you should put print statements in the interrupt service routine so you know when it happened, and prints before and after every line in your test. You'll either get the print from the ISR just after (or during) the print where it sets IEN if setting the IEN works, or no print from the ISR if it doesn't.

Still, if you can test for this error condition in your background you should treat it as such and restart the timer from there.

Tom

 

0 Kudos
Reply

1,911 Views
TomE
Specialist II

> Also verified the registers for correctness when the interrupt is not generated and everything looks fine.

I assume you mean all the interrupt controller registers and (most importantly) the CPU Status Register.

> MCF_INTC_ICR29 = MCF_INTC_ICRn_IP(7) | MCF_INTC_ICRn_IL(7) ; /* DSPI */

Never use IPL7. Just don't. That's the non-maskable interrupt. You have enough spare ones to move them all down by one.

Remember that unless you specifically set the CPU IPL to "7" at the top of every interrupt service routine, higher level interrupts can interrupt the lower priority ones. Make sure there are no shared variables between interrupt service routines.

> So next is I have two queries for my understanding w.r.t manual as listed below

So you want to know if the interrupt is edge-triggered on "ST" setting, or whether "ST" and "IEN" are combined in a simple "AND" gate in hardware to create the interrupt. NXP don't provide that sort of detail. To answer that question you have to do exactly what you are doing, which is setting the IE after ST has set. But not the way you're doing it.

> for(i=0i<500000;i++); // Approximately 1 secs (>5msec)

Have you measured that as taking 1 second? Given the CPU is meant to be running at 200MHz it should be able to execute that loop in 400-800 MICRO seconds. Even the first Arduino should be able to run that loop in less time than that. Secondly, any decent compiler should optimise that loop away completely. It has been a long time since compilers did exactly what you wrote. A better approach would be for the loop to explicitly read the SSR register and wait for the ST bit to set. Then set the IEN bit.

I can't see what this would tell you anyway. If your code only sets the IEN once and only clears the ST bit, then I can't see what's going wrong here. Maybe you're thinking of turning IEN on and off from the background to see if it can trigger a "missed" interrupt, is that it? It would be better to detect that ST is set and an interrupt hasn't happened, and then RESTART the counter from the background.

> SLT Terminal Count Register (STCNTn) => 0x0008BD36 (5 msecs count)

I'm trying to check that. The Reference Manual is pretty bad. Nothing says what clock runs the slice timers. Nothing says what clocks run anything, apart from the CPU. It is really hard to work out. In implies everything apart from the core runs at the XLB clock rate. But assuming you've got it right, then "8bd36" is 572726, and if that is 5ms, then on second is 114,545,200, and that's a weird clock rate. It is also too high for the XLB clock. If it is running at that rate it is running over the maximum specification.

I just found this post from you in September 2017:

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/Slice-Timers-for-MCF5485/m-p/706365

Using a clock of 28.6363MHz and a count of 0x8BD00. So I assume you're using the 1:4 clock ratio, an XLB clock of 114.5452MHz, which is more than 100MHz and outside of the specs. Likewise the CPU core frequency is 14% over the maximum. You should be running at the 1:2 clock rate or use a different crystal.

That might be your problem.

Tom

 

0 Kudos
Reply