EmbeddedRelated.com
Forums

Developing/compiling software

Started by Lodewicus Maas September 16, 2009
ChrisQ wrote:
> Mel wrote: >> ChrisQ wrote: >> >>> Stuff like that may be hidden by the compiler, much as one might stick a >>> bandaid on a sore to hide it, but the inefficiency is still there. >> >> That's not really the C programming attitude. I don't care what steps >> to the left or right the program takes while getting where I want it >> to go. If it meets specs and performance targets, then it's a >> product, and that's why we're there. > > Partly agree with that but having no idea what the complier is doing > hardly sounds like due diligence to me. With Keil and 8051, I don't > expect code efficiency and rarely if ever look at the asm output. That > is, I have confidence in the tools. But as a hardware and software bod, > have to decide on hardware / software tradeoffs for new projects. Cpu > architecture and features are pretty important at that level, though > modern micros often have far more grunt than is needed for the application. > > As a programmer, I want a broad canvas, big linear address space with no > gotchas or speed limits, but engineering isn't like that. It helps to > know what's going on under the hood.
For small systems, I fully agree - it's good to be able to write neat, portable C code, but you should understand what your compiler is doing and how your target works. That's how you get the best from the combination of tools and targets. For larger systems, the details get less important (though not irrelevant - for example, you would want to know how well the target supports floating point before using floats and doubles). And for really "big" systems (such as a PC), just code in Python and forget the low-level details.
> Besides, cpu architecture is interesting. Well, to some anyway... >
Absolutely.
ChrisQ wrote:
> David Brown wrote: > >> >> Personally, I think the general idea of "all global data is evil" is >> silly, especially for embedded development. But if you've got a >> programming method that helps you write better code, then that's far >> more important than what other people think! > > > Having had to wade through impenetrable code too many times in the past, > where it's hard to tell what's poking what and when, I try not to > inflict the same on others. One of the ways to do this is to encapsulate > functionality, keep data local as possible and communicate through well > defined inband interfaces. The typical embedded design can be split into > subsystems - for example, uarts / comms, timers, ports etc. There's no > reason why the internal data relating to a subsystem should be public, > even though it may need to be visible internally. Avoiding this makes > for a more reliable system design, it's easier to make changes, add > modules and to keep track of the big picture. Of course, none of this is > new, but it does seem to work... >
I agree 100% about encapsulation (at least, I agree about it as an ideal - sometimes you have to compromise in practice). What I take issue with is when people get obsessive about globals and think that it is somehow better to have functions called "SetUartTimeout" and "GetUartTimeout", doing nothing but accessing a static variable, instead of just using a globally visible variable "uartTimeout". The global must be part of the well-defined interface, not a backdoor into the module's interior, but there is absolutely no reason to pretend that having the global variable is somehow "riskier" or "unclear", or harder to use or change.

David Brown wrote:


> What I take issue with > is when people get obsessive about globals and think that it is somehow > better to have functions called "SetUartTimeout" and "GetUartTimeout",
Yes it is better. * Perhaps it could be necessary to add flushing the UART before changing timeouts. You just have to modify one function. * What if there is a need to have more then one uart? How about accessing N uarts? * What if there is a need to access the timeouts from more then one thread? * What if there is a name conflict due to the use of the global objects?
> doing nothing but accessing a static variable, instead of just using a > globally visible variable "uartTimeout".
I do require all access to such variables via member functions. I like an overloaded function UART.Timeout() instead of separate Set.. and Get.. functions.
> The global must be part of the well-defined interface,
Well defined interfaces exist only in the textbooks.
> not a backdoor into the module's interior, but > there is absolutely no reason to pretend that having the global variable > is somehow "riskier" or "unclear", or harder to use or change.
As the project grow large, is gets much harder to maintain the code which is controlled by the global variables. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
On Sep 28, 11:39 pm, Vladimir Vassilevsky <nos...@nowhere.com> wrote:
> David Brown wrote: > > What I take issue with > > is when people get obsessive about globals and think that it is somehow > > better to have functions called "SetUartTimeout" and "GetUartTimeout", > > Yes it is better. > > * Perhaps it could be necessary to add flushing the UART before changing > timeouts. You just have to modify one function. > > * What if there is a need to have more then one uart? How about > accessing N uarts? > > * What if there is a need to access the timeouts from more then one thread? > > * What if there is a name conflict due to the use of the global objects? > > > doing nothing but accessing a static variable, instead of just using a > > globally visible variable "uartTimeout". > > I do require all access to such variables via member functions. I like > an overloaded function UART.Timeout() instead of separate Set.. and > Get.. functions. > > > The global must be part of the well-defined interface, > > Well defined interfaces exist only in the textbooks. > > > not a backdoor into the module's interior, but > > there is absolutely no reason to pretend that having the global variable > > is somehow "riskier" or "unclear", or harder to use or change. > > As the project grow large, is gets much harder to maintain the code > which is controlled by the global variables. > > Vladimir Vassilevsky > DSP and Mixed Signal Design Consultanthttp://www.abvolt.com
On Sep 28, 11:39 pm, Vladimir Vassilevsky <nos...@nowhere.com> wrote:

