Wednesday, June 27, 2012

Bare metal development for ARM Cortex M microcontrolllers

What is bare metal?


Bare metal means running software directly on hardware, instead of running it on top of an Operating System (OS).

And why would you do that? Because sometimes OSes take way too much resources (RAM + Flash), especially when the target device is a low cost microcontroller (uC). Or maybe the application is not very complex and an OS is overkill. Also many OSes are created to run on targets that have a Memory Management Unit (MMU), and your target device might not have one.

Now, using an OS is not a bad thing, quite the opposite it has many advantages. It's highly probable that you are viewing this blog using a device that's running an OS (PC, laptop, smartphone, tablet, etc). And thanks to the OS you can do multitasking in that device, also you can easily add, remove or run software on that device. It's also (almost?) impossible to break or hang the device while developing/running applications, because the OS won't grant other applications access to core/low-level areas of the device.

If you have worked on 8-bit uC from Microchip (a PIC16F877A was my first contact with the world of embedded systems) or AVR (e.g. Arduino) then you have already done bare metal development and have (hopefully) enjoyed the process of controlling at 100% the hardware of a microcontroller.

The ARM world


Today, we have access to more powerful uCs like the ARM-based microcontrollers. Many companies have developed microcontrollers based on the ARM Cortex-M architecture, so there are hundreds of differents uCs, some with more peripherals, others are lower power, but all of them are unified by the ARM architecture, which simplifies the development on these devices.

Specifically, I'm working with the STM32F407VE uC, based on the Cortex-M4 architecture, that has an integrated FPU, which makes operating floating point numbers a snap. Trying to do a multiplication of floats in a 8-bit uC takes way too much Flash and runs way slower. Forget about doing many trigonometric operations or multiplying matrices.


Around 550 bytes needed to mutiply two floats in a 8-bit uC.

Bare metal development on ARM


If you have used IDEs like MPLABX, AVRStudio, etc. Then you have skipped  the (fun) part of setting up the memory distribution, and went straight to code up your application in the main function, after that you clicked the build button to create a hex file or similar, which later you flashed onto your uC to blink a LED, move a motor, etc.

Before jumping into the development, I want you to understand some basics. First, the ARM processor only knows binary (1011...), and in this case that binary is stored in an ELF file. To build this binary from source code (C/C++), which is more human readable, we need a toolchain and a linker script.

The toolchain, contains tools like the compiler and the linker to build the binary; and also provides a debugger, which allow us to run the program in the uC step by step, while observing the inner variables and registers of the uC.

The linker script is basically a map that tells the toolchain how to distribute the memory of the uC, and you can take a glimpse of it's implementation in the following image.

A small part of a linker script.

Obviously, we also need some hardware to flash the ELF file into the uC, and to debug the program in the uC. This hardware needs some connection to the uC, in the case of the ARM microcontrollers this can be via a JTAG or a SWD header. This hardware can be parallel port based or USB based, the latter is far more popular and is sometimes called JTAG dongle.

For example, I started with ARM uCs using a Bus Blaster (JTAG dongle) and a STM32F4Discovery, today I use a custom board for the F4 and a custom JTAG adapter for my projects. (you can see a picture of my hardware, in this post about Kicad)

I have created an Eclipse project template named bareCortexM that wraps all the needed tools, and the source code is available in this repository, go there for hands on experience in bare metal development. The project makes use of the following tools:

+ Eclipse, the IDE that wraps all the tools.
+ GNU Tools for ARM Embedded Processors, the toolchain.
+ openOCD, the glue between the JTAG dongle and the host PC.

On the following image you can see the full setup.

Debugging a STM32F407VE uC using bareCortexM.

Notice that a multiplication of floats takes only 5 instructions, 20 bytes, in constrast with the 500+ bytes of the  multiplication algorithm of the 8-bit uC.

Now that you know how to do bare metal development, you can go ahead and build your own OS or grab a peripheral library and start developing projects. I'll release a template peripheral library for the STM32 microcontrollers later this week. Check my post about libstm32pp, a template peripheral library.

Hands on experience


If you have a STM32 microcontroller + JTAG dongle or a development board like the STM32F4DISCOVERY, then go to this post for a detailed tutorial on how to set up the bareCortexM environment and the libstm32pp peripheral library and start developing on ARM right away.

4 comments:

  1. Hi. I have a small question. If I have already written a project in C (for example) and compile and build it in Eclipse - will it be executable without an OS, or I can run it under some OS?

    ReplyDelete
    Replies
    1. The comment below is misguided. These are old posts but a comment on this topic is in order since others will find this through google as I have.

      Your code will run as long as it was compiled using libraries that do not depend on having an OS. Example... If you use device tree links to IO then your code will not run without a linux version. If you use the memory locations and made your own references to IO then you will be all good.

      Many applications run without an OS. I have many control applications that control motors based on commands over ethernet, I2C...etc. Bare metal gives me the fastest tick possible. These controllers could perform under a realtime OS but if you don't need all the extras that come with using an OS you may as well skip it and code for the fastest most efficient environment of bare metal. If you want to make a PC and write software then install an OS and develop within the OS. But if you have a specific task that needs to be performed on specific hardware bare metal may be the best option.

      Delete
  2. Hi nrg,

    That depends IF you want it to run inside or outside an operating system.

    The the question is also on which kind of hardware you wish your software to run on. Standardized hardware or hardware you create and compose yourself.

    That choice has direct effect on how much you will have to code yourself to make things happen. If you wish to be the originator of all code and as such will have full control and knowledge of what will be inside your software package and your software to run without any OS then you will need to get full knowledge of the hardware of choice you wish to run you completely autonomous software on. You will have to code everything yourself. That includes getting knowledge of all categories of possible hardware within a standard or non-standard of choice. Choices are for example PC or Apple or other computersystems that are standardized. BIOS: The basic input output system standard makes things easy for you in your coding. Having knwoledge of the BIOS of a standard computer of choice will enable you to make software that runs without the necessity of an operating system. You will have to provide all code to communicate with the BIOS once the computer is switched on. You save your software on a floppy disk or USB stick, plug it in and restart your computer and there you go. I have to tell you that considering no operating system means not even considering one that would fit on a USB stick or floppy disk. You'd have to take care of all coding to make things happen.

    Or you could purchase your own components to make up a computer system which can go from a simple 8-bit micro processor chip, a memory chip and the extra necessary chip components to provide the possible connection to a keyboard and a monitor or small character LCD display. You could choose to make extra input and output elements so you could detect (input) and control (output) things you want your computer to deal with. That's always been the original thought in with computers from its inception more than half a century ago.

    You could also make things easy for yourself and develop your software to work inside an operating system that takes care of all the difficult and comprehensive software that takes care of the varieties of possible outputs and inputs you desire your application to deal with. As example if you would develop in the C-language and wish to put something on screen a simple instruction as putc() (http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frtref%2Fputc.htm) could be sufficient. But Eclipse would have to be configured and provided with enough auxiliary information (libraries, toolchains, etc) so it is able to deal with that putc() instruction. These libraries and toolchains, etc are geared towards the operating system in which you wish to run the application that you made in your project.

    I hope that satisfies your question.

    ReplyDelete
  3. I believe that moodle theme development is considering one that would fit on a USB stick or floppy disk. You'd have to take care of all coding to make things happen.

    ReplyDelete