Raspberry Pi Pico CMake项目头文件引入及PIO I2C链接错误排查
Raspberry Pi Pico PIO I2C 链接错误解决
问题概述
在Raspberry Pi Pico项目中添加PIO I2C功能时,编译通过但出现链接错误,提示:undefined reference to pio_i2c_read_blocking(pio_hw_t*, unsigned int, unsigned char, unsigned char*, unsigned int)
错误日志
[main] Building folder: Ghidorah [build] Starting build [proc] Executing command: /usr/bin/cmake --build /home/varun/Projects/Ghidorah/build --config Debug --target all -j 10 -- [build] [ 5%] Performing build step for 'PioasmBuild' [build] [ 5%] Built target bs2_default [build] [ 5%] Performing build step for 'ELF2UF2Build' [build] [ 16%] Built target FreeRTOS-Kernel [build] [ 18%] Built target bs2_default_padded_checksummed_asm [build] [100%] Built target elf2uf2 [build] [100%] Built target pioasm [build] [ 20%] No install step for 'ELF2UF2Build' [build] [ 20%] No install step for 'PioasmBuild' [build] [ 23%] Completed 'PioasmBuild' [build] [ 23%] Completed 'ELF2UF2Build' [build] [ 32%] Built target PioasmBuild [build] [ 34%] Built target ELF2UF2Build [build] [ 36%] Built target Ghidorah_i2c_pio_h [build] [ 37%] Linking CXX executable Ghidorah.elf [build] /usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: CMakeFiles/Ghidorah.dir/Sensors/mpu6050/source/mpu6050.cpp.obj: in function `scan()': [build] /home/varun/Projects/Ghidorah/Sensors/mpu6050/source/mpu6050.cpp:32: undefined reference to `pio_i2c_read_blocking(pio_hw_t*, unsigned int, unsigned char, unsigned char*, unsigned int)' [build] collect2: error: ld returned 1 exit status [build] gmake[2]: *** [CMakeFiles/Ghidorah.dir/build.make:936: Ghidorah.elf] Error 1 [build] gmake[1]: *** [CMakeFiles/Makefile2:1496: CMakeFiles/Ghidorah.dir/all] Error 2 [build] gmake: *** [Makefile:91: all] Error 2 [proc] The command: /usr/bin/cmake --build /home/varun/Projects/Ghidorah/build --config Debug --target all -j 10 -- exited with code: 2 [build] Build finished with exit code 2
当前CMakeLists.txt内容
# Generated Cmake Pico project file cmake_minimum_required(VERSION 3.13) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) # Initialise pico_sdk from installed location # (note this can come from environment, CMake cache etc) set(PICO_SDK_PATH "/home/varun/Dev-Tools/pico/pico-sdk") set(PICO_BOARD pico CACHE STRING "Board type") # Pull in Raspberry Pi Pico SDK (must be before project) include(pico_sdk_import.cmake) if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") endif() add_compile_options(-Wall -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int -Wno-unused-function # we have some for the docs that aren't called -Wno-maybe-uninitialized -fpermissive ) project(Ghidorah C CXX ASM) # Initialise the Raspberry Pi Pico SDK pico_sdk_init() # Add executable. Default name is the project name, version 0.1 add_executable(Ghidorah Ghidorah.cpp Sensors/mpu6050/source/mpu6050.cpp Sensors/mpu9250/source/mpu9250.cpp Sensors/adxl345/source/adxl345.cpp Sensors/lsm303dhlc/source/lsm303dhlc.cpp pio/pio_i2c.c) pico_generate_pio_header(Ghidorah ${CMAKE_CURRENT_SOURCE_DIR}/pio/i2c.pio) pico_set_program_name(Ghidorah "Ghidorah") pico_set_program_version(Ghidorah "0.1") pico_enable_stdio_uart(Ghidorah 1) pico_enable_stdio_usb(Ghidorah 0) # Add the standard library to the build target_link_libraries(Ghidorah pico_stdlib pico_multicore) # Add the standard include files to the build target_include_directories(Ghidorah PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required ${CMAKE_CURRENT_SOURCE_DIR}/ # SENSOR Sources ${CMAKE_CURRENT_SOURCE_DIR}/Sensors ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/mpu6050/ ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/mpu6050/include ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/mpu9250/ ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/mpu9250/include ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/adxl345/ ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/adxl345/include ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/lsm303dhlc/ ${CMAKE_CURRENT_SOURCE_DIR}/Sensors/lsm303dhlc/include # PIO Sources ${CMAKE_CURRENT_SOURCE_DIR}/pio ${CMAKE_CURRENT_SOURCE_DIR}/pio/) add_library(FreeRTOS-Kernel STATIC FreeRTOS-Kernel/event_groups.c FreeRTOS-Kernel/list.c FreeRTOS-Kernel/queue.c FreeRTOS-Kernel/stream_buffer.c FreeRTOS-Kernel/tasks.c FreeRTOS-Kernel/timers.c FreeRTOS-Kernel/portable/GCC/ARM_CM0/port.c FreeRTOS-Kernel/portable/Common/mpu_wrappers.c FreeRTOS-Kernel/portable/MemMang/heap_3.c) target_include_directories(FreeRTOS-Kernel PUBLIC FreeRTOS-Kernel/ FreeRTOS-Kernel/include/ FreeRTOS-Kernel/portable/Common/ FreeRTOS-Kernel/portable/GCC/ FreeRTOS-Kernel/portable/GCC/ARM_CM0/ FreeRTOS-Kernel/portable/MemMang/) # Add any user requested libraries target_link_libraries(Ghidorah hardware_dma hardware_gpio hardware_pio FreeRTOS-Kernel) pico_add_extra_outputs(Ghidorah)
解决方案
链接错误的核心原因是C++代码调用C语言实现的函数时,未声明C语言链接约定,导致编译器按C++名字修饰规则查找函数,无法匹配C语言编译的函数符号。
具体修复步骤:
- 修改PIO I2C头文件:在声明
pio_i2c_read_blocking的头文件(如pio_i2c.h)中,用extern "C"包裹所有函数声明,示例如下:
#ifdef __cplusplus extern "C" { #endif // 所有PIO I2C相关函数声明 void pio_i2c_read_blocking(pio_hw_t* pio, uint sm, uint8_t addr, uint8_t* dst, size_t len); // 其他函数声明... #ifdef __cplusplus } #endif
确认源文件编译状态:
pio_i2c.c是C语言文件,CMake会自动按C规则编译,且你的配置中已将其加入add_executable,这部分无需修改。清理重建项目:删除build目录,重新运行CMake配置和编译,确保修改生效。
额外检查点:
- 确认
pio_i2c.c中pio_i2c_read_blocking的函数签名与头文件声明完全一致(参数类型、数量、返回值类型均需匹配)。 - 若使用Pico SDK示例中的PIO I2C代码,需确保头文件已包含上述
extern "C"声明。
内容的提问来源于stack exchange,提问作者varun koganti
相关产品推荐
相关产品推荐

