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

memset in a interrupt service routine ISR

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



Joined: 19 Jan 2012
Posts: 3

View user's profile Send private message

memset in a interrupt service routine ISR
PostPosted: Thu Jan 19, 2012 2:37 pm     Reply with quote

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.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jan 19, 2012 2:40 pm     Reply with quote

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.
barryb



Joined: 19 Jan 2012
Posts: 3

View user's profile Send private message

memset in a interrupt service routine ISR
PostPosted: Fri Jan 20, 2012 10:37 am     Reply with quote

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
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jan 20, 2012 11:50 pm     Reply with quote

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);
}
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Jan 21, 2012 8:19 am     Reply with quote

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.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jan 21, 2012 9:55 pm     Reply with quote

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
barryb



Joined: 19 Jan 2012
Posts: 3

View user's profile Send private message

PostPosted: Mon Jan 23, 2012 11:50 am     Reply with quote

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.
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