Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ


На этом Π²ΠΈΠ΄Π΅ΠΎ ΠΏΠΎΠΊΠ°Π·Π°Π½Ρ‹: ΠΏΠ»Π°Ρ‚Π° Raspberry Pi3, ΠΊ Π½Π΅ΠΉ, Ρ‡Π΅Ρ€Π΅Π· Ρ€Π°Π·ΡŠΠ΅ΠΌ GPIO, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π° FPGA ΠΏΠ»Π°Ρ‚Π° ΠœΠ°Ρ€ΡΠΎΡ…ΠΎΠ΄2rpi (Cyclone IV), ΠΊ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€. Π’Ρ‚ΠΎΡ€ΠΎΠΉ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ Ρ‡Π΅Ρ€Π΅Π· ΡˆΡ‚Π°Ρ‚Π½Ρ‹ΠΉ Ρ€Π°Π·ΡŠΠ΅ΠΌ HDMI Raspberry Pi3. ВсС вмСстС Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚, ΠΊΠ°ΠΊ систСма с двумя ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π°ΠΌΠΈ.

Π”Π°Π»ΡŒΡˆΠ΅ расскаТу, ΠΊΠ°ΠΊ это Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ.

На популярной ΠΏΠ»Π°Ρ‚Π΅ Raspberry Pi3 Π΅ΡΡ‚ΡŒ Ρ€Π°Π·ΡŠΠ΅ΠΌ GPIO, Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ ΠΏΠ»Π°Ρ‚Ρ‹ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ: Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠΈ, свСтодиоды, Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π° ΡˆΠ°Π³ΠΎΠ²Ρ‹Ρ… Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠ΅ Π΄Ρ€ΡƒΠ³ΠΎΠ΅. ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Π°Ρ функция ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π²Ρ‹Π²ΠΎΠ΄Π° Π½Π° Ρ€Π°Π·ΡŠΠ΅ΠΌΠ΅ зависит ΠΎΡ‚ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΏΠΎΡ€Ρ‚ΠΎΠ². ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ GPIO ALT2 позволяСт ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ€Π°Π·ΡŠΠ΅ΠΌ Π² Ρ€Π΅ΠΆΠΈΠΌ DPI интСрфСйса, Display Parallel Interface. Π‘ΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΏΠ»Π°Ρ‚Ρ‹ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ для ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ VGA ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΎΠ², Ρ‡Π΅Ρ€Π΅Π· DPI. Однако, Π²ΠΎ-ΠΏΠ΅Ρ€Π²Ρ‹Ρ…, ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Ρ‹ VGA ΡƒΠΆΠ΅ Π½Π΅ Ρ‚Π°ΠΊ распространСны, ΠΊΠ°ΠΊ HDMI, Π° Π²ΠΎ-Π²Ρ‚ΠΎΡ€Ρ‹Ρ…, Ρ†ΠΈΡ„Ρ€ΠΎΠ²ΠΎΠΉ интСрфСйс всС Π»ΡƒΡ‡ΡˆΠ΅ Π°Π½Π°Π»ΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ. Π’Π΅ΠΌ Π±ΠΎΠ»Π΅Π΅, Ρ‡Ρ‚ΠΎ ЦАП Π½Π° ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Ρ… VGA ΠΏΠ»Π°Ρ‚Π°Ρ… Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ Π² Π²ΠΈΠ΄Π΅ R-2-R Ρ†Π΅ΠΏΠΎΡ‡Π΅ΠΊ ΠΈ часто Π½Π΅ Π±ΠΎΠ»Π΅Π΅ 6 Π±ΠΈΡ‚ Π½Π° Ρ†Π²Π΅Ρ‚.

Π’ Ρ€Π΅ΠΆΠΈΠΌΠ΅ ALT2 ΠΏΠΈΠ½Ρ‹ Ρ€Π°Π·ΡŠΠ΅ΠΌΠ° GPIO ΠΈΠΌΠ΅ΡŽΡ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:

Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ

