Files
Linus Torvalds 968cd8845a Only put the audio core in RAM, and check that it stays clean
Drop copy_to_ram.  It was always the lazy option - I didn't want to work
out which functions actually needed to be in SRAM, so I put all of them
there.  Now that the audio core is marked, the linker script already
does the right thing: it pulls '.time_critical*' out of flash, and
everything else is cold enough to run from XIP.

	RAM before:  73132 text + 386972 bss = 460104
	RAM after:   20504 data + 384652 bss = 405156

which is 54948 bytes back, and takes the headroom from 70K to 124K out
of 520K.  That matters more than it sounds: bss is already 384K, mostly
the 64K analyzer ring and the 64K FFT buffer, so headroom is the thing
that was going to run out first.

Also add scripts/check-audio.py, run after every link.  Everything in a
'.time_critical.audio_*' section may only call into another one, and
anything else fails the build.  Right now there is nothing on the
allowed list at all - the audio path doesn't call a single library
function - which is the whole reason to add the check now rather than
after it has rotted.  The last one to go was the newlib 'lrintf()' a
couple of commits ago.

The one thing this cannot check is that the code still *works* from
flash.  cpu1 is unaffected by construction since all of it is in RAM,
but cpu0 now takes XIP cache misses, and the tuner does an 8192-point
FFT at 25Hz.  I think the cache holds the inner loop fine.  I have not
proven it on hardware.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-07-27 12:41:32 -07:00

171 lines
4.6 KiB
CMake

