Interrupts for MKE02 (Cortex M0+)

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

Interrupts for MKE02 (Cortex M0+)

2,766 次查看
ankurmittal
Contributor II

Hi All,

I am using Freescale MKE02Z32 (Cortex M0+) micro-controller in one of application. Application is running with 3 interrupts enabled. One of these interrupts handles a very critical task and I don't want it to be disabled at any point of time.

Although as my main loop is running some segments (safety checks) of code that disable all interrupts causing problem to this task/ interrupt. Is there a solution or work around for this? i.e. I want my this one interrupt to remain enabled at all times (even if disable system interrupts for specific segment in periodic loop).

Note: Cortex M3/M4 have basepri registers on them. Is it possible to implement something like this on CM0+ also ?

0 项奖励
回复
6 回复数

2,373 次查看
egoodii
Senior Contributor III

Yes, BASEPRI is VERY handy in M4 for this exact reason:

extern u32_t Port_IntsDisableCount; // count of performed disables

#define DISABLE_PORT_INT()    Port_IntsDisableCount++;\
                  __set_BASEPRI( 1 << (8-ARM_INTERRUPT_LEVEL_BITS) ); //All SPI-device interrupts on Level 1, disable them (and lower)
#define ENABLE_PORT_INT()      if(--Port_IntsDisableCount==0) \
                  __set_BASEPRI( 0 );      //If we get back to 'base level', enable all interrupts

You can get a similar effect using the Interrupt Enable Register of NVIC, which is to say something like this (I don't have a KE04 header file, so names are guesses, plus of course you need your actual interrupt group):
extern u32_t Port_IntsDisableCount; // count of performed disables

#define DISABLE_PORT_INT()    Port_IntsDisableCount++;\
                  NVICICER = (1<<(INT_PORTC-16)) | (1<<(INT_UART0_RX_TX - 16)); //disable these


#define ENABLE_PORT_INT()      if(--Port_IntsDisableCount==0) \
                  NVICISER = (1<<(INT_PORTC-16)) | (1<<(INT_UART0_RX_TX - 16));      //If we get back to 'base level', enable all interrupts

Not as 'clean', but functional...if a 'disabled' interrupt occurs, it will merely set the 'pending' bit, awaiting a new 'enable' operation 'later'...

2,373 次查看
ankurmittal
Contributor II

Thanks for your reply/ suggestion. 

 

If my understanding is correct you are suggesting to disable and enable all other interrupts individually using NVIC (except the one that I want enabled at all times). Is this correct ?

 

Also you said:

"Not as 'clean', but functional...if a 'disabled' interrupt occurs, it will merely set the 'pending' bit, awaiting a new 'enable' operation 'later'..."

 

Although I am not clear on how pending bit will be set for a disabled interrupt ? Can you please elaborate further.

 

P.S. Also this was the last/ only way around I had in my mind :smileyhappy:

0 项奖励
回复

2,373 次查看
egoodii
Senior Contributor III

Yes, disable and enable 'all other interrupts' at the NVIC, although not exactly individually, but rather all 'in one go'.

'Disable', at this level, merely means the NVIC will NOT proceed with interrupt functions for that interrupt.  The 'pending' bit (in the Interrupt-Pending Register) WILL get set by an interrupt-signal, and in this way the NVIC remembers the 'need', and when 'all your interrupts' are re-enabled (in a block with one write to the NVIC Interrupt Set Enable Register)  later, all those pending will be evaluated in the normal priority to pick 'which'.

I say this is 'less clean' because the 'block disable' circumvents any normal 'priority hardware', AND because these macros 'assume' they know exactly which set of interrupts to disable then re-enable, 'at all times'.  I think you can organize your thoughts and processes to make these limitations 'very tolerable'.

It is 'unfortunate' that all documentation at this level of 'core operations' for ARM licensees must defer to arm.com, but there you can find the basic 'design guide/users guide' for Cortex M0, and that is where this functionality is described.

0 项奖励
回复

2,373 次查看
ankurmittal
Contributor II

Thanks for clarification. But I guess this would work only for non-core (IRQ No. >= 0) interrupts.

If the system is running core interrupts (i.e systick) that also need to be disabled. Then what would you suggest. (Additionally adding instruction to disabling/ enabling the systick)

0 项奖励
回复

2,373 次查看
mjbcswitzerland
Specialist V

Hi

Try with something like this:

static unsigned long _SYSTICK_CSR = 0;
static unsigned long NVICIntSet[NVIC_SET_REGISTERS] = {0};

#define DISABLEMASK_0_31   0xffffffff                // all to be disabled
#define DISABLEMASK_32_63  0xfffffffe                // all to be disabled apart from IRQ32
#define DISABLEMASK_64_95  0xffffffff                // all to be disabled
#define DISABLEMASK_96_127 0xffffffff                // all to be disabled
//etc.

extern void fnDisableOtherInterrupts(void)
{
    _SYSTICK_CSR = (SYSTICK_CSR & SYSTICK_TICKINT); // save original systick interrupt mask
    SYSTICK_CSR &= ~(SYSTICK_TICKINT);              // disable systick interrupt
    NVICIntSet[0] = IRQ0_31_SER;                    // save original NVIC interrupt flags
    IRQ0_31_CER = DISABLEMASK_0_31;                 // disable interrupts
    NVICIntSet[1] = IRQ32_63_SER;
    IRQ32_63_CER = DISABLEMASK_32_63;
    #if NVIC_SET_REGISTERS > 2
    NVICIntSet[2] = IRQ64_95_SER;
    IRQ64_95_CER = DISABLEMASK_64_95;
    #endif
    #if NVIC_SET_REGISTERS > 3
    NVICIntSet[3] = IRQ96_127_SER
    IRQ96_127_CER = DISABLEMASK_96_127;
    #endif
    // etc.
}

extern void fnReenableInterrupts(void)
{
    SYSTICK_CSR |= _SYSTICK_CSR;        // re-enable systick interrupt if it was previously enabled
    IRQ0_31_SER = NVICIntSet[0];        // re-enable previously enabled interrupts
    IRQ32_63_SER = NVICIntSet[1];
    #if NVIC_SET_REGISTERS > 2
    IRQ64_95_SER = NVICIntSet[2];
    #endif
    #if NVIC_SET_REGISTERS > 3
    IRQ96_127_SER = NVICIntSet[3];
    #endif
    // etc.
}

NVIC_SET_REGISTERS can be set to match the number of NVIC registers that need to be controlled for the specific processor. The example retains IRQ32, which can be adjusted to match the one that should never be disabled.

Regards

Mark

0 项奖励
回复

2,373 次查看
egoodii
Senior Contributor III

If the 'block of interrupts' to be enabled at the NVIC level is 'changeable', then Mark's addition of 'saving the incoming state' is a cool addition (for a few more instructions), but note of course that M0+ only has ONE set of 32 interrupts, so there is only one 'wordful' to read or write at any time.  Personally, however, I would want to keep the 'enable/disable process overhead' to a minimum and use macros rather than the cost of a full procedure:

extern uint32_t Port_IntsDisableCount; // count of performed disables

extern uint32_t SavedNVICints;

#define DISABLE_PORT_INT()   { Port_IntsDisableCount++;\

                  SavedNVICints = NVICICER;\
                  NVICICER = (1<<(INT_PORTC-16)) | (1<<(INT_UART0_RX_TX - 16));} //disable these


