Skip to content

Instantly share code, notes, and snippets.

@obstruse
Created August 19, 2022 01:57
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save obstruse/a3ea854c7bda6235aa7b2bf8fedb8e2e to your computer and use it in GitHub Desktop.
Save obstruse/a3ea854c7bda6235aa7b2bf8fedb8e2e to your computer and use it in GitHub Desktop.
I2C on the HDMI port
#!/usr/bin/python3
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
import pygame.time as time
import i2cVC
import random
random.seed()
i2c = i2cVC.i2cVC(addr=0x71, bus=3)
timer = time.Clock()
active = True
RED = 0b000000000000111111111111
GREEN = 0b111111111111000000000000
Rshift = 1
Gshift = 0
while active:
try :
if (RED & 1<<23) :
Rshift = 0
if (RED & 1) :
Rshift = 1
if (GREEN & 1<<23) :
Gshift = 0
if (GREEN & 1) :
Gshift = 1
if Rshift :
RED = RED << 1
else:
RED = RED >> 1
if Gshift :
GREEN = GREEN << 1
else :
GREEN = GREEN >> 1
i2c.writeBar(RED, GREEN)
timer.tick(15)
except KeyboardInterrupt:
#except :
active = False
i2c.writeClear()
from smbus2 import SMBus
import random
alpha = [0b0000000000000001,
0b0000000000000010,
0b0000000000000100,
0b0000000000001000,
0b0000000000010000,
0b0000000000100000,
0b0000000001000000,
0b0000000010000000,
0b0000000100000000,
0b0000001000000000,
0b0000010000000000,
0b0000100000000000,
0b0001000000000000,
0b0010000000000000,
0b0100000000000000,
0b1000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0000000000000000,
0b0001001011001001,
0b0001010111000000,
0b0001001011111001,
0b0000000011100011,
0b0000010100110000,
0b0001001011001000,
0b0011101000000000,
0b0001011100000000,
0b0000000000000000, #
0b0000000000000110, # !
0b0000001000100000, # "
0b0001001011001110, # #
0b0001001011101101, # $
0b0000110000100100, # %
0b0010001101011101, # &
0b0000010000000000, # '
0b0010010000000000, # (
0b0000100100000000, # )
0b0011111111000000, # *
0b0001001011000000, # +
0b0000100000000000, # ,
0b0000000011000000, # -
0b0000000000000000, # .
0b0000110000000000, # /
0b0000110000111111, # 0
0b0000000000000110, # 1
0b0000000011011011, # 2
0b0000000010001111, # 3
0b0000000011100110, # 4
0b0010000001101001, # 5
0b0000000011111101, # 6
0b0000000000000111, # 7
0b0000000011111111, # 8
0b0000000011101111, # 9
0b0001001000000000, # :
0b0000101000000000, # ;
0b0010010000000000, # <
0b0000000011001000, # =
0b0000100100000000, # >
0b0001000010000011, # ?
0b0000001010111011, # @
0b0000000011110111, # A
0b0001001010001111, # B
0b0000000000111001, # C
0b0001001000001111, # D
0b0000000011111001, # E
0b0000000001110001, # F
0b0000000010111101, # G
0b0000000011110110, # H
0b0001001000000000, # I
0b0000000000011110, # J
0b0010010001110000, # K
0b0000000000111000, # L
0b0000010100110110, # M
0b0010000100110110, # N
0b0000000000111111, # O
0b0000000011110011, # P
0b0010000000111111, # Q
0b0010000011110011, # R
0b0000000011101101, # S
0b0001001000000001, # T
0b0000000000111110, # U
0b0000110000110000, # V
0b0010100000110110, # W
0b0010110100000000, # X
0b0001010100000000, # Y
0b0000110000001001, # Z
0b0000000000111001, # [
0b0010000100000000, #
0b0000000000001111, # ]
0b0000110000000011, # ^
0b0000000000001000, # _
0b0000000100000000, # `
0b0001000001011000, # a
0b0010000001111000, # b
0b0000000011011000, # c
0b0000100010001110, # d
0b0000100001011000, # e
0b0000000001110001, # f
0b0000010010001110, # g
0b0001000001110000, # h
0b0001000000000000, # i
0b0000000000001110, # j
0b0011011000000000, # k
0b0000000000110000, # l
0b0001000011010100, # m
0b0001000001010000, # n
0b0000000011011100, # o
0b0000000101110000, # p
0b0000010010000110, # q
0b0000000001010000, # r
0b0010000010001000, # s
0b0000000001111000, # t
0b0000000000011100, # u
0b0010000000000100, # v
0b0010100000010100, # w
0b0010100011000000, # x
0b0010000000001100, # y
0b0000100001001000, # z
0b0000100101001001, # {
0b0001001000000000, # |
0b0010010010001001, # }
0b0000010100100000, # ~
0b0011111111111111]
class i2cVC :
def __init__(self, bus=1, addr=0x70, bright=8) :
self.bus = SMBus(bus)
self.addr = addr
self.bus.write_byte(self.addr,0x21) # oscillator on
self.bus.write_byte(self.addr,0x81) # no blink
self.bus.write_byte(self.addr,0xe2) # brightness 8
def writeChar(self, pos, char=' ') :
if isinstance(char,int) :
if char < 10 :
font = alpha[ord('0')+char]
else:
font = alpha[char%len(alpha)]
else:
font = alpha[ord(char)]
self.bus.write_byte_data(self.addr,pos*2,font & 0xff)
self.bus.write_byte_data(self.addr,pos*2+1,font >>8 )
def writeRandom(self) :
# 24 - 127
low = 48
high = 91
self.writeChar(0,random.randint(low,high))
self.writeChar(1,random.randint(low,high))
self.writeChar(2,random.randint(low,high))
self.writeChar(3,random.randint(low,high))
def writeClear(self) :
self.writeChar(0)
self.writeChar(1)
self.writeChar(2)
self.writeChar(3)
def writeWord(self, word ) :
if isinstance(word,int) :
w = word
for i in range(3, -1, -1) :
if w == 0 :
self.writeChar(i)
else:
self.writeChar(i,w%10)
w = w//10
else:
for i in range(0,4) :
if i < len(word) :
self.writeChar(i,word[i])
else :
self.writeChar(i)
def writeBar(self, RED=0, GREEN=0 ) :
# input is 2 24-bit words for RED and GREEN
# bargraph output written as 6 8-bit bytes
# (24 bars * 2 bits for color = 48 bits)
B = [0]*6
# the even bytes are RED
B[0] = (RED & 0x00000f) | ((RED & 0x00f000)>>8)
B[2] = ((RED & 0x0000f0)>>4) | ((RED & 0x0f0000)>>12)
B[4] = ((RED & 0x000f00)>>8) | ((RED & 0xf00000)>>16)
# the odd bytes are GREEN
B[1] = (GREEN & 0x00000f) | ((GREEN & 0x00f000)>>8)
B[3] = ((GREEN & 0x0000f0)>>4) | ((GREEN & 0x0f0000)>>12)
B[5] = ((GREEN & 0x000f00)>>8) | ((GREEN & 0xf00000)>>16)
for i in range(0,6) :
self.bus.write_byte_data(self.addr,i,B[i])
@obstruse
Copy link
Author

obstruse commented Aug 19, 2022

This is an old hack: connecting an I2C device to the DDC pins of an unused video port. DDC gives a low speed (80KHz) I2C bus - mostly used on old Linux workstations that had no other way to interface to I2C devices.

Also useful on a Raspberry Pi when the case blocks access to the I2C pins.

It works fine on a Pi-4, but i2cdetect is a little weird:

pi@rpi4:~/Python/i2c $ i2cdetect -y 21
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 
10: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 
20: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 
30: -- -- -- -- -- -- -- -- 38 39 3a 3b 3c 3d 3e 3f 
40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 
70: 70 71 72 73 74 75 76 77      

It's only reporting on addresses 0x30 - 0x37 and 0x50 - 0x5f. All of the addresses work however. The GIF above is an LED BarGraph on address 0x71, connected to the HDMI port on a Raspberry Pi 4 through an Adafruit HDMI breakout; Python with SMBus2

So, cool, right? Well... it only works at low speed, and there's only 50 mA of 5V available, and it takes some changes to use the standard device libraries, so really you're only going to use it for simple I2C interfaces like the Adafruit LED Backpack.... but, still...?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment