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

ISR
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

ISR
PostPosted: Wed May 03, 2023 2:01 pm     Reply with quote

I will use FAST in this #INT_OC1 ISR. But I looked at what the compiler automatically saves in the .lst file before adding FAST.

CCS C 5.115
dsPIC33EV256GM102
#use delay(internal = 140MHZ)

Code:

....................
.................... int1 writeNewFreq = FALSE;
....................
.................... #INT_OC1
.................... void OC1_isr(void)
*
005CE:  PUSH    42
005D0:  PUSH    36
005D2:  PUSH    54
005D4:  MOV     W0,[W15++]
005D6:  MOV     #2,W0
005D8:  REPEAT  #C
005DA:  MOV     [W0++],[W15++]
.................... {
....................    if(writeNewFreq)
005DC:  BTSS.B  1001.2
005DE:  BRA     600
....................    {
....................       pwm_set_frequency(destFreq); // yeni frekansı ayarla
005E0:  PUSH    1004
005E2:  POP     104E
005E4:  PUSH    1006
005E6:  POP     1050
005E8:  MOV     #1D80,W4
005EA:  MOV     W4,1052
005EC:  MOV     #42C,W4
005EE:  MOV     W4,1054
005F0:  CLR     1056
005F2:  CALL    4B4
....................       pwm_set_duty_percent(500); // duty cycle'ı %50'ye ayarla
005F6:  MOV     #1F4,W4
005F8:  MOV     W4,104E
005FA:  CALL    5B0
....................       
....................       writeNewFreq = FALSE;
005FE:  BCLR.B  1001.2
....................    }
00600:  BCLR.B  800.2
00602:  MOV     #1A,W0
00604:  REPEAT  #C
00606:  MOV     [--W15],[W0--]
00608:  MOV     [--W15],W0
0060A:  POP     54
0060C:  POP     36
0060E:  POP     42
00610:  RETFIE 
.................... }
....................

C below code
Code:

#INT_OC1
void OC1_isr(void)
{
   if(writeNewFreq)
   {
      pwm_set_frequency(destFreq); // yeni frekansı ayarla
      pwm_set_duty_percent(500); // duty cycle'ı %50'ye ayarla
      writeNewFreq = FALSE;
   }
}

The above codes are before adding FAST to the ISR. When I add FAST, the resulting codes are:
Code:

.................... int1 writeNewFreq = FALSE;
....................
.................... #INT_OC1 FAST
.................... void OC1_isr(void)
*
005CE:  PUSH.S 
.................... {
....................    if(writeNewFreq)
005D0:  BTSS.B  1001.2
005D2:  BRA     5F4
....................    {
....................       pwm_set_frequency(destFreq); // yeni frekansı ayarla
005D4:  PUSH    1004
005D6:  POP     104E
005D8:  PUSH    1006
005DA:  POP     1050
005DC:  MOV     #1D80,W4
005DE:  MOV     W4,1052
005E0:  MOV     #42C,W4
005E2:  MOV     W4,1054
005E4:  CLR     1056
005E6:  CALL    4B4
....................       pwm_set_duty_percent(500); // duty cycle'ı %50'ye ayarla
005EA:  MOV     #1F4,W4
005EC:  MOV     W4,104E
005EE:  CALL    5B0
....................       
....................       writeNewFreq = FALSE;
005F2:  BCLR.B  1001.2
....................    }
005F4:  BCLR.B  800.2
005F6:  POP.S   
005F8:  RETFIE 
.................... }

c below code
When I examined the ISR, I saw that it uses the W4 register. I wrote the following code for this. But it didn't work. Where am I making the mistake?
Code:
#INT_OC1 FAST
void OC1_isr(void)
{
     #word W4 = getenv("SFR:WREG4")
     unsigned int16 W4_SAVE = W4;
   
    if(writeNewFreq)
    {
       pwm_set_frequency(destFreq); // set new frequency
       pwm_set_duty_percent(500); // set duty cycle to 50%
     
       writeNewFreq = FALSE;
    }
    W4 = W4_SAVE;
}

_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
temtronic



Joined: 01 Jul 2010
Posts: 9253
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed May 03, 2023 3:46 pm     Reply with quote

curious..
What do you think W4 is supposed to contain ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Thu May 04, 2023 1:02 am     Reply with quote

Problem is that lots of other things may be being used. You have not
looked to see.
The calls:

005E6: CALL 4B4

005EE: CALL 5B0

each need to be looked through to see what other registers may be
changed.

For saving registers, the easiest thing is to PUSH them. So:
Code:

    #ASM
    PUSH W4
    #ENDASM

//and

    #ASM
    POP W4
    #ENDASM


saves and restores a register with the stack.

Honestly though the existing code is efficient, and avoids having to look
through potentially hundreds of lines of code to see what else is changed.
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Thu May 04, 2023 1:27 am     Reply with quote

thanks Ttelmah
_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Thu May 04, 2023 6:28 am     Reply with quote

Just thinking on, consider using:

Code:

//near the top of code just after processor include
#device NESTED_INTERRUPTS=TRUE

//Then
#INT_OC1 LEVEL=5
void OC1_isr(void)
{
    if(writeNewFreq)
    {
       pwm_set_frequency(destFreq); // set new frequency
       pwm_set_duty_percent(500); // set duty cycle to 50%
     
       writeNewFreq = FALSE;
    }
}


This makes your INT_OC1, able to interrupt the other interrupt handlers
Much more likely to have a real affect on the speed it occurs than the
FAST option.

This way INT_OC1 will trigger even if the code is servicing another interrupt.

The default interrupt LEVEL, is 4.
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Thu May 04, 2023 7:39 am     Reply with quote

Actually, I thought a lot about this subject and did some research. To share the information I have obtained;
In microcontrollers, there are two ways to handle ISRs (Interrupt Service Routines) that can improve their performance: FAST ISRs and nested ISRs.

FAST ISRs are used when the ISR needs to execute quickly and is time-critical. In a FAST ISR, the compiler generates a specialized interrupt handler that disables interrupts for the shortest possible time, allowing the ISR to execute quickly. To create a FAST ISR, you need to define it using the "#pragma interrupt" directive in your code.

Nested ISRs are used when an interrupt occurs while another interrupt is being serviced. In this case, the nested ISR is executed before the interrupted ISR is completed. To enable nested interrupts, you need to set the "NESTED_INTERRUPTS" configuration bit in your code, and use the "#INT_xxx LEVEL=y" directive to specify the priority level of the interrupt.

Here is an example code snippet that demonstrates how to define a FAST ISR and a nested ISR in a dsPIC33 microcontroller:
Example code
Code:
#include <33EV256GM102.h>
#use delay(internal = 140MHZ)


#INT_EXT
void isr_ext()
{
   // This is an example of a FAST ISR, which should be completed as quickly as possible.
   // Therefore, only a flag is set and the processing is completed in the main program.

   // Set a flag
   flag_external_interrupt = TRUE;

   // Realign
   CLEAR_INTERRUPT(INT_EXT);
}

#INT_TIMER1
void isr_timer1()
{
   // This is an example of a NESTED ISR, which is an ISR that must be completed as quickly as possible.
   // However, multiple ISRs can occur at the same time, so a priority must be assigned based on the level of the incoming ISR.

   // In addition to the variable used to process the external interrupt, this ISR also increments a counter.

   // Variable declarations
   static unsigned int counter = 0;

   // Increment counter
   counter++;

   // Clear interrupt
   CLEAR_INTERRUPT(INT_TIMER1);
}

void main()
{
   // External interrupt settings
   enable_interrupts(INT_EXT);
   ext_int_edge(H_TO_L);
   CLEAR_INTERRUPT(INT_EXT);

   // Timer interrupt settings
   enable_interrupts(INT_TIMER1);
   set_timer1(0);
   setup_timer1(T1_INTERNAL|T1_DIV_BY_1);
   CLEAR_INTERRUPT(INT_TIMER1);

   // Main loop
   while (1)
   {
      // Check external interrupt flag
      if (flag_external_interrupt)
      {
         // Process external interrupt
         // ...

         // Clear flag
         flag_external_interrupt = FALSE;
      }

      // Other operations
      // ...
   }
}

This sample code contains both FAST ISR and Nested ISR examples. For example, a FAST ISR is defined for an external interrupt (INT_EXT), while a Nested ISR is defined for a timer 1 interrupt (INT_TIMER1). In addition, priority interrupt levels are determined and interrupt flags are checked in the main program for operation.
_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Thu May 04, 2023 7:47 am     Reply with quote

Mr @temtronic to explain to your question I can summarize it as follows.

