HDMI Bootloader

Yes, that’s a bit of a click-baity title, but it’s technically true, I’ve managed to bootload an MSPM0L1304 over an HDMI connection.

Background

This all started when my roommate had an idea for a sort of game cheating product. The idea is that in some games, it is potentially advantageous to have the image stretched which makes aiming easier. While this is debatable, it is also desired. The way this is done is by displaying 4:3 aspect ratio resolution an a 16:9 monitor, hence stretching the image. Some games (like Valorant) try very hard to prevent you from doing this, usually by only allowing resolutions native to the monitor.

Our first attempt was to use and FPGA to literally stretch the video signal, but as we quickly discovered, all we had to do was modify the EDID (monitor identification information, including supported resolutions) data going to the PC to fool it into thinking the monitor only supported 4:3, thus allowing the game to be displayed in 4:3. The monitor knowing no better, would automatically scale this to 16:9, achieving the goal.

After this discovery, I designed a PCBA with an HDMI passthrough and MSPM0L1304 (with it’s dual I2C hardware) to intercept the EDID data (transmitted through I2C), and modify it to my liking.

Picture of the PCB
The HDMI passthrough PCB

Unfortunately, this did not give us what we were looking for in the game, more on that later, but for now, lets talk details about the bootloader!

Bootloader

Many modern MCUs come preloaded with some kind of bootloader software or hardware. The TI MSPM0 bootloader is based on hardware and allows bootloading through both I2C and UART.

While designing the PCB I realized that if I2C0 (the I2C module used for the bootloader) was connected to the PC side, I could use the PC to directly upload code to the MCU. I have previously come across Mixtela’s DDC OLED project (found here), so I knew that Linux allows for direct control of I2C ports in the PC’s HDMI connector, thus creating a bootloading program on the PC side would be no problem.

The Bootloading Program

Texas Instruments provides a comprehensive explanation of how their BSL works here. Using this document I was able to implement a bare minimum example of loading firmware from a TI-TXT format to the MCU through HDMI using this sequence from TI’s document:

Flowchart showing the sequence to bootload the MSPM0 series of MCUs

One can generate a TI-TXT directly in CCS or CCS-Theia (I used the latter). This file is simply a text file that contains the data for the MCU program and the address at which it should be programmed. I manually parsed through this file and tried my best to compensate for offsets, but it may not work will all TI-TXT files. The following code snippet shows my parser:

        with open(filename, "r") as fw_file:
            offset = 0
            for line in fw_file:
                if "@" not in line and "q" not in line:
                    line = line.strip()
                    values = line.split(' ')
                    data = [int("0x" + x, 16) for x in values]
                    print(offset)
                    self.program_block(int_to_4_byte_addr(offset), data)
                    offset += len(data)
                elif "@" in line:
                    value = line.strip().strip("@")
                    offset = int("0x" + value, 16)

If you’d like to try it yourself, my minimum example is provided on GitHub here. It’s MIT licensed, so feel free to use it in your projects 🙂 However, please be careful as messing with the I2C ports on a PC can potentially cause system damage.

Why?

So, why do we need an HDMI bootloader? In the case of this project, if it would have worked, an HDMI bootloader would provide a few benefits. Obviously, if we wanted to productize it, we could offer customers firmware updates. Another thing we were considering is sending settings over I2C to the device so that specific resolutions and other options could be changed. Other than that, I can’t really think of any good use case for a microcontroller that gets bootloaded over HDMI.

That being said, I think the idea of a MCU development kit that just has a male HDMI connector on it to plug into a laptop would be pretty cool. Then someone can load code onto it via HDMI, and interact with the board directly over I2C.

So Why Didn’t it Work?

As I mentioned, this project didn’t actually work for what we had wanted. After implementing a basic program that would read the monitor’s EDID, modify it and give the PC the modified data, we tried playing Valorant. It would seem that the game is actually very strict in that if you try to play the game in 4:3, whether you have a 16:9 or 4:3 monitor, it will forcibly squish the game. This means our 16:9 monitor will stretch it back out, back to the standard stretch.

Although this project didn’t work out to be what we wanted, I did enjoy working on it and learning about the intricacies of HDMI as well as becoming familiar with a new family of MCUs. If you have any questions please reach out to me! And if you’d like to contribute to the code, just make a merge request on GitHub.