![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
barryb
Joined: 19 Jan 2012 Posts: 3
|
memset in a interrupt service routine ISR |
Posted: Thu Jan 19, 2012 2:37 pm |
|
|
I am using Version 4.084 on a PIC18F458 processor. We have found that using memset within an ISR is a problem. Memset uses RAM to store the size and value for memset. This gets corrupted if an interrupt fires while inside the memset function (and the ISR also has a memset). I thought the compiler is supposed to disable interrupts for its library functions. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 19, 2012 2:40 pm |
|
|
Make it easier for us to help you. Post an extremely short, but complete
and compilable program that shows the problem. (like, 10 lines of code).
And with the #include, #fuses, #use delay(), etc. |
|
![](templates/subSilver/images/spacer.gif) |
barryb
Joined: 19 Jan 2012 Posts: 3
|
memset in a interrupt service routine ISR |
Posted: Fri Jan 20, 2012 10:37 am |
|
|
It is very easy. Put a memset in an isr, and in the main.
As you can see, memset uses RAM at:
159 @MEMSET.P1
15A-15B @MEMSET.P1
The memset does an RCALL to 0x9e, but I don't see any interrupt disable, therefore both the interrupt and the main will use 0x159-0x15B for the memset memory.
Now, I must wonder if the other functions such as memcpy, strcpy, etc have the same problem.
Code: |
#include "18F458.h"
#include "sfr_pic18f6680.h"
#EXPORT (FILE=HEX_FILE_NAME_STRING, HEX)
#device adc=10
#fuses HS // set clock as high speed oscillator
#fuses PUT // power up timer enabled
#fuses NOPROTECT // no code protection
#fuses BROWNOUT // enable brownout protection
#fuses BORV42 // set brownout voltage 4.2 Volts if using 5V PIC
#fuses NOLVP // low voltage in-circuit serial programming disabled
#fuses NOCPD // eeprom code data protection bit disabled (i.e. not protected)
#fuses NOWRT // write protection: disabled
///////////////////////////////////////////////////////////////////////////////
// Watchdog coniguration - watch dog nominal 7-33 mS (18 nominal)
// with postscaler 448 - 2112 (1152 nominal)
///////////////////////////////////////////////////////////////////////////////
#fuses NOWDT // watchdog under software control
#fuses WDT64 // watch dog postscaler x64
#define FOSC 4000000 // internal primary oscillator frequency
#use delay(clock=FOSC)
#priority canrx0,timer3,timer1,timer0,canwake
int8 buf_isr[20];
int8 buf_main[300];
typedef unsigned int16 UINT16;
#define TIMER0_RELOAD_VALUE (UINT16)(0xFFA0)
void main( void )
{
/**** Timer 0 ****/
SFR_T0CON.TMR0ON = 0; // disable timer0
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_1);
set_timer0(TIMER0_RELOAD_VALUE);
SFR_INTCON.TMR0IF = 0; // clear timer0 interrupt flag
SFR_T0CON.TMR0ON = 1; // enable timer0
SFR_INTCON.TMR0IE = 1; // enable timer0 interrupt
SFR_INTCON.GIE = 1; // enable global interrupts
for(;;)
{
memset(buf_main, 0xab, sizeof(buf_main));
memset(buf_main, 0xab, sizeof(buf_main));
memset(buf_main, 0xab, sizeof(buf_main));
restart_wdt(); // restart watchdog so that it doesn't time out
}
}
#INT_TIMER0 // denotes that the following function is an isr
void timer_timer0_isr()
{
memset(buf_isr, 0x47, sizeof(buf_isr));
set_timer0(TIMER0_RELOAD_VALUE);
}
|
Disassembly is below:
Code: |
--- C:\Work\Work\memset_bug_reproduce_18F458\18F458.h ------------1: //////// Standard Header file for the PIC18F458 device ////////////////
2: #device PIC18F458
009E 0101 MOVLB 0x1
00A0 675A TSTFSZ 0x5a, BANKED
00A2 D003 BRA 0xaa
00A4 675B TSTFSZ 0x5b, BANKED
00A6 D002 BRA 0xac
00A8 D007 BRA 0xb8
00AA 2B5B INCF 0x5b, F, BANKED
00AC C159 MOVFF 0x159, 0xfee
00B0 2F5A DECFSZ 0x5a, F, BANKED
00B2 D7FC BRA 0xac
00B4 2F5B DECFSZ 0x5b, F, BANKED
00B6 D7FA BRA 0xac
00B8 0100 MOVLB 0
00BA 0C00 RETLW 0
--- C:\Work\Work\memset_bug_reproduce_18F458\bmgr.c --------------------------------------------
00DC EF2C GOTO 0x58
1: #include "main.c"
0000 EF70 GOTO 0xe0
0008 6E05 MOVWF 0x5, ACCESS
000A CFD8 MOVFF 0xfd8, 0x6
000E CFE0 MOVFF 0xfe0, 0x7
0012 0100 MOVLB 0
0014 CFE9 MOVFF 0xfe9, 0xd
0018 CFEA MOVFF 0xfea, 0x8
001C CFE1 MOVFF 0xfe1, 0x9
0020 CFE2 MOVFF 0xfe2, 0xa
0024 CFD9 MOVFF 0xfd9, 0xb
0028 CFDA MOVFF 0xfda, 0xc
002C CFF3 MOVFF 0xff3, 0x14
0030 CFF4 MOVFF 0xff4, 0x15
0034 CFFA MOVFF 0xffa, 0x16
0038 C000 MOVFF 0, 0xf
003C C001 MOVFF 0x1, 0x10
0040 C002 MOVFF 0x2, 0x11
0044 C003 MOVFF 0x3, 0x12
0048 C004 MOVFF 0x4, 0x13
004C AAF2 BTFSS 0xff2, 0x5, ACCESS
004E EF2C GOTO 0x58
0052 B4F2 BTFSC 0xff2, 0x2, ACCESS
0054 EF5E GOTO 0xbc
0058 C00F MOVFF 0xf, 0
005C C010 MOVFF 0x10, 0x1
0060 C011 MOVFF 0x11, 0x2
0064 C012 MOVFF 0x12, 0x3
0068 C013 MOVFF 0x13, 0x4
006C C00D MOVFF 0xd, 0xfe9
0070 C008 MOVFF 0x8, 0xfea
0074 8E08 BSF 0x8, 0x7, ACCESS
0076 C009 MOVFF 0x9, 0xfe1
007A C00A MOVFF 0xa, 0xfe2
007E C00B MOVFF 0xb, 0xfd9
0082 C00C MOVFF 0xc, 0xfda
0086 C014 MOVFF 0x14, 0xff3
008A C015 MOVFF 0x15, 0xff4
008E C016 MOVFF 0x16, 0xffa
0092 5005 MOVF 0x5, W, ACCESS
0094 C007 MOVFF 0x7, 0xfe0
0098 C006 MOVFF 0x6, 0xfd8
009C 0010 RETFIE 0
00DA 94F2 BCF 0xff2, 0x2, ACCESS |
Code: |
--- C:\Work\Work\memset_bug_reproduce_18F458\main.c ---------------1:
2: #include "18F458.h"
3: #include "sfr_pic18f6680.h"
4:
5: #EXPORT (FILE=HEX_FILE_NAME_STRING, HEX)
6: #device adc=10
7:
8: #fuses HS // set clock as high speed oscillator
9: #fuses PUT // power up timer enabled
10: #fuses NOPROTECT // no code protection
11: #fuses BROWNOUT // enable brownout protection
12: #fuses BORV42 // set brownout voltage 4.2 Volts if using 5V PIC
13: #fuses NOLVP // low voltage in-circuit serial programming disabled
14: #fuses NOCPD // eeprom code data protection bit disabled (i.e. not protected)
15: #fuses NOWRT // write protection: disabled
16:
17: ///////////////////////////////////////////////////////////////////////////////
18: // Watchdog coniguration - watch dog nominal 7-33 mS (18 nominal)
19: // with postscaler 448 - 2112 (1152 nominal)
20: ///////////////////////////////////////////////////////////////////////////////
21: #fuses NOWDT // watchdog under software control
22: #fuses WDT64 // watch dog postscaler x64
23:
24: #define FOSC 4000000 // internal primary oscillator frequency
25:
26: #use delay(clock=FOSC)
27: #priority canrx0,timer3,timer1,timer0,canwake
28:
29:
30: int8 buf_isr[20];
31: int8 buf_main[300];
32:
33: typedef unsigned int16 UINT16;
34: #define TIMER0_RELOAD_VALUE (UINT16)(0xFFA0)
35: void main( void )
36: {
00E0 6AF8 CLRF 0xff8, ACCESS
00E2 9ED0 BCF 0xfd0, 0x7, ACCESS
00E4 8E08 BSF 0x8, 0x7, ACCESS
00E6 6AEA CLRF 0xfea, ACCESS
00E8 6AE9 CLRF 0xfe9, ACCESS
00EA 80C1 BSF 0xfc1, 0, ACCESS
00EC 82C1 BSF 0xfc1, 0x1, ACCESS
00EE 84C1 BSF 0xfc1, 0x2, ACCESS
00F0 96C1 BCF 0xfc1, 0x3, ACCESS
00F2 0E07 MOVLW 0x7
00F4 6EB4 MOVWF 0xfb4, ACCESS
37: /**** Timer 0 ****/
38: SFR_T0CON.TMR0ON = 0; // disable timer0
00F6 9ED5 BCF 0xfd5, 0x7, ACCESS
39: setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_1);
00F8 0E88 MOVLW 0x88
00FA 6ED5 MOVWF 0xfd5, ACCESS
40: set_timer0(TIMER0_RELOAD_VALUE);
00FC 0EFF MOVLW 0xff
00FE 6ED7 MOVWF 0xfd7, ACCESS
0100 0EA0 MOVLW 0xa0
0102 6ED6 MOVWF 0xfd6, ACCESS
41: SFR_INTCON.TMR0IF = 0; // clear timer0 interrupt flag
0104 94F2 BCF 0xff2, 0x2, ACCESS
42: SFR_T0CON.TMR0ON = 1; // enable timer0
0106 8ED5 BSF 0xfd5, 0x7, ACCESS
43: SFR_INTCON.TMR0IE = 1; // enable timer0 interrupt
0108 8AF2 BSF 0xff2, 0x5, ACCESS
44: SFR_INTCON.GIE = 1; // enable global interrupts
010A 8EF2 BSF 0xff2, 0x7, ACCESS
45:
46: for(;;)
47: {
48:
49: memset(buf_main, 0xab, sizeof(buf_main));
010C 6AEA CLRF 0xfea, ACCESS
010E 0E2D MOVLW 0x2d
0110 6EE9 MOVWF 0xfe9, ACCESS
0112 0EAB MOVLW 0xab
0114 0101 MOVLB 0x1
0116 6F59 MOVWF 0x59, BANKED
0118 0E01 MOVLW 0x1
011A 6F5B MOVWF 0x5b, BANKED
011C 0E2C MOVLW 0x2c
011E 6F5A MOVWF 0x5a, BANKED
0120 0100 MOVLB 0
0122 DFBD RCALL 0x9e
50: memset(buf_main, 0xab, sizeof(buf_main));
0124 6AEA CLRF 0xfea, ACCESS
0126 0E2D MOVLW 0x2d
0128 6EE9 MOVWF 0xfe9, ACCESS
012A 0EAB MOVLW 0xab
012C 0101 MOVLB 0x1
012E 6F59 MOVWF 0x59, BANKED
0130 0E01 MOVLW 0x1
0132 6F5B MOVWF 0x5b, BANKED
0134 0E2C MOVLW 0x2c
0136 6F5A MOVWF 0x5a, BANKED
0138 0100 MOVLB 0
013A DFB1 RCALL 0x9e
51: memset(buf_main, 0xab, sizeof(buf_main));
013C 6AEA CLRF 0xfea, ACCESS
013E 0E2D MOVLW 0x2d
0140 6EE9 MOVWF 0xfe9, ACCESS
0142 0EAB MOVLW 0xab
0144 0101 MOVLB 0x1
0146 6F59 MOVWF 0x59, BANKED
0148 0E01 MOVLW 0x1
014A 6F5B MOVWF 0x5b, BANKED
014C 0E2C MOVLW 0x2c
014E 6F5A MOVWF 0x5a, BANKED
0150 0100 MOVLB 0
0152 DFA5 RCALL 0x9e
52: restart_wdt(); // restart watchdog so that it doesn't time out
0154 0004 CLRWDT
53: }
0156 D7DA BRA 0x10c
54: }
55:
56: #INT_TIMER0 // denotes that the following function is an isr
57: void timer_timer0_isr()
0158 0003 SLEEP
58: {
59: memset(buf_isr, 0x47, sizeof(buf_isr));
00BC 6AEA CLRF 0xfea, ACCESS
00BE 0E19 MOVLW 0x19
00C0 6EE9 MOVWF 0xfe9, ACCESS
00C2 0E47 MOVLW 0x47
00C4 0101 MOVLB 0x1
00C6 6F59 MOVWF 0x59, BANKED
00C8 6B5B CLRF 0x5b, BANKED
00CA 0E14 MOVLW 0x14
00CC 6F5A MOVWF 0x5a, BANKED
00CE 0100 MOVLB 0
00D0 DFE6 RCALL 0x9e
60: set_timer0(TIMER0_RELOAD_VALUE);
00D2 0EFF MOVLW 0xff
00D4 6ED7 MOVWF 0xfd7, ACCESS
00D6 0EA0 MOVLW 0xa0
00D8 6ED6 MOVWF 0xfd6, ACCESS |
.sym file is below:
Code: |
000 @SCRATCH
001 @SCRATCH
001 _RETURN_
002 @SCRATCH
003 @SCRATCH
004 @SCRATCH
005 @INTERRUPT_AREA
006 @INTERRUPT_AREA
007 @INTERRUPT_AREA
008 @INTERRUPT_AREA
009 @INTERRUPT_AREA
00A @INTERRUPT_AREA
00B @INTERRUPT_AREA
00C @INTERRUPT_AREA
00D @INTERRUPT_AREA
00E @INTERRUPT_AREA
00F @INTERRUPT_AREA
010 @INTERRUPT_AREA
011 @INTERRUPT_AREA
012 @INTERRUPT_AREA
013 @INTERRUPT_AREA
014 @INTERRUPT_AREA
015 @INTERRUPT_AREA
016 @INTERRUPT_AREA
017 @INTERRUPT_AREA
018 @INTERRUPT_AREA
019-02C buf_isr
02D-158 buf_main
159 @MEMSET.P1
15A-15B @MEMSET.P1
F83 PSP_DATA
F89 LATA
F8A LATB
F8B LATC
F8C LATD
F92 TRISA
F92 SFR_TRISA
F93 SFR_TRISB
F93 TRISB
F94 SFR_TRISC
F94 TRISC
F95 SFR_TRISD
F95 TRISD
F96 SFR_TRISE
F97 SFR_TRISF
F98 SFR_TRISG
F9D SFR_PIE1
F9E SFR_PIR1
FA0 SFR_PIE2
FA1 SFR_PIR2
FA3 SFR_PIE3
FA4 SFR_PIR3
FAB SFR_UART_RCSTA
FAC SFR_UART_TXSTA
FAD SFR_UART_TXREG
FAE SFR_UART_RCREG
FAF SFR_UART_SPBRG
FB1 SFR_T3CON
FB2 SFR_TMR3L
FB3 SFR_TMR3H
FB4.6 C1OUT
FB4.7 C2OUT
FBB CCP_2_LOW
FBB-FBC CCP_2
FBC CCP_2_HIGH
FBE-FBF CCP_1
FBE CCP_1_LOW
FBF CCP_1_HIGH
FCD SFR_T1CON
FD0 SFR_RCON
FD5 SFR_T0CON
FD6 SFR_TMR0L
FD7 SFR_TMR0H
FE9-FEA @WRITE_PROGRAM_MEMORY.P1
FE9-FEA @MEMSET.P2
FE9-FEA @READ_PROGRAM_MEMORY.P3
FF0 SFR_INTCON3
FF1 SFR_INTCON2
FF2 SFR_INTCON
FF6-FF8 @WRITE_PROGRAM_MEMORY.P1
FF6-FF8 @READ_PROGRAM_MEMORY.P2
|
ROM Allocation:
Code: |
00E0 main
009E @MEMSET
00BC timer_timer0_isr
00E0 @cinit
|
User Memory space:
Code: |
Project Directory:
C:\Work\Work\memset_bug_reproduce_18F458\
Project Files:
bmgr.c
main.c
18F458.h
sfr_pic18f6680.h
typedefs.h
hardware.h
version.h
Units:
bmgr.c (main)
Compiler Settings:
Processor: PIC18F458
Pointer Size: 16
ADC Range: 0-1023
Opt Level: 9
Short,Int,Long: UNSIGNED: 1,8,16
Float,Double: 32,32
Output Files:
Errors: bmgr.err
Ext Symbols: bmgr.esym
INHX32: Bmgr_003_13.hex
Symbols: bmgr.sym
List: bmgr.lst
Debug/COFF: bmgr.cof
Project: bmgr.PJT
Call Tree: bmgr.tre
Statistics: bmgr.sta |
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jan 20, 2012 11:50 pm |
|
|
With your version (v4.084), I think the best way to fix the problem is just
to protect calls outside the isr with disable/enable interrupts, as shown
below in bold.
I looked at two different solutions and it seems that in the ASM code for
your version, the compiler still shares RAM locations for parameters. It
doesn't do that in vs. 4.128. That's why solutions that look as if they
might work with the latest version probably won't work with your version.
So the following code is probably the best or easiest way to do it.
Quote: |
#include <18F458.h>
#fuses HS, NOWDT
#use delay(clock=4M)
int8 buf_isr[20];
int8 buf_main[300];
//---------------------------
#int_timer0
void timer0_isr()
{
memset(buf_isr, 0x47, sizeof(buf_isr));
}
//======================================
void main( void )
{
disable_interrupts(GLOBAL);
memset(buf_main, 0xab, sizeof(buf_main));
enable_interrupts(GLOBAL);
while(1);
} |
|
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Jan 21, 2012 8:19 am |
|
|
Honestly speaking, I won't expect memset used in an ISR. Possibly CCS neither did, because they are usually protecting
all non-relocatable RTL functions with an automatic interrupt disable which is missing in this case.
But it should be easy for CCS to include memset in the list of protected functions. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jan 21, 2012 9:55 pm |
|
|
Here is a thread where it is said that CCS disables interrupts in too
many of the built-in functions:
http://www.ccsinfo.com/forum/viewtopic.php?t=25535
Probaly because of that thread (or an email) CCS added this #device option:
Code: |
#device WRITE_EEPROM=NOINT
|
|
|
![](templates/subSilver/images/spacer.gif) |
barryb
Joined: 19 Jan 2012 Posts: 3
|
|
Posted: Mon Jan 23, 2012 11:50 am |
|
|
I looked over the bug fixes since v4.084, and I don't see any mention of changing memset (or any other function) for use in interrupts.
Also, the FAQ says the following (so why don't they check their own library functions):
In order to prevent the above problem, the compiler will "protect" the function call to A() from main() by disabling all interrupts before the call to A() and restoring the interrupt state after A() returns. In doing so, the compiler can allow complete sharing of functions between the main program and the interrupt functions.
The programmer must take the following special considerations into account:
1.In the above example, interrupts will be disabled for the entire execution of A(). This will increase the interrupt latency depending on the execution time of A().
2.If the function A() changes the interrupts using ENABLE/DISABLE _INTERRUPTS then the effect may be lost upon the return from A(), since the entire INTCON register is saved before A() is called and restored afterwards. Furthermore, if the global interrupt flag is enabled in A(), the program may execute incorrectly.
3.A program should not depend on the interrupts being disabled in the above situation. The compiler may NOT disable interrupts when the function or any function it calls requires no local RAM.
4.The interrupts may be disabled, as described above for internal compiler functions called by the same manor. For example, multiplication invoked by a simple * may have this effect. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|