Описание отладочной платы
На плате установлен чип XC7Z020-2CLG484I, содержащий PS-часть с двумя ядрами ARM Cortex-A9. Периферия включает:
- CAN PS и RS-485
- DDR3 1 GB
- Отладка через FT2232HQ (JTAG + USB-UART)
- EEPROM (AT24C256C)
- 8 GB eMMC
- Ethernet PS + PL (RTL8211F-CG)
- FMC 40 pin
- LCD
- 256 Mbit QSPI NOR Flash
- RTC PCF8563
- USB 2.0 PS (USB3320)
Плата поставляется с предустановленным образом Linux в QSPI, однако необходимо научиться собирать кастомный образ с использованием Buildroot вместо PetaLinux.
Процесс загрузки платы RK-ZYNQ7020-F
Полная цепочка загрузки в режиме Non-secure:
BootROM → FSBL/U-Boot SPL → U-Boot → Linux kernel → rootfs
Этап 1 — BootROM
Неизменяемый код в кристалле, запускается первым после питания на CPU0. BootROM:
- Определяет источник загрузки по выводам MIO[8:2]
- Находит и проверяет заголовок boot.bin (идентификатор 0x584C4E58 — 'XLNX')
- Обрабатывает блок Register Initialization из Boot Header
- Копирует SPL во внутреннюю память OCM и передаёт управление
На этом этапе DDR не инициализирован — доступна только OCM.
Этап 2 — U-Boot SPL
Вместо традиционного FSBL используется U-Boot SPL, позволяющий собирать весь загрузочный процесс средствами Buildroot без Vitis. Новая последовательность:
BootROM → U-Boot SPL → U-Boot → Linux
Почему SPL необходим: полный U-Boot не помещается в OCM (256 КБ), а DDR ещё не инициализирован.
Функции SPL:
- Инициализация PS: тактирование, MIO, UART
- Настройка DDR по параметрам из ps7_init_gpl.c
- Загрузка полного u-boot.img с SD-карты в DDR
Критический файл ps7_init_gpl.c экспортируется из Vivado и содержит тайминги DDR, частоты PLL и конфигурацию MIO.
Этап 3 — U-Boot
Полный U-Boot исполняется из DDR:
- Инициализирует MMC, Ethernet, UART и периферию
- Ищет
/extlinux/extlinux.confна первом разделе SD-карты - Загружает uImage → 0x02000000, system.dtb → 0x01F00000
- При
bootm: копирует ядро (0x02000000 → 0x00008000), перемещает DTB в конец DDR, переводит CPU в режим SVC, прыгает на 0x00008000
Этап 4 — Linux Kernel
uImage содержит zImage с заголовком U-Boot. При запуске на 0x00008000 запускается декомпрессор, который проверяет перекрытие образа с собой, распаковывает vmlinux и передаёт управление stext(). Первые 32 КБ зарезервированы под начальную таблицу страниц (swapper_pg_dir).
Параметры монтирования rootfs из /extlinux/extlinux.conf: root=/dev/mmcblk0p2 rw rootwait. Без rootwait ядро упадёт в панику до готовности контроллера MMC.
Подготовка XSA в Vivado
Создание проекта и Block Design
Указываем компонент XC7Z020-2CLG484I, тип RTL Project. Создаём Block Design с одним IP-ядром ZYNQ7 Processing System (PL не используем).
Конфигурация PS
PS-PL Configuration: отключаем M AXI GP0 interface.
DDR: MT41K256M16 RE-125, 32 Bit.
MIO: Bank 0 — LVCMOS 3.3V, Bank 1 — LVCMOS 1.8V. SD0: MIO40-45, UART0: MIO 10/11, ENET0: MIO16-27.
Синтез и экспорт XSA
Run Synthesis → Run Implementation
File → Export → Export Hardware → Pre-synthesis
Сохраняем design_1_wrapper.xsa. Из него нам нужны:
| Файл | Назначение | Использование |
|---|---|---|
| ps7_init_gpl.c / .h | Ранняя инициализация PS | U-Boot SPL |
| *.hwh | XML-описание аппаратуры | xsct — генерация Device Tree |
| *.bit | Битстрим PL | При экспорте «с битстримом» |
Проверка конфигурации через Vitis
Создаём проект с design_1_wrapper.xsa как платформой, переводим плату в JTAG режим (DIP-переключатель BOOT_MODE), собираем и прошиваем Hello World.
Интерфейсы FT2232HQ: /dev/ttyUSB0 ← JTAG, /dev/ttyUSB1 ← UART (MIO10/MIO11). При успехе в терминале появится "Hello world".
Структура BR2_EXTERNAL
BR2_EXTERNAL — механизм Buildroot для хранения board-специфичных файлов вне основного дерева. Активируется переменной при вызове make:
make BR2_EXTERNAL=/path/to/buildroot_external zynq_rk7020f_defconfig
Структура внешнего дерева:
buildroot_external/
├── external.desc
├── Config.in
├── external.mk
├── configs/
│ └── zynq_rk7020f_defconfig
├── board/
│ └── zynq/
│ ├── RK-ZYNQ7020-F/
│ │ ├── dts/xilinx/
│ │ │ ├── zynq-7000.dtsi
│ │ │ └── zynq-rk7020f.dts
│ │ ├── patches/
│ │ ├── ps7_init/
│ │ │ ├── ps7_init_gpl.c
│ │ │ └── ps7_init_gpl.h
│ │ ├── rootfs_overlay/
│ │ ├── linux-config.fragment
│ │ ├── uboot-config.fragment
│ │ └── genimage.cfg
│ ├── post-build.sh
│ └── post-image.sh
└── package/
external.desc, Config.in, external.mk
# external.desc
name: FKA
desc: Buildroot
# Config.in
menu "Custom Packages"
source "$BR2_EXTERNAL_FKA_PATH/package/Config.in"
endmenu
menu "BootLoaders"
source "$BR2_EXTERNAL_FKA_PATH/boot/Config.in"
endmenu
# external.mk
include $(sort $(wildcard $(BR2_EXTERNAL_FKA_PATH)/package/*/*.mk))
include $(sort $(wildcard $(BR2_EXTERNAL_FKA_PATH)/boot/*/*.mk))
Генерация Device Tree через xsct
# dts_gen.tcl
hsi open_hw_design ./design_1_wrapper.xsa
hsi set_repo_path /home/fka/dev_linux/device-tree-xlnx
hsi create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0
hsi set_property CONFIG.periph_type_overrides {
{DEVICE_ID xc7z020}
} [hsi get_os]
hsi generate_target -dir ./dts_output
hsi close_hw_design [hsi current_hw_design]
Запуск: xsct, затем source dts_gen.tcl.
Для U-Boot SPL добавляем bootph-all в DTS:
&uart0 {
bootph-all;
cts-override;
device_type = "serial";
port-number = <0>;
status = "okay";
};
&sdhci0 {
bootph-all;
status = "okay";
xlnx,has-cd = <0x1>;
xlnx,has-power = <0x0>;
xlnx,has-wp = <0x0>;
};
Патч для добавления DTS в U-Boot
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -251,7 +251,8 @@
zynq-zturn.dtb \
zynq-zturn-v5.dtb \
zynq-zybo.dtb \
- zynq-zybo-z7.dtb
+ zynq-zybo-z7.dtb \
+ zynq-rk7020f.dtb
uboot-config.fragment
# Ранний вывод через UART
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ZYNQ=y
CONFIG_DEBUG_UART_BASE=0xE0000000
CONFIG_DEBUG_UART_CLOCK=100000000
# Поддержка serial в SPL
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DM_SERIAL=y
CONFIG_SPL_DM=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_SPL_OF_LIST="zynq-rk7020f"
# FAT и MMC
CONFIG_SPL_FS_FAT=y
CONFIG_SPL_MMC=y
CONFIG_SPL_OS_BOOT=n
# Без внешнего окружения
CONFIG_ENV_IS_IN_FAT=n
CONFIG_ENV_IS_NOWHERE=y
Адрес 0xE0000000 — физический адрес UART0 на Zynq-7000. Частота 100 МГц должна совпадать с ps7_init.
linux-config.fragment
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_XILINX=y
CONFIG_SPI_SPIDEV=y
CONFIG_OF_OVERLAY=y
CONFIG_OF_DYNAMIC=y
rootfs overlay
Buildroot выполняет rsync из директории overlay поверх output/target/ после сборки. Здесь задаём статический IP и конфиг SSH:
# etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
# etc/ssh/sshd_config
PermitRootLogin yes
PasswordAuthentication yes
Итоговый defconfig
# Архитектура
BR2_arm=y
BR2_cortex_a9=y
BR2_ARM_ENABLE_NEON=y
BR2_ARM_ENABLE_VFP=y
# Внешний тулчейн от Bootlin
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y
BR2_TOOLCHAIN_EXTERNAL_BOOTLIN_ARMV7_EABIHF_GLIBC_STABLE=y
# Board-специфичные файлы
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/patches"
BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/rootfs_overlay"
BR2_ROOTFS_POST_BUILD_SCRIPT="board/zynq/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="board/zynq/post-image.sh"
# Linux kernel
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_DEFCONFIG="xilinx_zynq"
BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/linux-config.fragment"
BR2_LINUX_KERNEL_UIMAGE=y
BR2_LINUX_KERNEL_UIMAGE_LOADADDR="0x8000"
BR2_LINUX_KERNEL_INTREE_DTS_NAME="xilinx/zynq-rk7020f"
BR2_LINUX_KERNEL_CUSTOM_DTS_DIR="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/dts"
# U-Boot SPL
BR2_TARGET_UBOOT=y
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="xilinx_zynq_virt"
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/uboot-config.fragment"
BR2_TARGET_UBOOT_SPL=y
BR2_TARGET_UBOOT_SPL_NAME="spl/boot.bin"
BR2_TARGET_UBOOT_NEEDS_DTC=y
BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/dts/xilinx/zynq-rk7020f.dts \
$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/dts/xilinx/zynq-7000.dtsi"
BR2_TARGET_UBOOT_CUSTOM_MAKEOPTS="DEVICE_TREE=zynq-rk7020f"
BR2_TARGET_UBOOT_ZYNQ_PS7_INIT_FILE="$(BR2_EXTERNAL_FKA_PATH)/board/zynq/RK-ZYNQ7020-F/ps7_init/ps7_init_gpl.c"
# rootfs
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
BR2_TARGET_ROOTFS_EXT2_SIZE="256M"
# Host инструменты
BR2_PACKAGE_HOST_DOSFSTOOLS=y
BR2_PACKAGE_HOST_GENIMAGE=y
BR2_PACKAGE_HOST_MTOOLS=y
Сборка
git clone --recurse-submodules https://github.com/FernandesKA/buildroot_custom
export BR2_EXTERNAL_FKA_PATH=$(pwd)/buildroot_external
cd buildroot
make BR2_EXTERNAL=$BR2_EXTERNAL_FKA_PATH zynq_rk7020f_defconfig
make
Подготовка SD-карты
Результат сборки в output/images/:
boot.bin ← U-Boot SPL
u-boot.img ← полный U-Boot
uImage ← ядро Linux
zynq-rk7020f.dtb ← Device Tree Blob
rootfs.ext4 ← корневая файловая система
Разметка карты через fdisk:
sudo fdisk /dev/sdX
o # новая таблица MBR
n # раздел 1, primary
[Enter]
+64M
t → c # W95 FAT32 (LBA)
a # bootable
n # раздел 2 — до конца карты
w # записать
sudo mkfs.vfat -F 32 -n BOOT /dev/sdX1
sudo mkfs.ext4 -L rootfs /dev/sdX2
Файлы на boot-разделе:
sudo mount /dev/sdX1 /mnt/boot
sudo cp output/images/{boot.bin,u-boot.img,uImage,zynq-rk7020f.dtb} /mnt/boot/
sudo mkdir -p /mnt/boot/extlinux
Содержимое /mnt/boot/extlinux/extlinux.conf:
label Linux
kernel /uImage
fdt /zynq-rk7020f.dtb
append root=/dev/mmcblk0p2 rw rootwait earlycon
| Параметр | Назначение |
|---|---|
| kernel /uImage | Путь к ядру на FAT |
| fdt /zynq-rk7020f.dtb | Путь к DTB |
| root=/dev/mmcblk0p2 | Корневая ФС — второй раздел |
| rw | Монтировать на запись |
| rootwait | Ждать инициализации MMC |
| earlycon | Вывод в UART до инициализации tty |
sudo dd if=output/images/rootfs.ext4 of=/dev/sdX2 bs=1M status=progress
sudo sync
sudo e2fsck -f /dev/sdX2 && sudo resize2fs /dev/sdX2
Автоматизация через genimage
# genimage.cfg
image boot.vfat {
vfat {
files = { "boot.bin", "u-boot.img", "system.dtb", "uImage" }
file extlinux/extlinux.conf { image = extlinux.conf }
}
size = 32M
}
image sdcard.img {
hdimage {}
partition boot {
partition-type = 0xC
bootable = "true"
image = "boot.vfat"
}
partition rootfs {
partition-type = 0x83
image = "rootfs.ext4"
}
}
sudo dd if=output/images/sdcard.img of=/dev/sdX bs=4M status=progress && sudo sync
Первый запуск и отладка
Проблема 1: SPL молчит после подачи питания
Проверить режим загрузки DIP-переключателем (SD boot). Если верный — включить DEBUG UART в uboot-config.fragment:
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_ZYNQ=y
CONFIG_DEBUG_UART_BASE=0xE0000000
CONFIG_DEBUG_UART_CLOCK=100000000
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DM_SERIAL=y
Проблема 2: SPL не видит MMC
U-Boot SPL 2025.01 (...)
Trying to boot from MMC1
spl: error reading image uImage, err - -22
SPL: failed to boot from all boot devices
Добавить в конфиг:
CONFIG_SPL_FS_FAT=y
CONFIG_SPL_MMC=y
CONFIG_SPL_OS_BOOT=n
Проблема 3: sdhci0 и uart0 не инициализируются в SPL
В новых версиях U-Boot устройства требуют свойства bootph-all в DTS — без него SPL не видит MMC несмотря на конфиг.
&sdhci0 { bootph-all; status = "okay"; ... };
&uart0 { bootph-all; ... };
Проблема 4: Bad CRC, using default environment
U-Boot ищет переменные окружения в FAT-файле uboot.env. Решение:
CONFIG_ENV_IS_IN_FAT=n
CONFIG_ENV_IS_NOWHERE=y
Проблема 5: Ethernet берёт случайный MAC
В Device Tree не задан local-mac-address. Добавить:
&gem0 {
phy-mode = "rgmii-id";
status = "okay";
xlnx,ptp-enet-clock = <0x69f6bcb>;
local-mac-address = [02 4F A3 7C 1B E9];
};
Успешная загрузка
U-Boot SPL 2025.01 (May 20 2026 - 23:45:43 +0300)
Silicon version: 3
Trying to boot from MMC1
U-Boot 2025.01 (May 20 2026 - 23:45:43 +0300)
CPU: Zynq 7z020
Silicon: v3.1
DRAM: ECC disabled 1 GiB
...
Found /extlinux/extlinux.conf
Retrieving file: /uImage
Retrieving file: /system.dtb
## Booting kernel from Legacy Image at 02000000 ...
Image Name: Linux-6.12.40-xilinx
Data Size: 6857832 Bytes = 6.5 MiB
Load Address: 00008000
Verifying Checksum ... OK
Loading Device Tree to 2fff9000 ... OK
Starting kernel ...
Итог
Полный путь от Vivado-проекта до работающей Linux-системы:
- Описание аппаратной платформы в Vivado, экспорт XSA с ps7_init_gpl.c
- Проверка базовой конфигурации через Vitis (UART Hello World)
- Понимание цепочки: BootROM → SPL → U-Boot → kernel
- Генерация Device Tree через xsct и device-tree-xlnx
- Организация BR2_EXTERNAL дерева
- Написание конфигурационных фрагментов для U-Boot и ядра
- Сборка образа через Buildroot
- Подготовка SD-карты с правильной разметкой и extlinux.conf
Все исходники: github.com/FernandesKA/buildroot_custom