> * Perhaps it could be necessary to add flushing the UART before changing > timeouts. You just have to modify one function. > > * What if there is a need to have more then one uart? How about > accessing N uarts? > > * What if there is a need to access the timeouts from more then one thread?
If a function results in simpler code, they should be used, of course. But if you know that you're not going to be using threads, there's only one UART on the device, and the UART doesn't need to be flushed, using a global may be appropriate. If the circumstances change, the code can always be modified. If you know the requirements are fixed, for instance the baud rate must be 9600, using 8N1, there is also no need to add functions to change these things.
> * What if there is a name conflict due to the use of the global objects?
Not likely if you start the name with 'uart' or something like that.
> As the project grow large, is gets much harder to maintain the code > which is controlled by the global variables.
Sure, but many projects never grow large.
On Mon, 28 Sep 2009 22:09:28 +0200, David Brown
<david.brown@hesbynett.removethisbit.no> wrote:

>ChrisQ wrote: >> David Brown wrote: >> >>> Personally, I think the general idea of "all global data is evil" is >>> silly, especially for embedded development. But if you've got a >>> programming method that helps you write better code, then that's far >>> more important than what other people think! >> >> Having had to wade through impenetrable code too many times in the past, >> where it's hard to tell what's poking what and when, I try not to >> inflict the same on others. One of the ways to do this is to encapsulate >> functionality, keep data local as possible and communicate through well >> defined inband interfaces. The typical embedded design can be split into >> subsystems - for example, uarts / comms, timers, ports etc. There's no >> reason why the internal data relating to a subsystem should be public, >> even though it may need to be visible internally. Avoiding this makes >> for a more reliable system design, it's easier to make changes, add >> modules and to keep track of the big picture. Of course, none of this is >> new, but it does seem to work... > >I agree 100% about encapsulation (at least, I agree about it as an ideal >- sometimes you have to compromise in practice). What I take issue with >is when people get obsessive about globals and think that it is somehow >better to have functions called "SetUartTimeout" and "GetUartTimeout", >doing nothing but accessing a static variable, instead of just using a >globally visible variable "uartTimeout". The global must be part of the >well-defined interface, not a backdoor into the module's interior, but >there is absolutely no reason to pretend that having the global variable >is somehow "riskier" or "unclear", or harder to use or change.
[First off, I want to make sure no one reading this is conflating the idea of 'global' with 'static'. A global definition (in c) is always a static definition. But not all static definitions are global.] There are few cases where a global static is better than a module- local static; where a function mediates access rather than allowing any part of the code in any other module to directly access the global static. The conceptual region where I imagine you may have a point is where there is a requirement for frequent access across a wide range of the total code space and the cost of a function call, both in code size and execution time, is too high to afford in the application. While that usually means the code factoring is wrongly arranged, it doesn't always mean that. And there are ways around this. In general, the code I can recall doing over the last few decades, even on smaller PICs, doesn't use global statics. Good factoring seems to almost always eliminate the need. An example where I've used global access to a static (for reading) is the current PID for the active, running process. In this case, access to reading the current process ID is so widely needed throughout other modules in an O/S and the memory and execution constraints may be so tight that it makes some sense. However, this can be carefully crafted together with the use of #define so that later changes could be reasonably performed without having to edit all the references. So you are right that one should be so afraid that they will not accept it for any use, at all. But be very, very wary of the idea. An example of how it can be done in c is something like this. The .h file for a module might include some code like this: #ifdef SOMECOMPILEOPTION extern unsigned int GetCurrentPID( void ); #else extern unsigned int currpid; #define GetCurrentPID( ) (currpid) #endif A function in the .c module can be provided (or selectively provided depending on a compile option) in the module written like this: #ifdef SOMECOMPILEOPTION static unsigned int currpid; unsigned int (GetCurrentPID)( void ) { return currpid; } #else unsigned int currpid; #endif (You can get trickier.) The reason for wrapping the function name in parentheses, if this isn't already obvious, is to avoid having the #define mess with the function definition. Now you can go either way by changing a compile option. Jon
Vladimir Vassilevsky <nospam@nowhere.com> writes:

