12
\$\begingroup\$

I have done some basic object oriented programming with C++ (creating a B-Tree, Hashing Algorithms, Double Linked Lists) and I have done small project in C (like making a scientific calculator etc.)

How different is hardware programming (specifically for micro controllers) from software/object oriented programming in terms of the mindset and "thinking" that the programmer has to have?

Is one usually considered harder than the other my most people?

With my background (as described above) would I need a lot of preparation for going into hardware programming or can I dive straight in without too much preparation?

\$\endgroup\$
7
  • 4
    \$\begingroup\$ The biggest learning curve will be how to drive the specific hardware in your micro. That will involve poring over the data sheets for hours. Unfortunately, there's no easy way out. \$\endgroup\$
    – drxzcl
    Jul 19, 2011 at 23:24
  • \$\begingroup\$ @rrazd, I noticed that you've included the arduino tag. Is this because you want to use the arduino wiring language and libraries? Or will you be writing your embedded applications in pure C? If you intend to stick with the arduino environment, it's pretty safe and easy to play around in as they have done some abstractions away from the hardware. \$\endgroup\$
    – Jon L
    Jul 19, 2011 at 23:53
  • \$\begingroup\$ @Jon i plan to use an arduino board for starters. Isn't it similar to C language? I thought it involved the same basic concepts.... \$\endgroup\$
    – rrazd
    Jul 19, 2011 at 23:59
  • 1
    \$\begingroup\$ I'm wondering whether you mean what many people would call 'I/O programming', or if you anticipate re-arranging hardware with code. The arduino is decidedly the former; the latter would be the domain of FPGAs. \$\endgroup\$
    – JustJeff
    Jul 20, 2011 at 1:02
  • 1
    \$\begingroup\$ @rrazd - I changed the title; "hardware programming" sounds too much like HDL (Hardware Description Language), e.g. VHDL and Verilog, which are used to program FPGAs and CPLDs. \$\endgroup\$
    – stevenvh
    Jul 20, 2011 at 6:24

7 Answers 7

10
\$\begingroup\$

You will have to completely abandon the object-oriented paradigm when dealing with most microcontrollers.

Microcontrollers are generally register- and RAM-limited, with slow clock rates and no pipelining / parallel code paths. You can forget about Java on a PIC, for example.

You have to get into an assembly-language mindset, and write procedurally.

You have to keep your code relatively flat and avoid recursion, as RAM limitations can often lead to stack issues.

You have to learn how to write interrupt service routines which are efficient (usually in assembly language).

You may have to refactor parts of the code manually, in assembly language, to implement functionality that the compiler doesn't support (or supports poorly).

You have to write mathematical code that takes into account the word size and lack of FPU capabilities of most microcontrollers (i.e. doing 32-bit multiplication on an 8-bit micro = evil).

It is a different world. To me, having a computer science or professional programming background can be as much of a hindrance as having no knowledge at all when dealing with microcontrollers.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ You do not have to entirely abandon the object oriented paradigm, but on smaller micros it may be necessary to abandon heavyweight object implementations and really think about what the best way to solve each problem is. Often that is procedural, but lightweight objects, well implemented (usually by hand), can at times shrink the size of complicated microcontrollor projects. \$\endgroup\$ Aug 30, 2011 at 6:23
  • 6
    \$\begingroup\$ All of this is true except abandoning object-orientation. You will probably not use a language with OO features but that doesn't rule out object orientation. For microcontrollers you are going to write drivers for all hardware peripherals (ADCs, serial bus controllers, PWM, etc etc). Such a driver should always be written in an object-oriented manner so that it is 1) autonomous and doesn't know/care about the rest of the program, and 2) implementing private encapsulation so that the rest of the program can't go in and fiddle with it. This is 100% possible in C and will not affect performance. \$\endgroup\$
    – Lundin
    Oct 18, 2011 at 14:11
  • 1
    \$\begingroup\$ I strongly disagree with the first sentence, all of my microcontroller projects were built with C++ and an object oriented approach, and the micros we used were not very large (32kB of ROM), the also object oriented bootloader was in less than 2kB, I don't really see limitation. You can't do crazy stuff but the design can be object oriented no problem. \$\endgroup\$
    – Arsenal
    Aug 24, 2015 at 12:31
  • \$\begingroup\$ @Arsenal Note I said 'most', and note that you're commenting on a four-year-old thread. :) \$\endgroup\$ Aug 25, 2015 at 2:39
  • \$\begingroup\$ I completely disagree with the first and the last sentence. And also assembly is used quite rarely and, mostly, only for 8-bit MCUs (just check this forum, how many posts with assembly code you can find?). You certainly can and (IMHO) should write in OO style for 32bit MCUs \$\endgroup\$ Jul 23, 2016 at 21:59