Π― здСсь раскрасил RGB Π²Ρ‹Π²ΠΎΠ΄Ρ‹ Ρ€Π°Π·ΡŠΠ΅ΠΌΠ° соотвСтствСнно Π² красный, Π·Π΅Π»Π΅Π½Ρ‹ΠΉ ΠΈ синий Ρ†Π²Π΅Ρ‚Π°. Π”Ρ€ΡƒΠ³ΠΈΠ΅ Π²Π°ΠΆΠ½Ρ‹Π΅ сигналы это сигналы синхронизации Ρ€Π°Π·Π²Π΅Ρ€Ρ‚ΠΊΠΈ V-SYNC ΠΈ H-SYNC, Π° Ρ‚Π°ΠΊ ΠΆΠ΅ CLK. Вактовая частота CLK это частота, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ значСния ΠΏΠΈΠΊcΠ΅Π»Π΅ΠΉ Π²Ρ‹Π΄Π°ΡŽΡ‚ΡΡ Π½Π° Ρ€Π°Π·ΡŠΠ΅ΠΌ, ΠΎΠ½Π° зависит ΠΎΡ‚ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ Π²ΠΈΠ΄Π΅ΠΎΡ€Π΅ΠΆΠΈΠΌΠ°.

Для ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Ρ†ΠΈΡ„Ρ€ΠΎΠ²ΠΎΠ³ΠΎ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π° Π½ΡƒΠΆΠ½ΠΎ Π·Π°Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡŒ сигналы DPI интСрфСйса ΠΈ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡ… Π² сигналы HDMI. Π‘Π΄Π΅Π»Π°Ρ‚ΡŒ это ΠΌΠΎΠΆΠ½ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠ°ΠΊΠΎΠΉ Π»ΠΈΠ±ΠΎ FPGA ΠΏΠ»Π°Ρ‚Ρ‹. Как оказалось, ΠΏΠ»Π°Ρ‚Π° ΠœΠ°Ρ€ΡΠΎΡ…ΠΎΠ΄2rpi ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для этих Ρ†Π΅Π»Π΅ΠΉ. По ΠΏΡ€Π°Π²Π΄Π΅ говоря, основной Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ этой ΠΏΠ»Π°Ρ‚Ρ‹ Ρ‡Π΅Ρ€Π΅Π· ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π½ΠΈΠΊ выглядит Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ

Π­Ρ‚Π° ΠΏΠ»Π°Ρ‚Π° слуТит для увСличСния числа GPIO ΠΏΠΎΡ€Ρ‚ΠΎΠ² ΠΈ для ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ большСго числа ΠΏΠ΅Ρ€ΠΈΡ„Π΅Ρ€ΠΈΠΉΠ½Ρ‹Ρ… устройств ΠΊ raspberry. ΠŸΡ€ΠΈ этом, 4 сигнала GPIO ΠΏΡ€ΠΈ Ρ‚Π°ΠΊΠΎΠΌ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ ΠΏΠΎΠ΄ JTAG сигналы, Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΈΠ· распбСрри ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ FPGA ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΡƒ Π² ΠŸΠ›Π˜Π‘. Из-Π·Π° этого Ρ‚Π°ΠΊΠΎΠ΅ ΡˆΡ‚Π°Ρ‚Π½ΠΎΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ½Π΅ Π½Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚, Π²Ρ‹ΠΏΠ°Π΄Π°ΡŽΡ‚ 4 DPI сигнала. По ΡΡ‡Π°ΡΡ‚ΡŒΡŽ, Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π³Ρ€Π΅Π±Π΅Π½ΠΎΡ‡ΠΊΠΈ Π½Π° ΠΏΠ»Π°Ρ‚Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΡƒΡŽ с Raspberry распиновку. Π’Π°ΠΊ, Ρ‡Ρ‚ΠΎ я ΠΌΠΎΠ³Ρƒ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΏΠ»Π°Ρ‚Ρƒ Π½Π° 90 градусов ΠΈ всС Ρ€Π°Π²Π½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π΅Π΅ ΠΊ ΠΌΠΎΠ΅ΠΉ ΠΌΠ°Π»ΠΈΠ½ΠΊΠ΅:

Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ

ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, придСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ внСшний JTAG ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°Ρ‚ΠΎΡ€, Π½ΠΎ это Π½Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°.