WREG4 is a special function register in PIC microcontrollers that can be used to store data temporarily. In the provided code, the value of WREG4 is saved in a variable named W4_SAVE using the built-in function "getenv()", which retrieves the value of a specified SFR (special function register). This is done to ensure that the interrupt service routine (ISR) does not overwrite the value of WREG4, which may be used by other parts of the program. At the end of the ISR, the original value of WREG4 is restored from W4_SAVE to ensure proper program execution.
_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Thu May 04, 2023 8:54 am     Reply with quote

You are not quite right in your summary.
The two options are _not_ distinct.

The fast option simply means the ISR does not save all the registers that
may be being used. Saves the instructions this involves, but means that
you have to save every register that your own code uses in the routine.

The LEVEL= option allows an ISR to interrupt other ISR's.
If you use FAST and the compiler is executing another interrupt the
servicing will be delayed till this original ISR completes. Likely to be a much
longer delay than the normal save overhead.

So the way to get an interrupt that is serviced quickly is to declare it
_both_ as FAST, and use the LEVEL directive.

Now, if you do this, and use your W4_SAVE approach, then the W4_SAVE
variable needs to be set as static. Otherwise this can overwrite variables
in other ISR's. The compiler does not automatically protect variables in
ISR's when nesting is enabled (it _did_ a while ago). This is why using the
stack is safer.
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Thu May 04, 2023 10:26 am     Reply with quote

If I understand you correctly, you are saying that the code should be as follows.
Code:

//near the top of code just after processor include
#device NESTED_INTERRUPTS=TRUE

//Then
#INT_OC1 FAST LEVEL=5
void OC1_isr(void)
{
     #word W4 = getenv("SFR:WREG4")
     static unsigned int16 W4_SAVE = W4;
   
    if(writeNewFreq)
    {
       pwm_set_frequency(destFreq); // set new frequency
       pwm_set_duty_percent(500); // set duty cycle to 50%
     
       writeNewFreq = FALSE;
    }
    W4 = W4_SAVE;
}

_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Fri May 05, 2023 12:45 am     Reply with quote

From what I understood when I looked at the datasheet yesterday
When I use the #device NESTED_INTERRUPTS=TRUE option, this enables nested interrupts, which allows interrupts set to a higher level to allow interrupts set to a lower level. I have to be very careful when I use the FAST option because when I enable nested interrupts I only have to do 1 ISR FAST. There is no provision in the compiler to preserve automatically saved records for a FAST ISR that could be interrupted by another FAST ISR. If this happens it will be W0 to W3 and the Status record may be corrupted.
_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Fri May 05, 2023 2:06 am     Reply with quote

No.....

The 'only one FAST' limit is on the PIC18's. On these there is a single set
of shadow registers for the core registers. So only one FAST interrupt
is allowed. On the PIC24/30/33 this limit doesn't exist, since the core
registers are saved into the standard stack using the PUSH.S instruction.
Very Happy

Have code here using assembler for the interrupt routines, so able to just
use the bare minimum registers, with three FAST interrupts for specific
hardware error conditions.

The compiler is very smart, and 'knows' what can't be done. So on a PIC18,
if you try to declare two 'FAST' interrupts, you will get a warning. Do the
same on a PIC33, and it'll happily accept this.
Unfortunately, there doesn't actually seem to be a manual page 'for'
the DsPIC interrupt handling.
MCUprogrammer



Joined: 08 Sep 2020
Posts: 221

View user's profile Send private message

PostPosted: Fri May 05, 2023 7:21 am     Reply with quote

Smile thanks
_________________
Best Regards...
MCUprogrammer
_______________________________
Work Hard
dyeatman



Joined: 06 Sep 2003
Posts: 1938
Location: Norman, OK

View user's profile Send private message

PostPosted: Fri May 05, 2023 9:14 am     Reply with quote

More details on DsPic interrupt handling are in the Family Reference Manual
https://ww1.microchip.com/downloads/en/devicedoc/70000600d.pdf
_________________
Google and Forum Search are some of your best tools!!!!
Ttelmah



Joined: 11 Mar 2010
Posts: 19559

View user's profile Send private message

PostPosted: Fri May 05, 2023 9:35 am     Reply with quote

It is the CCS manual page that I was saying is lacking.
They have a complete section on how the keywords are used with the
PIC18's, but nothing on the DsPIC's.
dyeatman



Joined: 06 Sep 2003
Posts: 1938
Location: Norman, OK

View user's profile Send private message

PostPosted: Fri May 05, 2023 9:41 am     Reply with quote

After going back and re-reading what you posted I re4alized that..and tried to
delete what I posted but you responded before I could. Apologies.
_________________
Google and Forum Search are some of your best tools!!!!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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