Question about coldfire V2 interrupt priority

cancel
Showing results for 
Search instead for 
Did you mean: 

Question about coldfire V2 interrupt priority

Jump to solution
2,750 Views
Contributor III

Hi all!

 I am now developing one mcf52259 board, By reading the reference manual, I got several questions about interrupt priority, hope your help,thanks!

the coldfire v2 core SOC use two stage priority mechanism, first all 63 interrupt source are organized into 7 levels with the level 7 holds highest priority. and within one level, can support up to 9 priorities. but the interrupt source 1~7 is not programmed, they is fixed at corresponding level's midpoint priority. my questions are:

1.  what is the  interrupt source 1~7's interrupt level?

2. if the SOC has two or three interrupt controllers, for example mcf52259 has two INTCs. which INTC has the higher priority? I means that, suppose the following situation: INTC0 's LEVEL 7/Priority 7 and INTC1's level 7 /Priority 7 both has one pending interrupt request,  and both request the coldfire core to acknowledge, then which INTC will be acknowledged by the core ?

Labels (1)
0 Kudos
1 Solution
97 Views
Contributor V

Hi

 

Almost all interrupt sources are configurable at runtime (an exception could be the eport module, for example). 7 levels with 8 priorities. Level 0 is a masked interrupt. 7x8 = 56 different interrupts. Note this is per interrupt controller. Then per interrupt controller, a single ICRn (level + priority) value must exist. Unique combination per interrupt controller to avoid unexistent interrupts at runtime if two occurs concurrently. INTC0 has priority over INTC1 and so forth

 

Hope this helps

View solution in original post

0 Kudos
17 Replies
97 Views
Contributor II

Hi everyone

 

I have a related question but at a lower level.

 

I'm developing a board based on the MCF52255, not using MQX (i.e., a bare board application). Since this is my first exposure to a 32-bit MCU, I am somewhat lost as to how to proceed with interrupts. The Reference Manual has a mass of information, and I've gone through the relevant sections carefully to set up a UART with interrupt. But this is as far as I got.

 

Assuming that I've set up the UART etc. correctly, my question is this: Must I define the interrupt names and numbers? If so, how? On the 8-bit devices these are predefined in the documentation and in CW, but it doesn't seem to be the case with the 32-bit devices, and the Reference Manual doesn't list these as is the case with 8-bit. I'm very familiar with 8-bit devices, which hardly bear any resemblence to the 32-bit devices.

 

I hope someone can point me in the right direction with this.

 

Thanks in advance.

 

 

0 Kudos
97 Views
Contributor I

Trusc,

 

The Pin usage configuration and the interrupt configuration for the V2's are both much more complicated than they were on the V1 or the CPU12's.

 

Here is my power up init for UART0 on the MCF52259, (written in GNU assembly) it works fine.

 

I hope this helps,

 

Mudwog

 

First attempt pasting the code here was all garbage, so now I'm attempting to attach it as a.txt file.

0 Kudos
97 Views
Contributor II

Hi Mudwog

 

Thanks for taking the trouble to send me the code.

 

In the meantime I have solved my problem by the simple expedient of starting a new project with initialization enabled. This allowed me to use Processor Expert to configure the UARTs and any other peripherals required. This is actually an educational way of doing it, because one can see exactly how the registers etc. were configured in the resulting MCU_init.c file.

0 Kudos
97 Views
Specialist V

Hi

 

The interrupt names and numbers are all defined in section 16.3.8.1 in the M52259 User's manual.

 

Regards

 

Mark

 

0 Kudos
97 Views
Contributor II

Thanks for your feedback, Mark.

 

Yes, I saw those definitions. What is not clear, is how to use them in an interrupt routine. For example, with the MC9S08SH8 I would write code such as

 

interrupt Vscirx void SCI_Interrupt(){ // my interrupt handling routine }

where in this case, the vecor name is Vscirx and the number is 17.

 

Regards,

Chris

0 Kudos
97 Views
Senior Contributor I

In order to create an ISR, you have to do 3 things:

1) Create an entry in the interrupt vector table. The table can reside in RAM, in which case this can be done at run time. The table can be placed in ROM (to save RAM), in which case this has to be done at build time.

2) The corresponding Interrupt Control Register should be programmed with desired interrupt level and priority.

3) The ISR itself should be defined with a special keyword so that the compiler generates the correct function prologue and epilogue. Usually, the keyword is __interrupt.

That's it.

0 Kudos
97 Views
Specialist I