10
\$\begingroup\$

You need to think about several things:

  • You will use C as the language
  • You can still create a feeling of object orientation using function pointers so that you can override functions etc. I have used this method in the past and current projects and works very well. So OO is partially there but not in C++ sense.

There are other limitations that will come in to play such as limited speed and memory. So as a general guideline, I avoid:

  • Using heap, if there is a way to solve the problem without Malloc, I do that. For example, I preallocate buffers and just use them.
  • I intentionally reduce the stack size in compiler settings to face with stack size issues early on, optimize that carefully.
  • I assume every single line of code will be interrupted by an event, so I avoid non reentrant code
  • I assume even interrupts are nested so I write that code accordingly
  • I avoid using OS unless it is necessary. 70% of the embedded projects doesn't really need an OS. If I must use an OS, I only use something with source code available. (Freertos etc)
  • if I am using an OS, I almost always abstract things so that I can change OS in a matter of hours.
  • For drivers etc. I will only use the libraries provided by the vendor, I never ever directly fiddle the bits, unless I have no other choice. This makes the code readable and improves debugging.
  • I look at the loops and other stuff, especially in ISR, to make sure they are fast enough.
  • I always keep a few GPIOs handy to measure stuff, context switching, ISR run time etc.

List goes on, I am probably below average in terms of software programming, I am sure there are better practices.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ +1 for the "you can use OO paradigms if you want". What you need to check at the door is not OO design. OOD is just a philosophy that encourages you to keep related code and data together. What you need to leave behind is the way OO is implemented in enterprise systems, with multiple layers of abstraction, inversion of control and all that jazz. Your firmware's task is to drive the hardware, that's it. \$\endgroup\$
    – drxzcl
    Jul 20, 2011 at 7:40
8
\$\begingroup\$

I do both, so here's my view.

I think the most important skill by far in embedded is your debugging ability. The required mindset is much different in that so much more can go wrong, and you must be very open to considering all the different ways what you are trying to do can go wrong.

