High-Level Languages for Microcontrollers

The main justifications for High Level Languages are that you can produce more lines of code, more bug free lines, more maintainable lines than you can in assembler during a given number of days. Having used quite a few different HLLs and assemblers on a wide variety of processors, I entirely agree.
An HLL takes care of the grisly details: where are the variables, how to manipulate things bigger than ALU registers, how to manage subroutine parameters and local variables, and so forth. Because humans do those things so poorly (no matter how carefully they work), any decent HLL compiler frees up desperately needed brainpower.
You trade off control over the details to focus on the Big Picture. You assume the compiler is doing a good job on its part and devote your attention to the Rest of The Story. When this synergism works well, your project will reap those HLL benefits.
Microcontroller systems (notably the 8051 family and other tiny micros) impose severe constraints on program size, data allocation, and run-time performance. Often the program must fit into 32K and respond to “real-time events” measured in a few microseconds. You cannot afford to trade off code space for execution speed and you must pay attention to the location of every variable in that precious internal CPU RAM. The difference between those statements is that one uses External Data Space and other uses Internal Data Space. because C hides the details of variable manipulation from you, you cannot tell which statement is which. I contend that you really ought not lose sight of a two-times increase in code size and a six-times increase in execution time quite that easily!
There are ways around the problems, which I have used on several projects. Microsoft’s “Hungarian notation” helps to identify the variables:
nsVarl= sVar2 + *npsVar3
indicates which variable are “near” and “far” although the space and time implications may not be obvious at first glance. And most current C dialects support keywords that give you control over memory allocation; if you are particularly lucky, you may actually be able to use the standard library routines in a mixed-memory-model project. I contend this wraps up the worst of both worlds in one ungainly package: the memory allocation headaches of assembler with none of its precision and a less readable, more fragile HLL program burdened with internal compiler details.
Even though combining HLL and assembler routines in one program (a.k.a., “tweaking the hot spots”) sounds inviting, approach with caution! HLLs make many assumptions about how memory is used; you must contort the assembly code into that mould. You’ll spend a lot of time jockeying the Hatfields and McCoys into the same EPROM.
If your project is blessed with ample CPU resources or it is so trivial that any CPU is adequate, there is no justification for assembly language. Pick a good HLL, implement the best algorithms you can find, and have at it. You’ll get good results and never miss the details.
However, when you set out to develop nontrivial code with tight timing requirements for a microcontroller with cramped address spaces and an idiosyncratic instruction set, I strongly suggest you gnaw the assembly language bullet from the start. If you do it right, the overall design can be just as clean and the code just as readable and maintainable as an equivalent HLL program. And those tight timing requirements won’t be such a big deal because you’ll polish them off first rather than patching them later.
Writing good microcontroller code requires detailed knowledge of the whole project: hardware, software, firmware, design requirements, whatever. If you don’t keep everything in mind all the time you will screw it up. An HLL doesn’t help by concealing details: it hurts by suppressing information you need to do the best possible job. Assembler doesn’t help by giving you full control: it burdens you with more details. Pick the right tool for the job and don’t believe the hype.

Comments are closed.