Embedded HandbookПриложения
Все разделы › XVI. Печатная плата
STM32F103 · уровень средний · 7 мин чтения
Открыть в интерактивном справочнике

131. KiCad: плата скриптом и проверка из командной строки

KiCad — бесплатный пакет для схем и плат, и у него есть то, чего нет у большинства коммерческих: плата доступна из Python, а проверки и выпуск файлов для завода — из командной строки. Значит, плату можно собрать, проверить и выпустить так же, как прошивку: скриптом, в контейнере, на сервере.

Здесь так и сделано. Плата с STM32F103C8 — кварц, развязка, разъём SWD, стабилизатор, светодиод — расставлена скриптом pcbnew, проверена DRC и выпущена в Gerber программой kicad-cli из образа kicad/kicad:9.0 (KiCad 9.0.9). Все числа раздела — из этих прогонов; принципы, по которым плата устроена, — в разделе 130.

Плата собрана без схемы — ради того, чтобы её можно было построить и проверить скриптом. В обычной работе детали и цепи приходят из схемы: в редакторе платы — Tools / Update PCB from Schematic (F8, в русском интерфейсе — «Обновить плату со схемы»). И из командной строки тогда проверяют и схему: kicad-cli sch erc — электрические правила, kicad-cli pcb drc --schematic-parity — совпадение платы со схемой.

Как это называется в документации

Оригинал Перевод
footprint посадочное место: контактные площадки и контур детали
symbol условное обозначение на схеме
pad контактная площадка
track, via дорожка, переходное отверстие
zone, copper pour полигон, заливка медью
courtyard зона, которую деталь занимает на плате
silkscreen шелкография, надписи на плате
solder mask паяльная маска
Design Rules Check (DRC) проверка правил разводки
unconnected items неразведённые соединения
netclass класс цепей: ширина дорожек и зазоры
Gerber, drill file файлы слоёв и сверловки для завода

131.1 Что лежит в проекте