cmake_minimum_required(VERSION 3.13...3.27)
# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include(pico-sdk/pico_sdk_init.cmake)
project(rp2350)
# initialize the Raspberry Pi Pico SDK
pico_sdk_init()
add_executable(blink)
# I should have used different PIO pins for MIDI
# but they conflict with the second rotary encoder
set(MIDI_HW OFF CACHE BOOL "Enable MIDI HW (not just MIDI over USB-C) support")
# The eeprom chip has changed from a 2kbit to a 64kbit one,
# and they aren't sw-compatible
set(EEPROM_64KBIT OFF CACHE BOOL "Configure for 64kbit eeprom chip")
set(SAMPLES_PER_SEC 48000.0)
set(SCRIPT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
#
# Only the audio core runs from RAM: everything marked with
# __audio_func() lands in a '.time_critical.audio_*' section, which the
# default linker script already pulls out of flash. The rest is cold
# enough to run from XIP.
#
# Math table generation
set(POW2_STEP_SHIFT 8)
set(POW2_HEADER "${CMAKE_CURRENT_BINARY_DIR}/pow2.h")
add_custom_command(
OUTPUT "${POW2_HEADER}"
COMMAND "${SCRIPT_DIR}/pow2.py"
"${POW2_HEADER}"
"${POW2_STEP_SHIFT}"
DEPENDS "${SCRIPT_DIR}/pow2.py"
)
target_sources(blink PRIVATE "${POW2_HEADER}")
set(LOG2_STEP_SHIFT 8)
set(LOG2_HEADER "${CMAKE_CURRENT_BINARY_DIR}/log2.h")
add_custom_command(
OUTPUT "${LOG2_HEADER}"
COMMAND "${SCRIPT_DIR}/log2.py"
"${LOG2_HEADER}"
"${LOG2_STEP_SHIFT}"
DEPENDS "${SCRIPT_DIR}/log2.py"
)
target_sources(blink PRIVATE "${LOG2_HEADER}")
set(SINE_STEP_SHIFT 8)
set(SINE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/quarter_sine.h")
add_custom_command(
OUTPUT "${SINE_HEADER}"
COMMAND "${SCRIPT_DIR}/quarter_sine.py"
"${SINE_HEADER}"
"${SINE_STEP_SHIFT}"
DEPENDS "${SCRIPT_DIR}/quarter_sine.py"
)
target_sources(blink PRIVATE "${SINE_HEADER}")
set(EQ_W0_HEADER "${CMAKE_CURRENT_BINARY_DIR}/eq-w0.h")
add_custom_command(
OUTPUT "${EQ_W0_HEADER}"
COMMAND "${SCRIPT_DIR}/eq-w0.py"
"${EQ_W0_HEADER}"
"${SAMPLES_PER_SEC}"
DEPENDS "${SCRIPT_DIR}/eq-w0.py"
)
target_sources(blink PRIVATE "${EQ_W0_HEADER}")
file(GLOB EFFECT_HEADERS CONFIGURE_DEPENDS "effects/*.h")
set(EFFECT_MAP_HEADER "${CMAKE_CURRENT_BINARY_DIR}/effect_map.h")
set(EFFECT_JS "${CMAKE_CURRENT_SOURCE_DIR}/WebMIDI/effects.js")
set(EFFECT_MD "${CMAKE_CURRENT_SOURCE_DIR}/MIDI_CC_MAP.md")
add_custom_command(
OUTPUT "${EFFECT_MAP_HEADER}" "${EFFECT_JS}" "${EFFECT_MD}"
COMMAND "${SCRIPT_DIR}/gen_effects.py"
"${CMAKE_CURRENT_SOURCE_DIR}/effects"
"${EFFECT_MAP_HEADER}"
"${EFFECT_JS}"
"${EFFECT_MD}"
${EFFECT_HEADERS}
DEPENDS "${SCRIPT_DIR}/gen_effects.py" ${EFFECT_HEADERS}
)
target_sources(blink PRIVATE "${EFFECT_MAP_HEADER}")
set(PIO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/pio")
pico_generate_pio_header(blink ${PIO_DIR}/ws2812.pio)
pico_generate_pio_header(blink ${PIO_DIR}/debounce.pio)
pico_generate_pio_header(blink ${PIO_DIR}/rotary.pio)
pico_generate_pio_header(blink ${PIO_DIR}/i2s.pio)
target_compile_definitions(blink PRIVATE
SYS_CLK_KHZ=153600
PLL_SYS_VCO_FREQ_HZ=768000000
PLL_SYS_POSTDIV1=5
PLL_SYS_POSTDIV2=1
MIDI_HW=$<BOOL:${MIDI_HW}>
EEPROM_64KBIT=$<BOOL:${EEPROM_64KBIT}>
SAMPLES_PER_SEC=${SAMPLES_PER_SEC}f
CFG_TUSB_MCU=OPT_MCU_RP2040
CFG_TUSB_OS=OPT_OS_PICO
CFG_TUSB_DEBUG=0)
target_sources(blink PRIVATE
blink.c
"${SINE_HEADER}"
tinyusb/src/tusb.c
tinyusb/src/common/tusb_fifo.c
tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c
)
target_sources(blink PRIVATE
usb-device.c
tinyusb/src/device/usbd.c
tinyusb/src/class/audio/audio_device.c
tinyusb/src/class/midi/midi_device.c
tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c)
target_link_libraries(blink
pico_stdlib
pico_multicore
hardware_gpio
hardware_pwm
hardware_pio
hardware_i2c
hardware_dma)
target_include_directories(blink PRIVATE
include
tinyusb/src
"${CMAKE_CURRENT_BINARY_DIR}")
#
# We really don't care about IEEE precision, nor
# do we want double-precision math just because
# of some random constant (and adding ".0f" to them
# everywhere is just cray-cray)
#
# Add -fsingle-precision-constant / -Wdouble-promotion
# when starting to do FP for audio
#
target_compile_options(blink PRIVATE
-Wall -O2
-ffast-math
-fsingle-precision-constant
-Wfloat-conversion)
# Our own sources only - we don't get to pick the SDK's warnings
set_source_files_properties(blink.c usb-device.c PROPERTIES
COMPILE_OPTIONS -Wdouble-promotion)
# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(blink)
# Nothing on the audio core is allowed to call out to a library
add_custom_command(TARGET blink POST_BUILD
COMMAND "${SCRIPT_DIR}/check-audio.py"
"$<TARGET_FILE:blink>.map"
"$<TARGET_FILE:blink>"
"${CMAKE_OBJDUMP}"
VERBATIM)