![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Guest
|
#LOCATE usage |
Posted: Mon Dec 06, 2004 5:01 pm |
|
|
Hi,
In my previous post (weird behavuar) I asked about some weird errors like corrupted string output and restarting or not starting at all on my
pic 18f8720. Some of the answers suggested to use a new chipset so we did a revision to A4 silicon.
Well, first it didn't start with several compilations so I tried a super simple compilation like this
main()
{ while(1) fprintf( DB9, "hi" ); }
That didn't work either until I removed this line:
#ZERO_RAM
Finally it started so I tried my normal version(88% rom). It started as well but again with weird errors like corrupted strings or no response with RS232. I have no clue what's wrong but the last big chance I did was using #locate for all global variables. Someone suggested to put all small variables in to memory bank0 and all large stuff(array's) in bank3 and higher so I did that. But no results. In fact, I have the feeling that #locate only makes it worse. On the A3 version, some compilations didn't work until I removed the #locate lines.
Maybe I'm using it wrong?
Code: |
float test1 #locate test1 0x20
int8 test2 #locate test2 0x24
|
If I understand well, #locate pins a variable on a fixed memory adress. If all those adresses were right, it would prevent variables writing at wrong adresses right? In that case, maybe I also have to #locate all local variables? But if that works I would also need to #locate all the variables in the standard libraries like STDLIB or STRING?
This problem is killing me. I guess there's a memory error but how could that prevent the device even from starting?
Compiler: 3.191
Optimizations: none
MPlab version 6.60
ROM : 88%
RAM : 71..80% (so there are lots of #locate's)
setup:
Code: |
#include <18f8720.h>
#device *=16
#fuses HS, NOPROTECT, BROWNOUT, BORV45, PUT, STVREN, NODEBUG, NOLVP, NOWRT, NOWRTD, WAIT, MCU, NOWDT
/* Timers, Cycles, clock etc. */
#ID CHECKSUM
#device ADC=10
#define CPU_CLK 9830400
#use DELAY(CLOCK=CPU_CLK, RESTART_WDT)
#define baudrateGPRS 57600
#define baudrateDB9 9600
#use rs232( baud=baudrateDB9, parity=N, xmit=PIN_G1, rcv=PIN_G2, ERRORS, RESTART_WDT, BRGH1OK, stream=DB9 )
#use rs232( baud=baudrateGPRS, parity=N, xmit=PIN_C6, rcv=PIN_C7, ERRORS, RESTART_WDT, BRGH1OK, stream=GPRS )
// Not sure about the restart_wdt above, I removed all watchdog stuff except these
#byte TIMER_1_LOW = 0xFCEBSA
#byte TIMER_1_HIGH = 0xFCF
#Build(reset=0x000)
|
Greetings |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Mon Dec 06, 2004 5:08 pm |
|
|
In addition:
I asked about locating local variables but that gives compiler errors, or I'm doing it wrong:
Code: |
void test()
{
char char1 = 0;
char char2 = 0;
#locate char1 = 0x111
#locate char2 = 0x112
...
|
Anyway, something else that might be completely wrong is the assigning
of all those global variables. Excuse if I'm wrong, I'm kinda new to these ccs functions and C. Just as in the code above, many global variables are getting an initial value. But the #locate instructions are executed later so maybe its value is lost? I think #locate is a pre-compiler instruction so it doesn't matter but I'm just checking for sure...
Greetings |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Dec 06, 2004 5:54 pm |
|
|
I wouldn't use the #locate. If you screw up and locate one variable at an address that is used by another, you will drive yourself bats. This would be especially true with arrays, and even more so if you think you will ever change the size! |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Mon Dec 06, 2004 5:59 pm |
|
|
Well, if the memory management was 100% correct I wouldn't bother myself with this stuff either. But someone told their was something wrong with the memory management gave some tips I followed. Maybe it's not nescesary to use this indeed, I don't know. I'm trying all kind of stuff to fix these weird bugs. Luckily I don't use malloc or dynamic memory so it makes it a little bit more easy.
Greetings |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Dec 06, 2004 6:04 pm |
|
|
#locate is a kind of pre-processor command, when CCS would have been a proper compiler it would have had a linker/locater and you would have placed a locate commands in the linker/locater definition file.
The #locate command will not work on local variables, so that explains your compiler errors.
The reason why you were told to place the larger variables is because of the bank switching architecture of the PIC processor. The PIC processors can access the variables in bank0 more easily than in the other banks. The CCS compiler does a great job in inserting and optimizing all the bank switch commands but, just sometimes, it makes an error.... #locating your large buffers at the end of memory will create more memory in bank0 and so minimizing the number of bank-switch commands. With less bank-switching commands the chance of this type of errors becomes smaller. It is also a good way of optimizing your code.
Remember, there is only a small chance this is the kind of error that is causing your problems. Especially your mentioning of the processor restarting is very strange, this can only be caused by a watchdog trigger or an instable power supply.
Use #locate sparsely. Manually locating variables is a lot of work and can cause other errors as well (overlapping variables......)
I would suggest to focus at the restarting processor first as this is such a rare type of error but pointing to a low level kind of error. If your base isn't right everything build upon it will collapse. Do a test with disabled watchdog and hook an oscilloscope to the power pins of the processor to check for voltage dips. Implement a way to log a message on power up showing the reason for starting up, see the function restart_cause(). This might give an answer as to why the processor is restarting. If your processor has a #BOR fuse (Brown Out Reset) then activate this one for detecting power supply dips.
Edit: I just see you already have the watchdog disabled and the brownout fuse enabled. |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Dec 06, 2004 6:21 pm |
|
|
The trick in finding errors is always to remove as much as code as possible until you end up with a small program that still generates the same error. You continue this process of removing code until you have one function or even one line of code that is causing your troubles.
Problem in your situation is that the error is not occuring at the same location everytime. Those are the hardest to find errors.
Above you described a small test program that failed, you fixed it by removing the #zero_ram directive. Maybe you should return to this failing version, just because it is so small and failing it is the kind of testprogram you are looking for!
#zero_ram generates quiet a lot of code with loops I suspect. This failing is another pointer to an hardware problem.
What voltage is your circuit running? And, I mean, not the designed voltage but what you meassure at the processor pins?
What is the brand and type of crystal you are using?
What are the type and capacity of the capacitors next to the crystal? |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Mon Dec 06, 2004 6:56 pm |
|
|
Thank you very much for detailed help! Maybe a failing power supply could couse this errors? To be honest, I don't have much knowledge of hardware, just programming some new ideas in an existing device. I like to answer your questions about the crystal and stuff but therefore I must ask the hardware guys at my work for help. Hopefully I can answer this tommorow.
Anyway, the restart-error sound logical to me, although the pic gets some backup power so if you pull out the power, it still remains active for a few seconds. The LCD screen doesn't flicker either and with the new A4 silicon thingy, I haven't noticed restarts, except that the system didn't start at all. I'd say the behavuar really depends on the compilation on the pic. Errors such as hang-ups didn't happen randomly at the initial fase. But the weird thing is that the code is correct and changing or adding something stupids like fprintf(..) often 'solves' the problem (or moves the problem elsewhere). What kind of hardware/power supply errors could cause that?
You're right about the small version, its perfect for testing purposes. It found out that #ZERO_RAM isn't the main cause. But maybe its the combination with the use of #LOCATE:
#LOCATE's #ZERO_RAM Result
disabled disabled it works
disabled enabled it works
enabled disabled it works
enabled enabled doesn't start
I'll try to give the information about the power supply tomorrow, now I need some sleep otherwise I'll turn insane with these bugs!
Greetings |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Dec 07, 2004 2:28 am |
|
|
Quote: | with the new A4 silicon thingy, I haven't noticed restarts, except that the system didn't start at all. |
This makes it less likely to be an hardware error. I would still add a printf for the restart_cause() result in your startup-code, but for now stop further investigating the hardware.
Quote: | But the weird thing is that the code is correct and changing or adding something stupids like fprintf(..) often 'solves' the problem (or moves the problem elsewhere). What kind of hardware/power supply errors could cause that? |
This is typical behaviour for RAM data corruption, a very common and hard to find problem. Somehow your program is writing and/or reading from RAM locations that are already in use for other variables and so corrupting data. Changes to your program will move the variables around and result in different behaviour, sometimes better, sometimes worse.
Do you have a development tool like an In Circuit Debugger? Using this tool you can set breakpoints and figure out when the code goes bad.
The small version with the #locate's and #zero_ram that fails, is it small enough to post here?
Have you checked the buffer sizes in the symbol file (*.sym) already? |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Tue Dec 07, 2004 4:00 am |
|
|
Hi again,
First about the supply and stuff:
>but what you >meassure at the processor pins? What is the brand and type
5 voltage power supply and the processor pins shouldn't be higher than that.
>of crystal you are using? What are the type and capacity of the
>capacitors next to the crystal?
10 MHz crystal and 15pf load capacity
And we don't have a Circuit Debugger.
I was thinking about data corruption as well, especially with the corrupted string occasions. But its weird as well that corrupted versions can give wrong output right at the start. At that point no pointer errors or array filling shouldn't have happened yet. And also printf with constant string parameters are messed up. Sometimes completely, and in other cases there's an extra character added. For example:
Code: |
fprintf( DB9, "I'm stupid" );
output -> "I'm sttupi<d"
|
I will make a small version that's suitable for the forum.
Thanks again for helping! |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Dec 07, 2004 5:13 am |
|
|
Quote: | we don't have a Circuit Debugger. |
In my opinion every professional organization can't do without.
A Microchip ICD2 In Circuit Debugger order number DV164005 costs about US$150 (you don't need the other more expensive sets with serial cable and/or power supply).
Just consider how much money your company invests in you, even if they would pay you nothing the overhead costs are at least $25/hour. So if the ICD would save you one day it has already earned your company money. |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Dec 07, 2004 5:41 am |
|
|
Code: | #define CPU_CLK 9830400 | and
It doesn't explain your problems, but here is a discrepancy...
Code: | fprintf( DB9, "I'm stupid" );
output -> "I'm sttupi<d" |
This kind of errors is even more weird. You are using the hardware UART which is known to be working correctly. So I expect the problem is in sending the data to the UART.
Are there any interrupt routines in your program? I'm especially concerned about interrupt routines that don't save and restore all registers. Do you have High Priority interrupts (CCS keyword '#int_<something> FAST')? |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Tue Dec 07, 2004 5:51 am |
|
|
>In my opinion every professional organization can't do without.
Maybe we have one at the office... I should ask about it. Mostly I'm programming this thing at home.
And yes, their is 1 timer used, gives an interrupt every second. I was concerned about that as well and if I remember right, the compiler gives a warning about that. I don't have the code here right now (I'm hanging around at school) but I'm pretty sure that #INT...fast is used 1 or 2 times. It's worth checking the system without the timer, although we need it in the end. Could it be that there's too much code inside the interrupt event? If the timer is causing havoc, we need a work around somehow. Thanks for noticing that. As I said, I will fix a small version for posting here tonight.
Bedankt! (I see you're from the Netherlands, me too) |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Dec 07, 2004 7:38 am |
|
|
Hoi
For normal interrupts the CCS compiler will save and restore all registers. The CCS compiler has poor support for the Fast interrupts; you yourself will have to take care of saving and restoring all registers that are modified in your interrupt.
I suggest you check the generated list file for the Fast interrupt. Look at all the modified registers and make sure they are saved on entry and restored on exit of the interrupt routine. Also be aware that the CCS compiler uses the memory addresses in the range 0 to about 5 as scratch registers; you will have to save and restore any of these modified registers as well (my guess is that this is where your problem is.....) |
|
![](templates/subSilver/images/spacer.gif) |
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Dec 07, 2004 6:33 pm |
|
|
First ask yourself do you really need the fast interrupts. Maybe stick them as normal for testing. BTW, how are you programming this thing. It must be incircuit but with what? About those RS232 errors, the compiler uses the clock define to figure out what to set the baud rate divisor so listing it incorrectly could cause a problem. |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Tue Dec 07, 2004 7:27 pm |
|
|
Hi,
I was wrong about the fast interrupts. We don't use them. But maybe its better to take a look at the code:
Code: |
/* Test version */
#include <18f8720.h>
#device *=16
/* Setup */
#fuses HS,NOPROTECT, BROWNOUT, BORV45, PUT, STVREN, NODEBUG,NOLVP, NOWRT, NOWRTD, WAIT, MCU, NOWDT
#ID CHECKSUM
#ZERO_RAM
#device ADC=10
#define CPU_CLK 9830400
#use DELAY(CLOCK=CPU_CLK, RESTART_WDT)
/* RS232 */
#define baudrateGPRS 57600
#define baudrateDB9 9600
#use rs232( baud=baudrateDB9, parity=N, xmit=PIN_G1, rcv=PIN_G2, ERRORS, /*RESTART_WDT,*/ BRGH1OK, stream=DB9 )
#use rs232( baud=baudrateGPRS, parity=N, xmit=PIN_C6, rcv=PIN_C7, ERRORS, /*RESTART_WDT,*/ BRGH1OK, stream=GPRS )
#byte TIMER_1_LOW = 0xFCE
#byte TIMER_1_HIGH = 0xFCF
#Build(reset=0x000)
/* Basic imports */
#include <stdlib.h>
#include <input.c>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
/* Some variables */
char BUF_Var[7] = "";
char BUF_Var2[7] = "";
char BUF_Var3[7] = "";
char BUF_Value[45] = "";
char BUF_Float[15] = "";
char BUF_SR[40] = "";
char BUF_SResult[255]= "";
byte cmd0[4];
byte cmd1[3];
unsigned int8 Trig_Allarm_Count[5];
BYTE Trigger_Active[5];
BYTE CHECK_SENSOR[6];
unsigned int8 allowAdress[9];
byte Array_Xmodem_Packet[134];
/* Memory locations */
/* Bank 3*/
#LOCATE cmd1 = 0x300 // byte 3 array
#LOCATE cmd0 = 0x303 // byte 4 array
#LOCATE Trig_Allarm_Count = 0x307 // byte 5 array
#LOCATE Trigger_Active = 0x30C // byte 5 array
#LOCATE CHECK_SENSOR = 0x311 // byte 6 array
#LOCATE Buf_Var = 0x318 // char 7 array
#LOCATE Buf_Var2 = 0x31F // char 7 array
#LOCATE Buf_Var3 = 0x326 // char 7 array
#LOCATE Current_Port = 0x32D // char 7 array
#LOCATE socket_seconds = 0x334 // byte 10 array
/* Bank 5*/
#LOCATE Array_Xmodem_Packet = 0x500 // byte 134 array
#LOCATE Buf_Float = 0x587 // float 15
#locate allowAdres = 0x5C3 // byte 9 array
#LOCATE Buf_Value = 0x5CC // char 45
/* Bank 6*/
#LOCATE BUF_SResult = 0x600 // char 255
#byte RCREG2 = 0xF6E
/* Rx 2 interrupt handler */
#int_rda2
void serial_isr_DB9()
{
// Empty
} // serial_isr_DB9
/* Timer 0 interrupt */
#int_rtcc
clock_isr()
{
// Empty as well
} // Timer
void main(void)
{
while(1)
fprintf( DB9, "What a nice program\r\n" );
}
|
The problem with this version was that it just didn't start. Although I'm not 100% sure if this version raises an error as well, I removed all kinds of global variables and structs, otherwise it would get too big for posting.
Ow, and you might see the code isn't case sensitive. I don't know if it matters for the compiler but today I used #case and made all the code case sensitive suitable.
Greetings |
|
![](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
|