> David Brown wrote: > > >> What I take issue with is when people get obsessive about globals >> and think that it is somehow better to have functions called >> "SetUartTimeout" and "GetUartTimeout", > > Yes it is better. > > * Perhaps it could be necessary to add flushing the UART before > changing timeouts. You just have to modify one function. > > * What if there is a need to have more then one uart? How about > accessing N uarts? > > * What if there is a need to access the timeouts from more then one thread? > > * What if there is a name conflict due to the use of the global objects? > >> doing nothing but accessing a static variable, instead of just using >> a globally visible variable "uartTimeout". > > I do require all access to such variables via member functions. I like > an overloaded function UART.Timeout() instead of separate Set.. and > Get.. functions.
How does that work, like: timeout = UART.Timeout(GET,UART1); ... UART.Timeout(SET,10000); ? I seem to end up with a lot of globals at what I would call the "application" level. By this I mean the code that describes what the machine does rather than its internal operation. So you end up with lots of code looking like: status_t status; /* global */ set_t set; /* global */ ... status.temperature = adc(0); status.pressure = adc(1); status.test_number++; if(set.test_time > SET_TEST_TIME_MAX) { status.flags |= STATUS_FLAG_ERROR_TEST_TIME; } ... Any part of the application can read and write settings, status variables etc. -- John Devereux
"John Devereux" <john@devereux.me.uk> wrote in message 
news:878wfyxlay.fsf@devereux.me.uk...
> Vladimir Vassilevsky <nospam@nowhere.com> writes: > >> David Brown wrote: >> >> >>> What I take issue with is when people get obsessive about globals >>> and think that it is somehow better to have functions called >>> "SetUartTimeout" and "GetUartTimeout", >> >> Yes it is better. >> >> * Perhaps it could be necessary to add flushing the UART before >> changing timeouts. You just have to modify one function. >> >> * What if there is a need to have more then one uart? How about >> accessing N uarts? >> >> * What if there is a need to access the timeouts from more then one >> thread? >> >> * What if there is a name conflict due to the use of the global objects? >> >>> doing nothing but accessing a static variable, instead of just using >>> a globally visible variable "uartTimeout". >> >> I do require all access to such variables via member functions. I like >> an overloaded function UART.Timeout() instead of separate Set.. and >> Get.. functions. > > How does that work, like: > > timeout = UART.Timeout(GET,UART1); > > ... > > UART.Timeout(SET,10000);
My assumption was he was meaning a more directly OO approach. // Declare two UART objects UART uart0( 0, 'n', 8, 1 ), uart2( 1, 'n', 8, 1 ); // Send to uart 0 uart0.send( "message to send" ); // Send to uart 1 uart1.send( "another message to send" ); -- Regards, Richard. + http://www.FreeRTOS.org Designed for Microcontrollers. More than 7000 downloads per month. + http://www.SafeRTOS.com Certified by T&#4294967295;V as meeting the requirements for safety related systems
Vladimir Vassilevsky wrote:
> > > David Brown wrote: > > >> What I take issue with is when people get obsessive about globals and >> think that it is somehow better to have functions called >> "SetUartTimeout" and "GetUartTimeout", > > Yes it is better. > > * Perhaps it could be necessary to add flushing the UART before changing > timeouts. You just have to modify one function. >
Then you've changed the API - your UartTimeout (variable or accessor functions) are not doing what they were doing before. It's okay to break existing code when you make significant changes to the API. Since you are now actually doing something when setting uartTimeout, you have to change the global variable to a function with a slightly different name. You need to grep through your source code that uses the uart, and modify that source code (or just attempt a rebuild - the compiler will tell you where the problems lie).
> * What if there is a need to have more then one uart? How about > accessing N uarts? >
Again, that's a big change in the functionality of the module, and requires a big change in the API.
> * What if there is a need to access the timeouts from more then one thread? >
If you need a module that supports multiple threads reading and/or writing the data, then you must take that into account. If that means that accesses must be wrapped in locks, then you don't have a simple read-write data item, and can't use a global. Global data is not appropriate for all uses. But when you have a clearly defined data item that can be safely read or written (according to whatever restrictions you have documented in the module interface), then wrapping the data in simple accessor functions is a waste of source code, a waste of object code, and a waste of runtime, and gives exactly zero benefits for modularisation, encapsulation, structure, clarity, code maintenance, or any other buzz words you like.
> * What if there is a name conflict due to the use of the global objects? >
Now you are getting silly. "uartTimeout" has no more or less a potential for name conflicts than "SetUartTimeout" and "GetUartTimeout". C works with a single global namespace - use appropriate naming conventions for your global objects (variables, functions or whatever). If your project is too big for that, try C++ and namespaces.
>> doing nothing but accessing a static variable, instead of just using a >> globally visible variable "uartTimeout". > > I do require all access to such variables via member functions. I like > an overloaded function UART.Timeout() instead of separate Set.. and > Get.. functions. > >> The global must be part of the well-defined interface, > > Well defined interfaces exist only in the textbooks. >
It's easy to give clear and safe interfaces for small modules.
>> not a backdoor into the module's interior, but there is absolutely no >> reason to pretend that having the global variable is somehow "riskier" >> or "unclear", or harder to use or change. > > As the project grow large, is gets much harder to maintain the code > which is controlled by the global variables. >
This is comp.arch.embedded - a great many of the projects here do not grow "large" because they are for small systems. The code is small enough that is not a big problem to keep track of modules and their interfaces, and that includes global variables. On the other hand, the waste of runtime and code space caused by unnecessary accessor functions /can/ be significant. For large projects, there are different balances - then there is much more reason to avoid global variables. But it is still a minor detail - finding a good way to specify your interfaces and keep your structure clean is more important. To take another example, suppose you have a module that collects samples from somewhere and puts it in an array dataSamples[]. Should that only be accessible through a function "int GetDataSample(int n)" ? That would make a summation function very slow. Should you have a "CopyDataSamples(int * dest, int n)" to let users have a local copy? Again, it's slow, and a waste of data space. Perhaps just "const int * AccessDataSamples(void)" to return a pointer to the data - it's fast, but loses the compile-time checking you get with simple clear access to the raw global data.
David Brown wrote:

