I am following up on my own post because several people who were kind enough to answer me asked about the problems we had with the ARM ADS
1.1 tools.
I haven't been working much on the ARM code in the product, I've been coding for a DSP on another board, but I do remember at least four specific problems, and I can describe three of them.
- We have a large application and as more of the features were added and the number of source files grew, we ran into a linker problem. At somewhere around (but not exactly) 256 files, somehow the linker garbled one file name and threw out an error about being unable to find the object file.
We fixed that one after I posted to these two groups and somebody suggested linking each set of related files into a library, and having a final link step that linked all the libraries. Since out multi-tasking system is composed of about 35 individual tasks, each in its own directory, we took that advice and it worked.
- We had a real nasty problem with pointers to members of structures. Our architecture, originally developed on a 32-bit x86 processor for a different RTOS, used message queues for inter task communication. I'll show some simplifier code...
Each task defines a message enum:
enum TASK_TYPE { TIMER_MSG, DATA_UPDATE_MSG /* etc. };
...then a structure for the data of each message type:
struct timer_data { uint32_t token; uint32_t time; }; struct update_data { int32_t x_pos; int32_t y_pos; }; /* etc. */
...and finally its overall message structure:
struct my_msg { enum TASK_TYPE msg_type; union { struct timer_data t_data; struct update_data u_data; }; };
A task blocks on a call to retrieve a pointer to a message structure from its queue. When it has a message and it is the highest priority task ready to run, that call returns, and it dispatches the message to the proper handler function:
for ( ; ; ) { struct my_msg *msg = rtos_get_message(queue_id); switch (my_msg->msg_type) { case TIMER_MSG: my_timer_handler(&my_msg->msg_data.t_data); break; case DATA_UPDATE_MSG: my_update_handler(&my_msg->msg_data.u_data); } }
In other words, the handler function is called with a pointer to data structure member of the union inside the message structure.
The ADS 1.1 compiler GOT THE ADDRESS WRONG. It was off by 4 or 8, I forget which. We walked through the code at the assembly level with the debugger. When it came to taking the address of a member of a structure from a pointer to the structure, IT JUST PLAIN ADDED THE WRONG OFFSET.
We did try ADS 1.2 on this one, and it had the same problem.
- We only bumped into this one a few weeks ago:
enum ( FALSE, TRUE } bool_t;
void some_func(void) { bool_t some_name = FALSE;
if (/* some condition */ && /* some other condition */) { some_name = TRUE; }
/* code */
if (bool_t) { /* code */ } }
If I remember correctly, the initialization of some_name to FALSE (0), did not happen. Unless the condition was true, setting it to TRUE (1), it remain uninitialized and had random garbage in it.
So we had to change all code like that to this:
if (/* some condition */ && /* some other condition */) { some_name = TRUE; } else { some_name = FALSE; }
We did not try ADS 1.2 on problems number 1 and 3, but it did not fix number 2. At that point we had lost enough time to be seriously behind schedule and decided we could live with the problems we knew and had workarounds for. We didn't have time to try out other tools and make a change without blowing the release data.
Now that version 1.0 went out the door on time, and we've got a little breathing space, we want to evaluate other tool sets.