You can configure your firmware constants, such as a WiFi password, or a LED color with the help of the flashing tool. To do that you'll need to include special configurable constant tags in your source code. Configuration inputs will automatically appear on your project's page after your firmware build is uploaded.
Examples: blink_simple (modified, Pico 2), access_point (modified, Pico w)
In this article we'll explore the ways to use this feature in your C project.
We need to update the linker scripts included in your copy of pico-sdk. We're doing this so that the configuration constants end up at the beginning of the UF2 firmware blocks.
You can find the linker scripts like this (Linux/WSL):
~/Documents/pico-sdk$ find -name memmap_default.ld ./src/rp2_common/pico_crt0/rp2350/memmap_default.ld ./src/rp2_common/pico_crt0/rp2040/memmap_default.ld
Please open the indicated files, and insert the .configurables section config just below .rodata.
.rodata : { (...) } > FLASH .configurables : SUBALIGN(256) { *(.configurables*) } > FLASH
typedef struct ConfigurableEnum { uint64_t magic1; int32_t type; int32_t value; char name[32]; char options[128]; uint64_t magic2; } ConfigurableEnum;
Remember to put your constants in their separate sections (alter the section name attribute).
__attribute__((section(".configurables_led_delay_ms"))) const volatile ConfigurableEnum led_delay = { 0xD6C9CD9844A1167A, // magic1 2, // type 250, // value "Blinking speed", // name "normal:250;fast:100;ultrafast:50;slow:600", // options 0xF5A1E6B1EBB053C5 // magic2 };
You can try this out with the blink_simple code example. You'll need to modify the example code to include the above struct declaration, and the constant definition.
Click here for an already modified example, ready to be flashed.
typedef struct { uint64_t magic1; int32_t type; int32_t padding1; char name[32]; char value[128]; uint64_t magic2; } ConfigurableString;
Remember to put your constants in their separate sections (alter the section name attribute).
__attribute__((section(".configurables_ap_name"))) const volatile ConfigurableString cfg_ap_name = { 0xD6C9CD9844A1167A, 3, 0, "AP name", "picow_test", 0xF5A1E6B1EBB053C5 }; __attribute__((section(".configurables_ap_password"))) const volatile ConfigurableString cfg_ap_password = { 0xD6C9CD9844A1167A, 3, 0, "AP password", "password", 0xF5A1E6B1EBB053C5 };
You can try this out with the Pico W access_point code example. You'll need to modify the example code to include the above struct declaration, and the constant definition. Please note that all reads from the ConfigurableString instances must be performed through a const volatile char * pointer. Otherwise, your compiler may optimize the read away, leaving the default value in its place.
Click here for an already modified example, ready to be flashed.
typedef struct { uint64_t magic1; int32_t type; int32_t value; char name[32]; uint64_t magic2; } ConfigurableInt32;
Remember to put your constants in their separate sections (alter the section name attribute).
__attribute__((section(".configurables_led_delay_ms"))) const volatile ConfigurableInt32 led_delay = { 0xD6C9CD9844A1167A, 1, 250, "LED_DELAY_MS", 0xF5A1E6B1EBB053C5, };
You can try this out with the blink_simple code example. You'll need to modify the example code to include the above struct declaration, and the constant definition.