|
|
View previous topic :: View next topic |
Author |
Message |
Daniel Brännwik Guest
|
Multiple use of the same RAM locations |
Posted: Fri Aug 08, 2003 11:06 am |
|
|
Hello,
I have come across a problem after I implemented a bootloader feature. The bootloader itself works ok but the implementation of it forced me to change a lot in the earlier program in order to have all functions at the proper addresses in flash.
I beleive that the problem has occured due to nested functions calls in the interrupt service routines in combination with use of the #separate and #inline directives.
What occurs is that local variabels in the main loop (and functions called from it) are shared with local variabels in the functions that are called from the irq routines. This leads to random runtime errors since the values in some local variables can be changed from another function if a irq happens simultaneously. I found the problem when I checked the .sym file created at compilation.
Is this a known problem and what can be done to solve it?
My first approach was to make all colliding variables static. This works in most cases but it takes a lot of extra RAM and is not particulary easy to maintain in the future development process.
Also it does not solve the cases where I have input data to a functions, like "void function1 (byte var)". "Var" can also collide with another local variable somewhere else.
The same applies for all scratch (temporary) variables that the compiler uses for doing operations invisible to the user.
Is there a way to reserve RAM where the compiler should put the local variables of a function? I have looked at the #reserve directive but it seems to do the opposite as what I want to achieve?
Any suggestion how to deal with this problem is highly appreciated. As always I have found this problem when time to delivery is very short.
I use PCW 3.164 and PIC16F877A.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516826 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: Multiple use of the same RAM locations |
Posted: Fri Aug 08, 2003 11:33 am |
|
|
:=What occurs is that local variabels in the main loop (and functions called from it) are shared with local variabels in the functions that are called from the irq routines.
------------------------------------------------------
Tradition is to keep irq routines short and set flags that
are polled in the main loop. Can you re-write your code to
do it this way ?
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516827 |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Multiple use of the same RAM locations |
Posted: Fri Aug 08, 2003 12:05 pm |
|
|
:=
:=Hello,
:=I have come across a problem after I implemented a bootloader feature. The bootloader itself works ok but the implementation of it forced me to change a lot in the earlier program in order to have all functions at the proper addresses in flash.
:=I beleive that the problem has occured due to nested functions calls in the interrupt service routines in combination with use of the #separate and #inline directives.
:=
:=What occurs is that local variabels in the main loop (and functions called from it) are shared with local variabels in the functions that are called from the irq routines. This leads to random runtime errors since the values in some local variables can be changed from another function if a irq happens simultaneously. I found the problem when I checked the .sym file created at compilation.
:=
:=Is this a known problem and what can be done to solve it?
:=My first approach was to make all colliding variables static. This works in most cases but it takes a lot of extra RAM and is not particulary easy to maintain in the future development process.
:=Also it does not solve the cases where I have input data to a functions, like "void function1 (byte var)". "Var" can also collide with another local variable somewhere else.
:=The same applies for all scratch (temporary) variables that the compiler uses for doing operations invisible to the user.
:=
:=Is there a way to reserve RAM where the compiler should put the local variables of a function? I have looked at the #reserve directive but it seems to do the opposite as what I want to achieve?
:=Any suggestion how to deal with this problem is highly appreciated. As always I have found this problem when time to delivery is very short.
:=
:=I use PCW 3.164 and PIC16F877A.
Concider the following code example.
RegisterMap is declared and located on the bank boundry to eliminate index conversion for arrays not located at start of bank.
All the other variables are located relative to the first variable declaration. bits, bytes, words and even another array.
When writing a function that uses a number of variables locating the variables in this manner will insure that they are all in the same bank of memory. This will eliminate a lot of the need for the compiler to perform bank switching. This can be observed in the listing file.
#include "18F452.h"
int8 RegisterMap[256]; // To provide access to Configuration map in an 8 bit format
#locate RegisterMap = 0x100 //Through 0x1FF(MAX)
int16 RegisterMap_16_Bit[128]; // To provide access to Configuration map in a 16 bit format
#locate RegisterMap_16_Bit = RegisterMap //Through 0x1FF(MAX)
int32 led_Status;
#locate led_Status = RegisterMap +1
#bit led_0 = led_Status.0
#bit led_1 = led_Status.1
#bit led_2 = led_Status.2
void main()
{ led_0=1;
led_1=0;
led_Status = 0xAFAF;
RegisterMap_16_Bit[0] = 1;
}
here is another example that I use to create/verify CRC16 checks on modbus packets.
#inline // Inline code runs faster
void Make_Check_CRC(void) // This function can be used to create or check CRC
{ int8 msgndx, msglen, crcdata, c; // Message index, length and indexed value
int16 crcacc; // CRC accumuliator
#byte crcacc_lo = crcacc // Alias name for CRC accumuliator low byte
#byte crcacc_hi = crcacc + 1 // Alias name for CRC accumuliator high byte
#bit LS_BIT_crcdata = crcdata.0 // Alias name for bit zero of data value copy
#bit LS_BIT_crcacc = crcacc.0 // Alias name for bit zero of CRC accumuliator
good_crc = 0; // Assume this packet is bad
//msglen // Note the packet length
crcacc = 0xFFFF; // Initialize the CRC accumuliator
Packet_Buffer_Index = 0; // First byte indexed as zero
while(Packet_Buffer_Index < Packet_Buffer_Byte_Count) // Last byte indexed as length -1
{ crcdata = PacketBuffer[Packet_Buffer_Index]; // Use direct addressing on copy of data value
for(Bit_Count=8;Bit_Count>0;Bit_Count--) // Process the data bits
{ if(LS_BIT_crcdata != LS_BIT_crcacc) // Should XOR be performed
crcacc = (crcacc >> 1)^0xA001; // Shift CRC 1 bit right load high with 0 then XOR
else // No XOR performed
crcacc = crcacc >> 1; // Shift CRC 1 bit right load high with 0
crcdata = crcdata >> 1; // Shift data to next bit
} // Processed all bits of byte
Packet_Buffer_Index++; // Advance index to the next byte
} // Solved values for CRC
if((crcacc_lo == PacketBuffer[Packet_Buffer_Byte_Count]) && (crcacc_hi == PacketBuffer[Packet_Buffer_Byte_Count]))
{ good_crc = 1; // The packet recieved was good
ChanAErrors = 0;
}
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516830 |
|
|
Daniel Brännwik Guest
|
Re: Multiple use of the same RAM locations |
Posted: Sat Aug 09, 2003 2:24 am |
|
|
:=:=What occurs is that local variabels in the main loop (and functions called from it) are shared with local variabels in the functions that are called from the irq routines.
:=------------------------------------------------------
:=
:=Tradition is to keep irq routines short and set flags that
:=are polled in the main loop. Can you re-write your code to
:=do it this way ?
I'm afraid not, since the irq in question is due to a synchronous USART communication where the PIC is slave. Therefore I need to make sure that the answer from the PIC is ready when the master clocks in the data.
(I have another irq from a timer and that is treated as you suggest.)
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516849 |
|
|
Daniel Brännwik Guest
|
Re: Multiple use of the same RAM locations |
Posted: Sat Aug 09, 2003 2:26 am |
|
|
<font face="Courier New" size=-1>:=Concider the following code example.
:=RegisterMap is declared and located on the bank boundry to eliminate index conversion for arrays not located at start of bank.
:=
:=All the other variables are located relative to the first variable declaration. bits, bytes, words and even another array.
:=
:=When writing a function that uses a number of variables locating the variables in this manner will insure that they are all in the same bank of memory. This will eliminate a lot of the need for the compiler to perform bank switching. This can be observed in the listing file.
:=
:=
:=
:=#include "18F452.h"
:=
:=int8 RegisterMap[256]; // To provide access to Configuration map in an 8 bit format
:=#locate RegisterMap = 0x100 //Through 0x1FF(MAX)
:=
:=int16 RegisterMap_16_Bit[128]; // To provide access to Configuration map in a 16 bit format
:=#locate RegisterMap_16_Bit = RegisterMap //Through 0x1FF(MAX)
:=
:=int32 led_Status;
:=#locate led_Status = RegisterMap +1
:=#bit led_0 = led_Status.0
:=#bit led_1 = led_Status.1
:=#bit led_2 = led_Status.2
:=
:=void main()
:={ led_0=1;
:= led_1=0;
:= led_Status = 0xAFAF;
:= RegisterMap_16_Bit[0] = 1;
:=}
:=
:=here is another example that I use to create/verify CRC16 checks on modbus packets.
:=
:=
:=#inline // Inline code runs faster
:=void Make_Check_CRC(void) // This function can be used to create or check CRC
:={ int8 msgndx, msglen, crcdata, c; // Message index, length and indexed value
:= int16 crcacc; // CRC accumuliator
:= #byte crcacc_lo = crcacc // Alias name for CRC accumuliator low byte
:= #byte crcacc_hi = crcacc + 1 // Alias name for CRC accumuliator high byte
:= #bit LS_BIT_crcdata = crcdata.0 // Alias name for bit zero of data value copy
:= #bit LS_BIT_crcacc = crcacc.0 // Alias name for bit zero of CRC accumuliator
:= good_crc = 0; // Assume this packet is bad
:= //msglen // Note the packet length
:= crcacc = 0xFFFF; // Initialize the CRC accumuliator
:= Packet_Buffer_Index = 0; // First byte indexed as zero
:= while(Packet_Buffer_Index < Packet_Buffer_Byte_Count) // Last byte indexed as length -1
:= { crcdata = PacketBuffer[Packet_Buffer_Index]; // Use direct addressing on copy of data value
:= for(Bit_Count=8;Bit_Count>0;Bit_Count--) // Process the data bits
:= { if(LS_BIT_crcdata != LS_BIT_crcacc) // Should XOR be performed
:= crcacc = (crcacc >> 1)^0xA001; // Shift CRC 1 bit right load high with 0 then XOR
:= else // No XOR performed
:= crcacc = crcacc >> 1; // Shift CRC 1 bit right load high with 0
:= crcdata = crcdata >> 1; // Shift data to next bit
:= } // Processed all bits of byte
:= Packet_Buffer_Index++; // Advance index to the next byte
:= } // Solved values for CRC
:= if((crcacc_lo == PacketBuffer[Packet_Buffer_Byte_Count]) && (crcacc_hi == PacketBuffer[Packet_Buffer_Byte_Count]))
:= { good_crc = 1; // The packet recieved was good
:= ChanAErrors = 0;
:= }
:=}
Thank you for your answer. I have found the #locate directive now and applied it on the variables in the irq functions. My program seems to be running fine now.
However I still suspect I have a potential problem left. It concerns the scratch variables that the compiler uses for internal use (for example when doing a division). When examining the symbol file (*.sym) I see that some scratch variables in the irq functions are located on the same address as other variables in the main loop. Even though the likeliness for a collision is reduced considerably now I think there's still a chance that it will happen.
Any idea how to control the location of these scratch variables?
</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516850 |
|
|
R.J.Hamlett Guest
|
Re: Multiple use of the same RAM locations |
Posted: Sat Aug 09, 2003 7:33 am |
|
|
:=<font face="Courier New" size=-1>:=Concider the following code example.
:=:=RegisterMap is declared and located on the bank boundry to eliminate index conversion for arrays not located at start of bank.
:=:=
:=:=All the other variables are located relative to the first variable declaration. bits, bytes, words and even another array.
:=:=
:=:=When writing a function that uses a number of variables locating the variables in this manner will insure that they are all in the same bank of memory. This will eliminate a lot of the need for the compiler to perform bank switching. This can be observed in the listing file.
:=:=
:=:=
:=:=
:=:=#include "18F452.h"
:=:=
:=:=int8 RegisterMap[256]; // To provide access to Configuration map in an 8 bit format
:=:=#locate RegisterMap = 0x100 //Through 0x1FF(MAX)
:=:=
:=:=int16 RegisterMap_16_Bit[128]; // To provide access to Configuration map in a 16 bit format
:=:=#locate RegisterMap_16_Bit = RegisterMap //Through 0x1FF(MAX)
:=:=
:=:=int32 led_Status;
:=:=#locate led_Status = RegisterMap +1
:=:=#bit led_0 = led_Status.0
:=:=#bit led_1 = led_Status.1
:=:=#bit led_2 = led_Status.2
:=:=
:=:=void main()
:=:={ led_0=1;
:=:= led_1=0;
:=:= led_Status = 0xAFAF;
:=:= RegisterMap_16_Bit[0] = 1;
:=:=}
:=:=
:=:=here is another example that I use to create/verify CRC16 checks on modbus packets.
:=:=
:=:=
:=:=#inline // Inline code runs faster
:=:=void Make_Check_CRC(void) // This function can be used to create or check CRC
:=:={ int8 msgndx, msglen, crcdata, c; // Message index, length and indexed value
:=:= int16 crcacc; // CRC accumuliator
:=:= #byte crcacc_lo = crcacc // Alias name for CRC accumuliator low byte
:=:= #byte crcacc_hi = crcacc + 1 // Alias name for CRC accumuliator high byte
:=:= #bit LS_BIT_crcdata = crcdata.0 // Alias name for bit zero of data value copy
:=:= #bit LS_BIT_crcacc = crcacc.0 // Alias name for bit zero of CRC accumuliator
:=:= good_crc = 0; // Assume this packet is bad
:=:= //msglen // Note the packet length
:=:= crcacc = 0xFFFF; // Initialize the CRC accumuliator
:=:= Packet_Buffer_Index = 0; // First byte indexed as zero
:=:= while(Packet_Buffer_Index < Packet_Buffer_Byte_Count) // Last byte indexed as length -1
:=:= { crcdata = PacketBuffer[Packet_Buffer_Index]; // Use direct addressing on copy of data value
:=:= for(Bit_Count=8;Bit_Count>0;Bit_Count--) // Process the data bits
:=:= { if(LS_BIT_crcdata != LS_BIT_crcacc) // Should XOR be performed
:=:= crcacc = (crcacc >> 1)^0xA001; // Shift CRC 1 bit right load high with 0 then XOR
:=:= else // No XOR performed
:=:= crcacc = crcacc >> 1; // Shift CRC 1 bit right load high with 0
:=:= crcdata = crcdata >> 1; // Shift data to next bit
:=:= } // Processed all bits of byte
:=:= Packet_Buffer_Index++; // Advance index to the next byte
:=:= } // Solved values for CRC
:=:= if((crcacc_lo == PacketBuffer[Packet_Buffer_Byte_Count]) && (crcacc_hi == PacketBuffer[Packet_Buffer_Byte_Count]))
:=:= { good_crc = 1; // The packet recieved was good
:=:= ChanAErrors = 0;
:=:= }
:=:=}
:=
:=Thank you for your answer. I have found the #locate directive now and applied it on the variables in the irq functions. My program seems to be running fine now.
:=However I still suspect I have a potential problem left. It concerns the scratch variables that the compiler uses for internal use (for example when doing a division). When examining the symbol file (*.sym) I see that some scratch variables in the irq functions are located on the same address as other variables in the main loop. Even though the likeliness for a collision is reduced considerably now I think there's still a chance that it will happen.
:=Any idea how to control the location of these scratch variables?
:=</font>
The scratch variables are normally saved by the IRQ handler. Look at the assembler for the standard handler, and you should find it saves the contents of these locations. :-)
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516854 |
|
|
Daniel Brännwik Guest
|
Re: Multiple use of the same RAM locations |
Posted: Sat Aug 09, 2003 8:15 am |
|
|
:=The scratch variables are normally saved by the IRQ handler. Look at the assembler for the standard handler, and you should find it saves the contents of these locations. :-)
:=
:=Best Wishes
I'm not sure what you mean. But I think the reason for my problems is that the compiler doesn't understand that the functions called from my isr are indeed connected to the isr.
I have, as I mentioned in an earlier post used #inline, #separate and #org statements extensively in order to get the program to work with my bootloader. I think this is the cause of the problems. Below is a snippet from my .sym file which illustrates what I mean:
0CD main2.ch_no - called from main
0CD @DIV88.@DIV88.P1
0CD @MUL88.@MUL88.P2
0CD main.@SCRATCH - used in main
0CD read_parameters.@SCRATCH - called from the isr!
0CD cmd_decode.@SCRATCH - called from the isr!
If for example "ch_no" in main2 is used when a irq comes its content will be corrupted. Or am I missing something?
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516855 |
|
|
R.J.Hamlett Guest
|
Re: Multiple use of the same RAM locations |
Posted: Sat Aug 09, 2003 2:34 pm |
|
|
:=:=The scratch variables are normally saved by the IRQ handler. Look at the assembler for the standard handler, and you should find it saves the contents of these locations. :-)
:=:=
:=:=Best Wishes
:=
:=I'm not sure what you mean. But I think the reason for my problems is that the compiler doesn't understand that the functions called from my isr are indeed connected to the isr.
:=I have, as I mentioned in an earlier post used #inline, #separate and #org statements extensively in order to get the program to work with my bootloader. I think this is the cause of the problems. Below is a snippet from my .sym file which illustrates what I mean:
:=
:=0CD main2.ch_no - called from main
:=0CD @DIV88.@DIV88.P1
:=0CD @MUL88.@MUL88.P2
:=0CD main.@SCRATCH - used in main
:=0CD read_parameters.@SCRATCH - called from the isr!
:=0CD cmd_decode.@SCRATCH - called from the isr!
:=
:=If for example "ch_no" in main2 is used when a irq comes its content will be corrupted. Or am I missing something?
This is not a problem.
If you look at the .asm file (from the windows system, select 'view', 'C/ASM List', and then look through this for the interrupt handler code (where this is, depends on the chip, but on a 16F, it is at address 4), then look carefully at the code that follows, you will see something like:
0004: MOVWF 7F
0005: SWAPF 03,W
0006: CLRF 03
0007: MOVWF 21
0008: MOVF 0A,W
0009: MOVWF 20
000A: CLRF 0A
000B: MOVF 04,W
000C: MOVWF 22
000D: MOVF 77,W
000E: MOVWF 23
000F: MOVF 78,W
0010: MOVWF 24
0011: MOVF 79,W
0012: MOVWF 25
0013: MOVF 7A,W
0014: MOVWF 26
0015: MOVF 7B,W
0016: MOVWF 27
Now this does the 'normal' interrupt essentials (of saving WREG, STATUS, and the BSR, but then goes on to copy the registers at locations 77 to 7B, into storage at locations 23 to 27. On this particular code, the locations at 77 to 7B, are the 'scratch' locations (these will move according to the code). The inverse code at the end of the interrupt handler, restores these locations. Hence the main code, and the ISR, can use the same scratch locations without a problem. In your case, the 'scratch' locations are up round 0CD, so you should find these being saved into the memory area referred to in the symbol listing as '@INTERRUPT_AREA'.
Your interrupt routine (unless you are writing your own 'int_global' handler, is not a 'stand alone' routine. When an interrupt occurs, 'int_global' is called, which saves the registers, and tests which interrupt is involved. It then calls the actual interrupt handler, in this 'saved' enviroment, then clears the interrupt flag, and restores the registers before exiting. The time involved in this can be significant (dozens of machine cycles added to the interrupt handler), hence if you want the fastest speed, and know you are not going to use the scratch area, you can write your own interrupt handler, and get rid of this time delay.
However for you, this overhead, ensures that the scratch area is not corrupted by the interrupt code (unless something else overwrites the storage used for these values...).
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516858 |
|
|
Michael Thompson Guest
|
Re: Multiple use of the same RAM locations |
Posted: Mon Aug 11, 2003 12:44 pm |
|
|
If one uses the #int pragma to specify that the function following this pragma is an interrupt function, the compiler will assign the local variables and scratch registers as static variables since the CCS C compiler does not use a stack for local function variables as does standard C. If not using the CCS compiler's #int pragma, then defining the interrupt function's variables as "static" would keep the variable locations from being reused. However, scratch registers would still be a problem.
Regards,
Mike
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516892 |
|
|
|
|
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
|