CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

#int_default with PCD compiler

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
SamMeredith



Joined: 13 Jul 2018
Posts: 23

View user's profile Send private message

#int_default with PCD compiler
PostPosted: Wed Nov 17, 2021 12:01 pm     Reply with quote

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: 9228
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Nov 17, 2021 1:27 pm     Reply with quote

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: 1349

View user's profile Send private message

PostPosted: Wed Nov 17, 2021 2:18 pm     Reply with quote

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: 19515

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 2:23 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 3:07 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 4:56 am     Reply with quote

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: 19515

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 7:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 10:50 am     Reply with quote

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: 1349

View user's profile Send private message

PostPosted: Thu Nov 18, 2021 3:16 pm     Reply with quote

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: 19515

View user's profile Send private message

PostPosted: Fri Nov 19, 2021 5:15 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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