This is the single biggest issue for new embedded developers. PC people tend to have it rougher, as they're used to so much just working for them. They'll tend to waste a lot of time searching for tools to do things for them instead (hint: there aren't many). There's a lot of banging heads into walls over and over, not knowing what else to do. If you feel you're getting stuck, step back and figure out if you can identify what all might be going wrong. Systematically go through narrowing your potential problems list until you figure it out. It follows directly from this process that you should limit the scope of problems by not changing too much at once.

Experienced embedded people tend to take debugging for granted... most of the people who can't do it well don't last long (or work in large companies that simply accept "firmware is hard" as an answer for why a certain feature is years late)

You're working on code that runs on an external system to your development system, with varying degrees of visibility into your target from platform to platform. If under your control, push for development aids to help increase this visibility into your target system. Use debug serial ports, bit banging debug output, the famous blinking light, etc. Certainly at a minimum learn how to use an oscilloscope and use pin I/O with the 'scope to see when certain functions enter/exit, ISRs fire, etc. I've watched people struggle for literally years longer than necessary simply because they never bothered to set up/learn how to use a proper JTAG debugger link.

It's much more important to be very aware of exactly what resources you have relative to a PC. Read the datasheets carefully. Consider the resource 'cost' of anything you are trying to do. Learn resource-oriented debugging tricks like filling stack space with a magic value to track stack usage.

While some degree of debugging skill is required for both PC and embedded software, it's much more important with embedded.

\$\endgroup\$
5
\$\begingroup\$

I'm presuming your C++ experience is PC-based.

An often made error by programmers moving from PC to microcontroller is that they don't realize how limited resources can be. On a PC nobody will stop you when you create a table with 100 000 entries, or write a program which compiles to 1MB of machine code.
There are microcontrollers which have a wealth of memory resources, especially in the high end, but it's still a far cry from what you'll be used to. For a hobby project you probably can always go for the maximum, but in a professional project you'll often be forced to work with the smaller device because it's cheaper.
On one project I was working with a TI MSP430F1101. 1KB of program memory, 128 bytes of configuration Flash, 128 bytes of RAM. The program didn't fit in the 1K, so I had to write a 23 bytes function in the configuration Flash. With these small controllers you calculate by the byte. On another occasion the program memory was 4 bytes too small. Boss wouldn't let me use the controller with more memory, but instead I had to optimize an already optimized machine code (it was already written in assembler) to fit the extra 4 bytes in. You get the picture.

Depending on the platform you're working on you'll have to deal with very low level I/O. Some development environments have functions to write to an LCD, but on others you're on your own, and will have to read the LCD's datasheet from start to finish to know how to control it.
You may have to control a relay, that's easier than an LCD, but it will require you to go to the register level of the microcontroller. Again a datasheet or user manual. You'll have to get to know the microcontroller's structure, which you'll find in a block diagram, again in the datasheet. In the microprocessor's days we talked about a programming model, which was basically a lineup of the processor's registers. Today's microcontrollers are so complex that a description of all the registers can take the best part of a 100 pages datasheet. IIRC just the description of the clock module for the MSP430 was 25 pages long.

You'll often have to deal with real time event handling. An interrupt you have to handle within 10\$\mu\$s, for example, and during that have another interrupt which requires the same timing accuracy.

Microcontrollers are often programmed in C. C++ is rather resources hungry, so that's usually out. (Most C++ implementations for microcontrollers offer a limited subset of C++.) Like I said, depending on the platform you may have an extensive library of functions available which could save you quite some developing time. It's worth taking some time to study it, it may save you a lot of time later on if you know what's available.

\$\endgroup\$
3
  • \$\begingroup\$ I've written games for the Atari 2600, which is a rather limited platform; my first published game was essentially 4K code (since I had a 32K cart, I added some extra goodies, but the 4K version was entirely playable); RAM is 128 bytes. I find it interesting to contemplate that in the year I wrote that game (2005), other games were published that were, literally, a million times as big. \$\endgroup\$
    – supercat
    Aug 29, 2011 at 15:17
  • \$\begingroup\$ @supercat - Yeah, but that was to be expected, in 2005 the Atari 2600 was already 200 years old! I've never played action games like FPSs, but when I look at what's needed to play them, a GPU much more powerful than your CPU, both programmatically and electrically, I can't help but shake my head :-). I played chess (Sargon) on a 16k TRS-80 IIRC. My brother's Flight Simulator didn't need more. \$\endgroup\$
    – stevenvh
    Aug 29, 2011 at 15:31
  • \$\begingroup\$ Not quite 200 years old. It debuted in 1977, so it wasn't even 30. While I agree that that was aeons ago in technological terms, I'm still blown away by the fact that there's not just a hundred-hold increase, nor a thousand-fold increase, but a MILLION-fold increase in both RAM and code size. Speed hasn't gotten quite that much of a boost, since the 2600 was 1.19MHz and newer systems are only in the low GHz range. They can do a lot more per cycle than the 2600 (which could--and had to--generate 1/76 of a video line each cycle) but I don't think they're 1,000,000x as fast. \$\endgroup\$
    – supercat
    Aug 29, 2011 at 15:48
3
\$\begingroup\$

"hardware programming" can mean a lot of things. Programming a very small chip (think 10F200, 512 instructions, a few bytes of RAM) can be almost like designing an electronic circuit. On the other side programming a big Cortex microcontroller (1 Mb FLASH, 64 kB RAM) can be a lot like PC/GUI programming, using a big GUI toolkit. IMHO a good embedded/real-time programmer needs skills both from the software egineering side and from the circuit design side. For the bigger uC C++ is a good language choice, for the very small ones C might be the only choice. Assemby knowledge can be handy, but I would not recommend doing serious projects entirely in assembly.

I have done serious embedded work with people from both (SWI and EE) sides. I generally prefer the SWI people, provided that they have some experience with multu-threaded programming.

Your question sounds like you want to dive into embedded programming. By all means do so. For the low-level aspects (interfacing the peripherals in your chip and the hardware around it) you will need to learn some new skills, but it is just a lot of work without many new concepts. For the higher layers of your projects you can draw on your existing knwoledge.

\$\endgroup\$
1
\$\begingroup\$

For every arduino library method that you call there is a wealth of C/C++ code that makes it possible, it's simply packaged nicely for you to use as an API. Take a look at the arduino source code under the directory hardware/arduino/* and you'll see all the C/C++ written for you which interacts directly with the AVR microcontroller's registers. If your objective is to learn how to write stuff like this (directly for the hardware) then there is a lot to cover. If your objective is to get something to work using their libraries then there might not be much to talk about as most of the hard work is done for you and their libraries and development environment are very easy to use.

Some rules of thumb though when working with resource constrained devices that could apply to either arduino environment or others:

Be aware of how much memory you are using. Both code size (which goes to flash memory) and static RAM usage (constants in your code that will always exist in RAM). I would argue that static RAM usage is a bit more important starting out, as it is easy to over look. It's not uncommon for you to have only 1000 bytes to work with for your stack, heap, and constants. Be wise in how you spend it, so avoid things like long arrays of integers (4-bytes each) when bytes or unsigned char's (1 byte each) will suffice. Another answer here covers some other important points very well so I'll stop here, I mainly wanted to get the point across that there is a lot to cover if you're not using the arduino library and writing your own C libraries.

\$\endgroup\$
0
\$\begingroup\$

Regarding microcontroller vs OOP programming, they are not something opposites. It is true that all vendor libraries are in plain C, but all platforms support C++ OOP too. Developers can build and do build C++ high level libraries and device firmware on top of that. The good example is Arduino libraries, official and user built - mostly C++ classes. Maybe not all OOP advantages can be fully utilized in embedded environment, but well known C++ vs C advantages are valid here too.

Regarding the mindset and thinking, as noted in other answers, microcontrollers are very resource constrained platforms (specially in RAM, less in speed) - stuff like dynamic memory allocation, C++ exceptions are usually ruled out. Given the right hardware is chosen, it is easy to adopt to these limitations and use other techniques (also widely used in other platforms).

In my view, the harder challenge might be one more extra dimension found in embedded programming - timing. This is because usually embedded software deal a lot with real-time events, strictly timed protocols to drive peripheral hardware and general task itself (these is some parallels in other "high level" platforms too, like multi-threaded applications).

Be prepared to read a lot of datasheets when dealing with new hardware - I guess it could be related to "mindset" question part :) Surely some EE and hardware knowledge would be needed.

Also I would like to note that these days embedded software development doesn't require assembly language. In fact Java (BTW it is OOP by default) is already here and getting stronger (at least for some class of embedded devices, for example IoT devices, it could have very bright future).

\$\endgroup\$
3
  • \$\begingroup\$ In terms of concerns, those around dynamic memory (re)allocation tend to be a greater impediment to traditional OO than timing. \$\endgroup\$ Jul 23, 2016 at 20:13
  • \$\begingroup\$ Maybe you are right. But there are people who programmed in 80-90s for MSDOS real mode software, with 64K (data memory segment) RAM space available and for them it was "natural". Maybe MSDOS PC was more "embedded" environment than todays STM32F4 :) \$\endgroup\$
    – Flanker
    Jul 23, 2016 at 20:33
  • \$\begingroup\$ The STM32F4 typically has more program memory in the form of flash, but the PC typically came with far more RAM memory to store mutable runtime objects. While the whole far pointer thing forced by segmented addressing was a pain, both lack a true MMU, and that's going to be even more of a concern on the system with less RAM, which is the STM32F4. Also PC uptimes tended to be shorter, and acceptable failure rates higher. \$\endgroup\$ Jul 23, 2016 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.