|
|
View previous topic :: View next topic |
Author |
Message |
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
#int_default with PCD compiler |
Posted: Wed Nov 17, 2021 12:01 pm |
|
|
The following line from the #int_default description in the CCS manual is not clear to me:
Quote: | Description:
The following function will be called if the device triggers an interrupt and none of the
interrupt flags are set. If an interrupt is flagged, but is not the one triggered, the
#INT_DEFAULT function will get called.
[PCD] A #INT_xxx handler has not been defined for the interrupt.
|
My understanding is that #int_default is fired if an interrupt is triggered but the corresponding interrupt enable flag (or the global interrupt enable flag?) is not set.
However the extra line for the PCD compiler suggests that simply having an #int_xxx isr defined, even if the interrupt enable flag is cleared, will prevent #int_default from firing.
Is this correct? Can anyone clear up my understanding of #int_default? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Nov 17, 2021 1:27 pm |
|
|
hmm.. I read it that, if using PCD and you do NOT have the ISR handler ,then the 'default' IS used, providing the INT bit is cleared (not enabled).
So, if you don't have an INT enabled OR there is NO 'handler', the default is used.
yeah, clear as mud ??
it may be that PICs that need PCD are more complicated ? or ther's more 'housekeeping' needed with PCD ??
don't use PCD but I'm sure someone will respond with what it really means... |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Wed Nov 17, 2021 2:18 pm |
|
|
I think #int_default is primarily used for bootloaders for remapping the IVT for an application. If you search this forum looking for "int_default" you'll find some threads for example.
Example usage for remapping:
Code: |
#int_default
void isr(void)
{
jump_to_isr(LOADER_END+5);
}
|
That code remaps a bootloader IVT to point to an application IVT assuming it is located at LOADER_END+5. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Nov 18, 2021 2:23 am |
|
|
Thing to understand, is that on PCB/PCM/PCH, there is only normally
one actual interrupt handler. #INT_default, replaces this master handler.
This handler normally then calls each of the separate functions for
the individual interrupts (by polling the interrupt flag/enable bits).
This is the situation Jeremiah is talking about, where it can then
be used to reroute the interrupt to a different master handler for a
bootloader.
On PCD, things are very different, since the hardware automatically
calls the individual routines for the individual interrupts. There is a
hardware vector table, and the vector is selected based on the actual
interrupt number. On PCD, #INT_default becomes the interrupt vector
selected if another handler does not exist.
Understand, the interrupt handlers only ever get called (on all the chips),
if the global interrupt enable is set, and the interrupt enable is set, and
the interrupt flag gets set. So this statement:
"My understanding is that #int_default is fired if an interrupt is triggered
but the corresponding interrupt enable flag (or the global interrupt enable
flag?) is not set.", is untrue.
In the event that an interrupt enable is not set, or the global enable is
not set, _nothing happens_. No interrupt handler is ever called. |
|
|
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
|
Posted: Thu Nov 18, 2021 3:07 am |
|
|
Thanks all.
I still wasn't 100% clear, so here are some concrete examples.
They mostly back up Ttelmah's points (though with one surprise).
All examples using a dsPIC33EP512MC806 with compiler V5.101
Code: | #include <33EP512MC806.h>
#use delay( crystal=12Mhz, clock=120Mhz, AUX:clock=48Mhz )
#pin_select U3TX=PIN_F2
#pin_select U3RX=PIN_B12
#use rs232( UART3, baud=115200, parity=N, bits=8, errors, TIMEOUT=1, stream=DEBUGSTREAM )
//-------------------------------------
//
//-------------------------------------
void main()
{
delay_ms(100);
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 7500); // 1mS @ 120MHz
while (TRUE) {};
}
//-------------------------------------
//
//-------------------------------------
#int_default
void isr()
{
fprintf(DEBUGSTREAM, "\r\nDefault ISR");
}
|
The base case: Timer is set but no interrupt enable flags are set. No interrupts fire.
Code: | #include <33EP512MC806.h>
#use delay( crystal=12Mhz, clock=120Mhz, AUX:clock=48Mhz )
#pin_select U3TX=PIN_F2
#pin_select U3RX=PIN_B12
#use rs232( UART3, baud=115200, parity=N, bits=8, errors, TIMEOUT=1, stream=DEBUGSTREAM )
//-------------------------------------
//
//-------------------------------------
void main()
{
delay_ms(100);
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 7500); // 1mS @ 120MHz
enable_interrupts(INT_TIMER2);
//enable_interrupts(INTR_GLOBAL);
while (TRUE) {};
}
//-------------------------------------
//
//-------------------------------------
#int_default
void isr()
{
fprintf(DEBUGSTREAM, "\r\nDefault ISR");
}
|
Now the timer2 interrupt is enabled. #int_default fires.
To my surprise the line enable_interrupts(INTR_GLOBAL) is not required.
Code: | #include <33EP512MC806.h>
#use delay( crystal=12Mhz, clock=120Mhz, AUX:clock=48Mhz )
#pin_select U3TX=PIN_F2
#pin_select U3RX=PIN_B12
#use rs232( UART3, baud=115200, parity=N, bits=8, errors, TIMEOUT=1, stream=DEBUGSTREAM )
//-------------------------------------
//
//-------------------------------------
void main()
{
delay_ms(100);
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 7500); // 1mS @ 120MHz
enable_interrupts(INT_TIMER2);
//enable_interrupts(INTR_GLOBAL);
while (TRUE) {};
}
//-------------------------------------
//
//-------------------------------------
#int_default
void isr()
{
fprintf(DEBUGSTREAM, "\r\nDefault ISR");
}
//-------------------------------------
//
//-------------------------------------
#int_timer2
void timer_isr()
{
fprintf(DEBUGSTREAM, "\r\n Count");
}
|
Finally an ISR is defined for #int_timer2.
The #int_timer2 ISR is run. The #int_default ISR is not run (again, surprisingly, global interrupt enable not required).
EDIT: Another variation which proves my original statement wrong.
Global interrupt enabled, timer2 interrupt not enabled. No interrupts fire.
Code: | #include <33EP512MC806.h>
#use delay( crystal=12Mhz, clock=120Mhz, AUX:clock=48Mhz )
#pin_select U3TX=PIN_F2
#pin_select U3RX=PIN_B12
#use rs232( UART3, baud=115200, parity=N, bits=8, errors, TIMEOUT=1, stream=DEBUGSTREAM )
//-------------------------------------
//
//-------------------------------------
void main()
{
delay_ms(100);
setup_timer2(TMR_INTERNAL | TMR_DIV_BY_8, 7500); // 1mS @ 120MHz
//enable_interrupts(INT_TIMER2);
enable_interrupts(INTR_GLOBAL);
while (TRUE) {};
}
//-------------------------------------
//
//-------------------------------------
#int_default
void isr()
{
fprintf(DEBUGSTREAM, "\r\nDefault ISR");
}
//-------------------------------------
//
//-------------------------------------
#int_timer2
void timer_isr()
{
fprintf(DEBUGSTREAM, "\r\n Count");
} |
Jeremiah is correct, the bootloader is exactly where I have encountered this. I had attempted to add interrupts to a bootloader and run into the interrupt vectoring problems that have been discussed elsewhere on this forum.
Last edited by SamMeredith on Thu Nov 18, 2021 6:47 am; edited 1 time in total |
|
|
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
|
Posted: Thu Nov 18, 2021 4:56 am |
|
|
A follow-up question about this statement:
Quote: | On PCD, things are very different, since the hardware automatically
calls the individual routines for the individual interrupts. |
(How) does this change the bootloader IVT mapping for PCD?
Suppose I have no interrupts defined/enabled in my bootloader, except for #int_default, as in ex_pcd_bootloader.c
Now the timer2 interrupt is triggered from my application.
This jumps to the IVT at the bottom of program memory. It finds no ISR for timer2 so instead #int_default runs, which jumps to the application IVT at LOADER_END + 5.
Now how does the application timer2 ISR get called? There still must be some process which polls interrupt flags at this point? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Nov 18, 2021 7:22 am |
|
|
No.
The key is that the 'jump_to_isr' routine is not a simple routine.
It automatically re-vectors all the interrupt calls. It is a horribly complex
piece of code. In the older PIC18's, this 'single' jump, actually generates
code for both the high priority and low priority interrupt handlers. Similarly
on the DSPIC's, it generates all the code to handle the whole interrupt table. |
|
|
SamMeredith
Joined: 13 Jul 2018 Posts: 23
|
|
Posted: Thu Nov 18, 2021 10:50 am |
|
|
Okay, that makes sense.
I have removed the interrupts from my bootloader, using polling-based methods instead as you've suggested elsewhere.
So I can just rely on the jump_to_isr() routine to handle things for me. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Thu Nov 18, 2021 3:16 pm |
|
|
Note that the PIC24 and dsPIC families have 2 IVT tables, a primary and an alternate. You can remap the primary for your application and still use the alternate IVT for your bootloader. You just have to make sure to manually switch from ALT back to primary before running the application in the bootloader. It's a bit tricky to handle but possible.
Still, it is generally easier just to poll in the bootloader.
Here is an example for a specific chip and an older compiler versions, so some of the details might be out of date, but the idea is generally there:
https://www.ccsinfo.com/forum/viewtopic.php?p=225229#225229
A side note on your surprise about not needing to enable global interrupts for PIC24 chips. That's been the case for a long time. It's because CCS enables them by default. I'm not sure why, but just a decision that they made. It might have to do with how global interrupts are handled differently than with the 8bit pics. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Fri Nov 19, 2021 5:15 am |
|
|
Yes. In fact there is also an example of how to do this for the bootloader.
ex_pcd_nootloader_AIVT.c (and a corresponding bootload).
Honestly polling is always the preferred way to do the bootloader, but
this is a very powerful way of allowing interrupts to be used in both. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|