Skip to content

Commit

Permalink
applet.rgb_grabber: implement.
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed Aug 14, 2018
1 parent 66aa942 commit ae5cbc1
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
2 changes: 1 addition & 1 deletion software/glasgow/access/direct/arguments.py
Expand Up @@ -67,7 +67,7 @@ def _pin_set(self, width, arg):
return numbers

def _add_pin_set_argument(self, parser, name, width, default, required):
help = "bind the applet I/O lines {!r} to pins SET".format(self._applet_name, name)
help = "bind the applet I/O lines {!r} to pins SET".format(name)
if default is not None:
help += " (default: %(default)s)"

Expand Down
1 change: 1 addition & 0 deletions software/glasgow/applet/__init__.py
Expand Up @@ -129,6 +129,7 @@ def wrapper(self):

# -------------------------------------------------------------------------------------------------

from .rgb_grabber import RGBGrabberApplet
from .hd44780 import HD44780Applet
from .i2c_master import I2CMasterApplet
from .i2c.bmp280 import I2CBMP280Applet
Expand Down
161 changes: 161 additions & 0 deletions software/glasgow/applet/rgb_grabber.py
@@ -0,0 +1,161 @@
import math
from migen import *
from migen.genlib.fsm import *
import logging
from migen.genlib.cdc import *

from . import GlasgowApplet


class RGBGrabberSubtarget(Module):
def __init__(self, rows, columns, vblank, pads, in_fifo):
rx = Signal(5)
gx = Signal(5)
bx = Signal(5)
dck = Signal()
self.specials += [
MultiReg(pads.r_t.i, rx),
MultiReg(pads.g_t.i, gx),
MultiReg(pads.b_t.i, bx),
MultiReg(pads.dck_t.i, dck)
]

dck_r = Signal()
stb = Signal()
self.sync += [
dck_r.eq(dck),
stb.eq(~dck_r & dck)
]

we = Signal.like(in_fifo.we)
din = Signal.like(in_fifo.din)
ovf = Signal()
ovf_c = Signal()
self.comb += [
in_fifo.we.eq(we & ~ovf),
in_fifo.din.eq(din),
]
self.sync += \
ovf.eq(~ovf_c & (ovf | (we & ~in_fifo.writable)))

pixel = Signal(15)
self.sync += \
If(stb, pixel.eq(Cat(rx, gx, bx)))

frame = Signal(5, reset_less=True)
ovf_r = Signal()
row = Signal(max=rows)
col = Signal(max=columns)
self.submodules.fsm = ResetInserter()(FSM(reset_state="CAPTURE-ROW"))
self.fsm.act("CAPTURE-ROW",
If(stb,
If(row == 0,
ovf_r.eq(ovf),
ovf_c.eq(1),
NextValue(frame, frame + 1),
NextState("SKIP-FIRST-PIXEL")
).Elif(row == rows,
NextValue(row, 0),
NextState("REPORT-FRAME")
).Else(
NextState("REPORT-FRAME")
)
)
)
self.fsm.act("SKIP-FIRST-PIXEL",
If(stb,
NextState("REPORT-FRAME")
)
)
self.fsm.act("REPORT-FRAME",
din.eq(0x80 | (ovf_r << 7) | (frame << 1) | (row >> 7)),
we.eq(1),
NextState("REPORT-ROW")
)
self.fsm.act("REPORT-ROW",
din.eq(row & 0x7f),
we.eq(1),
NextState("REPORT-1")
)
for (state, offset, nextstate) in (
("REPORT-1", 0, "REPORT-2"),
("REPORT-2", 5, "REPORT-3"),
("REPORT-3", 10, "CAPTURE-PIXEL")
):
self.fsm.act(state,
din.eq((pixel >> offset) & 0x1f),
we.eq(1),
NextState(nextstate)
)
self.fsm.act("CAPTURE-PIXEL",
If(stb,
If(col == columns - 1,
NextValue(col, 0),
NextValue(row, row + 1),
NextState("CAPTURE-ROW")
).Else(
NextValue(col, col + 1),
NextState("REPORT-1")
)
)
)

vblank_cyc = math.ceil(vblank * 0.9 * 30e6) # reset at 90% vblank
timer = Signal(max=vblank_cyc)
self.sync += [
If(dck,
If(timer != vblank_cyc,
timer.eq(timer + 1)
)
).Else(
timer.eq(0)
)
]
self.comb += [
self.fsm.reset.eq(timer == vblank_cyc),
# sync.oe.eq(self.fsm.reset),
]


class RGBGrabberApplet(GlasgowApplet, name="rgb-grabber"):
logger = logging.getLogger(__name__)
help = "grab images from RGB555 LCD bus"
description = """
Streams screen contents from a color parallel RGB555 LCD, such as Sharp LQ035Q7DH06.
"""

@classmethod
def add_build_arguments(cls, parser, access):
access.add_build_arguments(parser)
access.add_pin_set_argument(parser, "r", width=5)
access.add_pin_set_argument(parser, "g", width=5)
access.add_pin_set_argument(parser, "b", width=5)
access.add_pin_argument(parser, "dck")
parser.add_argument("--rows", type=int,
help="LCD row count")
parser.add_argument("--columns", type=int,
help="LCD column count")
parser.add_argument("--vblank", type=float,
help="vertical blanking interval, in us")

def build(self, target, args):
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)
target.submodules += RGBGrabberSubtarget(
rows=args.rows,
columns=args.columns,
vblank=args.vblank,
pads=iface.get_pads(args, pins=("dck",), pin_sets=("r", "g", "b")),
in_fifo=iface.get_in_fifo(depth=512 * 30, streaming=True),
)

async def run(self, device, args):
iface = await device.demultiplexer.claim_interface(self, self.mux_interface, args)

for _ in range(200):
sync = 0
while not (sync & 0x80):
sync = (await iface.read(1))[0]
frame = (sync & 0x3e) >> 1
row = ((sync & 0x01) << 7) | (await iface.read(1))[0]

print("frame {} row {}".format(frame, row))

0 comments on commit ae5cbc1

Please sign in to comment.