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

How to prevent inbuilt functions to disable interrupts?

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



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

How to prevent inbuilt functions to disable interrupts?
PostPosted: Thu Dec 29, 2005 1:22 pm     Reply with quote

Several inbuilt functions of the compiler disable interrupts to avoid data corruption problems. Examples of these functions are:
- read_eeprom
- strcpy
- memcpy
- etc

In my program I have a time critical High priority interrupt that I don't want to be disabled. I do see there are potential hazards, but in my interrupt I'm not using any of the above mentioned functions, so I should be safe.

Is it possible to change this behaviour of the compiler by setting an option?

If this option doesn't exists what other way is there to work around these limitations?

My current workaround is to stick with v3.226 which only disables the lower priority interrupts but I want to be able to upgrade to future versions as well.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 29, 2005 1:52 pm     Reply with quote

I made a test program and compiled it with PCH vs. 3.241.
I didn't see memcpy() strcpy() turn off interrupts. Only
the read_eeprom() function does it.
You're looking for some sort of pragma that disables that
aspect of the CCS library code. I don't think there is one.
But the read_eeprom() code is so short, that you could
copy it and write your own function by using #byte and #bit
statements:
Code:
..... c = read_eeprom(0);
012A:  MOVFF  FF2,41
012E:  BCF    FF2.7
0130:  CLRF   FA9
0132:  BCF    FA6.6
0134:  BCF    FA6.7
0136:  BSF    FA6.0
0138:  MOVF   FA8,W
013A:  BTFSC  41.7
013C:  BSF    FF2.7
013E:  MOVWF  40

Note:  main.c  address =  0x40


Test program:
Code:

#include <18F452.h> 
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#int_ext
void int_ext_isr(void)
{
char c;

c = 0x55;

}

//=============================
void main()
{
int8 source[20] = {"Hello World"};
int8 dest[20];
char c;

enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);

memcpy(dest, source, 20);

strcpy(dest, source);

c = read_eeprom(0);


while(1);
}
 
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Thu Dec 29, 2005 6:40 pm     Reply with quote

Quote:
I made a test program and compiled it with PCH vs. 3.241.
I didn't see memcpy() strcpy() turn off interrupts. Only
the read_eeprom() function does it.
You're looking for some sort of pragma that disables that
aspect of the CCS library code. I don't think there is one.
But the read_eeprom() code is so short, that you could
copy it and write your own function by using #byte and #bit


Check the errata for the processor you are using. I seem to remember there was a problem on the 18F family with the data in the holding register EEDATA being corrupted if not read immediately after the read EEPROM sequence.
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Dec 29, 2005 6:55 pm     Reply with quote

They want at least one instruction between writing to the EEADR
register and setting the RD bit (EECON1.0)
http://ww1.microchip.com/downloads/en/DeviceDoc/80245a.pdf
The CCS code satifies the errata:
Code:
... c = read_eeprom(0);
012A:  MOVFF  INTCON,@@41
012E:  BCF    INTCON.7
0130:  CLRF   EEADR        // Write to EEADR
0132:  BCF    EECON1.6
0134:  BCF    EECON1.7
0136:  BSF    EECON1.0     // Set RD bit
0138:  MOVF   EEDATA,W
013A:  BTFSC  @@41.7
013C:  BSF    INTCON.7
013E:  MOVWF  c
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Dec 30, 2005 7:13 pm     Reply with quote

PCM programmer wrote:
I made a test program and compiled it with PCH vs. 3.241.
I didn't see memcpy() strcpy() turn off interrupts. Only
the read_eeprom() function does it. [/code]
Thanks PCM, until now I just assumed the CCS compiler always turned of the interrupts but it turns out to be a little more intelligent. It looks like the CCS compiler is disabling interrupts for all functions that use the TBLRD registers but I haven't figured out why, this requires some more investigations after the weekend. I keep you updated.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Jan 02, 2006 10:56 am     Reply with quote

