I have a project that works until I add in some C modules that I inherited from someone else. The startup code (sam7.s) is the default startup code supplied by KEIL for the ATMEL AT91SAM7S256 (for MDK ARM V3.22a). The problem is that when the startup code gets to the point where it's supposed to branch to the C main function, it works okay until I add in these inherited C modules. Stepping through the startup code, the only difference I can find is that the top of the stack is in a different place for the two versions of the program. For the working version it's at 0x00201F20, and the non-working version it's at 0x002022C0. For the non-working version of code, when I get to the BX ASM statement shown below, rather than going to 'main', I end up in the default SWI handler.
; Enter the C code IMPORT __main LDR R0, =__main BX R0
The __main label in the MAP file is the same value for both versions of the code, and is at 0x0010014C.
Can anyone give me some hints as to what might be causing this problem, or how to debug it...?
Thanks!
P.S., I did find some references in the online knowledgebase to reserving space for the heap should this problem occur, and have reserved 0x8000 bytes for the heap, but that has had no effect on the symptom. Since this is a 'C'/ASM project (i.e., no C++ code), and no 'C' code could've been run yet (since the program hasn't made it to 'main' yet), I'm not sure how not reserving space for the heap could've caused this symptom either. Can anyone explain how not reserving space for the heap could cause this problem?
I would make sure you have include retarget.c in your project (look at examples if you have not). It is possible that the stdio system was initialized after including the other code and it was not initialized in your code.
You only reserve memory for a heap if you do dynamic memory allocations from said heap.
Thanks for the tip Robert.
I was not including a retarget.c file in my project, so I did a quick file search of my C:\KEIL\ARM directory and found quite a few to pick from. I looked at several for an ATMEL AT91SAM uC, and added the simplest one to my project to see what would happen. Here's what was in that file:
#include <rt_misc.h> #pragma import(__use_no_semihosting_swi) void _sys_exit(int return_code) { label: goto label; /* endless loop */ }
Now my project won't build (without errors) anymore. Apparently, the _sys_open and _ttywrch functions are being used somehow, although I can find no reference to them in any of my project files. I don't call printf, puts, scanf, or anything like that (aren't those the type of things that would fall under the "semihosting" category?); so I don't know why or where _sys_open or _ttywrch would be being called.
Besides... the right address for __main is in R0 when the BX R0 instruction is executed, so how could the uC not then branch to that address...? That code happens before any C code is executed. This problem (as best as I can tell) occurs whether I'm executing code from the debugger or not.
I'm stumped!
The code I inherited does do dynamic memory allocation (associated with file transfers across an EtherCAT network). I plan to eventually rewrite it so it doesn't. But for now... it does.
The __main is NOT your main. This does all the C initialization. I still suspect that you are having a retarget.c problem
You will need to add something like...
void _ttywrch (int ch) { return; } FILEHANDLE _sys_open (const char *name, int openmode) { return 0; }
to retarget.c
Thanks so much Robert!
Adding the right include file (rt_sys.h) to get the definition of FILEHANDLE before including the functions you provided has fixed the problem. I can finally get to the main function and continue with regular development/debugging.
Of course... now I've got to spend a little time analyzing this problem and your solution to get a better handle on what went wrong in the first place. The obvious place to start is the __main function (that I incorrectly thought was the C main function). My guess is that C startup stuff is in a KEIL library (hence, the IMPORT __main statement). If so, where's that source code? Is it published?
If you are not using a file IO in your application, you should consider using a microlib. The microlib does not support semihosting and therefore you do not need a retarget.c. The builded executable image is smaller and with some limitations, but more suitable for small embedded projects.
The standard runtime library is build for the underlying Operating System. All the system calls are coded as SWI's. For example a simple putchar function executes a SWI and activates a low level putchar function from the operating system. If you do not have one, you have to redirect the low level to your own implementation of these functions (in regarget.c). In this case you have to tell the linker not to use the semihosting interface with:
#pragma import(__use_no_semihosting_swi)
Franc
View all questions in Keil forum