НСбольшая ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° всС ΠΆΠ΅ Π΅ΡΡ‚ΡŒ. НС ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π²Ρ‹Π²ΠΎΠ΄ FPGA ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ, ΠΊΠ°ΠΊ Π²Ρ…ΠΎΠ΄ Ρ‚Π°ΠΊΡ‚ΠΎΠ²ΠΎΠΉ частоты. Π•ΡΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ нСсколько dedicated pin, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для этих Ρ†Π΅Π»Π΅ΠΉ. Π’Π°ΠΊ ΠΈ здСсь ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ GPIO_0 сигнал CLK Π½Π΅ ΠΏΠΎΠΏΠ°Π΄Π°Π΅Ρ‚ Π½Π° Π²Π²ΠΎΠ΄ FPGA, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ Π²Ρ…ΠΎΠ΄ Ρ‚Π°ΠΊΡ‚ΠΎΠ²ΠΎΠΉ частоты ΠŸΠ›Π˜Π‘. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ всС Ρ‚Π°ΠΊΠΈ ΠΏΡ€ΠΈΡˆΠ»ΠΎΡΡŒ ΠΊΠΈΠ½ΡƒΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΎΠΊ Π½Π° ΠΏΠ»Π°Ρ‚ΠΊΡƒ. Π― соСдиняю GPIO_0 ΠΈ сигнал KEY[1] ΠΏΠ»Π°Ρ‚Ρ‹:

Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ

Π’Π΅ΠΏΠ΅Ρ€ΡŒ расскаТу Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Π² ΠŸΠ›Π˜Π‘. Основная ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΈ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ HDMI сигналов это ΠΎΡ‡Π΅Π½ΡŒ высокиС частоты. Если ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Ρ†ΠΎΠΊΠΎΠ»Π΅Π²ΠΊΡƒ Ρ€Π°Π·ΡŠΠ΅ΠΌΠ° HDMI, Ρ‚ΠΎ Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ сигналы RGB Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ Π΄ΠΈΡ„Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ сигналами:

Π’Ρ‚ΠΎΡ€ΠΎΠΉ HDMI ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ ΠΊ Raspberry Pi3 Ρ‡Π΅Ρ€Π΅Π· DPI интСрфСйс ΠΈ FPGA ΠΏΠ»Π°Ρ‚Ρƒ

ИспользованиС Π΄ΠΈΡ„Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ сигнала позволяСт Π±ΠΎΡ€ΠΎΡ‚ΡŒΡΡ с синфазными ΠΏΠΎΠΌΠ΅Ρ…Π°ΠΌΠΈ Π½Π° Π»ΠΈΠ½ΠΈΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ. ΠŸΡ€ΠΈ этом, исходный Π²ΠΎΡΡŒΠΌΠΈΠ±ΠΈΡ‚Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ сигнала Ρ†Π²Π΅Ρ‚Π° прСобразуСтся Π² 10-Ρ‚ΠΈ Π±ΠΈΡ‚Π½Ρ‹ΠΉ TMDS (Transition-minimized differential signaling). Π­Ρ‚ΠΎ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ способ кодирования для удалСния постоянной ΡΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π΅ΠΉ ΠΈΠ· сигнала ΠΈ ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΉ сигналов Π² Π΄ΠΈΡ„Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ Π»ΠΈΠ½ΠΈΠΈ. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π½Π° ΠΎΠ΄ΠΈΠ½ Π±Π°ΠΉΡ‚ Ρ†Π²Π΅Ρ‚Π° Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π»ΠΈΠ½ΠΈΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ 10 Π±ΠΈΡ‚, Ρ‚ΠΎ получаСтся, Ρ‡Ρ‚ΠΎ тактовая частота сСриализатора Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π² 10 Ρ€Π°Π· Π²Ρ‹ΡˆΠ΅, Ρ‡Π΅ΠΌ тактовая частота пиксСлСй. Если Π²Π·ΡΡ‚ΡŒ ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ Π²ΠΈΠ΄Π΅ΠΎ Ρ€Π΅ΠΆΠΈΠΌ 1280Ρ…720 60Π“Ρ†, Ρ‚ΠΎ частота пиксСлСй Ρƒ Ρ‚Π°ΠΊΠΎΠ³ΠΎ Ρ€Π΅ΠΆΠΈΠΌΠ° 74,25ΠœΠ“Ρ†. На сСриализаторС Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ 742,5ΠœΠ“Ρ†.

ΠžΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ FPGA Π²ΠΎΠΎΠ±Ρ‰Π΅-Ρ‚ΠΎ Π½Π° Ρ‚Π°ΠΊΠΎΠ΅, ΠΊ соТалСнию, Π½Π΅ способны. Однако, ΠΏΠΎ Π½Π°ΡˆΠ΅ΠΌΡƒ ΡΡ‡Π°ΡΡ‚ΡŒΡŽ, Π² FPGA ΠΈΠΌΠ΅ΡŽΡ‚ΡΡ встроСнныС Π²Ρ‹Π²ΠΎΠ΄Ρ‹ DDIO. Π­Ρ‚ΠΎ Ρ‚Π°ΠΊΠΈΠ΅ Π²Ρ‹Π²ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠΆΠ΅ ΠΊΠ°ΠΊ Π±Ρ‹ ΡΠ²Π»ΡΡŽΡ‚ΡΡ сСриализаторами 2-ΠΊ-1. Π’ΠΎ Π΅ΡΡ‚ΡŒ ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π²Ρ‹Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π΄Π²Π° Π±ΠΈΡ‚Π° ΠΏΠΎ Ρ„Ρ€ΠΎΠ½Ρ‚Ρƒ ΠΈ спаду Ρ‚Π°ΠΊΡ‚ΠΎΠ²ΠΎΠΉ частоты. Π—Π½Π°Ρ‡ΠΈΡ‚ Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ FPGA ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π΅ 740ΠœΠ“Ρ†, Π° 370ΠœΠ“Ρ†, Π½ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π·Π°Π΄Π΅ΠΉcΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ элСмСнты DDIO Π² ΠŸΠ›Π˜Π‘. Π’ΠΎΡ‚ 370ΠœΠ“Ρ† ΡƒΠΆΠ΅ Π²ΠΏΠΎΠ»Π½Π΅ достиТимая частота. К соТалСнию, Ρ€Π΅ΠΆΠΈΠΌ 1280×720 это ΠΏΡ€Π΅Π΄Π΅Π». Π‘ΠΎΠ»Π΅Π΅ высокого Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π² нашСй FPGA Cyclone IV установлСнной Π½Π° ΠΏΠ»Π°Ρ‚Π΅ ΠœΠ°Ρ€ΡΠΎΡ…ΠΎΠ΄2rpi Π½Π΅ Π΄ΠΎΡΡ‚ΠΈΡ‡ΡŒ.

Π˜Ρ‚Π°ΠΊ, Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅, входная частота пиксСлСй CLK поступаСт Π½Π° PLL, Π³Π΄Π΅ умноТаСтся Π½Π° 5. На этой частотС Π±Π°ΠΉΡ‚Ρ‹ R, G, B, ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΡŽΡ‚ΡΡ Π² ΠΏΠ°Ρ€Ρ‹ Π±ΠΈΡ‚. Π­Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ TMDS энкодСр. Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π½Π° Verilog HDL выглядит Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

module hdmi(
	input wire pixclk,		// 74MHz
	input wire clk_TMDS2,	// 370MHz
	input wire hsync,
	input wire vsync,
	input wire active,
	input wire [7:0]red,
	input wire [7:0]green,
	input wire [7:0]blue,
	output wire TMDS_bh,
	output wire TMDS_bl,
	output wire TMDS_gh,
	output wire TMDS_gl,
	output wire TMDS_rh,
	output wire TMDS_rl
);

wire [9:0] TMDS_red, TMDS_green, TMDS_blue;
TMDS_encoder encode_R(.clk(pixclk), .VD(red  ), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_red));
TMDS_encoder encode_G(.clk(pixclk), .VD(green), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_green));
TMDS_encoder encode_B(.clk(pixclk), .VD(blue ), .CD({vsync,hsync}), .VDE(active), .TMDS(TMDS_blue));

reg [2:0] TMDS_mod5=0;  // modulus 5 counter
reg [4:0] TMDS_shift_bh=0, TMDS_shift_bl=0;
reg [4:0] TMDS_shift_gh=0, TMDS_shift_gl=0;
reg [4:0] TMDS_shift_rh=0, TMDS_shift_rl=0;

wire [4:0] TMDS_blue_l  = {TMDS_blue[9],TMDS_blue[7],TMDS_blue[5],TMDS_blue[3],TMDS_blue[1]};
wire [4:0] TMDS_blue_h  = {TMDS_blue[8],TMDS_blue[6],TMDS_blue[4],TMDS_blue[2],TMDS_blue[0]};
wire [4:0] TMDS_green_l = {TMDS_green[9],TMDS_green[7],TMDS_green[5],TMDS_green[3],TMDS_green[1]};
wire [4:0] TMDS_green_h = {TMDS_green[8],TMDS_green[6],TMDS_green[4],TMDS_green[2],TMDS_green[0]};
wire [4:0] TMDS_red_l   = {TMDS_red[9],TMDS_red[7],TMDS_red[5],TMDS_red[3],TMDS_red[1]};
wire [4:0] TMDS_red_h   = {TMDS_red[8],TMDS_red[6],TMDS_red[4],TMDS_red[2],TMDS_red[0]};

always @(posedge clk_TMDS2)
begin
	TMDS_shift_bh <= TMDS_mod5[2] ? TMDS_blue_h  : TMDS_shift_bh  [4:1];
	TMDS_shift_bl <= TMDS_mod5[2] ? TMDS_blue_l  : TMDS_shift_bl  [4:1];
	TMDS_shift_gh <= TMDS_mod5[2] ? TMDS_green_h : TMDS_shift_gh  [4:1];
	TMDS_shift_gl <= TMDS_mod5[2] ? TMDS_green_l : TMDS_shift_gl  [4:1];
	TMDS_shift_rh <= TMDS_mod5[2] ? TMDS_red_h   : TMDS_shift_rh  [4:1];
	TMDS_shift_rl <= TMDS_mod5[2] ? TMDS_red_l   : TMDS_shift_rl  [4:1];
	TMDS_mod5 <= (TMDS_mod5[2]) ? 3'd0 : TMDS_mod5+3'd1;
end

assign TMDS_bh = TMDS_shift_bh[0];
assign TMDS_bl = TMDS_shift_bl[0];
assign TMDS_gh = TMDS_shift_gh[0];
assign TMDS_gl = TMDS_shift_gl[0];
assign TMDS_rh = TMDS_shift_rh[0];
assign TMDS_rl = TMDS_shift_rl[0];

endmodule

module TMDS_encoder(
	input clk,
	input [7:0] VD,	// video data (red, green or blue)
	input [1:0] CD,	// control data
	input VDE,  	// video data enable, to choose between CD (when VDE=0) and VD (when VDE=1)
	output reg [9:0] TMDS = 0
);

wire [3:0] Nb1s = VD[0] + VD[1] + VD[2] + VD[3] + VD[4] + VD[5] + VD[6] + VD[7];
wire XNOR = (Nb1s>4'd4) || (Nb1s==4'd4 && VD[0]==1'b0);
wire [8:0] q_m = {~XNOR, q_m[6:0] ^ VD[7:1] ^ {7{XNOR}}, VD[0]};

reg [3:0] balance_acc = 0;
wire [3:0] balance = q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7] - 4'd4;
wire balance_sign_eq = (balance[3] == balance_acc[3]);
wire invert_q_m = (balance==0 || balance_acc==0) ? ~q_m[8] : balance_sign_eq;
wire [3:0] balance_acc_inc = balance - ({q_m[8] ^ ~balance_sign_eq} & ~(balance==0 || balance_acc==0));
wire [3:0] balance_acc_new = invert_q_m ? balance_acc-balance_acc_inc : balance_acc+balance_acc_inc;
wire [9:0] TMDS_data = {invert_q_m, q_m[8], q_m[7:0] ^ {8{invert_q_m}}};
wire [9:0] TMDS_code = CD[1] ? (CD[0] ? 10'b1010101011 : 10'b0101010100) : (CD[0] ? 10'b0010101011 : 10'b1101010100);