I just returned to work after the weekend and figured out the difference between my program and PCM's example: I copy the fixed data from Flash memory while PCM's example copies the data from RAM.
Here is the modified example program:
Code:
#include <18f458.h>
#FUSES HS, NOPROTECT, PUT, NOBROWNOUT, NOWDT, NOLVP
#use delay(clock=16000000)


//=============================
void main()
{
  int8 source[20] = {"Hello World"};
  int8 dest[20];
  char c;
 

  memcpy(dest, source, 20);           // No disabling of interrupts

  strcpy(dest, source);               // No disabling of interrupts

  c = read_eeprom(0);                 // Disables interrupts, but very short time and I can live with this.

  memcpy(dest, "Hello World", 12);    // Disables interrupts

  strcpy(dest, "Hello World");        // Disables interrupts

  while(1);
}


The memcpy that copies the data from ROM does so by using the TBLPTR registers. Even when you don't use interrupts in your program these functions will disable interrupts as a precaution. I don't know why the interrupts have to be disabled, could it be that an interrupt destroys the contents of the TBLPTR registers?
Ttelmah
Guest







PostPosted: Mon Jan 02, 2006 3:43 pm     Reply with quote

This is a fix, for a problem I had ages ago.
In 2002, using the 18F452, I had problems when an interrupt conatined a table based 'switch' instruction, and a TBLRD was used in the main. I sent CCS this email:

Quote:

What is happening, is that once a read or write is set up, if an interrupt
occurs, which itself uses these registers, the actual operation may access
an incorrect memory address, resulting in either incorrect retrieval, or
corruption of memory data. Since you set up such instructions for constant
array accesses, or for certain types of switch statement, the chances of
data corruption are significant (or branching to an invalid address). I
suspect that this is explains the problems I was having with memory access.
I have 'trimmed' the code, and am attaching it here:

#include <18F452.h>
#fuses
H4,NOPROTECT,NOWRT,NOOSCSEN,BROWNOUT,BORV45,WDT,WDT1,PUT,CCP2C1,STVREN,NOLVP
,NODEBUG
#use delay(clock=40000000, restart_wdt )

int State = 0;

#define InPin PIN_B0
#define OutPin PIN_B7

const int Array[]={ 1, 2, 3, 4 };

#int_ext
void
InterruptExt( void )
{
switch( State ) {
case 0:
output_bit( OutPin, 1 );
State = 1;
break;
case 1:
output_bit( OutPin, 0 );
State = 0;
break;
}
}

void
main( void )
{
int a;
int b;
output_bit( OutPin, 0 );
ext_int_edge(0, L_TO_H );
enable_interrupts( INT_EXT );
Enable_interrupts(GLOBAL);
while ( TRUE ) {
restart_wdt();
b = Array[a];
}
}

If you look at the generated assembler, you can see where the problem would
occur, in the interval between setting up the table read (for the constant
data array), and actually completing the transfer.
What is needed, is that interrupts are going to have to be disabled in the
'core' of all the table access functions, or the interrupt handler would
have to be modified to store and restore the status of these registers...


Part of the code showing the fault, was actually from another poster here.
CCS added code to disable interrupts around the TBLRD functions at this time. They still do not save these registers in the interrupt handler (takes quite a time to save and restore these), so the fix remains in place. That it is not there on the mem to mem copy, suggests that this problem might actually still exist for these routines...

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Jan 02, 2006 5:32 pm     Reply with quote

Quote:
CCS added code to disable interrupts around the TBLRD functions at this time. They still do not save these registers in the interrupt handler (takes quite a time to save and restore these), so the fix remains in place.
Thanks TTelmah, I'm thankful that people like you with historic info on the CCS compiler are hanging around at this forum.

Quote:
That it is not there on the mem to mem copy, suggests that this problem might actually still exist for these routines...
I checked the memcopy routines, they are save. The first example copies from RAM to RAM using the FSR0 registers which are saved in the default interrupt handlers. The second example copies from Flash to RAM with disabled interrupts so is save as well.

