View previous topic :: View next topic |
Author |
Message |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
ISR |
Posted: Wed May 03, 2023 2:01 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9168 Location: Greensville,Ontario
|
|
Posted: Wed May 03, 2023 3:46 pm |
|
|
curious..
What do you think W4 is supposed to contain ? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Thu May 04, 2023 1:02 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Thu May 04, 2023 1:27 am |
|
|
thanks Ttelmah _________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Thu May 04, 2023 6:28 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Thu May 04, 2023 7:39 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Thu May 04, 2023 7:47 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Thu May 04, 2023 8:54 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Thu May 04, 2023 10:26 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Fri May 05, 2023 12:45 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Fri May 05, 2023 2:06 am |
|
|
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.
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. |
|
![](templates/subSilver/images/spacer.gif) |
MCUprogrammer
Joined: 08 Sep 2020 Posts: 221
|
|
Posted: Fri May 05, 2023 7:21 am |
|
|
thanks _________________ Best Regards...
MCUprogrammer
_______________________________
Work Hard |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19358
|
|
Posted: Fri May 05, 2023 9:35 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
Posted: Fri May 05, 2023 9:41 am |
|
|
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!!!! |
|
![](templates/subSilver/images/spacer.gif) |
|