Три чіпи в один ланцюг
Задача з першої частини статті проста: на вході одноканальний FPD-Link III (це такий автомобільний стандарт передачі відео по одній парі дротів, як у штатних камерах і дисплеях VAG), на виході - дуальний FPD-Link III, а посередині треба заскейлити картинку. Звичайно ж, не просто x2, бо це було б занадто легко, а саме 1024×480 -> 1540×720. Співвідношення сторін нестандартне, скейл-фактор не цілий, але обидві осі множаться рівно на 1.5 - і це єдине, що в цій задачі виглядає симетрично.
Архітектурно виходить три чіпи в ряд. Перший - DS90UH928 від Texas Instruments, він приймає FPD-Link III з кабелю і перетворює його в OpenLDI (це паралельний LVDS-інтерфейс, по якому з 80-х розмовляють між собою матриці і відеопроцесори в ноутбуках). Другий - TW8844 від Renesas, відеопроцесор, який власне і робить скейлінг. Для отримання документації на цей чіп довелось зайнятись трьохденною бюрократією з запитами до виробника. Третій - DS90UH947, той самий, що й перший, тільки навпаки: збирає OpenLDI назад у FPD-Link III, який вже піде по кабелю до дисплея. Усі троє говорять між собою паралельно через диференційні пари, а конфігуряться по I2C з STM32. Тобто це фактично три перекладачі поспіль, кожен зі своїм діалектом.
Особливості організованого збочення
Тут є тонкий момент. TW8844 теоретично вміє видавати OpenLDI у двох режимах: single-pixel (4 диференційні пари даних + клок, тобто 10 окремих провідників на платі) і dual-pixel (8 пар + клок = 18 провідників). Другий режим потрібен, коли pixel clock (це частота, з якою чіп "виштовхує" пікселі) перевалює за 96 МГц - наприклад, для Full HD 1080p60 потрібно 148.5 МГц. Мій вихід 1540×720@60 - це лише ~76 МГц, тобто single-pixel вистачає за очі. І це добре, бо dual-pixel - це вдвічі більше високошвидкісних диф-пар на платі, і розводити їх з ідентичною довжиною на двошаровій платі я б не хотів. Бо коли пара "плюс" і "мінус" має різну довжину - сигнал розсинхронізовується, і приймач на тому кінці бачить смачну кашу замість пікселів.
Цікавий парадокс на стороні 947-го: він мусить видавати dual-link FPD-Link III (бо приймач на іншому кінці кабелю налаштований саме так), але приймати OpenLDI може single-pixel. Тобто 947 отримує одну "стрічку" пікселів від TW8844 і всередині розщеплює потік на два FPD-Link III виходи, передаючи парні пікселі по одному кабелю, непарні - по іншому. Datasheet прямо цей сценарій не ілюструє, але по електричних межах усе сходиться. Класична німецька архітектура: усе на місці, просто має сходитись по частотах.
Q1, UH і ціна за літеру
Чому саме DS90UH928, а не DS90UB928? Літера в індексі - зовсім різні чіпи з різних поколінь FPD-Link. UH - третє покоління, з вбудованим HDCP (це захист від копіювання, як у HDMI). UB - друге покоління, без HDCP. У моєму ланцюгу HDCP не потрібен, але приймач на дисплеї саме UH-серії, тому й серіалайзер на іншому кінці має бути сумісний. Бо інакше двоє стоять, дивляться один на одного і нічого не передають.
Суфікс -Q1 - це AEC-Q100 кваліфікація. Простими словами: чіп перевірений на ширший температурний діапазон, вібрацію і ще десяток автомобільних тестів. Той же кремній, той же datasheet, але інакший температурний діапазон (-40...+105 °C замість -40...+85 °C) і прохід через купу тестів на надійність. Чіп non-automotive (звичайний DS90UH928) коштує $4-5, його Q1-брат коштує $8-12. За літеру в назві ви платите подвійну, а то і більше, ціну, і це нормальна автоіндустрійна реальність - у штатних блоках стоять саме такі.
Живлення: чотири рейки і автомобільна реальність
Чіпи хочуть чотири різні напруги: 3.3 V, 1.8 V, 1.2 V і 1.1 V. Остання - найвибагливіша: 1.045-1.155 V, тобто ±5%, інакше внутрішня PLL (це фазове підстроювання частоти, серцевина серіалайзера) може просто не зайти в синхронізацію. І весь канал перетворюється на сміття.
На вході - KL30. Це автомобільний термін для постійного "плюса" від акумулятора, той самий, що йде на годинник і пам'ять магнітоли. А це не "12 V номінал", це 9 V на холодному пуску, 14.4 V при роботі генератора, 24 V при jump-start (запуск від іншої машини) і теоретично до 87 V при load dump (це коли клема акумулятора відлетіла на ходу, генератор у паніці викидає свою енергію кудись). Будь-який звичайний step-down з вхідним лімітом 28 V на load dump перетворюється на маленьке кладовище кремнію.
Знайшов TPS54360B від TI - synchronous buck (тобто понижуючий перетворювач без зовнішнього діода, що зменшує втрати), 60 V вхідної напруги, 3.5 A. 60 V - це той магічний поріг, який покриває jump-start без додаткового зовнішнього клемпа. Дорожче за класичний XL1509 (китайський аналог за $0.20), але економія на одному компоненті, який витримує KL30 без додаткових захистів, того варта. Робить 3.3 V з 12 V - і ця 3.3 V далі живить і саму систему, і вхід наступного перетворювача.
Цей наступний перетворювач - RY1303 від RYCHIP. Китайський трьохканальний PMIC (це чіп, що містить кілька регуляторів живлення в одному корпусі) у QFN-20 розміром 3×3 мм, за ~$0.15. Він приймає 2.7-5.5 V на вході (тобто наша 3.3 V підходить ідеально) і робить три незалежні канали з програмованим виходом. Налаштував його на 1.1, 1.2 і 1.8 V - все три рейки одним крихітним чіпом, який менший за зернятко рису. Кожен канал має свій сигнал увімкнення, тому STM32 може керувати порядком включення: спочатку 1.8, потім 1.2, останньою - 1.1 V для серіалайзера. Бо ці чіпи капризні і вимагають конкретного порядку подачі напруг, інакше можуть зависнути на старті.
Чи правильне рішення RY1303? Для прототипу - точно. Для авто-серії я б подивився на щось з AEC-Q100, бо RY1303 спроектований для IP-камер і відеореєстраторів, а не для бортової електроніки. Але зараз задача - щоб запрацювало.
Кераміка, ферити і трохи відчаю
З високошвидкісними чіпами завжди одне і те саме: вони не люблять "брудне" живлення. У TW8844 одних тільки 1.2 V пінів живлення - вісім штук. На кожен - по 100 нФ кераміки максимально близько до піна. Плюс по одному 4.7 мкФ tank-конденсатору на кожну рейку - це локальний резервуар заряду, який тримає напругу під час різких стрибків споживання, поки регулятор не встигне зреагувати. Маленькі 100 нФ фільтрують високочастотний шум, tank - середньочастотний, регулятор - все інше. Така собі ієрархія "хто за що відповідає".
Окрема пісня - ферит-бусини. Це маленькі пасивні фільтри, які виглядають як резистори, але для високих частот ведуть себе як індуктор з втратами. На постійному струмі вони пропускають усе, а ось 100 МГц шум на них просто перетворюється в тепло. Ставлю їх послідовно в живлення для аналогових і PLL-вузлів, щоб цифровий бруд не потрапляв туди, де він особливо шкідливий. Думайте про них як про глушник, тільки для електричних шумів.
Тут я застосував один трюк, який мені сподобався: на місцях, де скоріше за все треба ферит, але я не на 100% впевнений - поставив нульові резистори того ж типорозміру. Якщо плата завелась і нічого не шумить - лишаю нулі. Якщо є проблеми - перепаюю на ферити. Економимо ферити на тих позиціях, де вони не знадобились, але закладаємо можливість їх поставити без редизайну плати. Хитро, дешево, і ніхто не дізнається:)
Загалом дискретних пасивів (це резистори/конденсатори/ферити) у схемі вийде ~80 штук тільки на decoupling і фільтрацію. Це багато, але стандартно для чіпа з 156 ногами і купою живлень.
STM32 і фокус з open-drain
Керує всім STM32G030F6P6 в TSSOP-20. Маленький Cortex-M0+, 32 КБ флешу, 8 КБ ОЗП, рідні 3.3 V. Не найдешевший, не найжирніший - просто вистачає рівно під задачу: один I2C (на якому висять усі три чіпи, кожен зі своєю адресою), кілька GPIO (тобто звичайних "ніжок" для увімкнути/вимкнути) для скидання кожного чіпа, ще пара ліній для прийому переривань, і UART для дебагу (це послідовний інтерфейс, по якому MCU може плюватись текстом на компʼютер, типу "привіт, я живий, але нічо не працює, вітаю, ти просрав купу часу та грошей").

Робимо фокуси. Пін скидання у 947-го очікує сигналу не вище 1.8 V. STM32 же видає 3.3 V. Подати 3.3 V напряму - це "перевищити абсолютний максимум", що в кращому разі скоротить життя чіпа, в гіршому - вб'є його одразу.
Не проблема: GPIO в STM32 конфігуруться в режим open-drain. Це означає, що пін уміє тільки притягувати лінію до землі (видавати "0"), а в стані "1" просто переходить у байдужий "розімкнутий" стан, як вимкнений вимикач. Назовні через підтягуючий резистор лінію підтягую до 1.8 V (звідки нам її взяти - вже маємо!). І готово: коли MCU видає "0" - лінія йде в землю, чіп бачить low. Коли MCU "відпускає" - резистор підтягує лінію до 1.8 V, чіп бачить high і працює. MCU ніколи фізично не виводить 3.3 V на пін чіпа. Прийом стандартний, але якщо про нього не знати - можна спалити чіп з другої спроби і потім три дні думати, чому не працює.
З сигналами в зворотний бік фокус інший: вони мають 1.8 V high, а STM32 на 3.3 V живленні зчитає 1.8 V як "нічого зрозумілого, мабуть low". Тут довелось поставити BSS138 - крихітний транзистор-перекладач рівнів, по 5 центів за штуку. Дешево і працює.
CAN: прокинутий, але не торкнутий
CAN-шина проходить через мою плату наскрізно: вхідний роз'єм -> диференційна пара -> вихідний роз'єм. Жодного CAN-трансівера на платі, MCU до CAN не підключено. Просто транзитна траса.
У наступній ревізії скоріше за все прокину CAN через STM32 - додам трансівер і MCU зможе перехоплювати, фільтрувати, підмішувати свої пакети. Це відкриває нові можливості: реагувати на повідомлення від електроніки, генерувати фейкові пакети для тестів. Але це наступного разу. Спочатку треба, щоб картинка просто пройшла з входу на вихід.
Роз'єм, який не існує
Окремий квест - конектор. На вході та виході має стояти 99S21L-40MA5. Це OEM-конектор HSD4 (High-Speed Data, 4 диф-пари) + 4 контакти живлення + CAN, прямокутний, з кодуванням. У VAG-машинах такі стоять у штатних дисплеях і камерах. Знайти його в нормальних магазинах - нереально. Це конектор від другорядного китайського виробника, який поставляє його прямо на конвеєри автозаводів і нічого не продає у роздріб.
Знайшов на якомусь третьорядному китайському торговельному майданчику, по чотири долари за штуку. Ще потрібно буде знайти готові коси з тими ж конекторами на обох кінцях, бо паяти HSD-пари кустарним способом не хочеться. Бо економити на проводах - це як економити на гальмах.
Для додавання такого екзотичного роз'єму на плату - довелось власноруч перемалювати посадкове місце для конектора з креслення виробника.

0402 і чесні слова про DC bias
Намагаюсь усе паяти у типорозмірі 0402 - це SMD-компоненти розміром 1.0×0.5 мм, які людина без лупи на стіл уже не покладе. Це економить місце і дозволяє розкласти 23+ decoupling-конденсатори навколо TW8844. Але не все туди влізає: tank-конденсатори 4.7-22 мкФ на 0402 фізично не існують у потрібних напругах. Tank'и - 0603 або 0805 (1.6×0.8 мм або 2.0×1.25 мм відповідно, тобто "великі" за моїми мірками).
Тут варто зробити окрему ремарку, яка має значення для кожного, хто колись копався у платах. Якщо ви купили керамічний конденсатор 0402 на 10 мкФ / 10 V - ви не отримали 10 мкФ. Реальна ємність керамічних конденсаторів класу X5R/X7R падає від прикладеної постійної напруги. Це явище зветься DC bias. Конденсатор 0402 на 10 мкФ / 10 V при робочій 3.3 V показує реально 4-5 мкФ, при 5 V - 2-3 мкФ. Це не обман і не брак, це фізика діелектрика. Чим менший корпус і вище номінал - тим страшніше падіння. Це варто розуміти при проектуванні
Нульові резистори як любовна мова
Окрім тих, що замінюють ферити - нульові резистори у мене стоять буквально на всіх диф-парах між компонентами, на UART-лініях, на I2C, на GPIO до перших трансіверів. Фактично на будь-якому місці, де я можу переплутати "плюс і мінус" пари або поміняти місцями TX/RX. Якщо паяю прототип, а потім виявляється, що D+ і D- треба було поміняти - не треба перерозводити плату. Просто перепаюю два резистори "хрест-навхрест". Працює навіть на високих швидкостях, бо 0 Ом - це просто провідник, він не вносить опору.
Цей прийом коштує копійки на BOM, але рятує від 95% дурних помилок розводки. Особливо корисно на диференційних парах, де помилка з полярністю може бути неочевидною з документації, і ти про неї дізнаєшся тільки коли картинка на виході виглядає як абстрактне мистецтво.

Два чи чотири? Питання відкрите
Усі компоненти підібрані, BOM закритий, основні чіпи (усі троє - з чорних підпільних ринків Шеньчженя) уже їдуть до мене. Залишається саме PCB.
З високочастотним сигналом я раніше не працював. Розводка LVDS - це матчинг довжин пар (різниця між + і - - пари мікрометри), матчинг між парами (не зовсім мікрометри, але близько), контрольований імпеданс 100 Ом диференційно, мінімум перехідних отворів (via - це маленькі дірочки, через які траси переходять з одного шару плати на інший), GND-площина без розривів під трасами, AC-coupling конденсатори там, де треба, термінатори 100 Ом біля приймача. Ціла наука.
Спочатку хотів спробувати двошарову плату (це коли мідь тільки зверху і знизу, а посередині скловолокно) - це і дешевше, і простіше. Але можливо так не вийде: TW8844 - корпус LQFP-156 з кроком ніг 0.4 мм, fan-out (тобто "виведення" сигналів з-під чіпа) на двох шарах фізично не виходить без розпилення GND-полігону на нижньому боці. А розпиляний GND під LVDS-трасами = імпеданс плаває = картинка деградує = картинки на виході нема.
Можливо доведеться робити чотиришарову плату зі стандартним стеком "сигнал - земля - живлення - сигнал". Усі диференційні траси - на верхньому шарі, з суцільною землею прямо під ними. Живлення - у внутрішньому шарі полігонами. Низькошвидкісне (I2C, GPIO, UART) - на нижньому. JLCPCB робить чотиришарову плату 100×100 мм за ~$15 у малій партії, що, чесно кажучи, нічого не вартує порівняно з ціною часу, який витрачу на спроби втиснути усе у дві шари.