#define ENABLE_PORT_INT()      if(--Port_IntsDisableCount==0) \
                  NVICISER = SavedNVICints ;      //If we get back to 'base level', enable all interrupts we had before

Bringing in SysTick adds a new wrinkle.  This is another case where M0+ is 'less clean' than M4, since we can set SCB_SHPR3_PRI_15 to match our lower 'maskable interrupt' group, and thus BASEPRI in M4 will affect it as well.  But that does beg the question --- can you just 'work' with this lowered SysTick priority, and simply structure your code so that the SysTick handler interrupt is safe?

I fear that clearing 'TICKINT' does an 'actual' DISABLE, which means, like disabling any interrupt 'at the source' opens a window whereby the event will get 'missed entirely'.  The ICSR register mentions 'SysTick Pending', but I see no indication of how that might work.  I suppose you could also DISABLE and ENABLE the SyTick-counter operation at the same time as the TICKINT bit, BUT what consequence either possibility (rollover loss or count-clock-delay) has on your 'timekeeping' functions is 'up to you'.  Personally, I would eschew SYSTICK in this environment in favor of either RTC or FTM timekeeping, so that you can stick with NVIC-processed interrupts to get the proper 'pending' hardware to implement 'hold' on exceptions, and with that you can GUARANTEE a max interrupt-response-time for your 'critical' function to be the 'best hardware can do' (longest uninterruptable instruction, stacking process, plus.... which ARM lists at 15 clocks for zero-wait-state stack-RAM in M0+, 12 clocks in M4)

0 项奖励
回复