Everything in this file comes from the Raspberry Pi Pico for C/C++ SDK and Prof. Hunter Adams's SDK Architecture page. This file contains all of the same content, just organized into a different manner.
All libraries within the SDK (with the exception of the C/C++ standard libraries provided by the compiler) are INTERFACE
libraries. A CMake INTERFACE
library is a collection of:
- Source files
- Include paths
- Compiler definitions (visible to code as #defines)
- Compile and link options
- Dependencies on other INTERFACE libraries
All of these INTERFACE
libraries form a tree of dependencies, each contributing source files, include paths, compiler definitions, and compile/link options to the build. Collection of all of these dependencies is done recursively. They are collected based on the libraries you have listed in your CMakeLists.txt file, and by the libraries depended on by those libraries, and so on.
A single project may contain many executables, as is the case for the pico-examples
project. All of the code for each executable, including the SDK libraries, is (re)compiled for each executable from source. This allows you to specify customised settings for those libraries on a per-application basis, at compile-time.
The SDK libraries are arranged heirarchically. There are high-level libraries (pico_xxxx
) that generally enable the user to do things that have cross-cutting concerns between various pieces of hardware. For example, the sleep_
functions in pico_time
must be aware of both the RP2040's timer hardware and with the way that the RP2040 enters and exits low-power states.
Generally speaking, these libraries are build upon one or more lower-level hardware_
libraries, and often depend on one another. Section 4.2 of the SDK guide lists all these high-level libraries.
As per wikipedia, a runtime library is a set of low-level routines used by a compiler to invoke some of the behaviors of a runtime environment, by inserting calls to the runtime library into compiled executable binary. Section 4.4 of the SDK guide provides a description of all runtime libraries that bundle functionality which is common to most RP2040-based applications.
Hardware support libraries are individual libraries (hardware_xxx
) that provide actual API's for interacting with each piece of physical hardware/peripheral. They are lightweight and provide only thin abstractions. They generally provide functions for configuring or interacting with the peripheral hardware at a functional level, rather than accessing registers directly. These have been described quite extensively in section 4.1 of the SDK.
These libraries are intended to have very minimal runtime cost. They generally do not require any or much RAM, and do not rely on other runtime infrastructure. In general, their only dpendencies are the hardware_structs
and hardware_regs
libraries that contain definitions of memory-mapped register layout on the RP2040. Many of them are implemented as static inline functions, the idea being that you sacrifice no performance by using these functions as compared with using preprocessor macros with the hardware_regs
definitions.
The hardware_structs
library provides a set of C structures which represent the memory mapped layout of the RP2040 registers in the system address space. The struct headers are named consistently with both the hardware
libraries and the hardware_regs
register headers. So, for example, if you access the hardware_pio
library's functionality through hardware/pio.h
, the hardware_structs
library (a dependee of hardware_pio
) contains a header you can include as hardware/structs/pio.h
if you need to access a register directly, and this itself pulls in hardware/regs/pio.h
for register field definitions.
These are the lowest level libraries. The hardware_regs
library is a complete set of include files for all RP2040 registers, autogenerated from the hardware itself. These are heavily commented, and they define the offset of every register and the layout of the fields in those registers, as well as the access type of the field (e.g. read-only). Note that these contain only comments and #define
statements, so they can be included from both assembly files and C files.
The Pico SDK uses CMake to manage builds. The project files titled CMakeLists.txt
specify how your application or project should be built. To quote the SDK guide, "CMake is fundamental to the way the SDK is structured, and how applications are configured and built."
Some of the most commonly used syntax and ideas are as follows:
The
add_executable(programName fileName.c)
function in this file declares that a programprogramName
should be built from the C source filefileName.c
. This will also be the target name used to build the program, allowing the user to say something likemake programName
in the build directory to build this particular application.
target_link_libraries(programName library1 library2 ... libraryN)
is pulling in the SDK functionality that the program needs. If you don't ask for a library, it doesn't appear in your program binary.
pico_add_extra_outputs(programName)
creates UF2 files for loading onto the Pico via USB. If we didn't include this, the system would build an ELF file (executable linkable format) that could be loaded onto the Pico through the Serial Wire Debug port, with a debugger setup likegdb
andopenocd
. This also creates.hex
,.bin
,.map
, and.dis
files.