31 Mar 2022
I get a proclivity to silly and/or pointless initiatives. This is one amongst them. Conceived from a dialog that ended with “Hi there, it would technically be doable to…” – certain, let’s enact it.
DDC, display knowledge channel, is a protocol for reading knowledge about what resolutions and heaps others a video display helps. It was as soon as later extended to DDC/CI, that enables you to house brightness and diversified parameters, however fundamentally, the usual opinion was as soon as to stay a low-payment i2c eeprom on each and each arrangement with some general knowledge on it. (Technically, the usual opinion was as soon as even more sensible than that, however let’s no longer salvage into that.)
It began within the VGA days, however has was so entrenched that even approved hardware with HDMI or DisplayPort helps it. That is factual, in an HDMI cable, nestled amongst the excessive-saunter differential pairs, there would possibly be an exceedingly unhurried i2c bus.
Tiny OLED dot-matrix shows in general get an i2c controller, so I had the premise to strive to trail one straight into an HDMI port. Hilarious! Let’s enact it.
I chopped Up a broken HDMI cable and learned the pins we care about: SCL, SDA, 5V, DDC-GND, and HPD (Sizzling Plod Detect). A immediate google obtained us the pinout:
This arrangement exhibits an HDMI socket, ought to you would possibly possibly seemingly seemingly seemingly be poking pins into the cable then flip left to factual.
|HDMI Pin Amount||Signal|
|1||TMDS Date 2+|
|2||TMDS Files 2 protect|
|3||TMDS Files 2-|
|4||TMDS Files 1+|
|5||TMDS Files 1 protect|
|6||TMDS Files 1-|
|7||TMDS Files 0+|
|8||TMDS Files 0 protect|
|9||TMDS Files 0-|
|11||TMDS Clock protect|
|15||SCL (Serial Clock for DDC|
|16||SDA (Serial Files Line for DDC|
|17||DDC / CEC / HEC Ground|
|18||+5 V Energy (50 mA max)|
|19||Sizzling Plod Detect (1.3) / HEC Files+ (1.4)|
I’ve an inclination to engage low-misfortune choices when it comes to hardware hacking, no one likes seeing blue smoke, namely if the dev board was as soon as costly. As of late even though I salvage like residing on the brink, and I’ll solder this display straight onto the severed HDMI cable popping out of my reasonably fresh pc. What a thrill! If we mess Up, this silly experiment would possibly well seemingly additionally very smartly be very costly.
It is fundamental to register to download the HDMI spec which is more effort than I get for this, however the Sizzling Plod Detect pin has a elegant descriptive determine. I guessed that this both needs to be pulled Up or pulled down to keep that a cable is linked. Sticking a 20K resistor to the 5V pin perceived to enact the trick. With the oscilloscope, we are in a position to now witness project on the SCL/SDA traces when or no longer it is plugged into the pc.
I then boldly soldered a header connector to the four traces we care about. I would possibly well ordered just a few OLED shows for this experiment, they each and each exercise the SSD1306 controller, and advance on breakout boards with the four pins on a header.
i2c and SMBus
On linux we are in a position to entry i2c gadgets by loading the i2c-dev module (
modprobe i2c-dev) which makes a bunch of i2c gadgets seem at
/dev/i2c-*. My pc exhibits 9 i2c gadgets.
Most of these are in actuality SMBus, which is a subset of i2c. So a long way as we’re concerned or no longer it is right i2c with a bunch of extra restrictions, corresponding to limiting transactions to 32 bytes.
Furthermore it is worth installing the
i2c-instruments kit which comes with the i2cdetect utility and sets a udev rule for community permissions. To entry i2c gadgets without sudo, add your self to the i2c community (
sudo usermod -G i2c -a username) and log in again for it to lift end. I also needed to inch
udevadm trigger for the udev rule to lift end. May possibly perhaps need been more sensible to reboot (never!).
Beware: the i2c arrangement naming will not be any longer consistent. I figured out that
/dev/i2c-3 was as soon as the HDMI DDC line I would possibly well soldered to, however after unloading and re-loading the module, it turned
/dev/i2c-4. We would like to be in fact cautious about this, writing (or even reading) to the unsightly i2c arrangement would possibly well seemingly without considerations muck Up one of the critical critical pc hardware.
I keep in a single other kit,
ddcutil, first-rate so that you just can enact
ddcutil detect. This lists shows and their linked i2c bus. Furthermore it is doable to enact
i2cdetect -l which lists the i2c gadgets and their description. In my case, three of the i2c traces had “i915 gmbus” of their description, i915 is the intel graphics driver.
ddcutil is unruffled doubtlessly the finest potential to establish it out.
The scope confirmed the SCL/SDA traces are already pulled Up, so we ought to be in a house to place the hide without any diversified hardware. The 5V line on an HDMI port can it appears provide as a lot as 50mA, so we originate no longer even need an impact provide. Spruce!
i2cdetect can scan an i2c bus for gadgets. As anticipated, without the cable linked, it detected nothing on the bus. Nonetheless after I linked my severed cable, with the sizzling trail detect resistor in attach, a full load of responses seemed. I originate no longer know fairly what is occurring on here (does the video hardware expose a bunch of stuff when the cable is linked?) however the critical point is that after I linked the display, a further arrangement confirmed Up at
The quickest potential to focus on to the display is with a python script. The bundled smbus library lets us salvage going in a transient time.
import smbus bus=smbus.SMBus(4) # for /dev/i2c-4 i2caddr=0x3c bus.write_i2c_block_data(i2caddr, 0, [0xaf] ) # flip display on
There is a bunch of instructions we want to send earlier than we are in a position to in actuality display the rest, including enabling the fee pump. Point to that the SSD1306 datasheet, a minimal of the copy I learned, has an appnote appended onto the end of it that explains the initialization process more clearly than the major anecdote (one of the critical critical instructions are no longer documented within the major repeat desk). As repeatedly, the fastest potential to salvage going is to witness at the provision code to present libraries, so I learned any person else’s library for the SSD1306 and copied their init instructions. The display sprang to existence!
I also learned a script to attract text to an SSD1306, and hasty patched in my smbus stuff. Success!
No microcontroller, no diversified hardware, right an SSD1306 OLED plugged straight into the HDMI port. I gain this very enjoyable.
Dumping knowledge to it
Sticking with the python script for now, I would possibly well lift so that you just can lift a 128×64 pixel describe and dump it onto the display. The text-drawing routine I borrowed makes exercise of SSD1306 instructions to govern the column and web page address that knowledge is being written to, so a single character would possibly even be drawn without affecting the comfort of the display (hence the uninitialized background pixels remaining in that describe above).
There is a full load of diversified reminiscence addressing modes for this factor, along with complicated terminology. SEG or COL is the X coordinate, COM is the Y coordinate, however these are grouped into pages. The datasheet has some diagrams.
The display is monochrome, each and each web page is 8 rows (COMs) and as soon as we pipe knowledge to the display, each and each byte is one web page, one column of pixels. It would possibly well seemingly get made more sense to configure the display for vertical addressing mode, so the bits would all be in yell, however I figured it will seemingly be quickest to right enact the bit-shuffling at our end.
With python PIL (pillow) we are in a position to convert a describe to monochrome with
.convert(1) and serialize it with
.tobytes(). This would possibly get each and each byte characterize 8 horizontal pixels, however we need each and each byte to characterize 8 vertical pixels. As a substitute of performing some unhurried bitwise common sense, the fastest potential to repair here’s by rotating the describe 90 levels earlier than we serialize it, then loading these bytes into a numpy matrix and transposing it. It is the form of factor that both works completely first time, or outputs a full mess, wherein case you right permute the yell of operations till it works. So worthy more easy than pondering.
As I mentioned, SMBus would possibly well no longer enable us to send more than 32 bytes at a time, even though this arrangement is ideal frightful i2c. We can salvage around this by getting access to the i2c arrangement straight from python. The trick is to exercise
ioctl to configure the slave address. Within the kernel header file
i2c-dev.h there are definitions for the constants wished, we first-rate care about
import io, fcntl dev="/dev/i2c-4" I2C_SLAVE=0x0703 # from i2c-dev.h i2caddr=0x3c bus=io.beginning(dev, "wb", buffering=0) fcntl.ioctl(bus, I2C_SLAVE, i2caddr) bus.write(bytearray([0x00, 0xaf]))
By alternately sending 1024 bytes of zero or 0xFF, I would possibly well seemingly gauge how hasty this updated the display. Seemed to work fastest by sending 256 bytes at a time, no longer certain if that’s a limitation of the i2c hardware (is there some extra layer of buffering?).
With this I would possibly well seemingly salvage between 5 and 10 frames per 2d (when put next to about 2FPS with the SMBus limitation). I mediate the DDC is working at 100kHz, however regardless here’s indubitably pushing the boundaries of what it was as soon as intended for.
Blueprint it a video display
Lets right write our application to attract straight to this hide, however that’s no longer factual ample, I’d love it to be a video display.
(I’m no longer certain what our application here even is, however that’s inappropriate. I’d love it to be a video display!)
Lets write our hang video driver. As tutorial as this sounds, it will seemingly be a huge amount of work and I used to be as soon as reasonably hoping to get this wrapped Up within the midst of the night time.
There are a bunch of dummy video drivers in existence, these are intended for headless machines in yell to enable VNC and heaps others.
xserver-xorg-video-dummy would possibly well seemingly feature for us, however I get a awful feeling this would possibly occasionally well no longer play smartly at all with us also having proper display outputs. There is
Xvfb, a virtual framebuffer, however this would possibly occasionally well no longer enact us worthy factual if we’re looking out to get our desktop lengthen onto it.
Since I’m the utilization of xorg, it appears the factual potential to pretend a video display, without spending days on it, is to battle by means of xrandr.
xrandr is each and each a library, and a userspace commandline utility.
It took me a while to salvage to grips with the xrandr terminology. It is no longer namely smartly explained.
- The “framebuffer” is the total desktop, i.e. what will get saved ought to you lift a screenshot.
- An “output” is a bodily video output.
- A “video display” is virtual opinion, that in general is mapped to all or phase of the framebuffer, and in general corresponds to one output. As soon as you maximize a window, it fills the scale of the video display.
- Then again, you would possibly possibly seemingly seemingly additionally get one display output be just a few video display (to illustrate, to interrupt Up a widescreen display into successfully two shows)
- Or, more than one outputs would possibly even be one video display, i.e. more than one bodily shows would possibly even be handled as if they were a single display, maximizing a window would duvet all of them.
- a “mode” is a video format, consisting of a minimal of width, height and framerate. Specifically, VESA CVT modelines are old style, and ought to even be generated with the
- xrandr’s addmode and delmode consult with associating an present mode with a display output
- xrandr’s newmode and rmmode consult with including a brand fresh mode to the server, that would possibly well then be linked with an output
Point to that this listing is particular to xrandr, in diversified substances of linux, the terms “output”, “display”, “video display” and “hide” are in general old style otherwise.
On my pc, calling xrandr exhibits 5 video outputs: eDP-1, which is the major hide with a bazillion modes on hand, and four disconnected (HDMI-1, HDMI-2, DP-1, DP-2), presumably three of which are on hand by means of thunderbolt or something.
Faking a video display, strive 1
Looking around, it appears the advised potential to enact here’s to persuade xrandr that one amongst the unused video outputs is linked. For things like VNC there could be a full market for “dummy plugs” which construct a video card mediate a video display is linked. We obviously originate no longer need or wish to enact that, we ought to be in a house to coax xrandr into behaving by means of arrangement.
In yell to output our abnormally low resolution of 128×64 on HDMI, in principle we first generate a CVT modeline:
$ cvt 128 64 # 128x64 39.06 Hz (CVT) hsync: 3.12 kHz; pclk: 0.50 MHz Modeline "128x64_60.00" 0.50 128 136 144 160 64 67 77 80 -hsync +vsync
then we add this mode to the x server:
$ xrandr --newmode "128x64_60.00" 0.50 128 136 144 160 64 67 77 80 -hsync +vsync
At this point, xrandr exhibits the unused mode at the end of its output. Confusingly it appears like the mode is phase of the rest output listed, however it completely is no longer in fact (but). We subsequent add this mode to one amongst the outputs:
xrandr --addmode HDMI-1 128x64_60.00
and at remaining strive to exercise it:
xrandr --output HDMI-1 --mode 128x64_60.00 --factual-of eDP-1
I ought to illustrate, I’ve a hotkey on my pc which cycles by means of sane display modes, so I’m cosy trying whatever here, however otherwise there could be a likelihood you end Up unable to witness the rest. It would possibly well seemingly unruffled be doable to entry the diversified virtual terminals with ctrl+alt+F2 etc, since these configure the display the utilization of KMS (Kernel Mode Environment) that sits a layer below the X server.
I tried this with each and each HDMI-1 and HDMI-2. Both of them are listed as disconnected. Our cable linked to HDMI-1 is pulling the Sizzling Plod Detect pin excessive, however no longer responding to out of the ordinary DDC queries.
I could perhaps no longer get exhausted all possibilities, however I could perhaps no longer salvage this to work. I suspect the video driver merely can not address this ludicrously nonstandard resolution, and the modeline is ideal junk. The 39.06Hz indubitably raised one amongst my eyebrows. I tried again namely environment the framerate to 39.06Hz also, to no avail.
Honestly, abusing the video outputs like this appears like a wretched resolution anyway.
To tremendous Up this mess, first exercise
--delmode to liberate the modes from any outputs, then
--rmmode to procure them from the X server.
Faking a video display, strive 2
Will get to you trade display settings xrandr in most cases sets your complete linked settings mechanically, however if we saunter deeper we are in a position to manually fiddle with them. Following one other opinion on the earn, we ought to be in a house to construct a virtual video display by merely extending the framebuffer, and defining a video display to be there, without bothering to affiliate it with an output.
Interestingly, ought to you construct the framebuffer higher than wished, by default this can mechanically pan when your mouse approaches the border. Suited to grab, however here we want to namely quit that occuring. The
--panning choice takes as a lot as twelve parameters, for panning stutter, monitoring stutter, and border. Monitoring is the stutter our mouse cursor is proscribed to. Generally, panning, monitoring and framebuffer are all house to the identical size. I’m no longer certain what “border” represents within the context of panning, it did no longer appear to get any end after I performed with it.
Environment panning to 0x0 will disable it, however that also limits the monitoring stutter, so our mouse would possibly well no longer be in a house to attain the fresh bit of framebuffer. As a substitute we limit panning to the scale of the major video display, successfully disabling it, and lengthen the monitoring stutter into our fresh chunk of framebuffer. The plump repeat:
xrandr --fb 2048x1080 --output eDP-1 --panning 1920x1080/2048x1080
Then we are in a position to clarify a brand fresh video display to exist on this fresh chunk of framebuffer:
xrandr --setmonitor virtual 128/22x64/11+1920+0 none
The scale is determined in each and each pixels and mm, I guessed or no longer it is roughly 22m by 11mm, it would no longer in fact subject even though. “virtual” is the determine of this video display, we would possibly well seemingly name it the rest. “none” is the output. We can witness shows with
xrandr --listmonitors and later undo this muck with
xrandr --delmonitor virtual.
I will be capable to now point my script to dump that bit of framebuffer onto the OLED hide. Hurrah! One dinky order with this potential is that the monitoring will not be any longer L-fashioned, my mouse can entry the strip of framebuffer that would no longer correspond to any video display. I originate no longer know if there could be a straightforward repair for this, however if it in fact troubled us we would possibly well seemingly implement honorable cursor positions by means of Xlib in our script.
Reading the framebuffer
I blueprint I’d get to throw away the python script at this point however there would possibly be
python-xlib which affords us entry to most of what we need. It is a bit of disturbing that there would possibly be no longer in fact any documentation, and the potential names are no longer identical, to illustrate
XGetImage is now
Right here is some minutiae: originate you perceive that the mouse cursor is rendered by hardware? It is sensible, I hiss. It also explains why the mouse cursor is no longer in fact in general captured if you happen to lift a screenshot. Nonetheless we’re looking out to carry the framebuffer and the mouse on high of it so there would possibly be loads more work eager.
Getting the cursor describe would mechanically be carried out by means of
python-xlib hasn’t but utilized all of XFixes. I used to be as soon as ready to commence over in C till I spotted any person’s performed your complete work for me with this repo which binds to X11/XFixes the utilization of ctypes namely to salvage the cursor knowledge.
Now we get got every little thing we want to carry the fresh virtual video display describe, superimpose the cursor within the factual attach (remembering to adjust for xhot and yhot, the pointer/cursor describe offset), convert the final consequence to a monochrome describe with the factual amount of bit-shuffling and pipe it to the display repeatedly.
That is i3 workspace four, with a truly crushed i3status and incomprehensible dithered high corner of my background describe. Stunning!
To crimson meat Up the framerate, we would possibly well seemingly make stronger our script and first-rate send the changes in would prefer to redrawing the display each and every person. As out of the ordinary as this would possibly occasionally well additionally very smartly be, on condition that I get completely no exercise for this cramped 2d hide anyway, I’m no longer namely inclined to construct it happen.
If for some excited motive you are looking out to originate that out your self, the script would possibly even be learned on github.