Hi everyone !
I interested in messing with a VGA/HDMI/.. connector & the data exchanged between a device connected to it, read on ! ;p
As a reminder, EDID looks like that:
header: 00 ff ff ff ff ff ff 00
serial number: 50 a6 87 46 e1 0b 04 01 27 19
version: 01 03
basic params: 80 10 09 78 0a
chroma info: ee 91 a3 54 4c 99 26 0f 50 54
established: 21 08 00
standard: 81 80 a9 40 01 01 01 01 01 01 01 01 01 01 01 01
For a current project, I need to:
The goal is more or less an "HDMI DDC EDID MitM" ( we can change a lot of infos found in the original EDID )^^
Along with the above, it should also act as a "fast hdmi switcher", doing EDID handling & messing with hotplug pins ( since EDID is no longer re-read from the monitor when it's switching to a particular source, but instead read once, when the device connecting to the monitor does so in the background )
my current prototype consists of:
The Espruino listens for a pin rising ( the monitor's hdmi connector's hotplug pin ) before acting as an i2c master to then write & read data a monitor's ( fixed ) i2c adress 0X50.
The Arduino simulates a 'source' device connection by toggling its hdmi connector's hotplug pin before acting as an i2c slave with address 0x50 & provides EDID data whenever being requested to over i2c.
I am currently wondering what'd be the simplest & most robust way to communicate between the Espruino & the Arduino ( knowing that having a 3IN<->1OUT hdmi switch, I plan to use 2 more Arduinos, one for each hdmi IN ).
Every Arduino has only one hdmi device's i2c pins connected to it, and the Espruino is also using different i2c pins to communicate with the screen.
I hesitate between SPI & serial, and the only limitation ( at least those I see for now .. ) is using a pin for each on the Espruino & using a watch to listen for an Arduino's request of the ( modded ) monitor's EDID ( store within the Espruino's program & refreshed on boot ).
Moreover, we have limited memory on both the Espruino & the Arduino & although I did get away with modding the Arduino's "Wire" ( i2c ) lib, it seemed I couldn't get more than 256 bytes out of it at once ( and I couldn't figure out if this was coming from the Espruino side ? .. ) & while increasing the buffer seemed to free memory Arduino-side, I still can't get more than ~253 bytes when reading from an i2c address using Espruino ( I still have to run tests using an Arduino as i2c master to better identify the source of the trouble ).
To bypass this current limitation, I re-wrote the Arduino code to act more like my laptop ( & surely other 'source' devices ) does ( writing a byte to select the portion to be read from i2c, then reading max 128 bytes of data ).
As the EDID is 128 bytes big & so does the Extended one, writing 0x00 then reading 128 bytes gives to EDID, and writing 0x80 then reading 128 bytes gives to Extended data.
Also, writing a byte < 256 & then reading a number of bytes gives the n bytes starting from the previously written one ( seems to be the common way for i2c memory chips ? .. ).
This being said, it seems reading 128 bytes again & again without writing any returns the EDID or the Extended One alternatively in a cycle
I mostly replicated this behavior ( although I have to fix the code handling switching between sending alternatively each & sending only 128 bytes from a previously received one on the Arduino-side - which works but is still not working wip since it doesn't handle cycling without receiving a byte beforehand for now .. and yet it's not-that-bad-enough to work ;) )
Once the above was nearly ok, I decided to try scanning the available i2c devices in the monitor, but sadly none of the i2c scanners I found for Espruino worked :/ ..
.. so I modified a little bit the EDID sniffing code to instead trigger an i2c scan right after sensing a rise on the monitor's hotplog pin & it seems to work, albeit very slow for now
I'll try to mod an existing i2c scanner to do the work faster & give a prettier output, but part of my other code seems needed, at least for my monitor ( compared to other i2c devices I guess ? .. )
Code provided below is for:
( not fitting in one post .. :/ )
So, the said-prototype produces the following when connected to ( currently a laptop )
ps: among other stuff, there's a "possible easter egg' somewhere in it .. will you find it ? ^^
EDID version: 1.3
Manufacturer: TEF Model 4687 Serial Number 17042401
Made in week 39 of 2015
Maximum image size: 16 cm x 9 cm
RGB color display
First detailed timing is preferred timing
Display x,y Chromaticity:
Red: 0.6396, 0.3300
Green: 0.2998, 0.5996
Blue: 0.1503, 0.0595
White: 0.3125, 0.3291
Established timings supported:
640x480@60Hz 4:3 HorFreq: 31469 Hz Clock: 25.175 MHz
800x600@60Hz 4:3 HorFreq: 37900 Hz Clock: 40.000 MHz
1024x768@60Hz 4:3 HorFreq: 48400 Hz Clock: 65.000 MHz
Standard timings supported:
1280x1024@60Hz 5:4 HorFreq: 64000 Hz Clock: 108.000 MHz
1600x1200@60Hz 4:3 HorFreq: 75000 Hz Clock: 162.000 MHz
Detailed mode: Clock 148.500 MHz, 160 mm x 90 mm
1920 2008 2052 2200 hborder 0
1080 1084 1089 1125 vborder 0
VertFreq: 60 Hz, HorFreq: 67500 Hz
Detailed mode: Clock 85.500 MHz, 160 mm x 90 mm
1360 1424 1536 1792 hborder 0
768 771 777 795 vborder 0
VertFreq: 60 Hz, HorFreq: 47712 Hz
Monitor ranges (GTF): 23-61Hz V, 26-76kHz H, max dotclock 230MHz
Monitor name: VIRTUOSA
Has 1 extension blocks
Checksum: 0x18 (valid)
Wow, nice idea! I'd say definitely go for Serial between Espruino and the Arduino - it's nice and easy to wire up, and to debug with a USB-TTL converter.
To be honest even the I2C reader & decoder on something like Pixl.js would be a great debug tool - you could plug it into any HDMI device and see what it was capable of.
I should really add I2C and SPI slave support to Espruino - the issue really has been how to handle it when the JS takes so long to execute. It could just be a bunch of registers since that's what most I2C devices seem to do - but anyway, that's sidetracking the thread - I guess it should be a GitHub issue.
Hi there !
It indeed seems that Arduino <-serial->Espruino is the quickest & handy path to choose
( I am currently doing so to control & get feedbacks on a Teensy 3.6 - acting as an Xbox 360 controller - from Espruino ;) )
As I get enough time to do so, I'll update the reader/decoder part & start building a lib from those ( nb: it 'd require a whole lot of work additionally to the current one to get all the infos for a particular monitor, though )
As I currently don't own a Pixl.js ( I'd be more interested in a MDBT42Q breakout ;p ), I'll just pack the interesting bits & give that away in the forums ( or try building a canvas pixl.js screen emulator ? )
On the I2C & SPI slave subject, it 'd be really awesome to have, as this is one of the reason I still need to keep an Arduino closeby when messing with stuff ( on a side note, I currently face somewhat close ends as I'm trying to use a custom usb device descriptor different that a HID one ( that's why I'm using a Teensy for now to do the USB talk ;p ).
I guess I can help on neither, as I currently don't know either enough to be of any actual help implementing those on the Espruino platform :/
or try building a canvas pixl.js screen emulator ?
or try building a canvas pixl.js screen emulator ?
The Pixl just offers a global variable called g for graphics... If you just do something like http://www.espruino.com/Pico+LCD+Hello+World before you call your code then you're basically there with emulation :)
Do you think having the slave implemented as a bunch of registers would actually work in this case?
allright, I'll try to find a screen or make use of that ;)
on the i2c subject, did you have something like this in mind http://amitesh-singh.github.io/stm32/2018/01/07/making-i2c-slave-using-stm32f103.html ?
I honestly don't have enough skills to tell you if it'd work ( but a huge part of me thinks why not considering my quick & ugly arduino code worked ? )
I also wonder if it' be useful to have a callback called once data has been accessed ? ( or if it would just slow down the entire process .. )
For I2C, yes - that's pretty much the idea. The API used in the example looks different to the one I use (eg https://github.com/espruino/Espruino/blob/ab227f54ad5585d5ceaa7cfd6b54634ee0dc609d/targets/stm32/jshardware.c#L2338) but it's the same idea (also I'd have to make sure the code for I2C master still worked :).
Having said that, if you're doing it for yourself then yeah, just try it and see :)
You could have a callback for a read - the only issue is if you waited for the response. I think a lot of devices wouldn't be willing to wait for long enough so you'd really need to at least offer a solution that just pushed the data ASAP.
Don't worry about formatting, just type in the text and we'll take care of making sense of it. We will auto-convert links, and if you put asterisks around words we will make them bold.
For a full reference visit the Markdown syntax.
© Espruino, powered by microcosm.
Report a problem