PIT0 handler coldfire v2

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

PIT0 handler coldfire v2

1,470 Views
adelvallem
Contributor II

Hi, I'm working with the MCF52259 on Code Warrior.

I'm just starting with the coldfire architecture and I'm somewhat lost about interruptions handlers. I need an interrupt every 1 ms to do something and I already configured the PIT0 as follows

/* Initiatilize the PIT0 1ms
void Init_PIT_Interrupt()
{
  MCF_PIT0_PCSR = 0;  // PCSR[11-8]: no prescaler
                      // PCSR[6]: not affected by doze mode
                      // PCSR[5]: not affected by debug
                      // PCSR[4]: overwriting counter until it reaches 0
  MCF_PIT0_PCSR |= MCF_PIT_PCSR_PIE     // interrupt enable 
                 | MCF_PIT_PCSR_RLD;    // reload PMR when count reaches 0
                 
  MCF_PIT0_PMR = 1999; // PMR = -1 + (1ms * (4MHz) / (2^1))
                       // PMR = 1999
  MCF_PIT0_PCSR |= MCF_PIT_PCSR_EN;    // enable PIT
}

/* my interrupt handler */
void PIT0_interrupt_handler()
{
  // toggle LED or whatever
}

 

However, I haven't figured out how to declare the interrupt service routine, how will it be linked to my specific interruption? In Atmel and arm they regularly have a specific name. But here is different.

I already found __declspec(vectortable) vectorTableEntryType _vect[256] at exceptions.c file where I understand something must be changed, should I just put the name of my interrupt handler there?

If some could provide a simple example or a research resource would be helpful.

Thank you in advance

0 Kudos
3 Replies

1,460 Views
TomE
Specialist II

You're writing "PMR" wrong. You think you're starting the counter running from "1999", but you're not. It will START from "65535" and count down from there the first time. The way you have it set you won't get the first interrupt for about 32ms. This may not be important in your setup, but for some people it matters. You should at least be "surprised" by that. You have to set the OVW bit before writing PMR. Then you can clear OVW. Try finding that in the manual.

You're not ACKing the interrupt (yet), but you'll get that wrong too when you write it. See later.

Back to your question.

How you declare interrupts and link them together depends on the IDE you're using.

At the hardware level, you have to fill in the appropriate entry in the interrupt vector table (for that specific interrupt) to point to the address of your interrupt service routine. How you do that depends on the IDE. Some provide more help than others, but there should be some DOCUMENTATION that tells you how to do that, so you should read that first.

The "handler function" can't be a "normal function" as an interrupt service routine has to save more state and registers than a normal C function does.

So in real "bare metal programming" you can write some assembly code to do that and have that call your C function.

Or if using GCC you just add "__attribute__((interrupt_handler)) " before the function and it sets that up for you.

Or if using the NXP IDE - I don't know as I've never used it. It will do something similar. There should be documentation, and there's a Forum for CW where it might be worth asking these questions. There should also be example projects you can find that should give you a "worked example" of interrupts to copy from. Look for those. Like this ref:

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/how-to-setup-Interrupt-handler-for-UART0-...

You should search this forum for keywords. There's about 15 years worth of people having the same problems.

Mose Coldfire interrupts require specific acknowledgement. For the PIT you have to write a "1" to the interrupt status bit to clear it. But you can't do that with the NXP supplied headers without making the PIT lose time.

And since you're using the "Bear PIT" you should be careful not to fall into it. EVERYONE has programmed this device wrong (in two different ways) for all of its lifetime, and continue to do so. That's because because the Reference Manuals don't warn of two surprising characteristics. Headers have always been wrong for this chip which means that using them it is impossible not to trigger this problem. NXP's "response" was:

I talked with the apps team and they told me that the
redaction doesn’t seems to implies that writing the
same value to the PRE bits doesn't reset the timer.

Yes, that's the response. No manual updates. No errata.

And having to set OVR to get the PMR written the first time is just weird.

The PIT was derived from a working (simpler) timer back in 1998. That one was fine. Then they put the prescaler in the upper byte of the control register and then didn't declare proper headers. This has been causing problems ever since then.

Read this from me in 2010 and then be one of the few people on the planet who has programmed this peripheral so it doesn't lose time:

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/PIT-hw-boo-boo-Read-if-you-need-accurate-...

Here's the current Linux source code still showing the bug:

https://elixir.bootlin.com/linux/latest/source/arch/m68k/coldfire/pit.c

There's another trap with interrupts on the MCF52 series that causes weird unreliability. The ICR registers have to be set up with UNIQUE AND DIFFERENT Levels and Priorities. If you get that wrong the chip goes randomly crazy. The NXP sample code gets this wrong which doesn't help at all. Check these:

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/MCF52233-DEMO-Interrupt-Priorities-and-Le...

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/CFV2-vector-125-vector-or-ing/m-p/156249

https://community.nxp.com/t5/ColdFire-68K-Microcontrollers/INTERRUPT-PROBLEM-INTERRUPTS-STOPS-TO-WOR...

 

Tom

 

 

0 Kudos

1,442 Views
adelvallem
Contributor II

Hi TomE, thank you for your help, following your indications I somewhat figured it out.

My handler is something like this

void Init_PIT_Interrupt(void)
{
  
  MCF_PIT0_PCSR = 0;  //This will clear the whole register to assert:
                      // PCSR[11-8]: no prescaler
                      // PCSR[6]: not affected by doze mode
                      // PCSR[5]: not affected by debug
                      // PCSR[4]: overwriting counter until it reaches 0
  MCF_PIT0_PCSR = MCF_PIT_PCSR_PIE     // interrupt enable 
                 | MCF_PIT_PCSR_RLD;    // reload PMR when count reaches 0
  
  MCF_PIT0_PCSR |= MCF_PIT_PCSR_OVW;    // enabling the writing to PMR               
  MCF_PIT0_PMR = 19999; // Time out period = (2^PCSRn[PRE])*(PMR+1)/(Fsys/2)
                       // PMR = -1 +((Time out period * (Fsys/2)) / (2^PCSRn[PRE]))
                       // PMR = -1 + (1ms * (40MHz) / (2^1))
                       // PMR = 1999
  //MCF_PIT0_PCSR &= ~MCF_PIT_PCSR_OVW;
  
  MCF_INTC0_ICR55 = 0x36;                     // 2nd highest priority and level
  MCF_PIT0_PCSR |= MCF_PIT_PCSR_EN;    // enable PIT
  MCF_INTC0_INTFRCH = 0x800000;        // force interrupt to be active(?)

}

After the information you provided my handler, which is declared in the same source file where my vector table is, is the next:

#define MCF_PIT_PCSR_LB(x)  (*(vuint8*)(0x40150000 + ((x)*0x10000)))
__declspec(interrupt) void PIT0_isr(void)
{ 
  MCF_PIT_PCSR_LB(0) = MCF_PIT_PCSR_PIF; 
  MCF_GPIO_SETTA |= 0x04U;        // turn off lcd
  ++tick10ms;
}

 

PCSR_LB is accesing only 8 bits (this is what I understood from the information you provided to avoid losing time, besides the preescaler is not being used)

And the vector table has my function defined

   asm_exception_handler,           /* 117 (0x___) Reserved                   */
   asm_exception_handler,           /* 118 (0x___) Reserved                   */
   PIT0_isr,                      /* 119 (0x___) Reserved                   */
   asm_exception_handler,           /* 120 (0x___) Reserved                   */
   asm_exception_handler,           /* 121 (0x___) Reserved                   */

INTC0 + interrupt source = 64 + 55 = 119

How ever I still can't get the interrupt serviced.

Reading the RM it says this about the  Interrupt Pending Registers (IPRHn, IPRLn) 

The IPRHn and IPRLn registers, each 32 bits,provide
a bit map for each interrupt request to indicate if
there is an active request
(1 = active request, 0 = no request) for the given
source.

And in debug mode I get this

adelvallem_0-1623944329242.png

As you may noticed IPRH0 = 0x00800000 which is position 55 (IPR as a global register)

Does this mean that my interrupt is being triggered but not serviced? maybe my calculations where my handler should be placed within my vector table are wrong?

IMRH and IMRL are both low for my interrupts, meaning they are allowed.

Any suggestion is welcomed. Thank you in advanced.

 

0 Kudos

1,438 Views
adelvallem
Contributor II

Hi everyone I got it solved, so I let you know

I hadn't noticed the SR register as the manual says

The SR stores the processor status and includes the CCR, the interrupt priority mask, and other control bits. 

within this register the bits [10-8] are the interrupt level mask, which is initialized with 7 the highest possible level, my interruption was defined with level 6, so it would never be serviced because another higher event was "being handled".

I modified manually while debug and my code worked correctly.

Thank you TomE for your support.

0 Kudos