Stage 3: Write the Embedded Software

Our last posts about specifying the requirements for our design and designing the hardware to meet those requirements have laid the groundwork for everything we need to know and enables us to do the next stage in our design process: write some code for our microcontroller to program our FPGA.

A Haze of Code

The endless list of modern programming languages…

Writing code for computers of any size has evolved hugely over time. From the humble beginnings of punch cards to the modern high level languages like Java and C++, there has been some extraordinary progress in how we instruct computers to perform the tasks we want.

In the modern ecosystem of processing there are different languages for different levels of integration.

Assembler and C code are the usual choice for many embedded level programmers and C++, Java and Python are a significant few for application level programmers.

In this project we’re at the embedded level, so we get to choose between assembler and C. There are some libraries that exist for microcontrollers in C++ but they’re by no means ubiquitous in the industry as of yet.

Choosing between C and assembler is a choice made entirely upon two main aspects: the technical complexity of the task and the code latency/size requirements.

Assembler lends itself well to doing algorithmically simple tasks which are size and speed constrained. That’s because when you’re writing assembly, you’re manually telling the processor which specific opcode you’re using from the processors instruction set one instruction at a time.

C on the other hand lends itself well to the converse. C is much more adapted to doing complex algorithms in timing-relaxed memory-abundant environments.

When you write code in C, the instructions you specify can end up being one or more instructions of assembler in order to complete the task. C also had an added benefit in that it usually has supported libraries for the microcontroller you’re using making the implementation a lot easier for the most used functions. It’s for that reason that we’re going to write the program in C.

Setting up the toolchain

In this design we’re using a Microchip PIC32 microcontroller which has a tool-chain available for download called MPLAB-X.

This toolchain from microchip provides the ability to create projects and manage integration through their MPLAB-X integrated development environment. It does not however include the compiler libraries required in order to compile your source code into a programming file. In order to get your compiler, you have to download the XC compiler intended for your architecture. In this specific instance, we’re using a 32 bit processor, so we select the XC32 compiler.

This is what you need to get started with the PIC and program it “Bare Metal”. However, most manufacturers have preexisting code which can be used in order to make many jobs easier: Middleware.

Middleware is a fairly new phenomenon as microcontrollers become more powerful, complex and cheaper. It enables programmers to interact with an easier to interpret layer of code, removing the difficulty of driving complex peripherals and managing access to these from multiple different processes.

This is also a complexity/latency/size problem, similar to choosing the language it’s written in. For Microchip PIC products this middleware is called MPLAB Harmony. Because we can be fairly liberal with space and we want the processor to perform one specific function at first, we can use this library to do what we need.

This is all the software we need for the computer in order to be able to make our program for our microcontroller. The output of this process is a hex file which you can upload into your design.

Getting this file into the chip however requires a special bit of kit in order to do so- a programming tool.

Microchip has some really good programmers that work just out of the box, namely the PICKIT and the ICD tools. The latest forms of these programmers have had someone from the marketing department have a say in their design which is a shame, but the PICKIT3 is one of the PICKIT family which it preceded. We have a couple of these programmers handy so we’re just going to use one of those.

So that’s the complete toolchain setup. Now we can actually get onto setting up our project and developing/debugging code.

Writing the code

Writing embedded software for a project is not just a technical exercise. If it was then the code we write would likely not be re-usable and would have no structural sense to it.

Planning the software architecture in line with requirements and also building in the ability to re-use modular code blocks is always a necessary activity when doing any design for a product. This means that not only is it easier for others to interpret what’s going on, but also others can pick and choose to use different bits of code from your design in the future to make their job quicker and less risky.

Because of the size and scope of this project, the need to fully architect a piece of software is not as necessary. If this this project was part of a product however, it would be 100% necessary to do so regardless of it’s size.

Just to practically set out what we want to achieve with the code is always a good starting point when writing software. For our example there is a simple two step process that we want this processor to perform in our first iteration of software.

Firstly, we want to send the programming file stored on the microcontroller over SPI to the FPGA. This step includes checking and setting some states of GPIO in the process to ensure that the FPGA is ready to receive the data over the SPI port in the first place. Then, once this programming is complete, we want to flash an LED to show that the programming function has been completed successfully. This is a really simple implementation for our first revision of the software and should get the core of what we want to achieve done.

There are many other things that the processor can do for us but we’re interested in just getting the FPGA up and running, so we’ll do just that. The MCU also needs to be configured by the middleware to provide a clock out to the FPGA as well which we can configure in MPLAB Harmony.

Setting up the project

In order to set up the project we need to go through the steps of setting up an MPLAB Harmony project in the IDE. This is a fairly simple process of setting the name for a project and selectring which processor you want to use. When you have finished the initial setup steps you end up wit