I'm trying to set up a simple pin interrupt on IRQ7 in MQX, but I would like to avoid using the GPIO interrupt method (GPIO_IOCTL_ENABLE_IRQ). I've added the code below based on the MQX user guide, section 3.10.8, but modified to use the IRQ pin. As I understand it this is the EPORT vector, and I also set some of the EPORT registers for this pin. It installs the ISR OK, but apparently it never gets called because the tick count doesn't change. If I set the pin as GPIO I can read the signal no problem so I don't believe there is a hardware issue. Is there a problem with this code?
Thank you
typedef struct {
pointer OLD_ISR_DATA;
void (_CODE_PTR_ OLD_ISR)(pointer);
_mqx_uint TICK_COUNT;
} MY_ISR_STRUCT, _PTR_ MY_ISR_STRUCT_PTR;
void pin_isr(pointer user_isr_ptr)
{
MY_ISR_STRUCT_PTR isr_ptr;
isr_ptr = (MY_ISR_STRUCT_PTR)user_isr_ptr;
isr_ptr->TICK_COUNT++;
/* Chain to previous notifier */
(*isr_ptr->OLD_ISR)(isr_ptr->OLD_ISR_DATA);
}
void sensor_task(uint_32 initial_data)
{
MY_ISR_STRUCT_PTR isr_ptr;
isr_ptr = _mem_alloc_zero(sizeof(MY_ISR_STRUCT));
isr_ptr->TICK_COUNT = 0;
isr_ptr->OLD_ISR_DATA = _int_get_isr_data(MCF5225_INT_EPORT0_EPF7);
isr_ptr->OLD_ISR = _int_get_isr(MCF5225_INT_EPORT0_EPF7);
if (_int_install_isr(MCF5225_INT_EPORT0_EPF7, pin_isr, isr_ptr) == 0)
printf ("Failed to install ISR\n");
MCF_GPIO_PNQPAR |= 0x4000; //set IRQ7 pin PAR to primary function (IRQ)
MCF_EPORT_EPPAR |= 0x4000; //set IRQ7 to rising edge triggered (see RM sec 17.4.1)
MCF_EPORT_EPDDR &= 0x7F; //set IRQ7 pin as input (this is the reset condition)
MCF_EPORT_EPIER |= 0x80; //enable IRQ7
while (1) {
_time_delay_ticks(1000);
printf("\nTick count = %d\n", isr_ptr->TICK_COUNT);
}
}
Solved! Go to Solution.
Hello Angelo,
I can't locate in your code snippet where ido you enable interrupts? These 2 functions should be called to set interrupt level, unmask and enable it : _bsp_int_init and _bsp_int_enable. All you did was install your ISR routine.
Read more information in the MQX reference manual.
Regards,
MartinK
Hello Angelo,
I can't locate in your code snippet where ido you enable interrupts? These 2 functions should be called to set interrupt level, unmask and enable it : _bsp_int_init and _bsp_int_enable. All you did was install your ISR routine.
Read more information in the MQX reference manual.
Regards,
MartinK
Hello,
have you set your EPORT (IRQ) functionality in the GPIO registers?
jv
I have a new strange problem with this. It services the interrupts and the tick count keeps getting displayed, but after the first interrupt following reset, the shell stops working. Again I'm wondering if the ISR chaining has something to do with this, or if it is related to priority levels. The shell task is running with priority level 13, and sensor_task is at 9.
The chaining is not important, you don't have to do it.
I'm still having some trouble with the interrupt handler. Firstly, it tends to stop the shell from working. I'm thinking it might have something to do with priority levels of the tasks.
Also, sometimes when the IRQ is serviced the program halts completely. I understand there are some things I can't do within an ISR. Right now I'm trying to capture the time of the event, and I'm using _time_get_elapsed_ticks and _time_diff_ticks. Is there any problem doing this? Otherwise there doesn't seem to be any code that should cause it to stop. Just before exiting the ISR I have this line MCF_EPORT_EPFR |= 0x80;
Any advice why I get these lock-ups?
Thanks
Angelo
Hi Angelo,
ICRn7 is read only set to level 7. This effectively is a non-maskable interrupt to the ColdFire core and must be handled as such. It means it can interrupt MQX at any time, even during MQX critical section, thus, you should install and use kernel isr for it and must not call any MQX API function from it.
Requirements for a kernel isr:
A kernel ISR must save the registers that it needs and must service the hardware interrupt. When the kernel ISR is finished, it must restore the registers and perform a return-from-interrupt instruction.
A kernel ISR cannot call MQX functions. However, it can put data in global data, which a task can access.
By the way, if an interrupt flag register consists of w1c bits, you should clear a bit(bits) by a simple write operation:
MCF_EPORT_EPFR = 0x80;
if you want to clear only the masked bit and not other w1c bits.
Thank you Martin for your reply. So if I was using one of the other interrupts (1,3,5) these would not require a kernel ISR? I would like to avoid using a kernel ISR if possible. If I do have to do this, and if I can't call MQX functions, how can I get access to the low level timers, as I would through _time_get_elapsed_ticks?
Right, 1, 3, 5 or ok unless you have changed the BSP default macro:
#ifndef BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX
#define BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX (6L)
#endif
for 1, 3, 5 you can install an MQX isr and you can call non-blocking MQX functions from MQX isrs. _time_get_elapsed_ticks() should be non-blocking, I beleive.
Thanks. I'm not able to change the priority level for IRQ7, correct?
Are there any examples of kernel ISRs available that I could look at?
Look into any bare metal code example with interrupts for your MCF device.
If you wish to write a kernel isr in C, CW 10.x compiler should be useful in generating prologue and epilogue for a function that is declared as interrupt routine:
__declspec(interrupt) void my_isr(void)
{
/* your code here; call no MQX API functions */
}
I see, I thought you meant to use the MQX _int_install_kernel_isr
Yes, you're right - I had set the PAR to the primary function as shown in the code above, but I then commented it out to use it as GPIO and forgot to set it back for my last test.
I also realized after fixing this that I needed to clear the flag to avoid repeated interrupts, and now it's working as expected. The completed isr is below. Thank you both!
Is it important in this scenario to do the ISR chaining at the end of the function? I assume this is necessary if MQX is relying on this interrupt, but if I haven't set that elsewhere in the code is it relevant?
Angelo
void pin_isr(pointer user_isr_ptr)
{
MY_ISR_STRUCT_PTR isr_ptr;
isr_ptr = (MY_ISR_STRUCT_PTR)user_isr_ptr;
isr_ptr->TICK_COUNT++;
//clear interrupt flag
MCF_EPORT_EPFR |= 0x80; //clear flag bit for IRQ7 (by writing 1 to it - writing 0 has no effect)
// Chain to previous notifier
(*isr_ptr->OLD_ISR)(isr_ptr->OLD_ISR_DATA);
}
Thank you MartinK, that makes sense. But those calls aren't recognized, perhaps because this is MQX3.6.2. I checked some files in 3.8 and I see that the _bsp_int_init is usually aliased to _mcfxxxx_int_init, etc. so I put together these two lines to add after the install isr, but it's still doesn't work. I'm not sure if I'm enabling the interrupts, or just unmasking them. Is there some sort of master interrupt enable?
Thank you
// set the interrupt level, and unmask the interrupt in interrupt controller
_mcf5225_int_init(MCF5225_INT_EPORT0_EPF7, 3, 0, TRUE);
// enable interrupt
_mcf5225_int_unmask(MCF5225_INT_EPORT0_EPF7);