Atlantis wrote:
Yesterday I finally found out that it was and issue related to the stack overflow. I've able to work it around by reducing size of some buffers and making some other buffers and variables local. Now device ceased to reset itself, but there still are some bugs (for example quite rare false detection of button being pushed) which may or my not be caused by the same issue.
I'm glad to hear you located the issue. A stack overflow makes sense for global variables being overwritten. Many compilers place the stack right after the global variables and so this isn't as uncommon an issue as one might like.
Atlantis wrote:
I am kind of bothered by the fact that there was thank kind of a problem in a first place. Device has 8kB SRAM chip, which is a lot for such system.
You determined the stack size in your lib/ethergeiger.cfg file when you said:
Code:
__STACKSIZE__: value = $0200, type = weak;
The compiler likely looked at where your last global variable was placed, added the $200 you requested for the stack and started the stack there. Because the stack grows down towards lower addresses, once it got too full it started to overwrite the global variables. Unfortunately there isn't really any collision detection built in, so it's something you will need to watch for. Global variables that mysteriously change are indeed one of the symptoms. BigEd's suggestion of having your ISR keep tabs on it is not unreasonable. If you were able to simulate your program (difficult because of how much hardware is involved) you can put a breakpoint on a write to the last (lowest) byte in the stack so you know if it ever grows that large.
Atlantis wrote:
Is there any way to generate summarized information about RAM usage in cc65 compiled project. AVR-GCC provides such information regarding to flash (program size) and RAM (sum total size of all global variables). Can I get something similar here? Is there a way to diagnose and fix this problem?
Kind of. One issue is the way you are compiling your program. Your Makefile is compiling your .c files into .s files, then you are using the assembler to assemble your .s files into .o files, and then finally you link all of them together. The issue with this method of assembling your executables is that you are losing symbol information along the way. You can get some of the symbols by adding the -g command line option to ca65 when assembling, but I wasn't able to get them to flow all the way to the map or listing file. Your better option might be to use cl65 which knows how to compile and (optionally) link files and can turn a .c file directly into a .o file (including the variables). I modified your Makefile like so (only main.c shown):
Code:
main.o: main.c
cl65 --cpu 65c02 -g -c main.c
The -c option tells cl65 to compile but not link (so it will make a .o file) and the -g tells it to include extra debugging information (including the variable names). I also added "-Ln main.lst" to your a.out target's command line to create a list file. This is the file where the value (address) for a given symbol (variable or function name) will appear. Looking for your key variables, I find:
Code:
grep key *.lst
al 00880F ._key_init
al 008856 ._key_update
al 0092AC ._key3_func
al 009290 ._key2_func
al 009274 ._key1_func
al 009258 ._key0_func
al 0004FC ._key3
al 0004F7 ._key2
al 0004F2 ._key1
al 0004ED ._key0
and so I would be looking for writes to $04ED through $0500 (your key_t structures are 5 bytes big and this only shows the starting address). Unfortunately, it's really up to the application engineer to make sure the stack size is reasonable for the application, and I suspect there are a good number of devices that occasionally trash some of their variables due to a stack overflow that occurs on rare conditions and wasn't caught during development. Interrupts that happen during your ISR (it looks like your original ISR might be re-enabling interrupts before it finishes) are a very quick way to eat through a stack of any size, as 8BIT noted. Hopefully your rewritten ISR fixes that.