Skip to content

Commit 7ca4f5e

Browse files
authored
Pico 2 and Pico W support, new build system (#129)
* Build and compile inside build/ directory * Add family ID argument to process_ipl.py script * Update .gitignore * Add main build script * Update build workflow * Add GPIO status LED driver * Add CYW43 status LED driver * Abstract Status LED from hardware platform * Detect HW at runtime * Move version injection code to separate cmake file * Support rp2350-arm-s family ID in uf2 payload file * Adjust main program file to recent changes * Update year in file headers * Fix build script with platform workarounds * Update release workflow for new dist structure * Remove redundant tagging * Trigger build workflow after devcontainer * Update workflow names * Revert "Trigger build workflow after devcontainer" This reverts commit b4c5717. * Never push devcontainer image in build workflow * Fix build workflow name * Fetch full history before build * Update build summary * Automatically generate release notes * Add changelog to release * Fix changelog in releases * Use default commit template in release notes * Update changelog template * Fix author and commit link in changelogs * Use payload.dol for making builds * Add script for aligning RP2040 binaries * Move python scripts to tools/ * Fix process_ipl.py path * Remove delay when waiting for USB * Update .gitignore * Remove debugging info * Revert "Remove debugging info" This reverts commit 1d6876f. * [Workaround] Delay LED initialization
1 parent cd2ed24 commit 7ca4f5e

25 files changed

Lines changed: 641 additions & 91 deletions

.github/build_summary.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Files included in the build artifact
2+
3+
Most users should use one of the **`picoboot_full_*.uf2`** files (full package). Other files are intended for advanced users to update only specific parts of the firmware or payload.
4+
5+
| File Name | Platform | Description |
6+
| ------------------------- | ------------------------------------ | --------------------------------- |
7+
| `picoboot_full_pico.uf2` | Pico<br>Pico W | firmware + payload (full package) |
8+
| `picoboot_full_pico2.uf2` | Pico 2<br>Pico 2 W | firmware + payload (full package) |
9+
| `picoboot_pico.uf2` | Pico<br>Pico W | firmware only |
10+
| `picoboot_pico2.uf2` | Pico 2<br>Pico 2 W | firmware only |
11+
| `payload_pico.uf2` | Pico<br>Pico W | payload |
12+
| `payload_pico2.uf2` | Pico 2<br>Pico 2 W | payload |
13+
| `payload_universal.uf2` | Pico<br>Pico W<br>Pico 2<br>Pico 2 W | payload |

.github/release_description.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@DESCRIPTION@
2+
3+
## Changes in this release
4+
5+
@CHANGELOG@
6+
7+
## Useful Links
8+
9+
[Software features](https://github.com/redolution/gekkoboot/) | 🚀 [Installation Guide](https://support.webhdx.dev/gc/picoboot/installation-guide) | ⬆️ [Update Guide](https://support.webhdx.dev/gc/picoboot/update-picoboot) | 🛠️ [Troubleshooting](https://support.webhdx.dev/gc/picoboot/troubleshooting)
10+
11+
## Available files
12+
13+
* `picoboot_full_pico.uf2`: Compatible with Raspberry Pi Pico and Raspberry Pi Pico W.
14+
* `picoboot_full_pico2.uf2`: Compatible with Raspberry Pi Pico 2 and Raspberry Pi Pico 2 W.
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build
1+
name: Build PicoBoot
22
on:
33
push:
44
branches:
@@ -32,6 +32,8 @@ jobs:
3232

3333
- name: Checkout PicoBoot code
3434
uses: actions/checkout@v4
35+
with:
36+
fetch-depth: 0
3537

3638
- name: Set outputs
3739
id: vars
@@ -40,21 +42,19 @@ jobs:
4042
- uses: robinraju/release-downloader@v1
4143
id: gekkoboot-download
4244
with:
43-
repository: 'webhdx/iplboot'
45+
repository: 'webhdx/gekkoboot'
4446
latest: true
4547
fileName: '*.zip'
4648
out-file-path: gekkoboot
4749
extract: true
4850

49-
- name: Copy gekkoboot uf2 payload
51+
- name: Copy gekkoboot.dol
5052
run: |
5153
cd gekkoboot
52-
if [ -f "gekkoboot_pico.uf2" ]; then
53-
cp gekkoboot_pico.uf2 ${{ github.workspace }}/payload.uf2
54-
elif [ -f "iplboot_pico.uf2" ]; then
55-
cp iplboot_pico.uf2 ${{ github.workspace }}/payload.uf2
54+
if [ -f "gekkoboot.dol" ]; then
55+
cp gekkoboot.dol ${{ github.workspace }}/payload.dol
5656
else
57-
echo "Neither gekkoboot_pico.uf2 nor iplboot_pico.uf2 found."
57+
echo "gekkoboot.dol not found"
5858
exit 1
5959
fi
6060
@@ -63,15 +63,15 @@ jobs:
6363
with:
6464
imageName: ghcr.io/webhdx/picoboot
6565
cacheFrom: ghcr.io/webhdx/picoboot
66+
push: never
6667
runCmd: |
67-
cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .
68-
make
68+
tools/build.sh
6969
7070
- name: Upload artifacts
7171
uses: actions/upload-artifact@v4
7272
with:
7373
name: picoboot-${{ steps.vars.outputs.sha_short }}
74-
path: |
75-
picoboot_full.uf2
76-
picoboot.uf2
77-
payload.uf2
74+
path: dist/
75+
76+
- name: Add build summary
77+
run: echo "$(cat .github/build_summary.md)" >> $GITHUB_STEP_SUMMARY
Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
version:
77
description: 'Version to tag'
88
required: true
9-
default: 'v0.4'
9+
default: 'v0.5.0'
1010
type: string
1111
is_draft:
1212
description: 'Is draft release?'
@@ -47,7 +47,7 @@ jobs:
4747
4848
build:
4949
needs: tag
50-
uses: ./.github/workflows/10-build.yml
50+
uses: ./.github/workflows/build.yml
5151

5252
release:
5353
runs-on: ubuntu-latest
@@ -78,17 +78,40 @@ jobs:
7878
with:
7979
name: picoboot-${{ steps.vars.outputs.sha_short }}
8080
path: dist/
81+
82+
- name: Build Changelog
83+
id: build_changelog
84+
uses: mikepenz/release-changelog-builder-action@v5
85+
with:
86+
mode: "COMMIT"
87+
toTag: ${{ github.event.inputs.version }}
88+
configurationJson: |
89+
{
90+
"template": "#{{UNCATEGORIZED}}",
91+
"commit_template": "* #{{TITLE}} by @#{{AUTHOR}} (#{{MERGE_SHA}})",
92+
"empty_template": "_No notable changes in this version._",
93+
"categories": []
94+
}
95+
env:
96+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8197

82-
- name: Prepare release description
83-
run: |
84-
touch release-description.md
85-
echo "${{ github.event.inputs.release_description }}" >> release-description.md
98+
- name: Prepare release description
99+
env:
100+
DESCRIPTION: ${{ github.event.inputs.release_description }}
101+
RELEASE_NAME: ${{ steps.determine_name.outputs.name }}
102+
CHANGELOG: ${{ steps.build_changelog.outputs.changelog }}
103+
run: |
104+
content=$(cat .github/release_description.md)
105+
content=${content//@DESCRIPTION@/$DESCRIPTION}
106+
content=${content//@CHANGELOG@/$CHANGELOG}
107+
echo "$content" > release-description.md
86108
87109
- name: Calculate artifact checksum
88110
run: |
89111
echo '```' >> release-description.md
90112
cd dist/
91-
sha256sum picoboot_full.uf2 >> ../release-description.md
113+
sha256sum picoboot_full_pico.uf2 >> ../release-description.md
114+
sha256sum picoboot_full_pico2.uf2 >> ../release-description.md
92115
cd ../
93116
echo '```' >> release-description.md
94117
@@ -98,23 +121,13 @@ jobs:
98121
git config --global user.email "actions@github.com"
99122
100123
- name: Create Release
101-
id: create_release
102-
uses: actions/create-release@v1
103-
env:
104-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
124+
uses: softprops/action-gh-release@v2
105125
with:
126+
name: ${{ steps.determine_name.outputs.name }}
106127
tag_name: ${{ github.event.inputs.version }}
107-
release_name: ${{ steps.determine_name.outputs.name }}
108-
body_path: ${{ github.workspace }}/release-description.md
109128
draft: ${{ github.event.inputs.is_draft }}
110129
prerelease: ${{ github.event.inputs.is_prerelease }}
111-
112-
- name: Upload Release Asset
113-
uses: actions/upload-release-asset@v1
114-
env:
115-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116-
with:
117-
upload_url: ${{ steps.create_release.outputs.upload_url }}
118-
asset_path: ${{ github.workspace }}/dist/picoboot_full.uf2
119-
asset_name: picoboot_full.uf2
120-
asset_content_type: application/octet-stream
130+
body_path: ${{ github.workspace }}/release-description.md
131+
files: |
132+
dist/picoboot_full_pico.uf2
133+
dist/picoboot_full_pico2.uf2

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ _deps
55

66
# Build environment
77
build/
8+
dist/
89
CMakeFiles/
910
elf2uf2/
1011
generated/
@@ -20,3 +21,6 @@ picoboot.elf.map
2021
picoboot.hex
2122
*.uf2
2223
picoboot.pio.h
24+
gekkoboot.dol
25+
payload.dol
26+
src/version.h

CMakeLists.txt

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,25 @@ cmake_minimum_required(VERSION 3.13)
33
set(CMAKE_C_STANDARD 11)
44
set(CMAKE_CXX_STANDARD 17)
55

6-
find_package(Git)
7-
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty
8-
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
9-
OUTPUT_VARIABLE GIT_REPO_VERSION
10-
OUTPUT_STRIP_TRAILING_WHITESPACE)
11-
string(REGEX REPLACE "v([0-9]+\\.[0-9]+).*" "\\1" CMAKE_GIT_REPO_VERSION ${GIT_REPO_VERSION})
12-
string(REGEX REPLACE "^(.......-.*)|(.......)$" "0.0.0" CMAKE_GIT_REPO_VERSION ${CMAKE_GIT_REPO_VERSION})
13-
configure_file("src/version.h.in" "src/version.h")
14-
message("GIT_REPO_VERSION is ${GIT_REPO_VERSION}")
15-
message("CMAKE_GIT_REPO_VERSION is ${CMAKE_GIT_REPO_VERSION}")
6+
include(cmake/extract_version.cmake)
167

178
# Pull in Raspberry Pi Pico SDK (must be before project)
189
include(pico_sdk_import.cmake)
1910

20-
project(picoboot LANGUAGES C CXX ASM VERSION ${CMAKE_GIT_REPO_VERSION})
11+
project(picoboot LANGUAGES C CXX ASM VERSION ${PROJECT_VERSION_STRING})
2112

2213
# Initialise the Raspberry Pi Pico SDK
2314
pico_sdk_init()
2415

16+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/dist)
17+
2518
add_executable(picoboot
2619
src/picoboot.c
20+
src/hw.c
2721
src/pio.c
22+
src/status_led.c
23+
src/status_led/gpio.c
24+
src/status_led/cyw43.c
2825
)
2926

3027
pico_generate_pio_header(picoboot
@@ -33,31 +30,22 @@ pico_generate_pio_header(picoboot
3330

3431
pico_set_program_name(picoboot "PicoBoot")
3532
pico_set_program_description(picoboot "RP2040 based modchip for Nintendo GameCube")
36-
pico_set_program_version(picoboot ${GIT_REPO_VERSION})
33+
pico_set_program_version(picoboot ${FW_VER_STRING})
3734
pico_set_program_url(picoboot "https://github.com/webhdx/PicoBoot")
3835

39-
pico_set_binary_type(picoboot copy_to_ram)
4036
target_link_options(pico_standard_link INTERFACE "LINKER:--script=${CMAKE_CURRENT_LIST_DIR}/memmap_picoboot.ld")
4137

4238
pico_enable_stdio_uart(picoboot 0)
4339
pico_enable_stdio_usb(picoboot 1)
4440

4541
target_include_directories(picoboot PRIVATE src)
4642

47-
target_link_libraries(picoboot PRIVATE pico_stdlib hardware_pio hardware_dma)
43+
target_link_libraries(picoboot PRIVATE
44+
hardware_adc
45+
hardware_dma
46+
hardware_pio
47+
pico_cyw43_arch_none
48+
pico_stdlib
49+
)
4850

4951
pico_add_extra_outputs(picoboot)
50-
51-
function(merge_uf2 NAME BASE_TARGET INPUTS)
52-
get_target_property(BASE_TARGET_NAME ${BASE_TARGET} OUTPUT_NAME)
53-
if(BASE_TARGET_NAME STREQUAL "BASE_TARGET_NAME-NOTFOUND")
54-
get_target_property(BASE_TARGET_NAME ${BASE_TARGET} NAME)
55-
endif()
56-
57-
add_custom_target(${NAME} ALL
58-
COMMAND ${CMAKE_CURRENT_LIST_DIR}/merge_uf2.py ${NAME}.uf2 ${BASE_TARGET_NAME}.uf2 ${INPUTS}
59-
DEPENDS ${BASE_TARGET} ${INPUTS}
60-
COMMAND_EXPAND_LISTS)
61-
endfunction()
62-
63-
merge_uf2(picoboot_full picoboot "${CMAKE_CURRENT_LIST_DIR}/payload.uf2")

cmake/extract_version.cmake

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# CMake script to extract version information from Git and configure version.h
2+
3+
find_package(Git REQUIRED)
4+
5+
execute_process(
6+
COMMAND ${GIT_EXECUTABLE} describe --tags --always --dirty
7+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
8+
OUTPUT_VARIABLE GIT_DESCRIBE_OUTPUT
9+
OUTPUT_STRIP_TRAILING_WHITESPACE
10+
RESULT_VARIABLE GIT_DESCRIBE_RESULT
11+
)
12+
13+
set(FW_VER_STRING "0.0.0-unknown")
14+
set(FW_VER_MAJOR 0)
15+
set(FW_VER_MINOR 0)
16+
set(FW_VER_PATCH 0)
17+
18+
if(GIT_DESCRIBE_RESULT EQUAL 0 AND GIT_DESCRIBE_OUTPUT)
19+
set(FW_VER_STRING ${GIT_DESCRIBE_OUTPUT})
20+
if(FW_VER_STRING MATCHES "^v([0-9]+)\.([0-9]+)\.([0-9]+)")
21+
set(FW_VER_MAJOR ${CMAKE_MATCH_1})
22+
set(FW_VER_MINOR ${CMAKE_MATCH_2})
23+
set(FW_VER_PATCH ${CMAKE_MATCH_3})
24+
else()
25+
message(STATUS "Git version string '${FW_VER_STRING}' does not match vX.Y.Z format for MAJOR/MINOR/PATCH. Using 0.0.0 for these.")
26+
endif()
27+
else()
28+
message(WARNING "git describe failed or returned empty. Using default version: ${FW_VER_STRING}, MAJOR: ${FW_VER_MAJOR}, MINOR: ${FW_VER_MINOR}, PATCH: ${FW_VER_PATCH}")
29+
endif()
30+
31+
set(PROJECT_VERSION_STRING "${FW_VER_MAJOR}.${FW_VER_MINOR}.${FW_VER_PATCH}")
32+
33+
configure_file(
34+
"${CMAKE_SOURCE_DIR}/src/version.h.in"
35+
"${CMAKE_SOURCE_DIR}/src/version.h"
36+
)
37+
38+
message(STATUS "FW_VER_STRING: ${FW_VER_STRING}")
39+
message(STATUS "FW_VER_MAJOR: ${FW_VER_MAJOR}")
40+
message(STATUS "FW_VER_MINOR: ${FW_VER_MINOR}")
41+
message(STATUS "FW_VER_PATCH: ${FW_VER_PATCH}")
42+
message(STATUS "PROJECT_VERSION_STRING: ${PROJECT_VERSION_STRING}")

src/hw.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/**
2+
* Copyright (c) 2025 Maciej Kobus
3+
*
4+
* SPDX-License-Identifier: GPL-2.0-only
5+
*/
6+
7+
#include "hardware/adc.h"
8+
#include "pico/stdlib.h"
9+
#include "pico/platform.h"
10+
11+
#include "hw.h"
12+
13+
#define ADC_PIN_VSYS 29
14+
#define ADC_INPUT_VSYS 3
15+
16+
// Threshold for differentiating Pico from Pico W based on raw ADC reading.
17+
// Pico W typically has a much lower reading on VSYS ADC (e.g., ~0x01c).
18+
// Pico typically has a higher reading (e.g., ~0x2cd).
19+
// A value around 0x100 should be a safe threshold.
20+
#define PICO_W_ADC_THRESHOLD 0x100
21+
22+
hw_board_type_t hw_detect_board_type(void) {
23+
adc_gpio_init(ADC_PIN_VSYS);
24+
adc_select_input(ADC_INPUT_VSYS);
25+
26+
uint16_t adc_result = adc_read();
27+
28+
if (adc_result < PICO_W_ADC_THRESHOLD) {
29+
#if defined(PICO_RP2350)
30+
return HW_BOARD_TYPE_PICO_2_W;
31+
#else
32+
return HW_BOARD_TYPE_PICO_W;
33+
#endif
34+
} else {
35+
#if defined(PICO_RP2350)
36+
return HW_BOARD_TYPE_PICO_2;
37+
#else
38+
return HW_BOARD_TYPE_PICO;
39+
#endif
40+
}
41+
}
42+
43+
const char* hw_board_type_to_string(hw_board_type_t board_type) {
44+
switch (board_type) {
45+
case HW_BOARD_TYPE_PICO:
46+
return "Raspberry Pi Pico";
47+
case HW_BOARD_TYPE_PICO_W:
48+
return "Raspberry Pi Pico W";
49+
case HW_BOARD_TYPE_PICO_2:
50+
return "Raspberry Pi Pico 2";
51+
case HW_BOARD_TYPE_PICO_2_W:
52+
return "Raspberry Pi Pico 2 W";
53+
default:
54+
return "Unknown";
55+
}
56+
}

0 commit comments

Comments
 (0)