Device Tree Source (DTS) — Довідник з теорії Серія “STM32 з нуля без HAL” · Місяць 3 · Тиждень 1

Серія “STM32 з нуля без HAL” · Місяць 3 · Тиждень 1

Все що тут описано — перевірено на живому Luckfox Pico Pro (RV1106, Cortex-A7). Якщо ви працювали з STM32 bare-metal — ви вже знаєте 80% того що робить Device Tree, тільки записане іншою мовою.


Що таке Device Tree і навіщо він

На STM32 ви описуєте периферію прямо в коді:

На embedded Linux з ARM SoC (Cortex-A) ядро не знає яка периферія є на платі. Device Tree — це файл що описує апаратуру: які контролери є, за якими адресами, які переривання використовують, які піни зайняті.

Ядро Linux читає Device Tree і робить те що ви робили руками на STM32:

  • regioremap() (замість #define BASE_ADDR)
  • interruptsrequest_irq() (замість NVIC_ISER)
  • clocks → clock framework (замість RCC_APB2ENR)
  • pinctrl → pin mux (замість alternate function в GPIOx_CRH)

Структура файлів: DTS → DTSI → DTB

Аналогія з C:

  • .dtsi — як hal.h де описані всі можливості
  • .dts — як main.c де ви обираєте що використовувати
  • .dtb — як .bin — скомпільований результат

Розширення:

  • .dts — Device Tree Source (файл плати, верхній рівень)
  • .dtsi — Device Tree Source Include (бібліотека, включається в .dts)
  • .dtb — Device Tree Blob (скомпільований бінарний файл)

Синтаксис DTS: основні елементи

Ноди (nodes)

DTS — це дерево. Кожна нода описує пристрій або шину.

Формат імені ноди: label: name@unit-address

  • uart2 — мітка (label), для посилань через &uart2
  • serial — ім’я (тип пристрою)
  • ff4c0000 — unit address (зазвичай = перше значення з reg)

Властивості (properties)

Кожна нода містить властивості у форматі name = value;

Тип значення Приклад Коментар
Рядок compatible = "snps,dw-apb-uart"; В подвійних лапках
Список рядків compatible = "rockchip,rv1106-uart", "snps,dw-apb-uart"; Через кому
Число (cell) reg = <0xff4c0000 0x100>; В кутових дужках, 32-біт
Посилання (phandle) clocks = <&cru SCLK_UART2>; & — посилання на іншу ноду
Порожня (boolean) disable-wp; Наявність = true

Ключові властивості

compatible — як ядро знаходить драйвер

Список від конкретного до загального. Ядро пробує знайти драйвер по черзі:

  1. rockchip,rv1106-uart — специфічний для RV1106
  2. snps,dw-apb-uart — generic DesignWare UART (IP-блок від Synopsys)

Формат: виробник,модель. Якщо перший не знайдений — fallback на другий.

Gotcha: compatible в root node (/) описує саму плату, не драйвер:

reg — адреси MMIO регістрів

Формат: <base_address size>. UART2 починається з 0xff4c0000, блок регістрів займає 0x100 (256 байт).

Порівняння з STM32:

Як читати reg: формат залежить від #address-cells і #size-cells батьківської ноди:

  • #address-cells = <1> → адреса = 1 cell (32 біт)
  • #size-cells = <1> → розмір = 1 cell (32 біт)
  • #size-cells = <0> → розміру немає (I2C slave адреси)

Приклад для I2C пристрою:

interrupts — переривання

Три значення:

  • GIC_SPI — тип: Shared Peripheral Interrupt (загальне переривання периферії)
  • 27 — номер переривання
  • IRQ_TYPE_LEVEL_HIGH — тригер по рівню, активний HIGH

Порівняння з STM32:

GIC vs NVIC:

Cortex-M3 (STM32) Cortex-A7 (RV1106)
Контролер NVIC GIC (Generic Interrupt Controller)
Типи IRQ SPI, PPI, SGI
Налаштування Пряме через регістри Через Device Tree

clocks — тактування

Два клоки від CRU (Clock & Reset Unit):

  • SCLK_UART2 — клок для baud rate генератора (як APB clock на STM32)
  • PCLK_UART2 — клок шини APB для доступу до регістрів

Порівняння з STM32:

status — увімкнення/вимкнення

В базовому rv1106.dtsi ВСІ контролери disabled. Файл плати вмикає тільки те що реально використовується.

Порівняння з STM32: як RCC_APB2ENR — периферія є в чіпі, але без тактування не працює. В DTS — є в дереві, але без "okay" ядро не створить пристрій.

pinctrl — мультиплексор пінів

Посилання на конфігурацію пінів. uart2m1_xfer визначений в rv1106-pinctrl.dtsi:

Формат: <bank pin function pull_config>

  • 1 — GPIO bank 1
  • RK_PB3 — Port B, pin 3
  • 2 — alternate function 2 (= UART2 RX)
  • &pcfg_pull_up — внутрішня підтяжка вгору

Порівняння з STM32:

M0 vs M1: m1 в назві — варіант розводки пінів. RV1106 дозволяє вивести один і той же UART на різні фізичні піни. На STM32F103 аналог — AFIO_MAPR remap.


Механізм перевизначення (overlay)

DTS плати перевизначає властивості з DTSI за допомогою &label:

&uart3 — це посилання (reference) на ноду з міткою uart3. Можна перевизначити будь-яку властивість або додати нові дочірні ноди. Решта властивостей (reg, interrupts, clocks) залишаються з DTSI.


Спеціальні ноди

chosen — параметри завантаження

Не описує апаратуру — передає параметри ядру. bootargs — командний рядок ядра. U-Boot може доповнювати або перевизначати bootargs перед передачею ядру.

aliases — коротке іменування

Визначає нумерацію пристроїв: serial2/dev/ttyS2. Без alias ядро нумерує в порядку виявлення (непередбачувано).

memory — опис RAM

Rockchip FIQ Debugger — особливість консолі

На Luckfox Pico Pro (і більшості Rockchip плат) консоль працює НЕ через звичайний serial драйвер, а через FIQ Debugger:

FIQ (Fast Interrupt Request) — переривання з вищим пріоритетом ніж IRQ. Rockchip перехоплює UART2 через FIQ щоб консоль працювала навіть коли ядро зависло на рівні IRQ.

Результат:

  • Консоль = ttyFIQ0 (не ttyS2)
  • UART2 недоступний як звичайний serial порт
  • В bootargs: console=ttyFIQ0
  • earlycon=uart8250,mmio32,0xff4c0000 — рання консоль до ініціалізації FIQ

⚠ Це означає що для зв’язку зі STM32 потрібно використовувати інший UART (3, 4, або 5).


Bootargs: розбір командного рядка ядра

Реальний приклад з Luckfox Pico Pro:

0xff4c0000 в earlycon — та сама адреса що в reg UART2 в DTS.


Карта UART на Luckfox Pico Pro

UART Адреса Статус Піни (M1) Використання
uart0 0xff4a0000 disabled
uart1 0xff4b0000 disabled
uart2 0xff4c0000 fiq-debugger Pin 1 (TX), Pin 2 (RX) Консоль
uart3 0xff4d0000 disabled Pin 19 (TX), Pin 20 (RX) Вільний → STM32
uart4 0xff4e0000 disabled Pin 6 (TX), Pin 7 (RX) Вільний
uart5 0xff4f0000 disabled

Для зв’язку зі STM32 найзручніший UART3 — два піни поруч, без конфліктів.


Що далі

Тиждень 2: увімкнуємо UART3 в DTS → збираємо ядро → /dev/ttyS3 з’являється → STM32 підключаємо до пінів 19/20 → Linux шле команди, STM32 відповідає.

Довідник створений на основі реального DTS Luckfox Pico Pro (RV1106G, Buildroot 2023.02.6) Серія “STM32 з нуля без HAL” · github.com/pipicosim800-maker/stm32F103

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *