We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I get the error CONF_TNY.A51(1): error A43: RESPECIFIED PRIMARY CONTROL for the 1st line the file which is $DEBUGPUBLICS TIA Andy
The LX51 Misc tab in uVision has a "Disable Warning Numbers" widget. It corresponds to the DISABLEWARNING directive. Of course, turning off the warning will also eliminate all the desirable occurrences of the warning (if any). A better, but more time-consuming, answer is to use the OVERLAY directive to correct the call tree so that the linker understands that these routines are not not actually potentially called from different contexts. If you're doing co-op scheduling, then your program is really one big tree from the top level scheduler. Getting the overlays right will also reduce memory use for variables on the stack. Unfortunately, this is pretty much a manual process of examining the map file for the call tree and moving procedure calls. On the bright side, you should just have to move your top-level task body functions to the right place, and there shouldn't be too many of those.
Thanks. That's what I thought I needed to do too. TIA Andy
How exactly does one go about correcting the call tree? I looked at the call tree and all the tasks that are created are mapped at the root of the call tree. TIA Andy
Every new root of a call tree gives you a new context from which some routine might be called. Let's say you have two tasks, t1 and t2, both of which call a routine "common()". If t1 and t2 are their own roots of a call tree, then as far as the linker knows, there's the possibility that you can call common() twice at the same time. In this case, though, you know you're doing co-op scheduling. t1() and t2() aren't really roots of a call tree; they're handler routines called by some higher level scheduler. Since the scheduler is only going to call either t1 or t2 and let that call run to completion, you don't really have two separate contexts. Instead of:
t1 +--- common t2 +--- common scheduler
scheduler +-- t1 +--- common +-- t2 +--- common
Unfortuntately all my tasks never exits and each task does call a set of shared functions (although never at the same time). What is the proper way to implement tasks if say a task needs to be blocked at the middle of its excution to allow other tasks to run, but all tasks share a set of functions? (maybe that's a bad practice anyway..) I'm thinking if I can somehow fix the call tree so that it looks like this Init --> Task1CallTree --> Task2CallTree ... etc.. Then it might work? Sorta like call by stack? Is there a way to fix the tree that way? Andy
There is no proper way of doing that, at the heart of it. For the context of C51, what you're trying to do is, indeed, rather bad practice. You'ld have to make all "shared" functions reentrant, but that could cause such a large performance hit that it may blow up your whole project. I suggest you try hard to find another way of doing that.
If your tasks need to yield the processor in the middle of their execution -- that is, when you're some way down the stack, rather than at the top level of the task -- then you will need independent stacks for each task. The fact that you don't actually preempt might save you from having to store registers in your task context, but you still need to preserve the state of execution represented by the task stack. You'll still want each task to be the root of its own call tree. Assuming we're trying to avoid making the routines re-entrant, we're down to some ugly choices. You could say "programmer knows best", and just ignore the warning since you know the functions in question can't be called reentrantly. Unfortunately, I don't think you can suppress the warning on a function-by-function basis. If the functions are small, and naturally reentrant (that is, they require no auto variables or temporaries outside of registers, and all the parameters fit into registers for the call), then declaring them reentrant costs you nothing. You could also do the surgery on the call tree in reverse. That is, pull the function calls out of their proper place and assign them to one top level call (main, or C_INITSEG). They're not really called from there, but this will cause the compiler to generate only one set of addresses for locals and parameters. This bit of hackery will of course be completely mysterious six months down the road when you change the code and it starts acting flaky. Another way to achieve the same goal would be to re-architect the program so that the shared functions are their own tasks, little servers that do a job at the request of other tasks. Depending on your existing architecture, this might be a lot of work, and probably only worthwhile for major functions, but at least would have the benefit of making it explicit in the code that these functions cannot be called reentrantly, both the to the compiler and the programmer.
They're ugly choices indeed. I think I'll just have to think of a way to not block my tasks in the middle of excution by maybe introducing some kind of busy states into the tasks.