I'm not sure if the CCS solution poses a problem to me, I think it is allright. I have a time critical fast interrupt in my code and I was wondering why it was disabled as it doesn't do anything with the TBLRD registers. Optimizing my code I also noticed my 4 byte ROM constants to require almost 30 instructions initialization code each..... Sad

Maybe I'll write my own memcopy function which only disables the low priority interrupts, but I hate it when I have to move away from the standard C code. Mad

Thanks everyone for helping me out on this strange behavior.
Ttelmah
Guest







PostPosted: Tue Jan 03, 2006 4:20 am     Reply with quote

The real 'pity', is that the behaviour is not controlled by a flag, rather than defaulting. If the compiler simply tested whether any code inside the interrupt used TBLRD, and only if so, then enabled the behaviour, everyone would be happy. :-)
There are quite a few places like this, where default behaviours can be annoying.
I found myself thinking 'I remember something about this', when the behaviour was mentioned, and it took me a while to look through my email archive, and find the old mail.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Jan 03, 2006 7:44 am     Reply with quote

Trying to write my own memcpy function I failed because the CCS compiler doesn't allow me to pass a pointer to a constant in ROM. Aarghh... I knew it, but that's exactly why I was writing my own memcopy function in the first place! A chicken & egg problem...

I discovered the printf function to disable all interrupts as well so we now have the following list of functions disabling interrupts:
- read_eeprom
- write_eeprom
- memcpy(dest, constant string)
- strcpy(dest, constant string)
- printf(constant string)

I don't want to rewrite all these functions so I'll stick with v3.226 which only disables the normal interrupts but leaves the Fast interrupts alone...

Thanks everyone.
Ttelmah
Guest







PostPosted: Tue Jan 03, 2006 10:33 am     Reply with quote

Does the putc work-around?.
So:
Code:

void putmsg(int chr) {
   putc(chr);
}

//Then in the code
putmsg("Test Message");


I think you will find this transfers the message with the interrupts left enabled.
The same trick, can be used to move a constant string toa buffer, with:
Code:

int locn;
#define resetptr locn=0

void tobuff(int8 buff[],int chr) {
   buff[locn++]=chr;
}


//Then in the main code

resetptr;
tobuff(array,"Test message");

//Moves the constant message to the array


Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jan 04, 2006 5:27 pm     Reply with quote

Hi Ttelmah,
Thanks for the putc work-around idea. I haven't tried it because I've already spent too much time to this issue and using v3.226 will do for the moment. I don't have a good feeling about writing my own versions of the standard functions, maybe I'll ask CCS to add a new compiler option for disabling the extra code. Fast interrupt support in the compiler is a mess already anyway.
Guest
Guest







Delay too!
PostPosted: Thu Jan 26, 2006 5:42 pm     Reply with quote

Delay_ms switches off GIE - presumably to time things accurately. But int_rda2's that occur during the delay don't seem to fire their interrupt once GIE is set again.

Looked at the irq logic chain in Chapter 9 if the 6621's pdf - its all combinatorial, so there should be a rising edge to cause an interrupt when GIE is set again - any of you been through this process with analysing the other funcs that switch irq's off?

Ken Macfarlane
Ttelmah
Guest







PostPosted: Fri Jan 27, 2006 3:33 am     Reply with quote

Delay_ms, _does not_ turn off the interrupts, _unless_ you are using delays inside your interrupt handler. PCM_programmer, has published a method in the past, of forcing the compiler to generate two copies of the routine to stop this. _Every_ function (including your own), will have interrupts disabled, if the same routine is used inside and outside the interrupts (this is needed to prevent re-entrancy problems). You can always prevent this, by having two copies of the routine. The 'point' about this thread, was that a few functions, disable interrupts, even when they are not being used in both locations.
Have you got 'ERROR' enabled on the RDA2 UART?. If not, then the interrupt _will_ fire once, but then never again, since the UART will now be stuck in the 'overrun error' condition.

Best Wishes
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