40,81 €
Build safety-critical and memory-safe stand-alone and networked embedded systems
Key Features
Book Description
C++ is a great choice for embedded development, most notably, because it does not add any bloat, extends maintainability, and offers many advantages over different programming languages. Hands-On Embedded Programming with C++17 will show you how C++ can be used to build robust and concurrent systems that leverage the available hardware resources.
Starting with a primer on embedded programming and the latest features of C++17, the book takes you through various facets of good programming. You'll learn how to use the concurrency, memory management, and functional programming features of C++ to build embedded systems. You will understand how to integrate your systems with external peripherals and efficient ways of working with drivers. This book will also guide you in testing and optimizing code for better performance and implementing useful design patterns. As an additional benefit, you will see how to work with Qt, the popular GUI library used for building embedded systems.
By the end of the book, you will have gained the confidence to use C++ for embedded programming.
What you will learn
Who this book is for
If you want to start developing effective embedded programs in C++, then this book is for you. Good knowledge of C++ language constructs is required to understand the topics covered in the book. No knowledge of embedded systems is assumed.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 491
Veröffentlichungsjahr: 2019
Copyright © 2019 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Aaron LazarAcquisition Editor:Chaitanya NairContent Development Editor:Rohit Kumar SinghTechnical Editor:Ketan KambleCopy Editor: Safis EditingProject Coordinator:Vaidehi SawantProofreader: Safis EditingIndexer:Mariammal ChettiyarGraphics:Alishon MendonsaProduction Coordinator:Arvindkumar Gupta
First published: January 2019
Production reference: 1310119
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78862-930-0
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Maya Posch is a senior C++ developer with more than 15 years of experience. Discovering the joys of programming early on, and later the joys of electronics, she has always expressed a profound interest in technology, a passion that she gladly shares with others.
Describing herself as a C developer who happens to like C++ and Ada, she likes to seek the limits of what can be done with the minimum of code and hardware to accomplish everything that is cool, new, and exciting.
She also enjoys FPGA development, AI, and robotics research, in addition to creative writing, music, and drawing.
Frans Faase studied computer science at the University of Twente and received a master's degree in the field of compiler design and formal methods. He worked on some research projects in academia, but mostly worked as a software engineer in industry. He has about 20 years of experience of working with C++, both professional as recreational. He has contributed to several open source projects. Recently, he also gained some experience developing software for micro-controllers, mostly using the Arduino environment.
Patrick Mintram is a software engineer who has made his way up from electronics technician. He has made a career in the world of embedded systems, including developing and testing in a safety-critical environment and line-level repair and maintenance. He is married with two cats, Duke and Daisy, and spends his free time tinkering and running.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Hands-On Embedded Programming with C++17
About Packt
Why subscribe?
Packt.com
Contributors
About the author
About the reviewers
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
Section 1: The Fundamentals - Embedded programming and the role of C++
What Are Embedded Systems?
The many faces of embedded systems
Microcontrollers
TMS 1000
Intel MCS-48
Intel MCS-51
PIC
AVR
M68k and Z80-based
ARM Cortex-M
H8 (SuperH)
ESP8266/ESP32
Others
Challenges
System-on-Chip/Single Board Computer
Challenges
Summary
C++ as an Embedded Language
C++ relative to C
C++ as an embedded language
C++ language features
Namespaces
Strongly typed
Type conversions
Classes
Inheritance
Virtual base classes
Function inlining
Runtime type information
Exception handling
Templates
The standard template library
Maintainability
Summary
Developing for Embedded Linux and Similar Systems
Embedded operating systems
Real-time OSes
Custom peripherals and drivers
Adding an RTC
Custom drivers
Resource limitations
Example – club room monitoring
Hardware
Relays
Debounce
Debounce HAT
Power
Implementation
Listener
Club
HTTP request handler
Status handler
Data handler
Service configuration
Permissions
Final results
Example – basic media player
Summary
Resource-Restricted Embedded Systems
The big picture for small systems
Example – Machine controller for a laser cutter
Functional specification
The design requirements
Implementation-related choices
Embedded IDEs and frameworks
Programming MCUs
Memory programming and device debugging
Boot loader
Memory management
Stack and heap
Interrupts, ESP8266 IRAM_ATTR
Concurrency
AVR development with Nodate
Enter Nodate
Example – CMOS IC Tester
Usage
ESP8266 development with Sming
ARM MCU development
RTOS usage
Summary
Example - Soil Humidity Monitor with Wi-Fi
Keeping plants happy
Our solution
The hardware
The firmware
Setting up Sming
Plant module code
Makefile-user.mk
Main
OtaCore
BaseModule
PlantModule
Index.html
Compiling and flashing
First-time configuration
Using the system
Taking it further
Complications
Summary
Section 2: Testing, Monitoring
Testing OS-Based Applications
Avoiding real hardware
Cross-compiling for SBCs
Integration test for club status service
Mock versus hardware
Testing with Valgrind
Multi-target build system
Remote testing on real hardware
Summary
Testing Resource-Restricted Platforms
Reducing wear
Planning out a design
Platform-independent build systems
Using cross-compilers
Local and on-chip debugging
Example – ESP8266 integration test
The server
Makefile
The node
Makefile
Building the project
Summary
Example - Linux-Based Infotainment System
One box that does everything
Hardware needed
Software requirements
Bluetooth audio sources and sinks
Online streaming
Voice-driven user interface
Usage scenarios
Source code
Building the project
Extending the system
Summary
Example - Building Monitoring and Control
Plants, rooms, and beyond
Developmental history
Functional modules
Firmware source
Core
Modules
CO2 module
Jura
JuraTerm
Motion
PWM
I/O
Switch
Command and control server
Administration tool
Air-conditioning service
InfluxDB for recording sensor readings
Security aspects
Future developments
Summary
Section 3: Integration with other tools and frameworks
Developing Embedded Systems with Qt
The power of the right framework
Qt for command-line use
GUI-based Qt applications
Embedded Qt
Custom GUIs with stylesheets
QML
3D designer
An example of adding a GUI to the infotainment system
Main
QmlInterface
QML
Summary
Developing for Hybrid SoC/FPGA Systems
Going extremely parallel
Hardware description languages
FPGA architecture
Hybrid FPGA/SoC chips
Example – basic oscilloscope
The hardware
The VHDL code
The C++ code
Building the project
Summary
Best Practices
All the best-laid plans
Working with the hardware
The confusing world of peripherals
Knowing your tools
Choosing asynchronous methods
Reading the datasheet
Keeping interrupt handlers short
8-bit means 8 bits
Don't reinvent the wheel
Think before you optimize
Requirements are not optional
Documentation saves lives
Testing code means trying to destroy it
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
C++ does not add any bloat, extends maintainability, and offers many advantages over different programming languages, thus making it a good choice for embedded development. Do you want to build standalone or networked embedded systems and make them safety-critical and memory-safe? In this book, you will learn exactly how to do this. You will learn how C++ works and compares to other languages used for embedded development, how to create advanced GUIs for embedded devices in order to design an attractive and functional UI, and how to integrate proven strategies into your design for optimum hardware performance.
This book will take you through various embedded systems hardware boards so that you can choose the best one for your project. You will learn how to tackle complex architectural problems by fully embracing the proven programming patterns presented in the book.
If you want to start developing effective embedded programs in C++, then this book is for you. Good knowledge of C++ language constructs is required to understand the topics covered in the book. No knowledge of embedded systems is assumed.
Chapter 1, What Are Embedded Systems? makes you familiar with what an embedded system entails. By looking at the various categories and examples of embedded systems in each category, a good overview of what is meant with the term embedded and the wide variety within that term should be formed. It explores the wide range of historic and currently available microcontrollers and system-on-chip solutions you can find in existing systems as well as new designs.
Chapter 2, C++ as an Embedded Language, explains why C++ is actually as nimble as C and similar languages. Not only is C++ generally at least as fast as C, there is no additional bloat, and it offers many advantages with code paradigms and maintainability.
Chapter 3, Developing for Embedded Linux and Similar Systems, explains how to develop for Linux-based embedded systems and kin on SBCs and manage the differences between Linux-based and PC-based development.
Chapter 4, Resource-Restricted Embedded Systems,deals with planning for and using limited resources efficiently. We will take a look at how to select the right MCU for a new project and add peripherals and deal with Ethernet and serial interface requirements in a project. We will also look at an example AVR project, how to develop for other MCU architectures, and whether to use an RTOS.
Chapter 5, Example – Soil Humidity Monitor with Wi-Fi, explains how to create a Wi-Fi-enabled soil humidity monitor with actuator options for a pump or similar. Using the built-in web server, you can use its browser-based UI for monitoring and control, or integrate it into a larger system using its REST API.
Chapter 6, Testing OS-Based Applications, looks at how to develop and test embedded OS-based applications. You will learn how to install and use a cross-compilation toolchain, do remote debugging using GDB, and write a build system.
Chapter 7, Testing Resource-Restricted Platforms, shows how to effective develop for MCU-based targets. You will also see how to implement an integration environment that allows us to debug MCU-based applications from the comfort of a desktop OS and the tools it provides.
Chapter 8, Example – Linux-Based Infotainment System, explains how you can fairly easily construct an SBC-based infotainment system, using voice-to-text to construct a voice-driven UI. We will also look at how we can extend it to add even more functionality.
Chapter 9, Example – Building Monitoring and Control, shows how a building-wide monitoring and management system is developed, what its components looks like, and what lessons are learned during its development.
Chapter 10, Developing Embedded Systems with Qt, looks at the myriad of ways in which the Qt framework can be used to develop for embedded systems. We will look at how it compares with other frameworks and how Qt is optimized for these embedded platforms, before working through an example of a QML-based GUI that can be added to the previously-created infotainment system.
Chapter 11, Developing for Hybrid SoC/FPGA Systems, teaches you how to communicate with the FPGA side of a hybrid FPGA/SoC system and helps you understand how a variety of algorithms are implemented in FPGA and used on the SoC side. You will also learn how to implement a basic oscilloscope on a hybrid FPGA/SoC system.
Appendix, Best Practices, runs through a number of common issues and pitfalls that are likely to occur while working on an embedded software design.
A working knowledge of Raspberry Pi is required. You will need C++ compiler, the GCC ARM Linux (cross-) toolchain, the AVR toolchain, the Sming framework, Valgrind, the Qt framework, and the Lattice Diamond IDE.
You can download the example code files for this book from your account at www.packtpub.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packtpub.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Hands-On-Embedded-Programming-with-CPP-17. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
There are a number of text conventions used throughout this book.
CodeInText: Indicates code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "The C++ class itself is implemented in C as a struct containing the class variables."
A block of code is set as follows:
class B : public A { // Private members. public: // Additional public members. };
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
class B : public A { // Private members.
public:
// Additional public members. };
Any command-line input or output is written as follows:
sudo usermod -a -G gpio user
sudo usermod -a -G i2c user
Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "Compared to MCUs, SoCs are not as resource-limited, usually running a full operating system (OS) such as a Linux-derived OS, VxWorks, or QNX."
Feedback from our readers is always welcome.
General feedback: Email [email protected] and mention the book title in the subject of your message. If you have questions about any aspect of this book, please email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packtpub.com.
In this section the reader should become familiar with the many embedded platforms out there, along with a basic practical example project.
The following chapters will be covered in this section:
Chapter 1
,
What Are Embedded Systems?
Chapter 2
,
C++ as an Embedded Language
Chapter 3
,
Developing for Embedded Linux and Similar Systems
Chapter 4
,
Resource-Restricted Embedded Systems
Chapter 5
,
Example - Soil Humidity Monitor with Wi-Fi
Essentially , the embedded part of an embedded system refers to the state of being embedded into a larger system. The system that has been embedded is a computer system of some description, which has one or more very specific functions in the overall system, rather than being a general-purpose component. This larger system can be digital, mechanical, or analog in nature, while the additional integrated digital circuitry tightly interacts with data from and to interfaces, sensors and memory to implement the actual system functionality.
In this chapter, we will look at the following topics:
Different categories of embedded platforms
Examples of each category
Development challenges of each category
Every computerized function in today's devices is implemented using one or multiple microprocessors, meaning a computer processor (central processing unit, or CPU) usually contained in a single integrated circuit (IC). The microprocessor comprises at least the arithmetic logic unit (ALU) and control circuitry, but logically also registers, and input/output (I/O) banks, in addition to more advanced features commonly tailored to a specific product category (wearables, low power sensors, mixed signal, ...) or market (consumer, medical, automotive, ...).
At this point in history, almost all microprocessors are found in embedded systems. Even though people are likely to possess a computer, laptop, and smartphone, maybe even a tablet, the number of embedded microprocessors in a given household far dwarfs the number of general-purpose microprocessors.
Even within a laptop or PC, there are a number of embedded microprocessors in addition to its general-purpose CPU. These microprocessors have tasks like handling keyboard or mouse input, processing touch-screen inputs, converting streams of data into Ethernet packages, or creating video or audio output.
In older systems, such as the Commodore 64, this same pattern can be seen, with a CPU IC, sound IC, video IC, and so on. Whereas the CPU runs whatever code the application developer has written, the other chips in the system have very specific purposes, down to the controller IC for the floppy or hard disk drive.
Outside of general-purpose computers, we find embedded microprocessors everywhere, often in the form of even further integrated MCUs. They control kitchen devices, washing machines, and the engines of our cars, in addition to the higher-level functions and the processing of sensor information.
While the first microwaves were analog devices, using mechanical timers and variable resistors to set power level and duration, today's microwaves contain at least one microcontroller, which is responsible for handling user input, driving a display of some type, and configuring the microwave's systems. The display itself can have its own microcontroller, depending on the complexity of the chosen configuration.
Perhaps more excitingly, embedded systems also provide monitoring, automation and fail-safe features that keep airplanes flying, ensure that guided missiles and space rockets perform as intended, and enable ever-increasing possibilities in areas such as medicine and robotics. The avionics of an airplane constantly monitor countless parameters from a multitude of sensors, running the same code on its triple-redundant configuration to detect any possible glitches.
Tiny yet powerful microprocessors enable the rapid analysis of chemicals and DNA or RNA strands, which would have taken racks of equipment before. With the progress of technology, an embedded system has become small enough that it can be sent through the human body to monitor its health.
Beyond Earth, space probes and rovers on Mars, the Moon, and asteroids are performing a myriad of duties every day, again with the courtesy of well-tested embedded systems. The Moon missions themselves were made possible due to the first major example of an embedded system in the form of the Apollo Guidance Computer. This 1966-era embedded system consisted of wire-wrapped boards full of triple-input NOR logic gates, built for the explicit purpose of handling navigation, guidance, and control of the Command Module and Lunar Module launched by the Saturn V rockets.
The ubiquitous and versatile nature of embedded systems has made them an inseparable part of modern life.
For embedded systems, they are usually distinguished between the following categories:
Microcontrollers
(
MCUs
)
System-on-Chip
(
SoC
), often as a
Single-Board Computer
(
SBC
)
One of the driving factors of innovation in the field of embedded systems is cost, since they will often be high-volume, cheap consumer products. To that end, it helps to have the entire microprocessor, memory, storage, and input/output peripherals on a single chip, simplifying implementation effort, reducing PCB real estate, all with the added benefit of faster and simpler design and production with higher yield. This led to the development of microcontrollers (MCUs) during the 1970s: single-chip computer systems that could be added to a new design for a minimal cost.
With the introduction of Electrically Erasable Programmable Read-Only Memory (EEPROM) to MCUs in the early 1990s, it first became possible to rewrite the program memory of MCUs repeatedly without having to resort to erasing memory content using ultraviolet light through a special quartz window in the MCU's packaging. This allowed for much easier prototyping and further reduced cost and - as far as development and lower-volume production is concerned - in-circuit programming.
As a result of this, many systems that were previously controlled by intricate mechanical and analog mechanisms (like elevators and temperature controllers) now contain one or more MCUs, which handle the same functionality while reducing costs and increasing reliability. By having the features handled in software, developers were also free to add advanced features such as complex preset programs (for washing machines, microwaves, and so on) and simple to complex displays to provide feedback to the user.
The first commercially available MCU was Texas Instrument's TMS 1000, a general-purpose 4-bit, single-chip system. It was first made available for sale in 1974. The original model had 1 KB of ROM, 64 x 4 bits of RAM, and 23 I/O pins. They could be clocked at speeds from 100 to 400 KHz, with each instruction executing in six clock cycles.
Later models would increase the ROM and RAM sizes, though the basic design remained largely unchanged until production ceased in 1981:
The size of the MCU die was roughly 5 x 5 millimeters, small enough to fit in a DIP package. This type of MCU used mask-programmable ROM, meaning that you could not get a blank TMS 1000 chip and program it. Instead, you would have to send the debugged program to Texas Instruments to have it physically produced using a photolithography mask, resulting in a metallic bridge for each bit.
Being a fairly primitive design (relative to later MCUs), it lacked a stack and interrupts, had a set of 43 instructions and two general-purpose registers, making it quite similar to the Intel 4004 CPU. Some models had special peripherals for driving vacuum fluorescent displays (VFD) and for continuously reading inputs to handle user input via a keyboard without interrupting the main program. Its basic pinout looked as follows:
Obviously the pin functions predate the general purpose input/output (GPIO) pins we know today - the K pins can only be used for input, while output pins are denoted as O and control pins are marked with R. The OSC pins are to be connected to an external oscillator circuit. Much like with discrete logic ICs, the Init pin is used to initialize the chip on power-up and has to be kept high for at least six cycles, whereas recent MCUs have integrated Power-On Reset (POR) and a reset pin that needs at most a discrete resistor and capacitor.
According to the original Texas Instruments press release from 1974, these microcontroller could be had for as little as $3 or less if you bought them in large quantity. They would be used in popular toys such as the Speak and Spell, but also just about everywhere else, including household appliances, automobiles, and scientific equipment. By the time production ceased in the early 1980s, many millions had been sold.
It's also interesting to note that while one-time programmable low cost microcontrollers have gone down in price a lot, the class of products has persevered - as an example, the Padauk PMS150C can now be had for $0.03 and whilst offering an 8 bit architecture, its 1K words of ROM and 64 bytes of RAM sound oddly familiar.
Intel's response to Texas Instrument's successful TMS 1000 MCU was the MCS-48 series, with the 8048, 8035, and 8748 being the first models released in 1976. The 8048 has 1 KB of ROM and 64 bytes of RAM. It is an 8-bit design with a Harvard architecture (split code/data memory), introducing a native word size of 8 bits and interrupt support (two single-level) and is compatible with 8080/8085 peripherals, making it a highly versatile MCU. The advantage of wider ALU and register word sizes is still perceivable today, where for example a 32 bit addition is sequentially executed on an 8 bit MCU as a series of 8 bit additions with carry.
The MCS-48 features over 96 instructions, most of them a single byte in length, and allows for external memory to be added in addition to the internal memory. In a community effort, available information on the MCS-48 family has been compiled and released at https://devsaurus.github.io/mcs-48/mcs-48.pdf .
Here we consider the simplicity of the MCS-48 functional block diagram and compare it to that of its successors as follows:
Even for a design that was introduced just a few years after the TMS 1000, the rapid evolution of MCU designs is evident. Since MCU design evolved alongside popular CPU designs of the time, including the 6502, its 16-bit version, and what would eventually become the M68K processor family, there are many similarities to be found.
Due to its flexible design, it remained popular and in production until the 1990s, until the MCS-51 (8051) series gradually replaced it. See the next section for more details on the 8051.
The MCS-48 was used in the keyboard of the original IBM PC as its controller. It was also used with the 80286 and 80386 to perform A20 line gating and reset functions in the case of the former. Later PCs would integrate these features into Super I/O devices.
Other notable uses of the MCS-48 include the Magnavox Odyssey video game console and a range of Korg and Roland analog synthesizers. While masked ROM (up to 2 KB) was an option with the MCS-48 family, the 87P50 used an external ROM module for its programming, and the 8748 and 8749 featured up to 2 KB EPROM, which allowed for the MCU's internal programming to be altered repeatedly.
Like with standalone EPROM modules, this requires the package to contain a fused quartz window, which allows for ultraviolet light to reach the MCU die, as can clearly be seen in the following photograph of an 8749 MCU with EPROM (by Konstantin Lanzet, CC BY-SA 3.0):
The charge stored in the EPROM cells that defines bits as written dissipates within a 20-30 minute exposure to strong ultraviolet light. The same can be achieved in direct sunlight over the course of a few weeks. The erase cycle usually implies removing the package and putting it in the light tight erasing device. After this, the EPROM can be programmed anew. The specified data retention of an EPROM is about 10-20 years at 85°C, and because the degradation accelerates exponentially with temperature, statements of 100 years or more at room temperature are not uncommon (27C512A: 200 years).
Due to the expense of creating the quartz window and integrating it into the package, one-time programmable EPROMs were used for a while, which allow for the easy programming of an EPROM, but mounted the programmed die in an opaque package so that it could not be reprogrammed any more. Ultimately, EEPROMs became available in the early 1980s, which replaced EPROMs almost completely. EEPROMs can be rewritten about a million times before they begin to develop issues when retaining stored data. Their data retention performance is similar to that of EPROMs.
Recent chips from Cypress CY7C68013A (USB peripheral controller) to Ti CC2541 (a Bluetooth SoC) feature commodity 8051 cores, demonstrating that the Intel MCS-51 family design remains popular to this day. There's a plethora of derived MCUs by other manufacturers as well, even though Intel stopped producing this series of MCUs in March of 2007. First introduced in the 1980s, it's an 8-bit MCU like the 8048, but expands heavily on its feature set.
The functional block diagram as depicted in the Intel 80xxAH datasheet is shown as follows:
It's very similar to the Atmel (now microchip) AT89S51 which is still in production today.
Datasheets commonly address size and performance metrics in a Features list, as quoted below for the AT89S51:
4K Bytes of
in-system programmable
(
ISP
) flash memory - Endurance: 10,000 write/erase cycles (was 1,000,000 for EEPROM)
4.0 V to 5.5 V operating range
Fully static operation: 0 Hz to 33 MHz (was 12 MHz)
Three-level program memory lock
128 x 8-bit internal RAM
32 programmable I/O lines
but then the list goes on with modern core, peripheral, low power and usability features:
Two 16-bit timer/counters
Six interrupt sources
Full duplex UART serial channel
Low-power Idle and power-down modes
Interrupt recovery from power-down mode
Watchdog timer
Dual data pointer
Power-off flag
Fast programming time
Flexible ISP programming, byte- and page-mode
The only major changes to the 8051 architecture over the past decades involved migrating from the original n-type metal oxide semiconductor (NMOS) transistor technology to complementary MOS (CMOS) – usually denoted as 80C51 – and more recently the addition of USB, I2C, and SPI interfaces, as well as advanced power management and debugging interfaces that have become ubiquitous since the beginning of this century. The Atmel application note 3487A doesn't give a concise explanation for the letter S, however the then new in-circuit serial programming (ISP) might thereby be highlighted.
The pinout diagram of the AT89S51 documents the SPI pins (MOSI, MISO, SCK):
Beyond standalone MCUs, 8051 cores are also integrated into larger systems where a low-power, basic MCU is dedicated to diverse, low speed, real-time or high I/O count tasks. A broad range of chips from the likes of Ti CC2541 (Bluetooth low energy SoC) to Cypress CY7C68013A (FX2LP™ USB peripheral controller) underline the utility and relevance of the 8051 architecture to this day.
In field-programmable gate array (FPGA) or application specific integration circuit (ASIC) development, 8051-type processors are also commonly deployed as soft cores, where they are adapted and added to VHDL and Verilog HDL projects to handle tasks that lend themselves better to sequential execution without the need for tight timing or large bandwidth. Last but not least, the charm of soft cores lies in the ability to use full-featured development and debugging tools while maintaining tight integration with the remaining hardware design. The equivalent of only a few hundred bytes of program code run by a soft core might well be a large state machine, memories, counters and ALU-like logic, all of which raises the question which implementation is easier to validate and maintain.
The PIC family of MCUs was first introduced in 1976 by General Instrument, using their new CP1600 16-bit CPU. This CPU was nearly compatible with the PDP-11 series of processors with its instruction set.
In 1987, General Instrument spun off its microelectronics division to create Microchip Technology, which became an independent company in 1989. Microchip technology produces new PIC designs to this day. Alongside the evolution of PIC cores and peripherals, on-chip memory technology development yielded the introduction of light tight encapsulated EPROM for on-time programmable and later EEPROM for in-circuit reprogramming capabilities. Like most MCUs, PIC MCUs have a Harvard architecture. Today, PIC designs range from 8-bit to 32-bit, with a wide range of features. These are the PIC families as the time of writing this book:
Family
Pins
Memories
Details
PIC10
6-8
384-896 bytes ROM, 64-512 bytes RAM
8-bit, 8-16 MHz, modified Harvard
PIC12
8
2-16 KB ROM, 256 bytes RAM
8-bit, 16 MHz, modified Harvard
PIC16
8-64
3.5-56 KB ROM, 1-4 KB RAM
8-bit
modified Harvard
PIC17
40-68
4-16 KB ROM, 232-454 bytes RAM
8-bit, 33 MHz, superseded by the PIC18, though third-party clones exist.
PIC18
28-100
16-128 KB ROM, 3,728-4,096 bytes RAM
8-bit modified Harvard
PIC24 (dsPIC)
14-144
64-1,024KB ROM, 8-16 KB RAM
16-bit, DsPIC (dsPIC33) MCUs have digital signal processing (DSP) peripherals built in.
PIC32MX
64-100
32-512 KB ROM, 8-32 KB RAM
32-bit, 200 MHz MIPS M4K with MIPS16e mode, released in 2007.
PIC32MZ EC
PIC32MZ EF
PIC32MZ DA
64-288
512-2,048 KB ROM, 256-640 KB static RAM (32 MB DDR2 DRAM)
32-bit, MIPS ISA (2013), PIC32MZ DA version (2017) having a graphics core. Core speeds of 200 MHz (EC, DA) and 252 MHz (EF).
PIC32MM
20-64
16-256 KB RAM, 4-32 KB RAM
32-bit microMIPS, 25 MHz, variant optimized for low cost and low power.
PIC32MK
64-100
512-1,024 KB ROM, 128-256 KB RAM
32-bit, 120 MHz, MIPS ISA, variant introduced in 2017. Targeted at industrial control and other forms of deeply integrated applications.
The PIC32 families are interesting in that they're based on an MIPS processor core, and use this Instruction Set Architecture (ISA) instead of the PIC ISA that's used by all other PIC MCUs. The processor core design they share is the M4K, a 32-bit MIPS32 core from MIPS Technology. Between these families, the differences are easy to spot when looking at the block diagrams from their respective datasheets.
The decades of development in the PIC line of microcontrollers are perhaps best made tangible in the form of functional block diagrams, so we start by looking at the PIC10:
These are very small MCUs, with barely any peripherals around a processor core not more closely defined here—and the referenced table only mentions the memory layout. The I/O port is very minimal and the I2C and UART interfaces we know today are not implemented as peripheral logic. To pick an example for a controller next in line, the PIC16F84 datasheet is very detailed in terms of processor architecture and shows that more power-up and reset circuitry has been added while also expanding GPIO and adding EEPROM for easy integrated non-volatile storage. Self-contained serial peripherals are still absent.
Next, we'll have a look at the PIC18:
The PIC18 family is the latest 8-bit PIC architecture, with MCUs covering a wide range of applications. It has significantly more I/O options than the PIC10, PIC12, and PIC16 families, while also offering more options in terms of ROM and RAM and now providing USART in conjunction with a synchronous serial port for 4-wire SPI. Also note that the ports now have alternate pin functions and the routing from peripherals to the pins and the corresponding configuration registers are not shown for simplicity.
Next, let's observe the focus shifting from the core to Port and Peripheral capabilities in the PIC24 functional block diagram:
The diagram is similar to that of the PIC10, with the CPU abstracted away as a single block relative to the rest of the MCU. Each of the PORT blocks being a set of I/O pins, we're running out of space to display all the possible pin functions.
Each I/O pin can have a fixed function (linked with a peripheral module), or have an assignable function (hardware-level rerouting, or done in software). Generally, the more complex the MCU, the more likely it is that I/O pins are generic and not fixed-function.
Finally we have look at the PIC32:
This block diagram is for PIC32MX1XX/2XX devices in the PIC32MX family. It is usually clocked at 50 MHz.
An interesting property of the PIC32 architecture is that it effectively turns the Harvard architecture M4K MIPS CPU into a more John von Neumann-like architecture by having both program instructions and data travel over the System Bus Matrix. Note that the space dedicated to a single processor register in the PIC10 diagram now casually depicts a complex digital or mixed signal peripheral, or the powerful JTAG in-circuit programming and debugging interface.
The AVR architecture was developed by two students at the Norwegian Institute of Technology, with the original AVR MCU developed at Nordic VLSI (now Nordic Semiconductor). It was originally known as μRISC and available for licensing until the technology was sold to Atmel. The first Atmel AVR MCU was released in 1997.
Today, we can look back on a multitude of 8-bit AVR families:
Family
Pins
Memories
Details
ATtiny
6-32
0.5-16KB ROM 0-2 KB RAM
1.6-20 MHz. Compact, power-efficient MCUs, with limited peripherals.
ATmega
32-100
4-256 KB ROM 0.5-32 KB RAM
ATxmega
44-100
16-384 KB ROM, 1-32 KB RAM
32 MHz, largest AVR MCUs, with extensive peripherals and performance-enhancing features such as DMA.
There also used to be an 32-bit AVR32 architecture, but it was deprecated by Atmel as it moved to the ARM 32-bit architecture instead (SAM). See the ARM-based MCU section for more details on SAM. More detailed information is found in the corresponding Product Selection Guide.
Additionally, Atmel used to have so-called Field Programmable System Level Integrated Circuit (FPSLIC) MCUs: hybrid AVR/FPGA systems. These essentially allowed you to add your own peripherals and functionality to the hardware of an AVR MCU.
Let's look at the ATtiny family. This is the block diagram of the ATtiny212/412 series of MCUs:
This series of ATtiny MCUs can run up to 20 MHz, with up to 4 KB of Flash ROM and 256 bytes of SRAM, as well as up to 128 bytes of EEPROM, all in an 8-pin package. Despite its small size, it has a large number of peripherals, which can be routed to any supported pin:
Contrast this with the popular ATmega2560 and related MCUs, which have the following properties:
Device
Flash (KB)
EEPROM (KB)
RAM (KB)
General purpose I/O pins
16-bit PWM channels
UART
ADC channels
ATmega640
64
4
8
86
12
4
16
ATmega1280
128
4
8
86
12
4
16
ATmega1281
128
4
8
54
6
2
8
ATmega2560
256
4
8
86
12
4
16
ATmega2561
256
4
8
54
6
2
8
With GPIO pins numbering in the dozens, the block diagram is correspondingly more complex, with many more port blocks for the I/O pins:
Here, all the incoming and outgoing arrows indicate a single pin or block of pins, most of them general-purpose. Because of the large number of pins, it is no longer practical to use an inline package format (DIP, SOIC, and so on) for the physical chip.
For the ATmega640, 1280 and 2560, a 100-pin TQFP package is used, here with the functionality of each pin indicated as found in its datasheet:
The ATxmega family is very similar to the ATmega, with a similar pinout, mostly differentiating themselves using architectural changes and optimizations, more ROM and RAM, and peripheral options.
Whether to pick an ATtiny, ATmega, or ATxmega MCU depends first and foremost on the requirements you have for your project, specifically the required input and output, types of peripherals (serial, SPI, I2C, CAN, and so on), and the size of both the code and the RAM required to run this code.
The Zilog Z80 8-bit processor is an Intel 8080-compatible processor, which competed with other microprocessors during the 1980s, powering home computers and gaming systems including the Nintendo Game Boy, Sega Master System, Sinclair ZX80/ZX81/Spectrum, MSX, and Tandy TRS-80.
Zilog introduced an MCU (Z380) based around the Z80 microprocessor in 1994, with various updates over the years, including the Z8, eZ80, and others. Z80 clones are also quite common.
Another popular 1980s era microprocessor is the Motorola 68k (or 68000). It's 16-bit for its ALU and external data bus, but with 32-bit registers and 32-bit internal data bus. After its introduction in 1979, its architecture is still in use today, with Freescale Semiconductor (now NXP) producing a number of 68k microprocessors.
Motorola introduced numerous MCUs based around the 68k architecture, including the MC68320 communications controller in 1989. Current 68k-based MCU designs include the ColdFire, which is a fully 32-bit design.
A very common type of 32-bit MCU is the ARM Cortex-M family. It includes the M0, M0+, M1, M3, M4, M7, M23, and M33, with a number of them having a floating point unit (FPU) option for increased floating point performance.
Not only are they used as standalone MCUs, they are also commonly integrated into System-on-Chip (SoC) devices to provide specific functionality, such as touchscreen, sensor, or power management functionality. As Arm Holdings doesn't manufacture any MCUs themselves, many third-party manufacturers have licensed the designs, sometimes making their own modifications and improvements.
Here is a brief overview of these MCUs:
Core
Announced
Architecture
Instruction set
M0
2009
Armv6-M
Thumb-1, some of Thumb-2.
M0+
2012
Armv6-M
Thumb-1, some of Thumb-2.
M1
2007
Armv6-M
Thumb-1, some of Thumb-2.
M3
2004
Armv7-M
Thumb-1, Thumb-2.
M4
2010
Armv7-M
Thumb1, Thumb-2, optional FPU.
M7
2014
Armv7E-M
Thumb-1, Thumb-2, optional FPU.
M23
2016
Armv8-M
Thumb-1, some of Thumb-2.
M33
2016
Armv8-M
Thumb 1, Thumb-2, optional FPU.
The Thumb instruction sets are compact, 16-bit-length instructions, making them ideal for embedded, resource-restricted systems. Other ARM microprocessor families can also support this Thumb instruction set in addition to the 32-bit instruction set.
H8 family MCUs were commonly used with 8-, 16-, and 32-bit variations. Originally created in the early 1990s by Hitachi, new designs were still being created by Renesas Technology until a few years ago, though the latter recommends new designs use the RX (32-bit) or RL78 (16-bit) families. A notable use of an H8 MCU is in the Lego Mindstorms RCX controller, which uses an H8/300 MCU.
The ESP family are 32-bit MCUs that are produced by Espressif Systems, with integrated Wi-Fi (both) and Bluetooth (ESP32) functionality.
The ESP8266 first appeared in 2014, when it was sold by a third-party manufacturer, Ai-Thinker, in the form of a module (ESP-01) that could be used by another MCU or microprocessor-based systems to provide Wi-Fi functionality. The ESP-01 module contained firmware for this purpose, which allowed the module to be addressed using Hayes-style modem commands.
Its system specifications are as follows:
Tensilica Xtensa Diamond Standard L106 microprocessor (32-bit)
80-160 MHz CPU speed
Less than 50 KB of RAM available for user applications (with Wi-Fi stack loaded)
External SPI ROM (512 KB to 16 MB)
Wi-Fi support for 802.11 b/g/n
As the 32-bit MCU on the ESP-01 module was found to be capable of far more than the simple modem task assigned to it, it soon came to be used for more general-purpose tasks, with a range of upgraded ESP8266 modules (with integrated EEPROM chip), as well as breakout boards. Of the latter, the NodeMCU-style board has become very popular, though a number of other third-party manufacturers have made their own breakout boards, which provide different form factors and functionality.
The basic block diagram for the ESP8266EX looks as follows:
After the immense success of the ESP8266, Espressif Systems developed the ESP32, which used an upgraded, dual-core CPU, among other changes. Its block diagram looks like this:
Its specifications are as follows:
Xtensa 32-bit LX6 (dual-core) microprocessor
160-240 MHz CPU speed
520 KB of SRAM
Wi-Fi support for 802.11 b/g/n
Bluetooth v4.2 and BLE (low energy)
Both the ESP8266 and ESP32 are generally sold as complete modules, with the MCU, external ROM module, and a Wi-Fi antenna either integrated into the board or with an external antenna option:
The metal shielding can covering the board helps to protect the board from electromagnetic interference, benefiting its Wi-Fi (and Bluetooth, in the case of the ESP32) transceiver, but the whole design with a fixed antenna and geometry is required for FCC certification and later use as an approved module. Connecting an external antenna with higher gain may violate local regulations. The FCC ID it comes with is instrumental in getting a product containing such a module approved for commercialization.
In addition to the previously listed MCUs, there is a wide range of MCUs available from a number of manufacturers with different architectures. Some, like the Propeller MCU from Parallax with its multi-core architecture, are fairly unique, whereas most simply implement the usual single-core CPU architecture with a number of peripherals, RAM, and internal or external ROM.
Beyond physical chips, Altera (now Intel), Lattice Semiconductor, and Xilinx provide so-called soft cores, which are MCUs that are meant to be run on a FPGA chip, either as standalone components or as part of a larger design on that FPGA. These can also be targeted by C/C++ compilers.
The main development challenges with MCUs lie in the relatively limited resources that are available. Especially with the small, low-pin-count MCUs, you have to have a good idea of how many resources (CPU cycles, RAM, and ROM) a particular piece of code takes up, and whether it's realistic to add a specific feature.
This also means that picking the right MCU for a particular project takes both technical knowledge and experience. The former is required to pick an MCU that will suit the task; the latter is very helpful for the optimal MCU and helps to shorten the time that's required to make a choice.
Systems-on-Chips (SoCs) are similar to MCUs, but distinguish themselves from those types of embedded systems by having some level of integration while still requiring a number of external components to function. They are commonly found as part of a single board implementation (Single Board Computer (SBC)), including the PC/104 standard, and more recently form factors such as the Raspberry Pi and derivative boards:
This diagram was used from https://xdevs.com/article/rpi3_oc/. It clearly shows how an SBC (in this case, the Raspberry Pi 3) is laid out. The BCM2837 is the ARM-based SoC, providing the CPU core and basic peripherals (mostly broken out into the header section). All of the RAM is in an external module, as are the Ethernet and Wi-Fi peripherals. ROM is provided in the form of an SD (Flash) card, which also provides storage.
Most SoCs are ARM-based (Cortex-A family), though MIPS is quite common as well. SBCs are commonly used in industrial settings.
Other instances are mass produced boards, such as those for smartphones, which do not form a predefined form factor, but still follow the same pattern of having the SoC and external RAM, ROM, and storage, as well as various peripherals. This is in contrast with the MCUs of the previous section, which would always be able to function by themselves, except for the few requiring an external ROM.
Compared to MCUs, the development challenges of SoCs tend to be far less severe. Some of them are on the level and have an interface where you can even develop directly on the device, even doing compilation cycles on the device without having to do cross-compilation on a PC and copying over the binary. This is also helped by running a full OS instead of developing for the bare hardware.
The obvious disadvantage is that with this increase in features comes an increase in complexity, and the resulting complications, such as having to deal with user accounts, setting permissions, managing device drivers, and so on.
In this chapter, we got an in-depth look at what constitutes an embedded system. We learned how to distinguish between the various types of embedded systems, as well as how to determine the basics of picking the right MCU or SoC for a project.
After this chapter, the reader should feel comfortable reading through datasheets for MCUs and SoCs, explaining the differences between both, and determining what is needed for a given project.
The next chapter will look at why C++ is a highly suitable choice for the programming of embedded systems.
When it comes to embedded development on resource-restricted systems, it is still common to consider only C and ASM as viable choices, accompanied by the thought that C++ has a larger footprint than C, or adds a significant amount of complexity. In this chapter, we will look at all of these issues in detail and consider the merits of C++ as an embedded programming language:
C++ relative to C
Advantages of C++ as a multi-paradigm language
Compatibility with existing C and ASM
Changes with C++11, C++14, and C++17
The lineages of C and C++ both trace their lineage back to the ALGOL programming language, which saw its first version in 1958 (ALGOL 58), followed by updates in 1960 and 1968. ALGOL introduced the concept of imperative programming—a programming style in which statements explicitly tell the machine how to make changes to data for output and control flow.
A paradigm that emerges rather naturally from imperative programming is the use of procedures. We will start with an example, to introduce the terminology. Procedures are synonymous to sub-routines and functions. They identify the groups of statements and make them self-contained, which has the effects of confiningthereachofthese statements to the limited scope of the section they are contained within, creating hierarchy and consequentially introducing these procedures as new, more abstract statements. Heavy use of this procedural programming style finds its place in so-called structured programming, alongside loop and branching control structures.
Over time, structured and modular programming styles were introduced as techniques to improve the development, quality and maintainability of application code. The C language is an imperative, structured programming languagedue to its use ofstatements, control structuresandfunctions.
Take, for example, the standard Hello World example in C:
#include <stdio.h> int main(void) { printf("hello, world"); return 0; }
The entry point of any C (and C++) application is the main() function (procedure). In the first statement line of this function, we call another procedure (printf()), which contains its own statements and possibly calls other blocks of statements in the form of additional functions.
This way we have already made use of procedural programming by implementing a main() logical block (the main() function), which is called as needed. While the main() function will just be called once, the procedural style is found again in the printf() statement, which calls the statements elsewhere in the application without having to copy them explicitly. Applying procedural programming makes it much easier to maintain the resulting code, and create libraries of code that we can use across a number of applications, while maintaining only a single code base.
In 1979, Bjarne Stroustrup started work on C with Classes, for which he took the existing programming paradigms of C and added elements from other languages, in particular Simula (object-oriented programming: both imperative and structured) and ML (generic programming, in the form of templates). It would also offer the speed of the Basic Combined Programming Language (BCPL), without restricting the developer to its restrictive low-level focus.
The resulting multi-paradigm language was renamed to C++ in 1983, while adding additional features not found in C, including operator and function overloading, virtual functions, references, and starting the development of a standalone compiler for this C++ language.
The essential goal of C++ has remained to provide practical solutions to real-world issues. Additionally, it has always been the intention for C++ to be a better C, hence the name. Stroustrup himself defines a number of rules (as noted in Evolving C++ 1991-2006) that drive the development of C++ to this day, including the following:
C++'s evolution must be driven by real problems
Every feature must have a reasonably obvious implementation
C++ is a language, not a complete system
Don't try to force people to use a specific programming style
No implicit violations of the static type system
Provide as good support for user-defined types as for built-in types
Leave no room for a lower-level language below C++ (except assembler)
What you don't use, you don't pay for (zero-overhead rule)
If in doubt, provide means for manual control
The differences relative to C obviously goes beyond object-oriented programming. Despite the lingering impression that C++ is just a set of extensions to C, it has for a long time been its own language, adding a strict type system (compared to C's weak type system at that time), more powerful programming paradigms, and features not found in C. Its compatibility with C can therefore be seen more as coincidence, with C being the right language at the right time to be used as a foundation.
The problem with Simula at the time was that it was too slow for general use, and BCPL was too low-level. C, being a relatively new language at the time, provided the right middle ground between features and performance.
Around 1983 when C++ had just been conceived and got its name, popular personal computer systems for a general audience, as well as businesses, had specifications like ones listed in the following table:
System
CPU
Clock speed (MHz)
RAM (KB)
ROM (KB)
Storage (KB)
BBC Micro
6502 (B+ 6512A)
2
16-128
32-128
Max 1,280 (ADFS floppy)
Max 20 MB (hard drive)
MSX
Zilog Z80
3.58
8-128
32
720 (floppy)
Commodore 64
6510
~1
64
20
1,000 (tape)
170 (floppy)
Sinclair ZX81
Zilog Z80
3.58
1
8
15 (cartridge)
IBM PC
Intel 8080
4.77
16-256
8
360 (floppy)
Now compare these computer systems to a recent 8-bit microcontroller (MCU) such as the AVR ATMega 2560 with the following specifications:
16 MHz clock speed
8 KB RAM
256 KB ROM (program)
4 KB ROM (data)
The ATMega 2560 was launched in 2005 and is among the more powerful 8-bit MCUs available nowadays. Its features stack up favorably against the 1980s computer systems, but on top of that the MCU does not rely on any external memory components.
The MCU core clock speed is significantly faster these days thanks to improved silicon IC manufacturing processes which also provide smaller chip sizes, high throughput, and thus lower cost and what's more, 1980s architectures commonly took 2 to 5 clock cycles to retrieve, decode, execute an instruction and store the result as opposed to the single-cycle execution performance of the AVR.
Current MCU (Static) RAM limitations are mostly due to cost and power constraints yet can be easily circumvented for most MCUs using external RAM chips, along with adding low-cost flash-based or other mass storage devices.
Systems like the Commodore 64 (C64) were routinely programmed in C, in addition to the built-in BASIC interpreter (in a built-in ROM). A well-known C development environment for the Commodore 64 was Power C published by Spinnaker:
Power C was one brand of productivity software aimed at C developers. It came on a single, double-sided floppy disk and allowed you to write C code in an editor, then compile it with the included compiler, linker, header files, and libraries to produce executables for the system.
Many more of such compiler collections existed back then, targeting a variety of systems, showing the rich ecosystem that existed for software development. Among these, C++ was of course a newcomer. The first edition of Stroustrup's The C++ Programming Language was only being published in 1985, yet initially without a solid implementation of the language to go with it.