What the Reference Manuals need to make this easier to understand is a diagram at the top of the Interrupt Controller chapter showing how the peripherals connect through the interrupt controllers to the CPU.

 

I've checked through a few manuals to see if any of them have this and I couldn't find any. All interrupt controller chapters are cut/paste copies of an original one.

 

I suggest you draw your own diagram as an aid to understanding and to help when programming as you read the manuals.

 

I've also been looking for an App Note with a diagram of the interrupt structure, but couldn't find one in a quick search. Does anyone know of an App Note with this or a ColdFire Interrupt Controller Diagram anywhere on the web?

 

These 32-bit chips are a lot more flexible than the simple 8 bitters, and with that flexibility comes a lot of complexity.

 

Development systems can help to make this easier by predefining an interrupt setup, or by providing functions that hide some of the complexity from you. If you're running "bare bones" then you have to do all of this yourself somehow as already detailed.

 

Be aware that all of the peripherals have their own internal way of enabling their interrupts, and different ways of servicing them. Most peripherals require you to ack the interrupt in the peripheral somehow. So for a UART receive interrupt you have to read the character to make the interrupt go away. With other peripherals you have to write a "1" to a register to make it go away.

 

All these different interrupts feed into the interrupt controllers. Each one of these inputs has a control register that lets you set the level of interrupt (1-7 with zero being "disabled") to feed through to the CPU. These CPUs allow multiple levels of nested interrupts (interrupts interrupting other interrupt service routines). If you don't need this, then set everything to level 1. The interrupt controllers have relative priorities between them and between the different inputs as well. In most cases this only matters if two interrupts at the same level happen at the same time, which should be an unusual event.


Separately you have to set the interrupt vector for your service routine in the vector table. Some build systems let you specify this in the interrupt service routine definition. The vector table entries have the same order as the control registers in the interrupt controller, so you should be able to use some common #defines for these.


Find something that works and copy it. Like uTasker.

 

Tom

 

 

0 Kudos
97 Views
Specialist I

As an example, here's a cut down part of out "interrupts.h" file. This is for a gcc-based build, so may not translate directly into whatever you're using. This is running "bare metal" on an MCF5329. Now I'm looking at it I'm a bit surprised how steep the learning curve is, and how much code you have to get right before it will work at all.

 

First you need an assembly file to define the vector areas and to fill in some default interrupt vectors. In our case we have the ROM-based ones which are copied to static RAM:

 

vector.S:  .section  .vector_rom, "x"__ROMVEC:  .long   __stack               /* Reset: Initial Stack Pointer */  .long   start                 /* Reset: Initial Program Counter */  .long   BusError            /* Bus Error, Jim, but not as we know it. */  .long   AddrError            /* Address Error */... And so on ...  .org    0x100  .long   INTC0Default            /* User-Defined Interrupt 0 */  .long   INTC0Default            /* User-Defined Interrupt 1 */
  .long   INTC0Default            /* QSPI */  .long   INTC0Default            /* TMR0 */...  .long   INTC0Default            /* User-Defined Interrupt 62 */  .long   INTC0Default            /* User-Defined Interrupt 63 */  .long   INTC1Default            /* User-Defined Interrupt 64 */
  .long   INTC1Default            /* User-Defined Interrupt 65 */
...
  .long   INTC1Default            /* CAN1 buf 0 */
  .long   INTC1Default            /* CAN1 buf 1 */
  .long   INTC1Default            /* CAN1 buf 2 */
...
...  .long   IRQDefault            /* User-Defined Interrupt 185 */...  .long   IRQDefault            /* User-Defined Interrupt 191 */  .org    0x00000400  .section  .vector_ram__RAMVEC:  .space  0x400  .section  .textVecDefault:  halt  bra VecDefaultIRQDefault:  halt  bra IRQDefault... And so on for all the other default interrupts like INTC0Default and INTC1Default.".vector_ram" and ".vector_rom" are defined in the linker control script.

 This header file is included into every source file that needs to set and operate on interrupts:

 

