The ‘Lupik’-compiler suite from www.embuddy.se consists of ‘Lupik16’ for the mid-range 12F-16F/C series of cpu’s and ‘Lupik18’ for the high-end 18F-serie of cpu’s.
The developer of these compilers actually comes from embedded software rather than from the compiler industry and ventured into the business of compilers to develop practical tools for developers at a very reasonable price. This background seems to have produced a very simplistic and pragmatic tool, from a developer to fellow developers.
I have tested the compiler in three different projects: a small real time application for the 12F-series(a light-house simulator), a large and hard real time application for the 16F(part of an analogue synthesizer), which were surprisingly painless ported from HiTech, and a quite large astronomical calculation project for the 18F-series(not yet in production).
Installing the Lupik16 is straightforward. Download from www.embuddy.se, unzip the package and read through the manual. You get a 30 days trial, after that there are nag screens and some degradation of functionality.
There are two ways of installing the compiler:
- ‘Stand alone’-mode. The compiler does not need to be installed but can instead simply be unzipped into a directory of choice. I usually unzips in right into my source code folder, to keep my entire development environment version controlled. The compiler consists of just two core files and one include directory, which can be stripped down to contain only two files, (the cpu specific header and the standard library). This makes the entire installation so small that it does not affect the project size that much. A small batch-file can be written to define multiple source-files and compiler switches if wanted. Of course, it is possible to place the compiler in a centrally placed directory and modify the path to point at it, so that the same installation can be used from different projects, in this case it might also be useful to use the next option where the compiler is integrated with MPLAB.
- ‘Integrated’-mode. This integrates the compiler with MPLAB. This is accomplished by running a small script that registers the compiler with MPLAB. Create a new project with MPLAB the normal way, selecting ‘Lupik’ as tool-suite and you will get full support from MPLAB including source-code level debug. A tip is to unzip into a generic folder, e.g. ‘Program files\L18’ and then simply overwrite when a new version is released. In this case the paths will not need to be set once more.
Using the compiler in stand-alone mode
In stand-alone mode the compiler is used from the command line specifying source files and options with compiler switches. Output is in the form of both a hex file, a cof-file and an assembler file. The hex file can be directly programmed into the cpu with a stand alone programmer or via MPLab. The cof-file can be imported to MPLab and programmed into the cpu from there.
Using the assembler file as output is a quite interesting option especially for debugging purposes. Open the assembler file in MPLAB and build it and debugging can then be done on assembler level. Normally this is not very exciting but, the assembler files produced by the compiler is mixed with the C-source code in a very clever way and debugging in this way works surprisingly well.
There is even no need to create a project within MPLab, just open the assembler file and go. Again, the simplistic and practical idea behind the Lupik compiler shows off in the details.
One thing worth noting is that if the Lupik-generated hex-file is to be used, the cpu-fuses must of course be set in code, macros are available for this. If MPLAB is used to generate the hex-file, the fuses can of course be set from within there.
Using the compiler in integrated mode
In integrated mode the project is run as any other project within MPLAB. Create a project and add source files, select the Lupik compiler suite and you are ready to go. Compiler options and cpu fuses are set from within MPLab, and full source level debug is of course available.
Lupik does not use a separate linker, or even separate linker stage within the compiling process. Something that most modern languages also omits, e.g. C#. The reason for this might be to speed up the compilation process, but the main reason is probably to avoid yet another set of directives needed for the user to to specify the linking process. Again the simplistic philosophy of Lupik shows through. It is none the less possible to write code in separate source files, to enforce structured programming Just specify all source and header files at the command line and they are all built to form a single output. Any number of header and source-files can be specified and there is full support for static variables and functions.
There are some discrepancies towards the ANSI-specification, but mostly pragmatic to get C to work better for an embedded cpu. Other compiler vendors do the same thing, it is about how to define port-operations and other hardware-close operations.
There are some features missing, but as far as I found, all seems to have workarounds or alternatives. E.g. enum’s are missing which seems to be quite a small drawback, seldom used. Another is function pointers which does not have much meaning even in the somewhat larger 18F-models.
I have only been able to compare Lupik16 against HiTech. In this case Lupik16 produces considerably better code than un-optimised HiTech code. Turning on full optimisation in HiTech gives about 5% better code, but at close examination, individual fragments are still more compact with Lupik16.
Neither the Lupik16 nor the Lupik18 have much optimisation options. And using optimisation might also be a question of taste and need. I never develop code with optimisation turned on that affects my ability to debug the code, which is often the case. The reason is that I want to know that the code I develop and debug is the same as the code being tested and in the end used in production. Timing or other tricky bugs have a nasty habit of sneaking into projects when optimisation is turned on late in a project.
One optimization feature that does exist in Lupik16 is nevertheless unique as far as I know and therefore worth mentioning. Probably all developer of any major project for the 16F series has run into problem with running out of the precious eight levels of stack positions. Lupik takes care of this in two ways: by clearly showing the stack depth after the code is compiled. But, most important, by a very clever mechanism that synthesizes subroutine calls. This is accomplished by turning on the ‘-gr’ switch which when defined, replaces subroutine calls with goto’s and a return jump-table. Again, Lupik proves to be pragmatic and well aware of the daily chores of an embedded developer, such as keeping track of the stack.
Library functions are delivered in a separate file which is always automatically included. Only functions used are of coursed compiled. The library is actually written in C and thus fully possible to examine or recycle in your own source-files.
The functions available are mainly of two kinds, helper functions to support the PIC architecture, such as EEPROM read and write and math functions, which seems to more or less complete from a C perspective, including floating point math routines. Also, sprintf function was available in a development version when this review were written.
I have tested the math routines especially well for the Lupik18 compiler, within the astronomical project and it works flawless and with high precision.
Differences between Lupik16 and Lupik18
The two different compilers in the suite works identical from installation and usage perspective. I have only found some minor differences, such as that the stack synthesizer is omitted from Lupik18 which is natural since it is not needed.
Lupik16 supports more or less all PIC12 and PIC16 cpu’s and Lupik18 supports more or less all PIC18. New cpu’s added by Microchip is continuously added to the supported range. The webpage also states that if a new cpu is not supported it can be done so by request.
There is in my experience, always certain quirks when defining interrupts for an embedded cpu, but the Lupik handles this in an easy way.
Constant structs and arrays are nicely handled so that the compiler overcomes the 255 bytes limitation with the PIC architecture.
Because the PIC’s handles memory banks in quite an awkward way, the compiler needs to handle this in quite a complicated way. The Lupik documentation explains this process in every possible aspect, for users interested in this mechanism.
Inline assembler is fully supported, either one-liners or entire segments of code. Local and global variables are fully accessible between assembler and C.
I have used Lupik in its early beta-stage and have had the opportunity to communicate with the developer. Errors and bugs have always been promptly attended and fixed and all my suggestions for improvement considered and a few actually also implemented. Support is swift and prompt and there are currently no known bugs in the versions I have used.
The Lupik-suite of compilers are definitely industrial strength for a very reasonable price. They are user-friendly and produces result both for the experienced hobbyist or the demanding professional. Give it a try, I am happy that I did.
Mats Andreasen, A-Teknik, Gothenburg, Sweden
This site is non-profit. Ad revenue almost covers hosting costs.