always @(posedge clk) TMDS <= VDE ? TMDS_data : TMDS_code;
always @(posedge clk) balance_acc <= VDE ? balance_acc_new : 4'h0;

endmodule

ΠŸΠΎΡ‚ΠΎΠΌ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ ΠΏΠ°Ρ€Ρ‹ ΠΏΠΎΠ΄Π°ΡŽΡ‚ΡΡ Π½Π° DDIO Π²Ρ‹Ρ…ΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π²Ρ‹Π΄Π°Π΅Ρ‚ ΠΎΠ΄Π½ΠΎΠ±ΠΈΡ‚Π½Ρ‹ΠΉ сигнал ΠΏΠΎ Ρ„Ρ€ΠΎΠ½Ρ‚Ρƒ ΠΈ спаду.

Π‘Π°ΠΌ DDIO ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Π±Ρ‹ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ‚Π°ΠΊΠΈΠΌ Verilog ΠΊΠΎΠ΄ΠΎΠΌ:

module ddio(
	input wire d0,
	input wire d1,
	input wire clk,
	output wire out
	);

reg r_d0;
reg r_d1;
always @(posedge clk)
begin
	r_d0 <= d0;
	r_d1 <= d1;
end
assign out = clk ? r_d0 : r_d1;
endmodule

Но Ρ‚Π°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ скорСС всСго Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚. НуТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π°Π»ΡŒΡ‚Π΅Ρ€ΠΎΠ²ΡΠΊΡƒΡŽ ΠΌΠ΅Π³Π°Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ALTDDIO_OUT, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π° самом Π΄Π΅Π»Π΅ Π·Π°Π΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ DDIO элСмСнты. Π’ ΠΌΠΎΠ΅ΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΈΠΌΠ΅Π½Π½ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅Ρ‡Π½Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ALTDDIO_OUT.

Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, всС это выглядит Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΌΡƒΠ΄Ρ€Π΅Π½ΠΎ, Π½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚.

ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ вСсь исходный ΠΊΠΎΠ΄, написанный Π½Π° Verilog HDL, ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΎΡ‚ здСсь, Π½Π° github.

Бкомпилированная ΠΏΡ€ΠΎΡˆΠΈΠ²ΠΊΠ° для FPGA Π·Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ Π² EPCS Ρ‡ΠΈΠΏ, установлСнный Π½Π° ΠΏΠ»Π°Ρ‚Π΅ ΠœΠ°Ρ€ΡΠΎΡ…ΠΎΠ΄2rpi. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΏΡ€ΠΈ ΠΏΠΎΠ΄Π°Ρ‡Π΅ питания Π½Π° ΠΏΠ»Π°Ρ‚Ρƒ FPGA, ΠŸΠ›Π˜Π‘ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΈΠ· Ρ„Π»ΡΡˆ памяти ΠΈ ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²Π°Ρ‚ΡŒ.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½ΡƒΠΆΠ½ΠΎ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π°ΡΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ самого Raspberry.

Π― дСлаю экспСримСнты Π½Π° Raspberry PI OS (32 bit) based on Debian Buster, Version:August 2020,
Release date:2020-08-20, Kernel version:5.4.

НуТно ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΄Π²Π΅ Π²Π΅Ρ‰ΠΈ:

  • ΠΎΡ‚Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» config.txt;
  • ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡŽ X сСрвСра для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с двумя ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π°ΠΌΠΈ.

ΠŸΡ€ΠΈ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Ρ„Π°ΠΉΠ»Π° /boot/config.txt Π½ΡƒΠΆΠ½ΠΎ:

  1. Π²Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ использованиС i2c, i2s, spi;
  2. Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ DPI с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ овСрлСя dtoverlay=dpi24;
  3. Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎΡ€Π΅ΠΆΠΈΠΌ 1280×720 60Π“Ρ†, 24 Π±ΠΈΡ‚Π° Π½Π° Ρ‚ΠΎΡ‡ΠΊΡƒ Π½Π° DPI;
  4. ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ΅ количСство Ρ„Ρ€Π΅ΠΉΠΌΠ±ΡƒΡ„Ρ„Π΅Ρ€ΠΎΠ² 2 (max_framebuffers=2, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚ΠΎΠ³Π΄Π° появится Π²Ρ‚ΠΎΡ€ΠΎΠ΅ устройство /dev/fb1)

ΠŸΠΎΠ»Π½Ρ‹ΠΉ тСкст Ρ„Π°ΠΉΠ»Π° config.txt выглядит Ρ‚Π°ΠΊ.

# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

dtparam=i2c_arm=off
dtparam=spi=off
dtparam=i2s=off

dtoverlay=dpi24
overscan_left=0
overscan_right=0
overscan_top=0
overscan_bottom=0
framebuffer_width=1280
framebuffer_height=720
display_default_lcd=0
enable_dpi_lcd=1
dpi_group=2
dpi_mode=87
#dpi_group=1
#dpi_mode=4
dpi_output_format=0x6f027
dpi_timings=1280 1 110 40 220 720 1 5 5 20 0 0 0 60 0 74000000 3

# Uncomment this to enable infrared communication.
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
dtparam=audio=on

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2

[all]
#dtoverlay=vc4-fkms-v3d
max_framebuffers=2

ПослС этого, Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» для X сСрвСра для использования Π΄Π²ΡƒΡ… ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΎΠ² Π½Π° Π΄Π²ΡƒΡ… Ρ„Ρ€Π΅ΠΉΠΌΠ±ΡƒΡ„Ρ„Π΅Ρ€Π°Ρ… /dev/fb0 ΠΈ /dev/fb1:

Мой Ρ„Π°ΠΉΠ» ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ /usr/share/x11/xorg.conf.d/60-dualscreen.conf Ρ‚Π°ΠΊΠΎΠΉ

Section "Device"
        Identifier      "LCD"
        Driver          "fbturbo"
        Option          "fbdev" "/dev/fb0"
        Option          "ShadowFB" "off"
        Option          "SwapbuffersWait" "true"
EndSection

Section "Device"
        Identifier      "HDMI"
        Driver          "fbturbo"
        Option          "fbdev" "/dev/fb1"
        Option          "ShadowFB" "off"
        Option          "SwapbuffersWait" "true"
EndSection

Section "Monitor"
        Identifier      "LCD-monitor"
        Option          "Primary" "true"
EndSection

Section "Monitor"
        Identifier      "HDMI-monitor"
        Option          "RightOf" "LCD-monitor"
EndSection

Section "Screen"
        Identifier      "screen0"
        Device          "LCD"
        Monitor         "LCD-monitor"
EndSection

Section "Screen"
        Identifier      "screen1"
        Device          "HDMI" 
	Monitor         "HDMI-monitor"
EndSection

Section "ServerLayout"
        Identifier      "default"
        Option          "Xinerama" "on"
        Option          "Clone" "off"
        Screen 0        "screen0"
        Screen 1        "screen1" RightOf "screen0"
EndSection

Ну ΠΈ, Ссли Π΅Ρ‰Π΅ Π½Π΅ установлСна, Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Xinerama. Π’ΠΎΠ³Π΄Π° пространство Ρ€Π°Π±ΠΎΡ‡Π΅Π³ΠΎ стола Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΎ Π½Π° Π΄Π²Π° ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π°, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²Ρ‹ΡˆΠ΅ Π½Π° Π΄Π΅ΠΌΠΎ Ρ€ΠΎΠ»ΠΈΠΊΠ΅.

Π’ΠΎΡ‚ ΠΏΠΎΠΆΠ°Π»ΡƒΠΉ ΠΈ всС. Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΈ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Ρ‹ Raspberry Pi3 смогут ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ двумя ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€Π°ΠΌΠΈ.

ОписаниС ΠΈ схСму ΠΏΠ»Π°Ρ‚Ρ‹ ΠœΠ°Ρ€ΡΠΎΡ…ΠΎΠ΄2rpi ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π²ΠΎΡ‚ здСсь.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com