interrupt.h:extern void     ( *__RAMVEC[] ) ( void );/* * USAGE * * To register an interrupt, do the following IN THIS ORDER. * *  INT_SET_VECTOR( int_lcd, LcdIsr ); *  INT_SET_PRIORITY( int_lcd ); *  INT_UNMASK( int_lcd ); * * To deregister an interrupt it is only necessary to call the * INT_MASK() function. Disable ints during this call. */// All of these conditionals compile out to a constant#define INT_SET_VECTOR( x, isr )                                        \    do {                                                                \        __RAMVEC[( x.controller + 1 ) * 64 + x.source] = isr;           \    } while ( 0 );#define INT_LEVEL( x ) ( x.level )#define INT_SET_PRIORITY( x )                                           \    do {                                                                \        if ( x.controller == 0 )                                        \        {                                                               \            MCF_INTC0_ICR( x.source ) = MCF_INTC_ICR_IL( x.level );     \        }                                                               \        else                                                            \        {                                                               \            MCF_INTC1_ICR( x.source ) = MCF_INTC_ICR_IL( x.level );     \        }                                                               \    } while ( 0 );#define INT_UNMASK( x )                                                 \    do {                                                                \        if ( x.controller == 0 )                                        \        {                                                               \            MCF_INTC0_CIMR = x.source;                                  \        }                                                               \        else                                                            \        {                                                               \            MCF_INTC1_CIMR = x.source;                                  \        }                                                               \    } while ( 0 );... And so on, also similar definitions for:#define INT_MASK( x )                                                   \#define INT_FORCE( x )                                                  \#define INT_UNFORCE( x )                                                \#define INT_PENDING( pending, x )                                       \#define INT_MASKED( masked, x )                                         \typedef struct{    uint8_t controller;    uint8_t source;    uint8_t level;} INT_INFO;/* * Being "static const" these expans in-line when called and * are surprisingly efficient. * * INTERRUPT PRIORITY * * First, the IPL is considered. * Then any interrupt from INTC0 wins over INTC1. * Then the higher numbered interrupts win over the lower ones. */// controller [0, 1], source [0, 63], level IPL/SPL [1-7]static const INT_INFO int_qspi = { 0, 31, 5 };static const INT_INFO int_pit[PIT_NUM_CHANNELS] ={     { 1, 43, 6 },   /* PIT_TIMER_MAIN_TIMER:    IPL6 Reload */    { 1, 44, 7 },   /* PIT_TIMER_SOFT_WATCHDOG: IPL7 One-shot */    { 1, 45, 7 },   /* PIT_TIMER_POWER_HOLD:    IPL7 Reload */    { 1, 46, 1 },   /* PIT_TIMER_PSEUDO_MAIN:   IPL1 Reload */};static const INT_INFO int_i2c = { 0, 30, 4 };static const INT_INFO int_uart0 = { 0, 26, 4 };static const INT_INFO int_lcd = { 1, 51, 3 };static const INT_INFO int_usb = { 1, 48, 2 };static const INT_INFO int_dma[DMA_NUM_CHANNELS] ={     { 0, 32, 7 },   /* DMA Timer 0, used for profiling */    { 0, 33, 0 },   /* DMA Timer 1, used for system microsecond counter */    { 0, 34, 0 },   /* DMA Timer 2, Unused */    { 0, 35, 0 },   /* DMA Timer 3, Unused */};

Note that the above "controller [0, 1], source [0, 63], level IPL/SPL [1-7]" information is lifted directly from the Reference Manual for all of the peripherals in use, and is conveniently defined in one place, rather than being scattered in all of the code that sets the interrupt vectors.

 

The "level" is selected by YOU depending on what are the most important interrupts in your design, and considering what interrupt service routnes can safely interrupt other interrupt service routines.

 

Here's an example call to set up the LCD interrupt, using the "int_lcd" structure defined above, and using the "LcdIsr()" service routine:

 

void VideoModuleInitHw(sVideoHdwrConfig_t *a_pConfig){    ...    // Initialise LCD interrupt    INT_SET_VECTOR(int_lcd, LcdIsr);    INT_SET_PRIORITY(int_lcd);    INT_UNMASK(int_lcd);    ...__attribute__((interrupt_handler)) static void LcdIsr(void){ uint32_t dummy; dummy = MCF_LCDC_LISR;  /* clear hardware flags */...To disable interrupts to the level of the LCD controller (so in can't interrupt, but higher ones can):

       uint16_t  old_ipl = asm_set_ipl(INT_LEVEL(int_lcd));
    ... Do whatever has to be done without the interrupt ...
    asm_set_ipl(old_ipl);

 

Tom

 

 

0 Kudos
97 Views
Contributor II

Hi everyone

 

Thanks for your valuable feedback. It's much appreciated. I think I now have enough information to figure out how to do it.

 

Regards,

Chris

0 Kudos
97 Views
Senior Contributor I

One thing that took me a while to find out / confirm is that IRQn interrupts have effective priority of 3.5.

Example, if you have interrupts A&B where A = Level 1 Priority 3 and B = Level 1 Priority 4, /IRQ1 will have higher priority than A but lower priority than B.

 

The manuals call them Priority 8 which is really confusing!

0 Kudos
97 Views
Specialist I

I'm glad I'm working on a V3 and not a V2 CPU.

 

With the V3, there is no "Priority" field in the ICR registers. All of the 64 interrupts on a single controller have fixed priorities, so this is one thing the programmer can't change, but is one thing less to worry about. If a programmerfinds the fixed priorities don't fit the design, then the only option is to use the LEVELS to get it the way they want. A good feature is that the Edge Port inputs can be set to any interrupt level - they're not fixed like they are in the V2, where the hardware designer has to be involved in the interrupt priority decisions.


With the V2, "It is the responsibility of the software to program the ICRnx registers with unique and non-overlapping level and priority definitions." There are 56 interrupts (ICRn8 to ICRn63) on each controller than need setting and only 8 different priorities available, so the programmer has to use different interrupt levels as well - not because they need things to have different levels, but just to make them unique! I prefer the simplification of the V3.

 

It would be a good idea for anyone programming a V2 chip to define all of the system ICR values (the values loaded into the ICR registers) in the one place in the one file to make it easy to check there aren't any duplications. It would also be worth adding a function that writes to the ICRs that reads all of the other ICRs first to make sure there's no accidental duplication at run time.

 

Tom

 

0 Kudos
97 Views
Specialist V

Hi

 

I would take some examples to start with.

 

For example the following is from the uTasker project showing how to set up the UART1 interrupt:

 

1. The interrupt handler is entered (it can also be fixed in Flash but is more flexible when set to SRAM)

 

fnSetIntHandler(UART1_VECTOR, (unsigned char *)_SCI1_Interrupt);

 2. This routine does

unsigned char *fnSetIntHandler(int iVectNumber, unsigned char *new_handler){    extern unsigned long __VECTOR_RAM[];    unsigned char *old_handler;        old_handler = (unsigned char *)__VECTOR_RAM[iVectNumber];    __VECTOR_RAM[iVectNumber] = (unsigned long)new_handler;    return old_handler;     }

 3. The vector number corresponds to that in the user's manual (14 for UART1 - so vector is 0x40 + 0x0e)

#define UART1_VECTOR        0x4e

 4. The handling routine itself is defined as

__declspec(interrupt) void _SCI1_Interrupt(void){}

 5. Interrut priorities are defined in their own ICR registers, eg.

IC_ICR_0_14 = (INTERRUPT_LEVEL_3 | INTERRUPT_PRIORITY_3);

 

 

Regards

 

Mark

0 Kudos
97 Views
Contributor I

Hi Mark

Can u tell me the Interrupt subroutine format in BareBoard project for MCF54418.

I am writing a timer program for Bootloader.

regards

Shuaib

0 Kudos
97 Views
Contributor IV

bluehacker wrote:

  

1.  what is the  interrupt source 1~7's interrupt level?

 


Edge port 1 can cause a level 1 interrupt. Edge port 7 can cause a level 7 interrupt. The 52259 defines an "edge port 0"; I don't know if you can actually use this as an interrupt.

0 Kudos
97 Views
Specialist II

 bkatt,

Thanks for clarification of unclear Freescale EPORT/Interrupt documentation item.

I see the same behavior with 5270.

Note, that level 7 interrupt is non-masked. Thus, IRQ7 pin needs to be treated differently vs the other IRQx pins.

 

"Edge port 1 can cause a level 1 interrupt. Edge port 7 can cause a level 7 interrupt."

 

 

0 Kudos
98 Views
Contributor V

Hi

 

Almost all interrupt sources are configurable at runtime (an exception could be the eport module, for example). 7 levels with 8 priorities. Level 0 is a masked interrupt. 7x8 = 56 different interrupts. Note this is per interrupt controller. Then per interrupt controller, a single ICRn (level + priority) value must exist. Unique combination per interrupt controller to avoid unexistent interrupts at runtime if two occurs concurrently. INTC0 has priority over INTC1 and so forth

 

Hope this helps

View solution in original post

0 Kudos
97 Views
Contributor III

thanks for Paolo Renzo.

you answered y second questions, many thanks!

Then what about the first question? what is the eport module(interrupt source 1~7)'s interrupt level? Level 1,or Level2?..... 

0 Kudos