跳至内容
返回

ESP32-C3 PlatformIO 'embed_txtfiles' 修复

发布于:  at  09:13 下午

前言

9.9元入手了一块ESP32-C3板子, 用来取代手上引脚不足的ESP8266. 但是编译时候总是失败,从Log上看是这一步出了错误.

prepare_file([".pio\build\esp32c3\lite.ttf.txt.o"], ["src\lite.ttf"])
Converting .pio\build\esp32c3\lite.ttf.txt.o
'xtensa-esp32-elf-objcopy' \xb2\xbb\xca\xc7\xc4ڲ\xbf\xbb\xf2\xcdⲿ\xc3\xfc\xc1Ҳ\xb2\xbb\xcaǿ\xc9\xd4\xcb\xd0еij\xcc\xd0\xf2
\xbb\xf2\xc5\xfa\xb4\xa6\xc0\xed\xceļ\xfe\xa1\xa3
*** [.pio\build\esp32c3\lite.ttf.txt.o] Error 1

此外并没有任何提示了.

错误分析

lite.ttf是我的一个放在src目录下的文件,

为其在platformio.ini配置”board_build.embed_txtfiles = src/lite.ttf”,就可以让这个文件嵌入固件中. 从日志里看到是转化的时候出了问题, xtensa-esp32-elf-objcopy

xtensa是ESP32,ESP32-S2,ESP32-S3的处理器结构,而ESP32-C3是RISC-V的,所以这里出错应该是结构不匹配. 去ESP-IDF的文件夹搜索”elf-objcopy”后发现的确有不同很多类似关键字.

for dir in esp32 esp32s2 esp32c3 esp32s3; do
    if [ $dir = esp32 ]; then
        TOOLCHAIN="xtensa-esp32-elf"
    elif [ $dir = esp32s2 ]; then
        TOOLCHAIN="xtensa-esp32s2-elf"
    elif [ $dir = esp32c3 ]; then
        TOOLCHAIN="riscv32-esp-elf"
    elif [ $dir = esp32s3 ]; then
        TOOLCHAIN="xtensa-esp32s3-elf"
    else
        echo "$dir does not exist"
    fi
    if [ -d "$dir" ]; then
        cd $dir
        git status libphy.a | grep "modified" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo $dir/libphy.a fixed
            $TOOLCHAIN-objcopy --redefine-sym ets_printf=phy_printf libphy.a
        fi

所以应该是PlatformIO在转化的时候调用了错误的程序导致的.

解决问题

去PlatformIO的工作目录(.platformio)下搜索xtensa-esp32-elf-objcopy

[
    "xtensa-esp32-elf-objcopy",
    "--input-target",
    "binary",
    "--output-target",
    "elf32-xtensa-le",
    "--binary-architecture",
    "xtensa",
    "--rename-section",
    ".data=.rodata.embedded",
    "$SOURCE",
     "$TARGET",
]

确实搜索到了多个包含这个关键字的文件_embed_files.py (platforms\espressif32\builder\frameworks_embed_files.py) 其中platforms下有好几个文件夹

├── .platformio
   └── platforms
       └── espressif32
       └── espressif32@src-ba2d3999402da5eaf2c9d5863ef113c7
       └── espressif32@src-ebefb4289db63a9f0ca5ee29fa328eef
       └── espressif8266
       └── raspberrypi

这应该是不同项目所需的platform,凑巧这次C3项目的platform是专门下载的,所以从文件夹修改日期上来看,我这次C3使用的应该是espressif32@src-ebefb4289db63a9f0ca5ee29fa328eef 打开espressif32@src-ebefb4289db63a9f0ca5ee29fa328eef下的_embed_files.py 里面果然还在使用xtensa-esp32-elf-objcopy 按照ESP-IDF里面的描述,应该使用riscv32-esp-elf-objcopy,并且要把xtensa相关的都修改为riscv.

所以最后修改成了

[
    "riscv32-esp-elf-objcopy",
    "--input-target",
    "binary",
    "--output-target",
    "elf32-littleriscv",
    "--binary-architecture",
    "riscv",
    "--rename-section",
    ".data=.rodata.embedded",
    "$SOURCE",
    "$TARGET",
]

重新执行编译,这一次终于通过了.

Building in release mode
prepare_file([".pio\build\esp32c3\lite.ttf.txt.o"], ["src\lite.ttf"])
Converting .pio\build\esp32c3\lite.ttf.txt.o
revert_original_file([".pio\build\esp32c3\lite.ttf.txt.o"], ["src\lite.ttf"])
Linking .pio\build\esp32c3\firmware.elf
Retrieving maximum program size .pio\build\esp32c3\firmware.elf
Checking size .pio\build\esp32c3\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   4.7% (used 15480 bytes from 327680 bytes)
Flash: [=         ]  14.1% (used 443870 bytes from 3145728 bytes)
Building .pio\build\esp32c3\firmware.bin
esptool.py v3.1
Merged 2 ELF sections

