||4 months ago|
|generators||4 months ago|
|.gitignore||1 year ago|
|CMakeLists.txt||1 year ago|
|Config.cpp||1 year ago|
|Config.h||1 year ago|
|LICENSE||1 year ago|
|README.md||1 year ago|
|ucmf.cpp||1 year ago|
ucmf - microcontroller make frontend
ucmf (microcontroller make frontend) is a helper program to produce makefiles for microcontroller projects.
One of the problem of microcontroller projects is that different compilers are required for different microcontroller families. Even within a family, it may be necessary to write code for a specific microcontroller model. Uploading compiled programs to microcontrollers is also different on every microcontroller family.
ucmf tries to faciliate the process of compiling and uploading programs to microcontrollers by generating an ordinary makefile from a configuration file that contains a space-separated list of source code files and other information like the default microcontroller family and model for which to compile the program. All that is required to build a program is a call to "make". To upload a program, call "make upload". The makefile generated by ucmf will do the rest.
ucmf attempts to follow the same principle as CMake in the sense that developers can focus on programming instead of thinking about how to compile and deploy a program.
You need CMake to compile ucmf. Then, you can invoke CMake like this to create a Makefile in a new subdirectory called "build":
cmake -B build
Now, go into that directory and call make:
cd build make
You now have the ucmf executable ready to be used.
When called, ucmf looks for a file called "ucmf.config". This is the project file where all the settings are stored in. The following is an examle for a project file:
PROJECT_NAME=hello-world SOURCES=hello_world.cpp #Change the following two lines, if you are building for #another microcontroller than an ATTiny45: UC_FAMILY=AVR UC_MODEL=attiny45 #Depending on the microcontroller family, only one of the two #following sources will be included: UC_FAMILY_SOURCES::AVR=print_avr.cpp UC_FAMILY_SOURCES::GAMEBOY=print_gameboy.cpp
Each line in the project file can either be empty, a comment (introduced with a '#' character) or a configuration variable. There can only be one variable per line. Everything behind the fist '=' character is treated as value, while everything before that character is treated as the name of the variable.
- PROJECT_NAME: The name of the project.
- SOURCES: A space-separated list of source code files.
- UC_FAMILY: The family (or vendor) of microcontrollers for which the source code shall be compiled. This must be written in uppercase.
- UC_MODEL: The exact model of the microcontroller for which the source code shall be compiled.
- UC_FAMILY_SOURCES::<UC_FAMILY>: A space-separated list of source code files that are specific to a microcontroller family. They are only included in the sources list when the corresponding microcontroller family is set in UC_FAMILY.
Overriding project configuration
The variables in the file "ucmf.config" can be seen as default variables. They can be overridden by a "localised" configuration file called "ucmf-local.config". That file is useful for configuration variables that only apply to the environment where the program is built. It is therefore a good place to set the serial port of the microcontroller programmer or to set a different microcontroller family or model. The example "ucmf.config" configuration file from above could be extended by the following variables in a "ucmf-local.config" file:
UC_FAMILY=8051 UC_MODEL=default 8051::PROGRAMMER_PORT=/dev/ttyUSB0
ucmf will first read the "ucmf.config" file and then the "ucmf-local.config" file, if it exists. Configuration variables in "ucmf.config" are overridden, if they also appear in the "ucmf-local.config" file.
Generators can have their own configuration variables that are prefixed with the short name of the generator, followed by two colons ("::").
The AVR generator uses avr-gcc/avr-g++ for compilation and avrdude for uploading code to a microcontroller. The following special configuration variables can be used with it:
The programmer to be used. This has to be set to the programmer-id of a programmer that is supported by avrdude. Call avrdude with the question mark as programmer-id to get a list of all supported programmers:
avrdude -c ?
The port where the programmer is connected to. This may be a serial port or another port, depending on how the programmer is connected to the computer.
The baud rate that shall be used when communicating with the programmer.
The Gameboy generator uses sdcc as compiler. Due to the nature of gameboy program development, an "upload" target is not provided by the generated makefile.
The 8 character long program name for the cartidge (or cartidge image). If this is omitted, the project name will be used and shortened to 8 characters, if it is longer than 8 characters.
Extending your source code for ucmf
Makefiles generated by ucmf will add extra C/C++ preprocessor definitions so that you can write different source code for different microcontroller families and different models. The UC_FAMILY and UC_MODEL configuration variables are translated into preprocessor definitions in uppercase and prefixed with "UC_FAMILY_" and "UC_MODEL_" repsectively. If you want to have source code for the AVR and 8051 microcontroller families, you can do the following in your C/C++ source code:
#if defined UC_FAMILY_AVR (some C/C++ code for AVR microcontrollers) #if defined UC_MODEL_ATMEGA328 (specific code for the Atmega328) #else (code for all other AVR microcontrollers) #endif #elif defined UC_FAMILY_8051 (other C/C++ code for 8051 microcontrollers) #endif
Navigate to the project directory where you placed the "ucmf.config" file and then invoke ucmf without any parameters:
If ucmf didn't report any errors, you will find a Makefile in your project directory that you can run with the usual make command:
The default target in the makefile is the "build" target, which compiles the source code and produces a compiled output file that can be a binary or a hex-coded file or something else, depending on what is the most useful output for the microcontroller family.
Another target in the makefile is called "upload". It is responsible for uploading the compiled program onto the microcontroller. It must be explicitly executed and isn't run automatically to prevent possible damage to microcontrollers connected to the computer invoking the make command. To upload the compiled program to the microcontroller, simply call make like this:
If all went fine, you now have uploaded the program on a microcontroller, ready to be run from there.
A note about the generated makefiles
Depending on the microcontroller family, the makefile generator in ucmf may provide additional targets to the two basic "build" and "upload" targets. If the generator does not include a "help" target that describes all the available targets, you need to look in the makefile itself to find out about the names of the additional targets.
Contributing and development
Requesting features and reporting bugs:
You can write feature requests and report bugs on Codeberg:
Makefile generator development
The main power of ucmf lies in its makefile generators. There are a few rules for makefile generators to generate standardised makefiles.
Make UC_FAMILY and UC_MODEL available to the source code
The UC_FAMILY and UC_MODEL configuration variables have to be made available to the source code as preprocessor definitions. The UC_FAMILY variable can be hardcoded in the generator when it can only be used for one microcontroller family. The UC_MODEL variable has to be converted to uppercase letters.
Example ucmf.config file content:
These two lines from the configuration file have to be transformed by the generator to the following preprocessor definitions:
These preprocessor definitions have to be passed to the compiler that builds all targets for the "build" target in the makefile.
Provide at least the "build" and "upload" target
The "build" target is responsible for building the program from source code. The "upload" target handles the process of uploading a program to a microcontroller. If the "upload" target cannot be used for the microcontroller family you are writing a generator for, you can simply generate the "upload" target with one line echoing a text telling the user that the upload target is not supported for this microcontroller family.
The build target must be the default target that is executed when make is invoked without any parameter.