> > I agree 100% about encapsulation (at least, I agree about it as an ideal > - sometimes you have to compromise in practice). What I take issue with > is when people get obsessive about globals and think that it is somehow > better to have functions called "SetUartTimeout" and "GetUartTimeout", > doing nothing but accessing a static variable,
<...> I guess you would take issue with a lot of my code then, because it uses a lot of that type of construct to hide internals and there are no globals other than const data at all in systems designed here. Within modules, all vars and const data is declared static, so it doesn't get exported to the linker. If you accept that all computing is just data movement and processing, the interfaces between modules become the defining nodes of system design. A typical example might be timer pool support which needs only a system interrupt tick timer call to function. The programming interface consists of a group of functions to do stuff like request, cancel, check, refresh timer etc and all you get back from or provide to the interface is a U8 timer handle or a status. There is also a callback facility on timeout, though this is only for short code sections as it runs in interrupt context. The whole point of it is that it's a proven library module that I never have to rewrite, can take it to any project, compile it and it just works. That's probably a simple and unfair example, as it's easy to fully encapsulate, but the same process is used for ports, where a more or less standard driver module abstracts the hardware into a port id and bit which are defined for the project in a project_defs file. If fast access is needed to a port, a special driver is written for that function alone and all hardware references are again abstracted out as far as possible. The similar process is used for comms, which is usually built as an upper and lower layer. Upper layer has the app call interface, lower layer interrupt handler. The two are connected by queues in both directions. At this level, a call interface structure contains all the data and references for a uart and it's queues and this structure is shared between the layers. In this way, the code becomes completely reentrant and one set of upper level code and queue functions is shared across all uarts. On some projects with 4 or more comms channels, this save a lot of code space even though it's larger than it would normally be for a single uart channel. Only the interrupt handlers are uart specific and this is because it's more efficient in terms of interrupt handler times. A lot of the ideas for this came from classic os design and while you might argue that it's inappropriate for small systems, it's surprising how usefull it is at any level. There's quite a bit more effort up front to start with, but the payback is not on this project but on the next one and so on. You find that there are fewer bugs and a lot of stuff works the first time because you think systems design, not programs. On subsequent projects, you find that a lot of the code is reusable without change and all you have to write is the application layer, or part of it. Over time, you build up functionality to the point where you hardly ever need to look at stuff like the standard c lib, (which has all the wrong types anyway) and you thus have complete visibility of all the code... Regards, Chris