Zephyr设备树生成流程

本文说明zephyr的dts生成C宏的主要流程。

Zephyr构建过程简述一文中我们知道zephyr对dts的使用是将dts其生成C宏,由代码来使用宏,当时大体提到过dts生成C宏的流程,本文更详细的介绍dts如何生成宏,但生成宏规则不在本文介绍范围内。

概览 链接到标题

下图说明了dts生成宏的详细过程,摘自zephyr官方文档,链接详见文末参考 dts.png 对于整个流程有4种输入文件: sources (.dts) : 一般是board的dts文件 includes (.dtsi):被dts包含的dtsi文件,是soc或者驱动级的公用描述 overlays (.overlay):对于相同的应用采用不同的板子时,可以在应用下放不同overlay文件配置应用要用的设备 bindings (.yaml): binding文件,用于帮助dts生成宏 以上文件通常会出现在下面路径

boards/<ARCH>/<BOARD>/<BOARD>.dts
dts/common/skeleton.dtsi
dts/<ARCH>/.../<SOC>.dtsi
dts/bindings/.../binding.yaml
app/xxx.overlay

3种输出文件: zephyr.dts:该文件是dts,dtsi,overlay合并为一个文件,作为调试参考用 devicetree.h:dts最后生成的宏,会被代码引用 devicetree.conf:dts生成的conf,会被Kconfig引用 下面我们分析详细流程

1 合并整个dts 链接到标题

合并生成dts 链接到标题

将dts和overlay合并为dts.pre.tmp文件 dts.cmake中取得board的dts, 该dts中会include其它dtsi部分

set_ifndef(DTS_SOURCE ${BOARD_DIR}/${BOARD}.dts)

加入到变量dts_files中

set(dts_files
  ${DTS_SOURCE}
  ${shield_dts_files}
  )

将overlay放入dts_files中

string(REPLACE " " ";" DTC_OVERLAY_FILE_AS_LIST ${DTC_OVERLAY_FILE})
    list(APPEND
      dts_files
      ${DTC_OVERLAY_FILE_AS_LIST}
      )

读出dts文件作为编译的-i选项DTC_INCLUDE_FLAG_FOR_DTS

  foreach(dts_file ${dts_files})
    list(APPEND DTC_INCLUDE_FLAG_FOR_DTS
         -include ${dts_file})

通过预编译将所有的dts merge为一个dts文件${BOARD}.dts.pre.tmp

  execute_process(
    COMMAND ${CMAKE_C_COMPILER}
    -x assembler-with-cpp
    -nostdinc
    ${DTS_ROOT_SYSTEM_INCLUDE_DIRS}
    ${DTC_INCLUDE_FLAG_FOR_DTS}  # include the DTS source and overlays
    ${NOSYSDEF_CFLAG}
    -D__DTS__
    -P
    -E   # Stop after preprocessing
    -MD  # Generate a dependency file as a side-effect
    -MF ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.d
    -o  ${PROJECT_BINARY_DIR}/${BOARD}.dts.pre.tmp
    ${ZEPHYR_BASE}/misc/empty_file.c
    WORKING_DIRECTORY ${APPLICATION_SOURCE_DIR}
    RESULT_VARIABLE ret
    )

这里提一下empty_file.c,之前一直没搞清楚zephyr里面放个空文件搞什么,现在才知道是为了用来预编译帮助生成一些东西,除了在dts外,构建过程的其它地方也有使用。

检查dts语法 链接到标题

使用dtc工具检查merge后的dts.pre.tmp文件是否符合dts语法,在zephyr中dtc只用于检查合并后的dts.pre.tmp文件的正确性

  execute_process(
    COMMAND ${DTC}
    -O dts
    -o - # Write output to stdout, which we discard below
    -b 0
    -E unit_address_vs_reg
    ${DTC_NO_WARN_UNIT_ADDR}
    ${DTC_WARN_UNIT_ADDR_IF_ENABLED}
    ${EXTRA_DTC_FLAGS} # User settable
    ${BOARD}.dts.pre.tmp
    OUTPUT_QUIET # Discard stdout
    WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
    RESULT_VARIABLE ret
    )

2.生devicetree_unfixed.h和devicetree.conf 链接到标题

获取dts的binding文件,也就是dts/binding下的yaml文件

foreach(dts_root ${DTS_ROOT})
    set(full_path ${dts_root}/dts/bindings)
    if(EXISTS ${full_path})
      list(APPEND
        DTS_ROOT_BINDINGS
        ${full_path}
        )
    endif()
  endforeach()

使用gen_defines.py搭配yaml文件解析{BOARD}.dts.pre.tmp 生成devicetree.conf,devicetree_unfixed.h和zephyr.dts zephyr.dts只是方便调试查看,不会对之后的构建有任何帮助。

  set(CMD_NEW_EXTRACT ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/dts/gen_defines.py
  --dts ${BOARD}.dts.pre.tmp
  --dtc-flags '${EXTRA_DTC_FLAGS}'
  --bindings-dirs ${DTS_ROOT_BINDINGS}
  --conf-out ${DEVICETREE_CONF}
  --header-out ${DEVICETREE_UNFIXED_H}
  --dts-out ${PROJECT_BINARY_DIR}/zephyr.dts # As a debugging aid
  )

3. 生成devicetree_fixed.h 链接到标题

在soc目录下不同的架构有一些dts_fixup.h文件,该文件是为了将dts生成的宏转为一些代码里面固定的宏,例如

#define DT_RTC_0_NAME				DT_NXP_IMX_GPT_COUNTER_1_LABEL
#define DT_RTC_1_NAME				DT_NXP_IMX_GPT_COUNTER_2_LABEL

这种方式将逐渐被废弃,但目前还在用,这里也说明一下生成过程: dts_fixup.h合并成为devicetree_fixed.h,在根目录CMakeList.txt中处理。

取出各个地方的dts_fixup.h

set_ifndef(  DTS_BOARD_FIXUP_FILE                                   ${BOARD_DIR}/dts_fixup.h)
set_ifndef(    DTS_SOC_FIXUP_FILE                 ${SOC_DIR}/${ARCH}/${SOC_PATH}/dts_fixup.h)
set(           DTS_APP_FIXUP_FILE                      ${APPLICATION_SOURCE_DIR}/dts_fixup.h)

定义要生成文件devicetree_fixups.h路径DTS_CAT_OF_FIXUP_FILES

set_ifndef(DTS_CAT_OF_FIXUP_FILES ${ZEPHYR_BINARY_DIR}/include/generated/devicetree_fixups.h)

读出各个dts_fixup.h的内容将其写入devicetree_fixups.h

file(WRITE ${DTS_CAT_OF_FIXUP_FILES} "/* May only be included by devicetree.h */\n\n") foreach(fixup_file ${DTS_BOARD_FIXUP_FILE}
    ${DTS_SOC_FIXUP_FILE}
    ${DTS_APP_FIXUP_FILE}
    ${shield_dts_fixups}
    ) if(EXISTS ${fixup_file}) file(READ ${fixup_file} contents)
    file(APPEND ${DTS_CAT_OF_FIXUP_FILES} "${contents}") endif() endforeach()

4. 生成devicetree.h 链接到标题

合并 devicetree_unfixed.h 和 devicetree_fixed.h 到devicetree.h,采用头文件直接include方式

#include <devicetree_unfixed.h>
#include <devicetree_fixups.h>

参考 链接到标题

https://docs.zephyrproject.org/latest/guides/dts/intro.html#input-and-output-files