What are the peripheral devices in a microcontroller

Controlling the LCD via SPI: An introduction to project development with an EFM8 microcontroller

Controlling the LCD via SPI: An introduction to project development with an EFM8 microcontroller

Microcontroller-based embedded designs start with hardware and then move from lower to higher level firmware development. We will explore this design process as part of a simple program that uses a SiLabs EFM8 microcontroller to display a horizontally scrolling line on a 128 x 128 pixel LCD.

Previous articles in this series

  • Silicon Laboratories' EFM8 Series: A Powerful New Embedded Development Platform

Required hardware / software

  • SLSTK2000A EFM8 evaluation board

  • Simplicity Studio integrated development environment

A few words about working with microcontrollers

In general, a microcontroller project can be discussed in terms of four interconnected functional blocks: port input / output, peripherals, firmware and external components. The lowest level is represented by the port I / O configuration, which ensures that the port pins correctly handle the actual voltage signals that serve as outputs from the microcontroller or as inputs. Peripherals (such as timers or serial communication modules) act as an intermediary between the port I / O and the firmware: Peripherals process I / O signals to or from the port pins and initiate events that affect firmware execution. Firmware is the collection of instructions that govern the entire operation of the device; Firmware can communicate directly with port pins, but often the firmware interacts with peripherals which offload the processor by performing low-level hardware tasks independently. Ultimately, these three blocks - port I / O, peripherals, and firmware - work together to successfully connect to other components in the system.

Hardware and implementation details differ from microcontroller to microcontroller. Therefore, a familiarization process is required when you start developing projects with a new device. A well-written, well-illustrated data sheet is just as helpful here as a well-commented sample code. But in the end, you need firsthand experience (along with a lot of patience when things don't work out at first) to familiarize yourself with the quirks of a new microcontroller.

Fortunately, built-in configuration tools make this familiarization process faster and less painful. Simplicity Studio includes a sophisticated hardware configuration tool that significantly reduces the time and effort required to correctly configure the various registers to operate the processor core, clock sources, power supply, pins and peripherals.

Project overview

The goal is to display a horizontally scrolling line on a 128 x 128 pixel LCD module. This unexciting functionality serves as a convenient way to explore fundamental aspects of implementing projects with the EFM8 through Simplicity Studio. Configuring the hardware of a microcontroller can be a complicated process, and this article cannot cover all of the concepts and techniques. That said, we'll try to highlight some key implementation details, and then future articles will focus more on higher-level functionality.

Port I / O

First we have to assign port pins to the corresponding peripheral devices and, if necessary, configure pins as outputs. You will find that the basic task of choosing the input / output status of a pin is more complicated than expected. It is not that easy to set a configuration bit to 1 for input and 0 for output. Therefore, it is important to understand what is really happening to these pins:

This diagram shows the input / output circuit of a port pin. The transistor labeled "WEAK" acts as a high-value resistor (approx. 200 kΩ). When the pin is set to "push-pull" mode, the output is directly connected to V via one of the output transistors DD or connected to ground. Therefore, the pin "drives" a logic low or logic high level, so that in this mode the pin is an output. If not in push-pull mode, the pin is in "open-drain" mode. This means that the upper driver transistor (not the one labeled "WEAK") is deactivated. Here's an important point: you can't name this "input mode" because the pin can still drive logic low through the lower transistor. The pin is only a real input if you configure it as an open drain and write a 1 to the corresponding bit in the port pin latch register. Now both driver transistors are blocked and the pin is pulled up to VDD by the "weak" pull-up transistor. This arrangement is necessary because sometimes (e.g. with the serial I 2 C-Bus) a pin can work both as an input and as an output in open-drain mode.

After resetting, all port pins are set to input mode by default, so we can only configure a few pins for output mode and leave the rest alone. But first we need to assign the peripherals so we know which pins should be outputs. SiLabs microcontrollers connect peripheral devices with port pins via a so-called crossbar, which is a somewhat confusing but also very versatile architecture. For this project, the only peripheral device that requires connector pins is the SPI bus.

SPI_SCK (serial clock) and SPI_MOSI (master-out-slave-in) must be configured as push-pull outputs; SPI_MISO (master-in-slave-out) is not used in this project. We also need to set P0.1 to push-pull as this pin is used as the slave select signal (see the SPI discussion below). Note that P0.0 to P0.5 in the crossbar configuration must all be "skipped" to ensure that the SPI signals appear on the pins that are routed to the pins of the serial LCD interface.


This project uses three peripherals: SPI0, Timer2 and Timer4.

In the picture above, the watchdog timer is only checked because it has been deactivated as part of the hardware configuration process. SPI is a fairly simple serial communication interface capable of full duplex communication between a "master" and one or more "slaves".

The slave select signal generated by the SPI peripheral device (NSS in the diagram above) is not compatible with the LCD interface, which is why we have to send this signal manually via P0.1.

Timer2 is used to set the frame rate by triggering an LCD update on overflow. The LCD data sheet recommends a frame rate between 54 and 65 Hz. We have therefore configured Timer2 to overflow after 16.665 ms, which corresponds to 60 Hz:

Timer4 is used to implement short delays required by the serial interface of the LCD. The clock source is configured so that a Timer4 count is approximately 0.33 μs.


An interrupt is a hardware-controlled signal that causes the processor to execute a specific section of code. Interrupts are the primary means by which a microcontroller's firmware responds to important events, both internal (like a timer overflow) and external (like a transition from a low to a high voltage on a port pin). In this project, interrupts generated by Timer2 are used to schedule LCD updates according to the predetermined frame rate, and SPI0 interrupts control the code that handles serial communication with the LCD.


Fortunately, code required to configure the microcontroller and set up interrupt service routines is automatically generated by the hardware configuration tool. The rest of the code is mostly the following: the SPI state machine in Interrupts.c, the processing of LCD data and addresses in LCD.c, and the infinite loop that initiates LCD write events in SPI_Test_main.c. You can download all project and source files at the bottom of this page. The code is written using informative variable names and has many explanatory comments so it should be very helpful for you to understand the details of the firmware used in this project.

This flowchart illustrates the functionality of the state machine that controls SPI transmissions:

The following timing diagram for "All Clear Mode" shows the general characteristics of the serial interface between the microcontroller and the LCD. Further modes can be found in the data sheet of the LCD module.

The LCD is arranged as 128 horizontal lines of 128 pixels each. To create a horizontal black line across the display, we erase all pixels on white and then write all zeros to one line address. To create the scrolling effect, let's update the display as follows:

  • Timer2 overflows and causes an interrupt. Write the first line in black.
  • Timer2 overflows again. Write the same line on all white lines and increment the line address.
  • Timer2 overflows and we write the new line on all black, then another overflow and we delete the new line.
  • This continues until we have reached the last line, where the process begins with the address of the first line.

Download code


Next in line: Displaying Characters on an LCD Using an EFM8 Microcontroller

Give this project a try for yourself! Get the parts list.