Файл Что в нём
*.kicad_pro настройки проекта: правила, классы цепей
*.kicad_sch схема
*.kicad_pcb плата: посадочные места, дорожки, полигоны
*.kicad_sym библиотека условных обозначений
*.pretty/*.kicad_mod библиотека посадочных мест: папка, в ней по файлу на корпус

Все файлы — текст в скобочной записи, их удобно хранить в git и сравнивать. Штатные библиотеки ставятся вместе с KiCad: обозначение STM32F103 — в MCU_ST_STM32F1.kicad_sym, корпус — Package_QFP.pretty/LQFP-48_7x7mm_P0.5mm.kicad_mod.


131.2 Плата из Python

Модуль pcbnew — тот же код, что рисует плату в окне. Посадочное место берётся из библиотеки, ставится в точку и получает цепи на выводах:

def place(lib, name, ref, x, y, rot=0, pins=None):
    fp = pcbnew.FootprintLoad(FP + lib + ".pretty", name)
    fp.SetReference(ref)
    fp.SetPosition(VECTOR2I(mm(x), mm(y)))
    fp.SetOrientationDegrees(rot)
    b.Add(fp)
    for pad in fp.Pads():
        n = (pins or {}).get(pad.GetNumber())
        if n:
            pad.SetNet(net(n))
    return fp

Контроллер — одна строка с таблицей выводов: какой вывод к какой цепи. На этой плате 15 посадочных мест и 13 цепей.


131.3 Развязка: по нормали к ряду выводов

Первая расстановка была наивной: конденсатор рядом с выводом, «первый» вывод конденсатора — к питанию, дорожка напрямик. DRC нашёл в ней 20 нарушений, и три из них — короткие замыкания: дорожка от конденсатора к VDD шла наискосок и задевала соседние выводы корпуса — GND и свободный вывод (131.5).

Правильно — поставить конденсатор на нормаль к ряду выводов, наружу, и подключить к VDD ближний к нему вывод конденсатора. Дорожка тогда прямая и проходит мимо соседей, а земляной вывод конденсатора сразу уходит переходным отверстием в сплошную землю нижнего слоя:

    for i, vdd in enumerate(("24", "36", "48", "9"), 1):
        px, py = xy(pad(mcu, vdd))
        dx, dy = px - MCU[0], py - MCU[1]
        if abs(dy) > abs(dx):                         # верхний или нижний ряд: нормаль по Y
            nx, ny, rot = 0.0, (1.0 if dy > 0 else -1.0), 90
        else:                                         # левый или правый ряд: нормаль по X
            nx, ny, rot = (1.0 if dx > 0 else -1.0), 0.0, 0
        c = place("Capacitor_SMD", "C_0603_1608Metric", "C%d" % i, px + nx * 2.8, py + ny * 2.8, rot)
        track((px, py), xy(near), "+3V3")             # прямая дорожка по нормали — мимо соседних выводов
        fx, fy = xy(far)
        v = (fx + nx * 1.0, fy + ny * 1.0)
        track((fx, fy), v, "GND")
        via(v, "GND")                                 # земля конденсатора — сразу в полигон нижнего слоя

Дорожка от каждого вывода VDD до конденсатора — 2,025 мм: центр конденсатора стоит в 2,8 мм от вывода, а площадка корпуса 0603 — в 0,775 мм от его центра, 2,8 − 0,775 = 2,025.

Развязка у вывода VDD: наискосок дорожка к первому выводу конденсатора задевает соседний GND, по нормали — прямая дорожка 2,025 мм и через 1,0 мм переходное в землю

Плата после исправлений: сверху — развязка у четырёх выводов питания, снизу — сплошная земля


131.4 Земля: полигон и его заливка

Нижний слой целиком — полигон цепи GND. Контур задают точками, а медь внутри рассчитывает отдельный шаг — заливка: она обходит чужие площадки с зазором и соединяет свои через тепловые перемычки.

Здесь ловушка: заливка для платы, собранной скриптом в памяти, в KiCad 9 без окна падает — Segmentation fault внутри ZONE_FILLER.Fill. Работает, если плату сначала сохранить, загрузить из файла и собрать связность:

b = pcbnew.LoadBoard(path)
b.BuildConnectivity()
filler = pcbnew.ZONE_FILLER(b)
ok = filler.Fill(b.Zones())
pcbnew.SaveBoard(path, b)

На готовой плате медь заливки — 1330,2 мм².


131.5 DRC из командной строки

kicad-cli pcb drc --severity-all --format json -o drc.json board.kicad_pcb

Отчёт в JSON делится на две части: нарушения правил и неразведённые соединения. Наивная расстановка из 131.3:

Нарушение Сколько Что это
shorting_items 3 дорожка +3V3 задевает чужие выводы корпуса
solder_mask_bridge 3 те же места: между разными цепями не остаётся маски
courtyards_overlap 4 детали налезают друг на друга — стабилизатор, конденсаторы, разъём
copper_edge_clearance 1 вывод разъёма ближе допустимого к краю платы
silk_over_copper 5 надписи на площадках
silk_edge_clearance 2 шелкография у самого края
silk_overlap 2 надписи налезают друг на друга

Всего 20 нарушений семи видов и 29 неразведённых соединений. После исправлений из 131.3 и перестановки узла питания — 0 нарушений и 24 неразведённых соединения: это сигнальные цепи, которые остались разводить руками, а не ошибки.

Ключ --exit-code-violations делает код возврата ненулевым — и считает при этом не только нарушения, но и неразведённые соединения. У исправленной платы нарушений 0, неразведённых 24 — и код тот же, 5, что у наивной. Поэтому на сервере сборки (раздел 110) ключ ставят, когда плата разведена целиком; до того DRC пускают без него и проверяют в отчёте JSON число нарушений.


131.6 Файлы для завода

kicad-cli pcb export gerbers --layers F.Cu,B.Cu,F.Mask,B.Mask,F.Silkscreen,B.Silkscreen,F.Paste,Edge.Cuts -o fab/ board.kicad_pcb
kicad-cli pcb export drill -o fab/ board.kicad_pcb

Без списка слоёв export gerbers выпускает все слои платы — 24 слоя и файл задания, 25 файлов, вместе с пользовательскими, сборочными и зонами деталей, которые заводу не нужны. Со списком — ровно то, что нужно для изготовления: восемь слоёв, файл описания задания .gbrjob и сверловка .drl, всего 10 файлов.

Конвейер платы в контейнере kicad/kicad:9.0: make_board.py строит board.kicad_pcb, заливка полигона — только после сохранения и загрузки из файла иначе Segmentation fault, DRC в JSON — 20 нарушений у наивной платы и 0 после правок при 24 неразведённых, экспорт со списком слоёв — 10 файлов вместо 25


131.7 Грабли

Симптом Причина
DRC: shorting_items на выводах корпуса дорожка от развязки идёт наискосок через соседние выводы
Segmentation fault в скрипте заливка полигона у платы, собранной в памяти, — заливать загруженную из файла
на заводе «лишние слои» Gerber без списка слоёв — выпущены все 24 слоя
DRC в сборке падает, хотя нарушений нет --exit-code-violations считает и неразведённые соединения
DRC чист, а плата не работает неразведённые соединения — отдельный список, не нарушения
у коллеги другие правила правила и классы цепей живут в *.kicad_pro — хранить его в git вместе с платой

131.8 Итоги

Дальше: раздел 132 «DipTrace» — тот же путь в другой программе.

Открыть в интерактивном справочнике