_embed_files.py

## Copyright 2014-present PlatformIO <contact@platformio.org>
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
##    http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.

import shutil
from os import SEEK_CUR, SEEK_END
from os.path import basename, isfile, join

from SCons.Script import Builder

Import("env")

board = env.BoardConfig()

##
## Embedded files helpers
##


def extract_files(cppdefines, files_type):
    files = []
    if "build." + files_type in board:
        files.extend(
            [
                join("$PROJECT_DIR", f)
                for f in board.get("build." + files_type, "").split()
                if f
            ]
        )
    else:
        files_define = "COMPONENT_" + files_type.upper()
        for define in cppdefines:
            if files_define not in define:
                continue

            value = define[1]
            if not isinstance(define, tuple):
                print("Warning! %s macro cannot be empty!" % files_define)
                return []

            if not isinstance(value, str):
                print(
                    "Warning! %s macro must contain "
                    "a list of files separated by ':'" % files_define
                )
                return []

            for f in value.split(":"):
                if not f:
                    continue
                files.append(join("$PROJECT_DIR", f))

    for f in files:
        if not isfile(env.subst(f)):
            print('Warning! Could not find file "%s"' % basename(f))

    return files


def remove_config_define(cppdefines, files_type):
    for define in cppdefines:
        if files_type in define:
            env.ProcessUnFlags("-D%s" % "=".join(str(d) for d in define))
            return


def prepare_file(source, target, env):
    filepath = source[0].get_abspath()
    shutil.copy(filepath, filepath + ".piobkp")

    with open(filepath, "rb+") as fp:
        fp.seek(-1, SEEK_END)
        if fp.read(1) != "\0":
            fp.seek(0, SEEK_CUR)
            fp.write(b"\0")


def revert_original_file(source, target, env):
    filepath = source[0].get_abspath()
    if isfile(filepath + ".piobkp"):
        shutil.move(filepath + ".piobkp", filepath)


def embed_files(files, files_type):
    for f in files:
        filename = basename(f) + ".txt.o"
        file_target = env.TxtToBin(join("$BUILD_DIR", filename), f)
        env.Depends("$PIOMAINPROG", file_target)
        if files_type == "embed_txtfiles":
            env.AddPreAction(file_target, prepare_file)
            env.AddPostAction(file_target, revert_original_file)
        env.AppendUnique(PIOBUILDFILES=[env.File(join("$BUILD_DIR", filename))])


def transform_to_asm(target, source, env):
    files = [join("$BUILD_DIR", s.name + ".S") for s in source]
    return files, source


env.Append(
    BUILDERS=dict(
        TxtToBin=Builder(
            action=env.VerboseAction(
                " ".join(
                    [
                        "riscv32-esp-elf-objcopy",
                        "--input-target",
                        "binary",
                        "--output-target",
                        "elf32-littleriscv",
                        "--binary-architecture",
                        "riscv",
                        "--rename-section",
                        ".data=.rodata.embedded",
                        "$SOURCE",
                        "$TARGET",
                    ]
                ),
                "Converting $TARGET",
            ),
            suffix=".txt.o",
        ),
        TxtToAsm=Builder(
            action=env.VerboseAction(
                " ".join(
                    [
                        join(
                            env.PioPlatform().get_package_dir("tool-cmake") or "",
                            "bin",
                            "cmake",
                        ),
                        "-DDATA_FILE=$SOURCE",
                        "-DSOURCE_FILE=$TARGET",
                        "-DFILE_TYPE=TEXT",
                        "-P",
                        join(
                            env.PioPlatform().get_package_dir("framework-espidf") or "",
                            "tools",
                            "cmake",
                            "scripts",
                            "data_file_embed_asm.cmake",
                        ),
                    ]
                ),
                "Generating assembly for $TARGET",
            ),
            emitter=transform_to_asm,
            single_source=True,
        ),
    )
)


flags = env.get("CPPDEFINES")
for files_type in ("embed_txtfiles", "embed_files"):
    if (
        "COMPONENT_" + files_type.upper() not in env.Flatten(flags)
        and "build." + files_type not in board
    ):
        continue

    files = extract_files(flags, files_type)
    if "espidf" in env.subst("$PIOFRAMEWORK"):
        env.Requires(join("$BUILD_DIR", "${PROGNAME}.elf"), env.TxtToAsm(files))
    else:
        embed_files(files, files_type)
        remove_config_define(flags, files_type)

环境:

PLATFORM: Espressif 32 (3.3.0+sha.3b5de56) > Espressif ESP32 Dev Module
 - framework-arduinoespressif32 0.0.0+sha.68daea4
 - tool-esptoolpy 1.30100.210531 (3.1.0)
 - toolchain-riscv-esp 1.80400.0 (8.4.0)
 - toolchain-riscv32-esp 8.4.0+2021r1

在以下平台分享此文章: