Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use type abstraction in embedded systems

Tags:

I've worked on a number of different embedded systems. They have all used typedefs (or #defines) for types such as UINT32.

This is a good technique as it drives home the size of the type to the programmer and makes you more conscious of chances for overflow etc.

But on some systems you know that the compiler and processor won't change for the life of the project.

So what should influence your decision to create and enforce project-specific types?

EDIT I think I managed to lose the gist of my question, and maybe it's really two.

With embedded programming you may need types of specific size for interfaces and also to cope with restricted resources such as RAM. This can't be avoided, but you can choose to use the basic types from the compiler.

For everything else the types have less importance.
You need to be careful not to cause overflow and may need to watch out for register and stack usage. Which may lead you to UINT16, UCHAR. Using types such as UCHAR can add compiler 'fluff' however. Because registers are typically larger, some compilers may add code to force the result into the type.

i++;
can become
ADD REG,1
AND REG, 0xFF
which is unecessary.

So I think my question should have been :-

given the constraints of embedded software what is the best policy to set for a project which will have many people working on it - not all of whom will be of the same level of experience.

like image 658
itj Avatar asked Aug 10 '08 07:08

itj


People also ask

What is abstraction in embedded systems?

10 Hardware Abstraction Layers for Embedded Systems. Embedded system development is about programming at the hardware level. But hardware abstraction layers (HALs) are a way to provide an interface between hardware and software so applications can be device independent. This is becoming more common in embedded systems.

What are the major levels of abstraction in embedded system?

In hardware design, we are familiar with several levels of abstraction: polygon, transistor, gate, and register-transfer (RTL).

What is Hal in embedded systems?

A HAL is a hardware abstraction layer that defines a set of routines, protocols and tools for interacting with the hardware. A HAL is focused on creating abstract, high level functions that can be used to make the hardware do something without having to have a detailed knowledge of how the hardware is doing it.

Which one of these provides an abstraction layer between embedded hardware and application software?

A hardware abstraction layer (HAL) is a logical division of code that serves as an abstraction layer between a computer's physical hardware and its software. It provides a device driver interface allowing a program to communicate with the hardware.


2 Answers

I use type abstraction very rarely. Here are my arguments, sorted in increasing order of subjectivity:

  1. Local variables are different from struct members and arrays in the sense that you want them to fit in a register. On a 32b/64b target, a local int16_t can make code slower compared to a local int since the compiler will have to add operations to /force/ overflow according to the semantics of int16_t. While C99 defines an intfast_t typedef, AFAIK a plain int will fit in a register just as well, and it sure is a shorter name.

  2. Organizations which like these typedefs almost invariably end up with several of them (INT32, int32_t, INT32_T, ad infinitum). Organizations using built-in types are thus better off, in a way, having just one set of names. I wish people used the typedefs from stdint.h or windows.h or anything existing; and when a target doesn't have that .h file, how hard is it to add one?

  3. The typedefs can theoretically aid portability, but I, for one, never gained a thing from them. Is there a useful system you can port from a 32b target to a 16b one? Is there a 16b system that isn't trivial to port to a 32b target? Moreover, if most vars are ints, you'll actually gain something from the 32 bits on the new target, but if they are int16_t, you won't. And the places which are hard to port tend to require manual inspection anyway; before you try a port, you don't know where they are. Now, if someone thinks it's so easy to port things if you have typedefs all over the place - when time comes to port, which happens to few systems, write a script converting all names in the code base. This should work according to the "no manual inspection required" logic, and it postpones the effort to the point in time where it actually gives benefit.

  4. Now if portability may be a theoretical benefit of the typedefs, readability sure goes down the drain. Just look at stdint.h: {int,uint}{max,fast,least}{8,16,32,64}_t. Lots of types. A program has lots of variables; is it really that easy to understand which need to be int_fast16_t and which need to be uint_least32_t? How many times are we silently converting between them, making them entirely pointless? (I particularly like BOOL/Bool/eBool/boolean/bool/int conversions. Every program written by an orderly organization mandating typedefs is littered with that).

  5. Of course in C++ we could make the type system more strict, by wrapping numbers in template class instantiations with overloaded operators and stuff. This means that you'll now get error messages of the form "class Number<int,Least,32> has no operator+ overload for argument of type class Number<unsigned long long,Fast,64>, candidates are..." I don't call this "readability", either. Your chances of implementing these wrapper classes correctly are microscopic, and most of the time you'll wait for the innumerable template instantiations to compile.

like image 98
Yossi Kreinin Avatar answered Sep 21 '22 05:09

Yossi Kreinin


The C99 standard has a number of standard sized-integer types. If you can use a compiler that supports C99 (gcc does), you'll find these in <stdint.h> and you can just use them in your projects.

Also, it can be especially important in embedded projects to use types as a sort of "safety net" for things like unit conversions. If you can use C++, I understand that there are some "unit" libraries out there that let you work in physical units that are defined by the C++ type system (via templates) that are compiled as operations on the underlying scalar types. For example, these libraries won't let you add a distance_t to a mass_t because the units don't line up; you'll actually get a compiler error.

Even if you can't work in C++ or another language that lets you write code that way, you can at least use the C type system to help you catch errors like that by eye. (That was actually the original intent of Simonyi's Hungarian notation.) Just because the compiler won't yell at you for adding a meter_t to a gram_t doesn't mean you shouldn't use types like that. Code reviews will be much more productive at discovering unit errors then.

like image 39
Chris Hanson Avatar answered Sep 20 '22 05:09

Chris Hanson