{"id":50365789,"url":"https://github.com/rh1tech/frank-hdmi-audio","last_synced_at":"2026-05-30T04:03:51.511Z","repository":{"id":358222787,"uuid":"1240271691","full_name":"rh1tech/frank-hdmi-audio","owner":"rh1tech","description":"RP2350 HDMI video + audio driver (libdvi-based, with HDMI data-island audio). Pico SDK library, GPL-3.0.","archived":false,"fork":false,"pushed_at":"2026-05-16T09:33:12.000Z","size":1053,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T11:31:29.015Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://rh1.tech","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rh1tech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-16T00:21:36.000Z","updated_at":"2026-05-16T09:33:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rh1tech/frank-hdmi-audio","commit_stats":null,"previous_names":["rh1tech/frank-hdmi-audio"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rh1tech/frank-hdmi-audio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rh1tech%2Ffrank-hdmi-audio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rh1tech%2Ffrank-hdmi-audio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rh1tech%2Ffrank-hdmi-audio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rh1tech%2Ffrank-hdmi-audio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rh1tech","download_url":"https://codeload.github.com/rh1tech/frank-hdmi-audio/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rh1tech%2Ffrank-hdmi-audio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33679310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-30T04:03:50.823Z","updated_at":"2026-05-30T04:03:51.505Z","avatar_url":"https://github.com/rh1tech.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# frank-hdmi-sound\n\nFRANK HDMI Sound is a small HDMI video and audio driver for the \nRaspberry Pi RP2350, packaged as a Pico SDK library. It outputs \n640x480p60 video from a 320x240 palette-indexed framebuffer and embeds \n32 kHz stereo PCM in the HDMI data-island stream. No external DAC, \nno separate audio path.\n\nThe TMDS encoding core is based on\n[PicoDVI](https://github.com/Wren6991/PicoDVI) by Wren6991, via shuichitakano's\n[PicoDVI-audio](https://github.com/shuichitakano/PicoDVI-audio) fork,\nwhich adds HDMI data-island audio support. The libdvi integration\npattern follows\n[pico-zxspectrum](https://github.com/fruit-bat/pico-zxspectrum). This\nlibrary extracts and generalises the HDMI path originally written for\n[frank-snes](https://github.com/rh1tech/frank-snes).\n\n![hello_hdmi test pattern: navy field with a 32-pixel grid, three coloured squares and a marching white block](screenshots/screen1.png)\n\nCaptured from the bundled `hello_hdmi` example over an HDMI capture\ncard. Audio (440 Hz tone, then a multi-voice melody) is carried in the\nsame HDMI stream.\n\n## What you get\n\n- 640x480p60 HDMI video on a single PIO block.\n- 320x240 logical canvas. The libdvi 16bpp encoder is pixel-doubling,\n  so the source framebuffer is 320 wide on the wire.\n- 8-bit palette-indexed framebuffer with a 256-entry RGB888 LUT.\n- 32 kHz stereo PCM audio in the HDMI data-island stream.\n- Producer/consumer split across the two RP2350 cores: Core 1 owns\n  the DVI engine, Core 0 stays free for application work.\n- CPU at 504 MHz. libdvi divides its serialiser SMs and the PWM\n  pixel clock by 2 so the 252 MHz TMDS bit clock stays at spec.\n\n## What you do not get\n\n- Frame buffers larger than 320x240. Smaller buffers are centred with\n  a black pillarbox and letterbox; larger buffers are clipped.\n- 50 Hz, 720x576, or 1280x720 modes. The vendored libdvi build can\n  do them; this driver only wires up 640x480p60.\n- A per-line scanline callback. Application work has to live on\n  Core 0.\n- HDMI hot-plug detect, EDID, or HDCP. The driver assumes a passive\n  HDMI sink (TV, capture card, monitor) that locks on the TMDS\n  stream unconditionally.\n\n## Pin layout\n\nThe driver writes a TMDS clock pair on `(CLK_PIN, CLK_PIN+1)` and three\nTMDS data pairs on `(D0_PIN, D0_PIN+1)`, `(D1_PIN, D1_PIN+1)`,\n`(D2_PIN, D2_PIN+1)`. `CLK_PIN` must be even (PWM slice constraint).\n\nDefault layout matches the FRANK / M2 board:\n\n| Signal | GPIO  |\n|--------|-------|\n| CLK-   | 12    |\n| CLK+   | 13    |\n| D0-    | 14    |\n| D0+    | 15    |\n| D1-    | 16    |\n| D1+    | 17    |\n| D2-    | 18    |\n| D2+    | 19    |\n\nOverride at build time:\n\n```cmake\ntarget_compile_definitions(your_target PRIVATE\n    FRANK_HDMI_PIN_CLK=10\n    FRANK_HDMI_PIN_D0=12\n    FRANK_HDMI_PIN_D1=14\n    FRANK_HDMI_PIN_D2=16\n)\n```\n\nIf your board has the differential pair wired with the positive leg on\nthe lower-numbered GPIO of each pair, also set\n`FRANK_HDMI_INVERT_DIFFPAIRS=1`.\n\n## Prerequisites\n\n- Pico SDK 2.0 or later. Set `PICO_SDK_PATH` in your environment.\n- Pico 2 (RP2350) board. RP2040 is not supported.\n- ARM GNU toolchain (`arm-none-eabi-gcc`).\n- `picotool` on `PATH` for flashing.\n\n## Using the library in your project\n\n1. Drop the directory into your project tree. A vendored copy, a git\n   submodule, or `FetchContent` all work.\n\n2. Add it to your top-level CMake:\n\n   ```cmake\n   add_subdirectory(third_party/frank-hdmi-sound)\n\n   target_link_libraries(your_app\n       frank_hdmi_sound\n       pico_stdlib\n       pico_multicore\n   )\n   ```\n\n3. Bring up the driver from your `main()`:\n\n   ```c\n   #include \"pico/stdlib.h\"\n   #include \"pico/multicore.h\"\n   #include \"hardware/clocks.h\"\n   #include \"frank_hdmi.h\"\n\n   static uint8_t fb[320 * 240];\n\n   int main(void) {\n       set_sys_clock_khz(504000, true);\n\n       /* Fill some palette entries. */\n       frank_hdmi_set_palette(0, 0x000000);\n       frank_hdmi_set_palette(1, 0xFFFFFF);\n\n       frank_hdmi_init();\n       frank_hdmi_set_buffer(fb, 320, 240);\n       multicore_launch_core1(frank_hdmi_run_core1);\n\n       /* Draw into fb at any time.  Core 1 picks up the changes on\n        * the next scanline read. */\n       while (1) tight_loop_contents();\n   }\n   ```\n\n4. Push audio whenever you have samples ready:\n\n   ```c\n   int16_t buf[2 * 533];   /* one video frame's worth at 32 kHz */\n   /* fill buf with stereo int16 samples */\n   frank_hdmi_audio_write(buf, 533);\n   ```\n\n   The audio ring is 2048 frames, which is about 64 ms at 32 kHz.\n   The driver drops samples silently on overflow; it never blocks\n   the producer.\n\n## Building the example\n\n```sh\ngit clone https://github.com/rh1tech/frank-hdmi-audio\ncd frank-hdmi-audio\nmkdir build \u0026\u0026 cd build\ncmake -DPICO_PLATFORM=rp2350 ..\nmake -j\npicotool load -fx examples/hello_hdmi/hello_hdmi.elf\n```\n\nThe example draws a navy-and-grid test pattern with three R/G/B\nsquares and a marching white block, then plays:\n\n1. A pure 440 Hz tone for 3 seconds.\n2. 1 second of silence.\n3. A multi-voice test melody (synth lead, bass, kick, snare) on\n   loop.\n\nA pre-built UF2 for the M2 board is also checked in at\n`release/hello_hdmi_m2.uf2`.\n\nFor a step-by-step walkthrough (toolchain install, configure, flash,\nverify, integrate, plus a debugging reference covering every bug the\ndriver hit during bring-up), see [docs/BUILDING.md](docs/BUILDING.md).\n\nFor a from-scratch tutorial that builds an app like `hello_hdmi` one\npiece at a time with explanations for every non-obvious line, see\n[docs/WRITING_AN_APP.md](docs/WRITING_AN_APP.md).\n\n## System clock\n\nThe driver does not change the CPU clock. The vendored libdvi build is\nconfigured with `DVI_SM_CLKDIV=2`, so the TMDS bit clock is sys_clock\ndivided by 2. Concretely:\n\n| `set_sys_clock_khz` | TMDS bit clock | Notes |\n|---------------------|----------------|-------|\n| 504 000             | 252 MHz        | Recommended. |\n| 252 000             | 126 MHz        | Fails: too slow for 640x480p60. |\n\nIf you need to run the CPU at a different speed, set `DVI_SM_CLKDIV`\naccordingly when adding the subdirectory:\n\n```cmake\nset(DVI_SM_CLKDIV 1 CACHE STRING \"\" FORCE)   # CPU = TMDS = 252 MHz\nadd_subdirectory(third_party/frank-hdmi-sound)\n```\n\n## Memory footprint\n\n| Section          | Bytes      | Where |\n|------------------|------------|-------|\n| TMDS DMA buffers | ~12 KB (3 × ~3.8 KB) | main SRAM |\n| Audio ring       | 8 KB       | main SRAM |\n| Scanline buffers | 1.25 KB (2 × 640 B) | main SRAM |\n| Palette LUT      | 512 B      | scratch_y |\n| `fill_scanline`  | ~200 B     | scratch_y |\n\nTotal: ~22 KB main SRAM, ~700 B scratch_y. That leaves plenty of\nroom for an application working set on the RP2350's 512 KB.\n\n## Acknowledgements\n\n- [Luke Wren](https://github.com/Wren6991) for PicoDVI.\n- [shuichitakano](https://github.com/shuichitakano) for the\n  PicoDVI-audio fork that adds HDMI data-island audio.\n- [fruit-bat](https://github.com/fruit-bat) and contributors for\n  pico-zxspectrum, whose libdvi integration pattern this driver\n  follows.\n\n## Licence\n\nThe driver source (`src/frank_hdmi.{c,h}`, the example, build system,\ndocs) is GPL-3.0-or-later, Copyright (c) 2026 Mikhail Matveev.\n\nThe driver internals (`src/frank_dvi*.{c,h}`,\n`src/frank_serialiser*`, `src/frank_audio_ring*`,\n`src/frank_data_packet*`, `src/frank_tmds*`,\n`src/frank_queue_inline.h`) are based on libdvi by Luke Wren and\nshuichitakano. BSD-3-Clause, Copyright (c) 2021 Luke Wren and\ncontributors. Each file carries the BSD notice; local changes are\ntagged `PATCH (frank-hdmi-sound):` so they can be lifted back\nupstream if anyone wants to.\n\n## Author\n\nMikhail Matveev \u003c[xtreme@rh1.tech](mailto:xtreme@rh1.tech)\u003e\n\n[https://rh1.tech](https://rh1.tech) | [GitHub](https://github.com/rh1tech/frank-hdmi-audio)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frh1tech%2Ffrank-hdmi-audio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frh1tech%2Ffrank-hdmi-audio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frh1tech%2Ffrank-hdmi-audio/lists"}