2. Embedded Systems - RIT-Launch-Initiative/Liftoff-Project GitHub Wiki

Intro

Alright now for the fun stuff. When developing embedded systems, your software will be running on microcontrollers and not your own development machine. These systems are usually resource constrained in terms of processing and memory.

GPIO

Microcontrollers will have pins known as General Purpose Input Output (GPIO). These pins can generate signals that are high (1) or low (0). For example, if a microcontroller was to power on an LED, you would set the GPIO connected to that LED to high.

Communicating With Peripherals

There are many protocols that you should expect to be using for your microcontroller to communicate with other devices (on and off the PCB). GPIO pins can be repurposed to generate specific signals that make up a protocol standard. If you want to know what an abbreviation I mention is, you can look it up (or scroll down and hope I linked a resource for you). Here are the main three you are expected to know

UART

Universal Asynchronous Receiver Transmitter or UART is a way for serial data to be exchanged using two wires (Tx and Rx). This is normally used to communicate between two separate devices. The most common use you will find is getting print statements from your microcontroller to your computer. Since your application will run on another device, you cannot use the print statements you would normally use in most of your code.

image

I2C

I2C is a two wire protocol (SDA, SCL) where there is one controller and multiple peripherals. Normally your microcontroller will be the controller and your peripherals will be sensors on the same board as the microcontroller. Peripheral devices will not transmit data unless it is addressed by its controller. In order for a microcontroller to address a peripheral, it must be given the peripherals I2C address. I2C addresses are normally 7 bit numbers (there is also 10 bit, but we most likely will never use this) meaning that addresses can only be from 0 - 127.

image

SPI

Serial Peripheral Interface or SPI is a four wire protocol (MISO, MOSI, SCLK and CS). Just like I2C, SPI has one controller and several peripherals. MISO and MOSI may also be known as Data In and Data Out, due to controversy. In order for data to be transmitted, the controller first sets the chip select of the peripheral device to low before transmitting out of its MOSI pin into the peripheral's MISO pin. Then chip select is brought back to high. The benefit to SPI compared to I2C is speed, but at the cost of reliability when it comes to error handling.

image

Interrupts

This is an especially important topic. In computing, interrupts ensure more efficient use of the CPU compared to polling. Polling is a blocking operation, where the CPU spinlocks (think of a while loop) until certain conditions are met. They are called interrupts because it will interrupt the current execution to do the work it needs to and therefore should run as fast as possible to return to main execution ASAP. Instead of the CPU constantly checking for keyboard input from a user (polling) which takes up precious clock cycles, an interrupt signal is sent to the CPU that then gets the CPU to handle input. Interrupts also enable exceptions in higher level languages like Python and Java to work. In our context, we use interrupts to do other work while waiting for data from a peripheral like a sensor. Once the CPU is ready to handle I/O an interrupt occurs to carry out the necessary operations such as reading and writing to the data bus. There are also external interrupts where a peripheral can send a signal to a GPIO pin connected to the CPU to trigger some action that is up to the programmer. Polling should be avoided in general to ensure our software can control the hardware in an efficient manner.

image

Hardware Abstraction Layer

Writing software to communicate with hardware directly can be extremely complicated. Fortunately, microcontroller manufacturers will make a hardware abstraction layer, which is an API for controlling the hardware. This means you don't need to manually set registers with specific values to do things like set up a hardware clock, initialize bus controllers, generate electrical signals, etc. There are also specialized functions in the STM32 HAL that handles interrupts for you. In these exercises you will learn how to use the STM32 HAL to experiment with most of the above mentioned topics.

Exercises (Estimated Time: 30 minutes)

DISCLAIMER: No hardware at the moment, but please try to experiment with the HAL 0. Make sure you have the ARM Toolchain set up. You will be doing all your work within the EmbeddedSystems folder. To compile your code create a new folder within which can be named whatever you want, but "build" is preferable. Within that new directory run cmake ... This will read the CMakeLists.txt file in the EmbeddedSystems folder and generate a Makefile which can then be compiled when you enter make

  1. You will learn GPIO by blinking an LED connected to an F446 Nucleo. Read the comments for the function named gpio_practice
  2. You will be using UART to send characters for your computer to receive and print. Read the comments for the function named uart_practice.
  3. You will be using I2C to read sensor data from a temperature sensor. Read the following datasheet to know what I2C address to use and its memory address to read from. Furthermore, you will look in the associated i2c header to know what functions to use. You will need to implement i2c_practice. Afterwards, call your uart_practice function from i2c_practice to send the data to your terminal to verify you are getting the correct values.
  4. Finally, you will do the same thing you did for i2c_practice, but using HAL SPI functions. You know what to do here :)

Additional Resources

Common Pin Abbreviations

Digikey I2C Guide

Digikey SPI Guide

Nucleo F446RE Pinout

ARM Cortex M4 User Guide