forked from raspberrypi/pico-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CMakeLists.txt
137 lines (122 loc) · 5.58 KB
/
CMakeLists.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
if ((NOT DEFINED PICO_RISCV_TOOLCHAIN_PATH) OR (NOT DEFINED PICO_ARM_TOOLCHAIN_PATH))
# Must define PICO_RISCV_TOOLCHAIN_PATH and PICO_ARM_TOOLCHAIN_PATH
# to ensure both compilers are present
message(
"Skipping universal examples as PICO_RISCV_TOOLCHAIN_PATH and "
"PICO_ARM_TOOLCHAIN_PATH are not defined"
)
return()
endif()
include(ExternalProject)
# The way this universal build works is it builds separate binaries for each platform,
# then links them into a single block loop. This universal binary will then run on any
# platform
# - On RP2040 the bootrom will just execute the RP2040 binary at the start of flash
# - On RP2350 the bootrom will search the block loop for the appropriate IMAGE_DEF for
# Arm/RISC-V, translate it's address to the start of flash using the rolling window
# delta, and execute it on the appropriate CPU
#
# The build will output a TARGET.bin file which can be written using picotool, and a
# TARGET.uf2 file which can be dragged and dropped onto the device in BOOTSEL mode
function (add_universal_target TARGET SOURCE)
set(oneValueArgs SOURCE_TARGET PADDING PACKADDR)
set(multiValueArgs PLATFORMS)
cmake_parse_arguments(PARSE_ARGV 2 PARSED "" "${oneValueArgs}" "${multiValueArgs}")
set(SOURCE_TARGET ${TARGET})
if (PARSED_SOURCE_TARGET)
set(SOURCE_TARGET ${PARSED_SOURCE_TARGET})
endif()
set(PADDING 0x1000)
if (PARSED_PADDING)
set(PADDING ${PARSED_PADDING})
endif()
set(PACKADDR 0x10000000)
if (PARSED_PACKADDR)
set(PACKADDR ${PARSED_PACKADDR})
endif()
set(PLATFORMS "rp2040;rp2350-arm-s;rp2350-riscv")
if (PARSED_PLATFORMS)
set(PLATFORMS ${PARSED_PLATFORMS})
endif()
# rp2040 must come first, as that has checksum requirements at the start of the binary
list(FIND PLATFORMS "rp2040" idx)
if (idx GREATER 0)
message(FATAL_ERROR "rp2040 must come first in PLATFORMS for universal binaries")
endif()
add_custom_target(${TARGET} ALL)
set(DEPS "")
set(BINS "")
# Build binaries for each of the platforms
foreach(platform IN LISTS PLATFORMS)
ExternalProject_Add(${TARGET}_${platform}
PREFIX pioasm
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/wrapper
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${platform}/wrapper
CMAKE_ARGS
"--no-warn-unused-cli"
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DPICO_EXAMPLES_PATH:FILEPATH=${PICO_EXAMPLES_PATH}"
"-DPICO_PLATFORM=${platform}"
"-DPICO_ARM_TOOLCHAIN_PATH=${PICO_ARM_TOOLCHAIN_PATH}"
"-DPICO_RISCV_TOOLCHAIN_PATH=${PICO_RISCV_TOOLCHAIN_PATH}"
"-DPICO_BOARD_RP2040=${PICO_BOARD_RP2040}"
"-DPICO_BOARD_RP2350=${PICO_BOARD_RP2350}"
"-DUNIVERSAL_PROJECT_DIR:FILEPATH=${SOURCE}"
"-DUNIVERSAL_BINARY_DIR:FILEPATH=${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${platform}"
"-DSOURCE_TARGET=${SOURCE_TARGET}"
"-Dpicotool_DIR=${picotool_INSTALL_DIR}/picotool"
"-Dpioasm_DIR=${PIOASM_INSTALL_DIR}/pioasm"
BUILD_ALWAYS 1 # force dependency checking
INSTALL_COMMAND ""
)
set(ORIGINAL_BIN ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}/${platform}/${SOURCE_TARGET}.bin)
list(APPEND DEPS ${TARGET}_${platform})
list(APPEND BINS ${ORIGINAL_BIN})
endforeach()
set(BINDIR ${CMAKE_CURRENT_BINARY_DIR}/${TARGET})
set(COMBINED ${BINDIR}/${TARGET}.bin)
pico_init_picotool()
if (NOT picotool_FOUND)
message(FATAL_ERROR "Cannot link universal binary without picotool")
endif()
# Link the binaries for different platforms into a single block loop, with
# appropriate rolling window deltas. This creates a universal binary file,
# which will run on any of the platforms when loaded using picotool.
add_custom_target(${TARGET}_combined
COMMAND picotool link ${COMBINED} ${BINS} --pad ${PADDING}
DEPENDS ${DEPS}
)
# Create UF2s targeting the absolute and rp2040 family IDs, then combine these
# into a single universal UF2. This is required as there isn't a single family
# ID which is accepted by both RP2040 and RP2350. Instead, the 2 UF2 files are
# concatenated together and the device ignores the part not targeting it.
add_custom_target(${TARGET}_rp2350_uf2
COMMAND picotool uf2 convert ${COMBINED} ${BINDIR}/rp2350.uf2 --family absolute --offset ${PACKADDR}
DEPENDS ${TARGET}_combined
)
add_custom_target(${TARGET}_rp2040_uf2
COMMAND picotool uf2 convert ${COMBINED} ${BINDIR}/rp2040.uf2 --family rp2040 --offset ${PACKADDR}
DEPENDS ${TARGET}_combined
)
add_custom_target(${TARGET}_uf2
COMMAND ${CMAKE_COMMAND} -E cat ${BINDIR}/rp2040.uf2 ${BINDIR}/rp2350.uf2 > ${BINDIR}/${TARGET}.uf2
DEPENDS ${TARGET}_rp2350_uf2 ${TARGET}_rp2040_uf2
)
add_dependencies(${TARGET} ${TARGET}_combined ${TARGET}_uf2)
endfunction()
# hello_universal binary
add_universal_target(hello_universal
${CMAKE_CURRENT_LIST_DIR}/hello_universal
)
# blink binary
add_universal_target(blink_universal
${CMAKE_CURRENT_LIST_DIR}/../blink
SOURCE_TARGET blink
)
# nuke binary - is no_flash, so needs to be sent to SRAM on RP2040
add_universal_target(nuke_universal
${CMAKE_CURRENT_LIST_DIR}/../flash/nuke
SOURCE_TARGET flash_nuke
PACKADDR 0x20000000
)