Exemple #1
0
    def __init__(self, master, getSpeed, name, increaseKey, decreaseKey):
        super().__init__(master)
        self.name = name
        self.frame = tk.Frame()

        self.getSpeed = getSpeed

        self.frame.rowconfigure(0, minsize=100, weight=1)
        self.frame.columnconfigure([0, 1, 2, 3], minsize=100, weight=1)

        self.name_label = tk.Label(master=self.frame, text=f"{self.name}")
        self.name_label.grid(row=0, column=0)

        self.btn_decrease = tk.Button(master=self.frame,
                                      text="-",
                                      command=self.increase)
        self.btn_decrease.bind('<Button-1>', self.decrease)
        self.btn_decrease.grid(row=0, column=1, sticky="nsew")

        self.label = tk.Label(master=self.frame, text="0")
        self.label.grid(row=0, column=2)

        self.btn_increase = tk.Button(
            master=self.frame, text="+",
            command=self.decrease)  # command=self.stop for debouncer fail
        self.btn_increase.bind('<Button-1>', self.increase)
        self.btn_increase.grid(row=0, column=3, sticky="nsew")

        # failsafe for when debouncer fails
        # master.bind('<KeyPress-' + increaseKey + '>', self.increase)
        # master.bind('<KeyRelease-' + increaseKey + '>', self.stop)
        # master.bind('<KeyPress-' + decreaseKey + '>', self.decrease)
        # master.bind('<KeyRelease-' + decreaseKey + '>', self.stop)

        self.up_debouncer = Debouncer(self.increase, self.decrease)
        master.bind('<KeyPress-' + increaseKey + '>',
                    self.up_debouncer.pressed)
        master.bind('<KeyRelease-' + increaseKey + '>',
                    self.up_debouncer.released)
        self.down_debouncer = Debouncer(self.decrease, self.increase)
        master.bind('<KeyPress-' + decreaseKey + '>',
                    self.down_debouncer.pressed)
        master.bind('<KeyRelease-' + decreaseKey + '>',
                    self.down_debouncer.released)

        self.frame.pack()
Exemple #2
0
 def __init__(self):  #initiating instance of self
     self.app = tk.Tk()  #start tkinter interface
     self.debouncer = Debouncer(
         self.system, self.released
     )  #call debouncer function from debouncer.py and feed input and output functions to arguments
     self.app.bind('<KeyPress>', self.debouncer.pressed
                   )  #bind key press to in-built debouncer function
     self.app.bind('<KeyRelease>', self.debouncer.released
                   )  # bind key release to in-built debouncer function
Exemple #3
0
    def __init__(self):
        # start the video stream object then initialize the frame
        self.netController = NetControl()
        self.netController.startVideo()
        self.frame = None

        # initialize the root window and image panel
        self.root = tki.Tk()
        self.panel = None

        # set a callback to handle when the window is closed
        self.root.wm_title("Robot Control App")
        self.root.wm_protocol("WM_DELETE_WINDOW", self.onClose)

        # setup the key debouncer
        self.debouncer = Debouncer(self._pressed_cb, self._released_cb)
        self.root.bind('<KeyPress>', self.debouncer.pressed)
        self.root.bind('<KeyRelease>', self.debouncer.released)

        self.updateVideo()
# Power to the speaker and neopixels must be enabled using this pin

enable = DigitalInOut(POWER_PIN)
enable.direction = Direction.OUTPUT
enable.value = True

i2c = busio.I2C(board.SCL, board.SDA)
rtc = adafruit_ds3231.DS3231(i2c)

audio = audioio.AudioOut(board.A0)

strip = neopixel.NeoPixel(NEOPIXEL_PIN, NUM_PIXELS, brightness=1, auto_write=False)
strip.fill(0)                          # NeoPixels off ASAP on startup
strip.show()

switch = Debouncer(SWITCH_PIN, Pull.UP, 0.01)

# create a PWMOut object on Pin A2.
pwm = pulseio.PWMOut(SERVO_PIN, duty_cycle=2 ** 15, frequency=50)

# Create a servo object, my_servo.
servo = servo.ContinuousServo(pwm)
servo.throttle = 0.0

# Set the time for testing
# Once finished testing, the time can be set using the REPL using similar code
if TESTING:
    #                     year, mon, date, hour, min, sec, wday, yday, isdst
    t = time.struct_time((2018,  12,   31,   23,  58,  55,    1,   -1,    -1))
    # you must set year, mon, date, hour, min, sec and weekday
    # yearday is not supported, isdst can be set but we don't do anything with it at this time
Exemple #5
0
def make_criket_signal_debouncer(pin):  # create pin signal objects
    ss.pin_mode(pin, ss.INPUT_PULLUP)
    return Debouncer(lambda: ss.digital_read(pin))
Exemple #6
0

# define and set up inputs to use the debouncer
def make_criket_signal_debouncer(pin):  # create pin signal objects
    ss.pin_mode(pin, ss.INPUT_PULLUP)
    return Debouncer(lambda: ss.digital_read(pin))


# The IR sensors on are pullups, connect to ground to activate
clock_pin = make_criket_signal_debouncer(crickit.SIGNAL1)
voice_1_pin = make_criket_signal_debouncer(crickit.SIGNAL2)
voice_2_pin = make_criket_signal_debouncer(crickit.SIGNAL3)
voice_3_pin = make_criket_signal_debouncer(crickit.SIGNAL4)
voice_4_pin = make_criket_signal_debouncer(crickit.SIGNAL5)
# Crickit capacitive touch pads
touch_1_pad = Debouncer(lambda: crickit.touch_1.value)
touch_4_pad = Debouncer(lambda: crickit.touch_4.value)
touch_2_3_pad = Debouncer(
    lambda: crickit.touch_2.value and crickit.touch_3.value)

crickit.continuous_servo_1.set_pulse_width_range(min_pulse=500, max_pulse=2500)
speed = -0.04  #this is clockwise/forward at a moderate tempo


def play_voice(vo):
    mixer.stop_voice(vo)
    mixer.play(samples[vo], voice=vo, loop=False)


while True:
    clock_pin.update()  #debouncer at work
Exemple #7
0
import time
import board
import busio
import digitalio
import rotaryio
import pulseio
import adafruit_ssd1306
from adafruit_motor import servo

from debouncer import Debouncer

#--------------------------------------------------------------------------------
# Initialize Rotary encoder

button = Debouncer(board.D12, digitalio.Pull.UP, 0.01)
rotary_encoder = rotaryio.IncrementalEncoder(board.D10, board.D11)

#--------------------------------------------------------------------------------
# Initialize I2C and OLED

i2c = busio.I2C(board.SCL, board.SDA)

oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
oled.fill(0)
oled.show()

min_pulses = [500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000]
max_pulses = [2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350, 2400, 2450, 2500]

min_pulse_index = 10
Exemple #8
0
    def elaborate(self, platform):
        m = Module()

        # get clock domains
        m.submodules.domains = ULX3SDomainGenerator()

        led = [platform.request("led", count) for count in range(8)]

        # help me debounce the button
        button = platform.request("button_fire", 1)
        debouncer = Debouncer()
        m.submodules.debouncer = debouncer
        m.d.comb += debouncer.btn.eq(button)

        m.submodules.mem = mem = sdram_controller()

        data_buffer = Signal(32)

        address = 0x1205
        data = 0x12345678

        with m.FSM(domain="compute"):
            with m.State("WRITE"):
                m.d.comb += mem.address.eq(address)
                m.d.comb += mem.data_in.eq(data)
                m.d.comb += mem.req_write.eq(1)
                m.next = "WRITE_COMPLETE"

            with m.State("WRITE_COMPLETE"):
                m.d.comb += mem.address.eq(address)
                m.d.comb += mem.data_in.eq(data)
                with m.If(mem.write_complete):
                    m.next = "READ"

            with m.State("READ"):
                m.d.comb += mem.address.eq(address)
                m.d.comb += mem.req_read.eq(1)
                m.next = "READ_COMPLETE"

            with m.State("READ_COMPLETE"):
                m.d.comb += mem.address.eq(address)
                with m.If(mem.data_valid):
                    m.d.compute += data_buffer.eq(mem.data_out)
                    m.next = "BYTE_0_TO_LED"

            with m.State(f"BYTE_0_TO_LED"):
                m.d.comb += led_display_signal(m, led[0:8], data_buffer[0:8])
                with m.If(debouncer.btn_up):
                    m.next = "BYTE_1_TO_LED"

            with m.State(f"BYTE_1_TO_LED"):
                m.d.comb += led_display_signal(m, led[0:8], data_buffer[8:16])
                with m.If(debouncer.btn_up):
                    m.next = "BYTE_2_TO_LED"

            with m.State(f"BYTE_2_TO_LED"):
                m.d.comb += led_display_signal(m, led[0:8], data_buffer[16:24])
                with m.If(debouncer.btn_up):
                    m.next = "BYTE_3_TO_LED"

            with m.State(f"BYTE_3_TO_LED"):
                m.d.comb += led_display_signal(m, led[0:8], data_buffer[24:32])
                with m.If(debouncer.btn_up):
                    m.next = "WRITE"

        return m
Exemple #9
0
#!/usr/bin/python
import time
from debouncer import Debouncer
from gpio import PiGpio

# create an instance of the pi gpio driver.
pi_gpio = PiGpio()
# create an instance of the switch debouncer
db = Debouncer()
#
print('Debounce my Input Switch (Ctrl-C to stop)...')
while True:
    switch_raw = pi_gpio.read_switch()
    switch_debounced = db.debounce(switch_raw)
    pi_gpio.set_led(1, (switch_raw == 1))
    pi_gpio.set_led(2, (switch_debounced == 1))

    print('SW RAW: {0} SW DEBOUNCED: {1}'.format(switch_raw, switch_debounced))
    time.sleep(0.2)
Exemple #10
0
#!/usr/bin/python
import time
from gpio import PiGpio
from bmp280 import PiBMP280
from debouncer import Debouncer
from flask import *

app = Flask(__name__)
pi_gpio = PiGpio()
db = Debouncer()
# create an array of my pi bmp280 sensor dictionaries
sensor = {"name": "bmp280", "addr": 0x76, "chip": PiBMP280(0x76), "data": {}}
(chip_id, chip_version) = sensor["chip"].readBMP280ID()
sensor["data"]["chip_id"] = chip_id
sensor["data"]["chip_version"] = chip_version


# ============================== Functions ====================================
def get_sensor_values():
    (temperature, pressure) = sensor["chip"].readBMP280All()
    sensor["data"]["temperature"] = {"reading": temperature, "units": "C"}
    sensor["data"]["pressure"] = {"reading": pressure, "units": "hPa"}
    return sensor["data"]


@app.route("/")
def index():
    return render_template('index.html')
    # create an instance of my pi gpio object class.
    #pi_gpio = PiGpio()
    #switch_state = pi_gpio.read_switch()
    def elaborate(self, platform):
        # VGA constants
        pixel_f = self.timing.pixel_freq
        hsync_front_porch = self.timing.h_front_porch
        hsync_pulse_width = self.timing.h_sync_pulse
        hsync_back_porch = self.timing.h_back_porch
        vsync_front_porch = self.timing.v_front_porch
        vsync_pulse_width = self.timing.v_sync_pulse
        vsync_back_porch = self.timing.v_back_porch

        # Pins
        clk25 = platform.request("clk25")
        ov7670 = platform.request("ov7670")
        led = [platform.request("led", i) for i in range(8)]
        leds = Cat([i.o for i in led])
        led8_2 = platform.request("led8_2")
        leds8_2 = Cat([led8_2.leds[i] for i in range(8)])
        led8_3 = platform.request("led8_3")
        leds8_3 = Cat([led8_3.leds[i] for i in range(8)])
        leds16 = Cat(leds8_3, leds8_2)
        btn1 = platform.request("button_fire", 0)
        btn2 = platform.request("button_fire", 1)
        up = platform.request("button_up", 0)
        down = platform.request("button_down", 0)
        pwr = platform.request("button_pwr", 0)
        left = platform.request("button_left", 0)
        right = platform.request("button_right", 0)
        sw = Cat([platform.request("switch", i) for i in range(4)])
        uart = platform.request("uart")
        divisor = int(platform.default_clk_frequency // 460800)
        esp32 = platform.request("esp32_spi")

        csn = esp32.csn
        sclk = esp32.sclk
        copi = esp32.copi
        cipo = esp32.cipo

        m = Module()

        # Clock generator.
        m.domains.sync = cd_sync = ClockDomain("sync")
        m.domains.pixel = cd_pixel = ClockDomain("pixel")
        m.domains.shift = cd_shift = ClockDomain("shift")

        m.submodules.ecp5pll = pll = ECP5PLL()
        pll.register_clkin(clk25, platform.default_clk_frequency)
        pll.create_clkout(cd_sync, platform.default_clk_frequency)
        pll.create_clkout(cd_pixel, pixel_f)
        pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0))

        # Add CamRead submodule
        camread = CamRead()
        m.submodules.camread = camread

        # Camera config
        cam_x_res = 640
        cam_y_res = 480

        camconfig = CamConfig()
        m.submodules.camconfig = camconfig

        # Connect the camera pins and config and read modules
        m.d.comb += [
            ov7670.cam_RESET.eq(1),
            ov7670.cam_PWON.eq(0),
            ov7670.cam_XCLK.eq(clk25.i),
            ov7670.cam_SIOC.eq(camconfig.sioc),
            ov7670.cam_SIOD.eq(camconfig.siod),
            camconfig.start.eq(btn1),
            camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])),
            camread.href.eq(ov7670.cam_HREF),
            camread.vsync.eq(ov7670.cam_VSYNC),
            camread.p_clock.eq(ov7670.cam_PCLK)
        ]

        # Create the uart
        m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart)

        # Frame buffer
        x_res = cam_x_res // 2
        y_res = cam_y_res

        buffer = Memory(width=16, depth=x_res * y_res)
        m.submodules.r = r = buffer.read_port()
        m.submodules.w = w = buffer.write_port()

        # Button debouncers
        m.submodules.debup = debup = Debouncer()
        m.submodules.debdown = debdown = Debouncer()
        m.submodules.debosd = debosd = Debouncer()
        m.submodules.debsel = debsel = Debouncer()
        m.submodules.debsnap = debsnap = Debouncer()
        m.submodules.debhist = debhist = Debouncer()

        # Connect the buttons to debouncers
        m.d.comb += [
            debup.btn.eq(up),
            debdown.btn.eq(down),
            debosd.btn.eq(pwr),
            debsel.btn.eq(right),
            debsnap.btn.eq(left),
            debhist.btn.eq(btn2)
        ]

        # Image processing configuration registers
        flip = Signal(2, reset=1)  # Flip the image horizontally or vertically
        mono_en = Signal(reset=0)  # Convert to monochrome
        invert = Signal(reset=0)  # Invert monochrome image
        thresh_en = Signal(reset=0)  # Apply threshold to monochrome image
        threshold = Signal(8, reset=0)  # Threshold value
        border = Signal(reset=0)  # Use OSD to show a border
        filt_en = Signal(reset=0)  # Apply a color filter
        l = Rgb565(reset=(18, 12, 6))  # Image filter low values
        h = Rgb565(reset=(21, 22, 14))  # Image filter high values
        grid = Signal(reset=0)  # Use OSD to show a grid
        hist_view = Signal(reset=1)  # Switch to histogram view
        hist_chan = Signal(2, reset=0)  # The histogram channel to calculate
        ccr = CC(reset=(0, 0, 18, 12, 16))  # Color control record
        sharpness = Signal(
            unsigned(4), reset=0
        )  # Used to select image convolution kernel for blur/sharpness
        roi = Roi()  # Region on interest
        frozen = Signal(reset=1)  # Freeze/unfreeze video display
        sat_en = Signal()
        saturation = Signal(5, reset=16)

        # Control synchronization of camera with fifo
        sync_fifo = Signal(reset=0)

        # OSD control signals
        osd_val = Signal(
            4, reset=0)  # Account for spurious start-up button pushes
        osd_on = Signal(reset=1)
        osd_sel = Signal(reset=1)

        # Snapshot signals
        snap = Signal(reset=0)
        writing = Signal(reset=0)
        written = Signal(reset=0)
        byte = Signal(reset=0)
        w_addr = Signal(18)

        # Signals for calculating histogram
        hist_val = Signal(6)

        # Signals for displaying histogram
        hist_color = Signal(8)
        hbin = Signal(6, reset=0)
        bin_cnt = Signal(5, reset=0)
        old_x = Signal(10)

        # Frame buffer coordinates
        frame_x = Signal(10)
        frame_y = Signal(9)

        # VGA signals
        vga_r = Signal(8)
        vga_g = Signal(8)
        vga_b = Signal(8)
        vga_hsync = Signal()
        vga_vsync = Signal()
        vga_blank = Signal()

        # Pixel from camera
        pix = Rgb565()

        # Fifo stream
        m.submodules.fifo_stream = fs = FifoStream()

        # SPI memory for remote configuration
        m.submodules.spimem = spimem = SpiMem(addr_bits=32)

        # Color Control
        m.submodules.cc = cc = ColorControl()

        # Image convolution
        m.submodules.imc = imc = ImageConv()

        # Statistics
        m.submodules.stats = stats = Stats()

        # Histogram
        m.submodules.hist = hist = Hist()

        # Filter
        m.submodules.fil = fil = Filt()

        # Monochrome
        m.submodules.mon = mon = Mono()

        # Saturation
        m.submodules.sat = sat = Saturation()

        # Sync the fifo with the camera
        with m.If(~sync_fifo & (camread.col == cam_x_res - 1)
                  & (camread.row == cam_y_res - 1)):
            m.d.sync += sync_fifo.eq(1)

        with m.If(btn1):
            m.d.sync += sync_fifo.eq(0)

        # Set histogram value to the data for the chosen channel
        with m.Switch(hist_chan):
            with m.Case(0):
                m.d.comb += hist_val.eq(cc.o.r)
            with m.Case(1):
                m.d.comb += hist_val.eq(cc.o.g)
            with m.Case(2):
                m.d.comb += hist_val.eq(cc.o.b)
            with m.Case(3):
                m.d.comb += hist_val.eq(mon.o_m)

        # Copy camera data to Rgb565 record
        m.d.comb += [
            pix.r.eq(camread.pixel_data[11:]),
            pix.g.eq(camread.pixel_data[5:11]),
            pix.b.eq(camread.pixel_data[:5])
        ]

        # Input image processing pipeline
        pipeline = [
            [
                fs,
                {
                    "i": pix,  # Fifo stream
                    "i_valid": camread.pixel_valid & camread.col[0],
                    "i_ready": cc.o_ready,
                    "i_en": sync_fifo
                },
                True
            ],
            [sat, {
                "i_en": sat_en,
                "i_saturation": saturation
            }, True],
            [cc, {
                "i_cc": ccr
            }, True],  # Color control
            [
                fil,
                {
                    "i_en": filt_en,  # Color filter
                    "i_frame_done": fs.o_eof,
                    "i_l": l,
                    "i_h": h
                },
                True
            ],
            [
                mon,
                {
                    "i_en": mono_en | invert
                    | thresh_en,  # Monochrome, invert and threshold
                    "i_invert": invert,
                    "i_thresh": thresh_en,
                    "i_threshold": threshold
                },
                True
            ],
            [
                imc,
                {
                    "i_ready": 1,  # Image convolution
                    "i_reset": ~fs.i_en,
                    "i_sel": sharpness
                },
                True
            ],
            [
                stats,
                {
                    "i":
                    cc.o,  # Statistics               
                    "i_valid":
                    cc.o_valid,
                    "i_avg_valid": (fs.o_x >= 32) & (fs.o_x < 288) &
                    (fs.o_y >= 112) & (fs.o_y < 368),
                    "i_frame_done":
                    fs.o_eof,
                    "i_x":
                    fs.o_x,
                    "i_y":
                    fs.o_y,
                    "i_roi":
                    roi
                },
                False
            ],
            [
                hist,
                {
                    "i_p": hist_val,  # Histogram         
                    "i_valid": mon.o_valid,
                    "i_clear": fs.o_eof,
                    "i_x": fs.o_x,
                    "i_y": fs.o_y,
                    "i_roi": roi,
                    "i_bin": hbin
                },
                False
            ]
        ]

        def execute(pl):
            us = None  # Upstream
            for p in pl:
                mod = p[0]
                d = p[1]
                st = p[2]  # Stream or Sink
                if st and us is not None:
                    m.d.comb += mod.i.eq(us.o)
                    m.d.comb += mod.i_valid.eq(us.o_valid)
                    m.d.comb += us.i_ready.eq(mod.o_ready)
                if st:
                    us = mod
                for k in d:
                    m.d.comb += mod.__dict__[k].eq(d[k])

        execute(pipeline)

        # Take a snapshot, freeze the camera, and write the framebuffer to the uart
        # Note that this suspends video output
        with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))):
            with m.If(frozen):
                m.d.sync += frozen.eq(0)
            with m.Else():
                m.d.sync += [
                    snap.eq(1),
                    frozen.eq(0),
                    w_addr.eq(0),
                    written.eq(0),
                    byte.eq(0)
                ]

        # Wait to end of frame after requesting snapshot, before start of writing to uart
        with m.If(imc.o_eof & snap):
            m.d.sync += [frozen.eq(1), snap.eq(0)]
            with m.If(~written):
                m.d.sync += writing.eq(1)

        # Connect the uart
        m.d.comb += [
            serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])),
            serial.tx.ack.eq(writing)
        ]

        # Write to the uart from frame buffer (affects video output)
        with m.If(writing):
            with m.If(w_addr == x_res * y_res):
                m.d.sync += [writing.eq(0), written.eq(1)]
            with m.Elif(serial.tx.ack & serial.tx.rdy):
                m.d.sync += byte.eq(~byte)
                with m.If(byte):
                    m.d.sync += w_addr.eq(w_addr + 1)

        # Connect spimem
        m.d.comb += [
            spimem.csn.eq(~csn),
            spimem.sclk.eq(sclk),
            spimem.copi.eq(copi),
            cipo.eq(spimem.cipo),
        ]

        # Writable configuration registers
        spi_wr_vals = Array([
            ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, l.r, h.r,
            l.g, h.g, l.b, h.b, sharpness, filt_en, border, mono_en, invert,
            grid, hist_view, roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:],
            roi.en, None, None, None, threshold, thresh_en, hist_chan, flip,
            None, None, None, None, None, None, None, None, None, frozen, None,
            None, sat_en, saturation, ccr.offset
        ])

        with m.If(spimem.wr):
            with m.Switch(spimem.addr):
                for i in range(len(spi_wr_vals)):
                    if spi_wr_vals[i] is not None:
                        with m.Case(i):
                            m.d.sync += spi_wr_vals[i].eq(spimem.dout)

        # Readable configuration registers
        spi_rd_vals = Array([
            ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, l.r, h.r,
            l.g, h.g, l.b, h.b, sharpness, filt_en, border, mono_en, invert,
            grid, hist_view, roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:],
            roi.en, fil.o_nz[16:], fil.o_nz[8:16], fil.o_nz[:8], threshold,
            thresh_en, hist_chan, flip, stats.o_min.r, stats.o_min.g,
            stats.o_min.b, stats.o_max.r, stats.o_max.g, stats.o_max.b,
            stats.o_avg.r, stats.o_avg.g, stats.o_avg.b, frozen, writing,
            written, sat_en, saturation, ccr.offset
        ])

        with m.If(spimem.rd):
            with m.Switch(spimem.addr):
                for i in range(len(spi_rd_vals)):
                    with m.Case(i):
                        m.d.sync += spimem.din.eq(spi_rd_vals[i])

        # Add VGA generator
        m.submodules.vga = vga = VGA(
            resolution_x=self.timing.x,
            hsync_front_porch=hsync_front_porch,
            hsync_pulse=hsync_pulse_width,
            hsync_back_porch=hsync_back_porch,
            resolution_y=self.timing.y,
            vsync_front_porch=vsync_front_porch,
            vsync_pulse=vsync_pulse_width,
            vsync_back_porch=vsync_back_porch,
            bits_x=16,  # Play around with the sizes because sometimes
            bits_y=16  # a smaller/larger value will make it pass timing.
        )

        # Fetch histogram for display
        m.d.sync += old_x.eq(vga.o_beam_x)

        with m.If(vga.o_beam_x == 0):
            m.d.sync += [hbin.eq(0), bin_cnt.eq(0)]
        with m.Elif(vga.o_beam_x != old_x):
            m.d.sync += bin_cnt.eq(bin_cnt + 1)
            with m.If(bin_cnt == 19):
                m.d.sync += [bin_cnt.eq(0), hbin.eq(hbin + 1)]

        # Switch between camera and histogram view
        with m.If(debhist.btn_down):
            m.d.sync += hist_view.eq(~hist_view)

        # Connect frame buffer, with optional x and y flip
        m.d.comb += [
            frame_x.eq(
                Mux(flip[0], x_res - 1 - vga.o_beam_x[1:], vga.o_beam_x[1:])),
            frame_y.eq(Mux(flip[1], y_res - 1 - vga.o_beam_y, vga.o_beam_y)),
            w.en.eq(imc.o_valid & ~frozen),
            w.addr.eq(imc.o_y * x_res + imc.o_x),
            w.data.eq(imc.o.as_data()),
            r.addr.eq(Mux(writing, w_addr, frame_y * x_res + frame_x))
        ]

        # Apply the On-Screen Display (OSD)
        m.submodules.osd = osd = OSD()

        m.d.comb += [
            osd.x.eq(vga.o_beam_x),
            osd.y.eq(vga.o_beam_y),
            hist_color.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)),
            osd.i_r.eq(
                Mux(hist_view,
                    Mux((hist_chan == 0) | (hist_chan == 3), hist_color, 0),
                    Cat(Const(0, unsigned(3)), r.data[11:16]))),
            osd.i_g.eq(
                Mux(hist_view,
                    Mux((hist_chan == 1) | (hist_chan == 3), hist_color, 0),
                    Cat(Const(0, unsigned(2)), r.data[5:11]))),
            osd.i_b.eq(
                Mux(hist_view,
                    Mux((hist_chan == 2) | (hist_chan == 3), hist_color, 0),
                    Cat(Const(0, unsigned(3)), r.data[0:5]))),
            osd.on.eq(osd_on),
            osd.osd_val.eq(osd_val),
            osd.sel.eq(osd_sel),
            osd.grid.eq(grid),
            osd.border.eq(border),
            osd.roi.eq(roi.en & ~hist_view),
            osd.roi_x.eq(roi.x),
            osd.roi_y.eq(roi.y),
            osd.roi_w.eq(roi.w),
            osd.roi_h.eq(roi.h)
        ]

        # OSD control
        dummy = Signal()
        osd_vals = Array([
            ccr.offset, ccr.brightness, ccr.redness, ccr.greenness,
            ccr.blueness, sharpness, sat_en, saturation, mono_en, invert,
            thresh_en, threshold, hist_chan,
            Cat(border, grid), flip, filt_en
        ])

        with m.If(debosd.btn_down):
            m.d.sync += osd_on.eq(~osd_on)

        with m.If(osd_on):
            with m.If(debsel.btn_down):
                m.d.sync += osd_sel.eq(~osd_sel)

            with m.If(debup.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(osd_val - 1)
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(1)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i] + 1)

            with m.If(debdown.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(osd_val + 1)
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(0)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i] - 1)

        # Show configuration values on leds
        with m.Switch(osd_val):
            for i in range(len(osd_vals)):
                with m.Case(i):
                    m.d.comb += leds.eq(osd_vals[i])

        # Generate VGA signals
        m.d.comb += [
            vga.i_clk_en.eq(1),
            vga.i_test_picture.eq(0),
            vga.i_r.eq(osd.o_r),
            vga.i_g.eq(osd.o_g),
            vga.i_b.eq(osd.o_b),
            vga_r.eq(vga.o_vga_r),
            vga_g.eq(vga.o_vga_g),
            vga_b.eq(vga.o_vga_b),
            vga_hsync.eq(vga.o_vga_hsync),
            vga_vsync.eq(vga.o_vga_vsync),
            vga_blank.eq(vga.o_vga_blank),
        ]

        # VGA to digital video converter.
        tmds = [Signal(2) for i in range(4)]
        m.submodules.vga2dvid = vga2dvid = VGA2DVID(
            ddr=self.ddr, shift_clock_synchronizer=False)
        m.d.comb += [
            vga2dvid.i_red.eq(vga_r),
            vga2dvid.i_green.eq(vga_g),
            vga2dvid.i_blue.eq(vga_b),
            vga2dvid.i_hsync.eq(vga_hsync),
            vga2dvid.i_vsync.eq(vga_vsync),
            vga2dvid.i_blank.eq(vga_blank),
            tmds[3].eq(vga2dvid.o_clk),
            tmds[2].eq(vga2dvid.o_red),
            tmds[1].eq(vga2dvid.o_green),
            tmds[0].eq(vga2dvid.o_blue),
        ]

        # GPDI pins
        if (self.ddr):
            # Vendor specific DDR modules.
            # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended)
            # onboard GPDI.
            m.submodules.ddr0_clock = Instance("ODDRX1F",
                                               i_SCLK=ClockSignal("shift"),
                                               i_RST=0b0,
                                               i_D0=tmds[3][0],
                                               i_D1=tmds[3][1],
                                               o_Q=self.o_gpdi_dp[3])
            m.submodules.ddr0_red = Instance("ODDRX1F",
                                             i_SCLK=ClockSignal("shift"),
                                             i_RST=0b0,
                                             i_D0=tmds[2][0],
                                             i_D1=tmds[2][1],
                                             o_Q=self.o_gpdi_dp[2])
            m.submodules.ddr0_green = Instance("ODDRX1F",
                                               i_SCLK=ClockSignal("shift"),
                                               i_RST=0b0,
                                               i_D0=tmds[1][0],
                                               i_D1=tmds[1][1],
                                               o_Q=self.o_gpdi_dp[1])
            m.submodules.ddr0_blue = Instance("ODDRX1F",
                                              i_SCLK=ClockSignal("shift"),
                                              i_RST=0b0,
                                              i_D0=tmds[0][0],
                                              i_D1=tmds[0][1],
                                              o_Q=self.o_gpdi_dp[0])
        else:
            m.d.comb += [
                self.o_gpdi_dp[3].eq(tmds[3][0]),
                self.o_gpdi_dp[2].eq(tmds[2][0]),
                self.o_gpdi_dp[1].eq(tmds[1][0]),
                self.o_gpdi_dp[0].eq(tmds[0][0]),
            ]

        return m
def run():
    display = Display()
    generator = Generator()
    button_a = Debouncer(board.D9, digitalio.Pull.UP, 0.01)
    button_b = Debouncer(board.D6, digitalio.Pull.UP, 0.01)
    button_c = Debouncer(board.D5, digitalio.Pull.UP, 0.01)
    encoder_button = Debouncer(board.D12, digitalio.Pull.UP, 0.01)
    encoder = rotaryio.IncrementalEncoder(board.D10, board.D11)

    current_position = None               # current encoder position
    change = 0                            # the change in encoder position
    delta = 0                             # how much to change the frequency by
    shape = shapes.SINE                          # the active waveform
    frequency = 440                       # the current frequency

    display.update_shape(shape)           # initialize the display contents
    display.update_frequency(frequency)

    while True:
        encoder_button.update()
        button_a.update()
        button_b.update()
        button_c.update()
        current_position, change = get_encoder_change(encoder, current_position)

        if change != 0:
            if not button_a.value:
                delta = change * 1000
            elif not button_b.value:
                delta = change * 100
            elif not button_c.value:
                delta = change * 10
            else:
                delta = change
            frequency = change_frequency(frequency, delta)

        if encoder_button.fell:
            shape = change_shape(shape)

        display.update_shape(shape)
        display.update_frequency(frequency)
        generator.update(shape, frequency)
Exemple #13
0
 def __init__(self):
     self.app = tk.Tk()
     self.debouncer = Debouncer(self._pressed_cb, self._released_cb)
     self.app.bind('<KeyPress-Right>', self.debouncer.pressed)
     self.app.bind('<KeyRelease-Right>', self.debouncer.released)
Exemple #14
0
""" This module contains the app bootstrapping code and web routes """

import toml
from debouncer import Debouncer
from flask import Flask
from flask import abort, request
from discord import Embed
from raven.contrib.flask import Sentry

app = Flask(__name__)
config = toml.load("config.toml")
debouncer = Debouncer(config)

if config['sentry']:
    sentry = Sentry(app=app, dsn=config['sentry'])


@app.route("/push", methods=['POST'])
def push():
    """ Handles a POST on /push with Webhook data """
    if request.headers['Authorization'] != config['token']:
        abort(401)
    if request.json is None:
        abort(400)

    embed = Embed.from_data(request.json)
    debouncer.push(embed)
    return ""


debouncer.start()
Exemple #15
0
    def elaborate(self, platform):
        # VGA constants
        pixel_f           = self.timing.pixel_freq
        hsync_front_porch = self.timing.h_front_porch
        hsync_pulse_width = self.timing.h_sync_pulse
        hsync_back_porch  = self.timing.h_back_porch
        vsync_front_porch = self.timing.v_front_porch
        vsync_pulse_width = self.timing.v_sync_pulse
        vsync_back_porch  = self.timing.v_back_porch

        # Pins
        clk25   = platform.request("clk25")
        ov7670  = platform.request("ov7670")
        led     = [platform.request("led", i) for i in range(8)]
        leds    = Cat([i.o for i in led])
        led8_2  = platform.request("led8_2")
        leds8_2 = Cat([led8_2.leds[i] for i in range(8)])
        led8_3  = platform.request("led8_3")
        leds8_3 = Cat([led8_3.leds[i] for i in range(8)])
        leds16  = Cat(leds8_3, leds8_2)
        btn1    = platform.request("button_fire", 0)
        btn2    = platform.request("button_fire", 1)
        up      = platform.request("button_up", 0)
        down    = platform.request("button_down", 0)
        pwr     = platform.request("button_pwr", 0)
        left    = platform.request("button_left", 0)
        right   = platform.request("button_right", 0)
        sw      =  Cat([platform.request("switch",i) for i in range(4)])
        uart    = platform.request("uart")
        divisor = int(platform.default_clk_frequency // 460800)
        esp32   = platform.request("esp32_spi")

        csn     = esp32.csn
        sclk    = esp32.sclk
        copi    = esp32.copi
        cipo    = esp32.cipo

        m = Module()
        
        # Clock generator.
        m.domains.sync  = cd_sync  = ClockDomain("sync")
        m.domains.pixel = cd_pixel = ClockDomain("pixel")
        m.domains.shift = cd_shift = ClockDomain("shift")

        m.submodules.ecp5pll = pll = ECP5PLL()
        pll.register_clkin(clk25,  platform.default_clk_frequency)
        pll.create_clkout(cd_sync,  platform.default_clk_frequency)
        pll.create_clkout(cd_pixel, pixel_f)
        pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0))

        # Add CamRead submodule
        camread = CamRead()
        m.submodules.camread = camread

        # Camera config
        cam_x_res = 640
        cam_y_res = 480

        camconfig = CamConfig()
        m.submodules.camconfig = camconfig

        # Connect the camera pins and config and read modules
        m.d.comb += [
            ov7670.cam_RESET.eq(1),
            ov7670.cam_PWON.eq(0),
            ov7670.cam_XCLK.eq(clk25.i),
            ov7670.cam_SIOC.eq(camconfig.sioc),
            ov7670.cam_SIOD.eq(camconfig.siod),
            camconfig.start.eq(btn1),
            camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])),
            camread.href.eq(ov7670.cam_HREF),
            camread.vsync.eq(ov7670.cam_VSYNC),
            camread.p_clock.eq(ov7670.cam_PCLK)
        ]

        # Create the uart
        m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart)

        # Input fifo
        fifo_depth=1024

        m.submodules.fifo = fifo = SyncFIFOBuffered(width=16,depth=fifo_depth)

        # Frame buffer
        x_res= cam_x_res // 2
        y_res= cam_y_res

        buffer = Memory(width=16, depth=x_res * y_res)
        m.submodules.r = r = buffer.read_port()
        m.submodules.w = w = buffer.write_port()

        # Button debouncers
        m.submodules.debup   = debup = Debouncer()
        m.submodules.debdown = debdown = Debouncer()
        m.submodules.debosd  = debosd = Debouncer()
        m.submodules.debsel  = debsel = Debouncer()
        m.submodules.debsnap = debsnap = Debouncer()
        m.submodules.debhist = debhist = Debouncer()

        # Connect the buttons to debouncers
        m.d.comb += [
            debup.btn.eq(up),
            debdown.btn.eq(down),
            debosd.btn.eq(pwr),
            debsel.btn.eq(right),
            debsnap.btn.eq(left),
            debhist.btn.eq(btn2)
        ]

        # Image processing options
        flip        = Signal(2, reset=1)
        mono        = Signal(reset=0)
        invert      = Signal(reset=0)
        gamma       = Signal(reset=0)
        border      = Signal(reset=0)
        filt        = Signal(reset=0)
        grid        = Signal(reset=0)
        histo       = Signal(reset=1)
        hbin        = Signal(6, reset=0)
        bin_cnt     = Signal(5, reset=0)
        thresh      = Signal(reset=0)
        threshold   = Signal(8, reset=0)
        hist_chan   = Signal(2, reset=0)

        ccc         = CC(reset=(0,18,12,16))
        sharpness   = Signal(unsigned(4), reset=0)

        osd_val     = Signal(4, reset=0) # Account for spurious start-up button pushes
        osd_on      = Signal(reset=1)
        osd_sel     = Signal(reset=1)
        snap        = Signal(reset=0)
        frozen      = Signal(reset=1)
        writing     = Signal(reset=0)
        written     = Signal(reset=0)
        byte        = Signal(reset=0)
        w_addr      = Signal(18)

        # Color filter
        l           = Rgb565(reset=(18,12,6)) # Initialised to red LEGO filter
        h           = Rgb565(reset=(21,22,14))

        # Region of interest
        roi         = Roi()

        # VGA signals
        vga_r       = Signal(8)
        vga_g       = Signal(8)
        vga_b       = Signal(8)
        vga_hsync   = Signal()
        vga_vsync   = Signal()
        vga_blank   = Signal()

        # Fifo co-ordinates
        f_x          = Signal(9)
        f_y          = Signal(9)
        f_frame_done = Signal()

        # Pixel from fifo
        pix         = Rgb565()

        # SPI memory for remote configuration
        m.submodules.spimem = spimem = SpiMem(addr_bits=32)

        # Color Control
        m.submodules.cc = cc = ColorControl()

        # Image convolution
        m.submodules.imc = imc = ImageConv()

        # Statistics
        m.submodules.stats = stats = Stats()

        # Histogram
        m.submodules.hist = hist = Hist()

        # Filter
        m.submodules.fil = fil = Filt()

        # Monochrome
        m.submodules.mon = mon = Mono()

        # Sync the fifo with the camera
        sync_fifo = Signal(reset=0)
        with m.If(~sync_fifo & ~fifo.r_rdy & (camread.col == cam_x_res - 1) & (camread.row == cam_y_res -1)):
            m.d.sync += [
                sync_fifo.eq(1),
                f_x.eq(0),
                f_y.eq(0)
            ]

        with m.If(btn1):
            m.d.sync += sync_fifo.eq(0)

        # Connect the fifo
        m.d.comb += [
            fifo.w_en.eq(camread.pixel_valid & camread.col[0] & sync_fifo), # Only write every other pixel
            fifo.w_data.eq(camread.pixel_data), 
            fifo.r_en.eq(fifo.r_rdy & ~imc.o_stall)
        ]

        # Calculate fifo co-ordinates
        m.d.sync += f_frame_done.eq(0)

        with m.If(fifo.r_en & sync_fifo):
            m.d.sync += f_x.eq(f_x + 1)
            with m.If(f_x == x_res - 1):
                m.d.sync += [
                    f_x.eq(0),
                    f_y.eq(f_y + 1)
                ]
                with m.If(f_y == y_res - 1):
                    m.d.sync += [
                        f_y.eq(0),
                        f_frame_done.eq(1)
                    ]
        
        # Extract pixel from fifo data
        m.d.comb += [
            pix.r.eq(fifo.r_data[11:]),
            pix.g.eq(fifo.r_data[5:11]),
            pix.b.eq(fifo.r_data[:5])
        ]

        # Connect color control
        m.d.comb += [
            cc.i.eq(pix),
            cc.i_cc.eq(ccc)
        ]

        # Calculate per-frame statistics, after applying color correction
        m.d.comb += [
            stats.i.eq(cc.o),
            stats.i_valid.eq(fifo.r_rdy),
            # This is not valid when a region of interest is active
            stats.i_avg_valid.eq((f_x >= 32) & (f_x < 288) &
                                 (f_y >= 112) & (f_y < 368)),
            stats.i_frame_done.eq(f_frame_done),
            stats.i_x.eq(f_x),
            stats.i_y.eq(f_y),
            stats.i_roi.eq(roi)
        ]
        
        # Produce histogram, after applying color correction, and after monochrome, for monochrome histogram
        with m.Switch(hist_chan):
            with m.Case(0):
                m.d.comb += hist.i_p.eq(cc.o.r)
            with m.Case(1):
                m.d.comb += hist.i_p.eq(cc.o.g)
            with m.Case(2):
                m.d.comb += hist.i_p.eq(cc.o.b)
            with m.Case(3):
                m.d.comb += hist.i_p.eq(mon.o_m)

        m.d.comb += [
            hist.i_valid.eq(fifo.r_rdy),
            hist.i_clear.eq(f_frame_done),
            hist.i_x.eq(f_x),
            hist.i_y.eq(f_y),
            hist.i_roi.eq(roi),
            hist.i_bin.eq(hbin) # Used when displaying histogram
        ]

        # Apply filter, after color correction
        m.d.comb += [
            fil.i.eq(cc.o),
            fil.i_valid.eq(fifo.r_en),
            fil.i_en.eq(filt),
            fil.i_frame_done.eq(f_frame_done),
            fil.i_l.eq(l),
            fil.i_h.eq(h)
        ]

        # Apply mono, after color correction and filter
        m.d.comb += [
            mon.i.eq(fil.o),
            mon.i_en.eq(mono),
            mon.i_invert.eq(invert),
            mon.i_thresh.eq(thresh),
            mon.i_threshold.eq(threshold)
        ]

        # Apply image convolution, after other transformations
        m.d.comb += [
            imc.i.eq(mon.o),
            imc.i_valid.eq(fifo.r_rdy),
            imc.i_reset.eq(~sync_fifo),
            # Select image convolution
            imc.i_sel.eq(sharpness)
        ]

        # Take a snapshot, freeze the camera, and write the framebuffer to the uart
        # Note that this suspends video output
        with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))):
            with m.If(frozen):
                m.d.sync += frozen.eq(0)
            with m.Else():
                m.d.sync += [
                    snap.eq(1),
                    frozen.eq(0),
                    w_addr.eq(0),
                    written.eq(0),
                    byte.eq(0)
                ]

        # Wait to end of frame after requesting snapshot, before start of writing to uart
        with m.If(imc.o_frame_done & snap):
            m.d.sync += [
                frozen.eq(1),
                snap.eq(0)
            ]
            with m.If(~written):
                m.d.sync += writing.eq(1)

        # Connect the uart
        m.d.comb += [
            serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])),
            serial.tx.ack.eq(writing)
        ]

        # Write to the uart from frame buffer (affects video output)
        with m.If(writing):
            with m.If(w_addr == x_res * y_res):
                m.d.sync += [
                    writing.eq(0),
                    written.eq(1)
                ]
            with m.Elif(serial.tx.ack & serial.tx.rdy):
                m.d.sync += byte.eq(~byte)
                with m.If(byte):
                    m.d.sync += w_addr.eq(w_addr+1)

        # Connect spimem
        m.d.comb += [
            spimem.csn.eq(~csn),
            spimem.sclk.eq(sclk),
            spimem.copi.eq(copi),
            cipo.eq(spimem.cipo),
        ]

        # Writable configuration registers
        spi_wr_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b,
                             sharpness, filt, border, mono, invert, grid, histo,
                             roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, None, None, None,
                             threshold, thresh, hist_chan, flip,
                             None, None, None, None, None, None, None, None, None,
                             frozen])

        with m.If(spimem.wr):
            with m.Switch(spimem.addr):
                for i in range(len(spi_wr_vals)):
                    if spi_wr_vals[i] is not None:
                        with m.Case(i):
                            m.d.sync += spi_wr_vals[i].eq(spimem.dout)

        # Readable configuration registers
        spi_rd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b,
                             sharpness, filt, border, mono, invert, grid, histo,
                             roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, fil.o_nz[16:], fil.o_nz[8:16], fil.o_nz[:8],
                             threshold, thresh, hist_chan, flip,
                             stats.o_min.r, stats.o_min.g, stats.o_min.b,
                             stats.o_max.r, stats.o_max.g, stats.o_max.b,
                             stats.o_avg.r, stats.o_avg.g, stats.o_avg.b,
                             frozen, writing, written])

        with m.If(spimem.rd):
            with m.Switch(spimem.addr):
                for i in range(len(spi_rd_vals)):
                    with m.Case(i):
                        m.d.sync += spimem.din.eq(spi_rd_vals[i])

        # Add VGA generator
        m.submodules.vga = vga = VGA(
           resolution_x      = self.timing.x,
           hsync_front_porch = hsync_front_porch,
           hsync_pulse       = hsync_pulse_width,
           hsync_back_porch  = hsync_back_porch,
           resolution_y      = self.timing.y,
           vsync_front_porch = vsync_front_porch,
           vsync_pulse       = vsync_pulse_width,
           vsync_back_porch  = vsync_back_porch,
           bits_x            = 16, # Play around with the sizes because sometimes
           bits_y            = 16  # a smaller/larger value will make it pass timing.
        )

        # Fetch histogram for display
        old_x = Signal(10)
        m.d.sync += old_x.eq(vga.o_beam_x)

        with m.If(vga.o_beam_x == 0):
            m.d.sync += [
                hbin.eq(0),
                bin_cnt.eq(0)
            ]
        with m.Elif(vga.o_beam_x != old_x):
            m.d.sync += bin_cnt.eq(bin_cnt+1)
            with m.If(bin_cnt == 19):
                m.d.sync += [
                    bin_cnt.eq(0),
                    hbin.eq(hbin+1)
                ]

        # Switch between camera and histogram view
        with m.If(debhist.btn_down):
            m.d.sync += histo.eq(~histo)
       
        # Connect frame buffer, with optional x and y flip
        x = Signal(10)
        y = Signal(9)
        
        m.d.comb += [
            w.en.eq(imc.o_valid & ~frozen),
            w.addr.eq(imc.o_y * x_res + imc.o_x),
            w.data.eq(Cat(imc.o.b, imc.o.g, imc.o.r)),
            y.eq(Mux(flip[1], y_res - 1 - vga.o_beam_y, vga.o_beam_y)),
            x.eq(Mux(flip[0], x_res - 1 - vga.o_beam_x[1:], vga.o_beam_x[1:])),
            r.addr.eq(Mux(writing, w_addr, y * x_res + x))
        ]

        # Apply the On-Screen Display (OSD)
        m.submodules.osd = osd = OSD()

        hist_col = Signal(8)

        m.d.comb += [
            osd.x.eq(vga.o_beam_x),
            osd.y.eq(vga.o_beam_y),
            hist_col.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)),
            osd.i_r.eq(Mux(histo, Mux((hist_chan == 0) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[11:16]))),
            osd.i_g.eq(Mux(histo, Mux((hist_chan == 1) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(2)), r.data[5:11]))),
            osd.i_b.eq(Mux(histo, Mux((hist_chan == 2) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[0:5]))),
            osd.on.eq(osd_on),
            osd.osd_val.eq(osd_val),
            osd.sel.eq(osd_sel),
            osd.grid.eq(grid),
            osd.border.eq(border),
            osd.roi.eq(roi.en & ~histo),
            osd.roi_x.eq(roi.x),
            osd.roi_y.eq(roi.y),
            osd.roi_w.eq(roi.w),
            osd.roi_h.eq(roi.h)
        ]

        # OSD control
        osd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, mono, flip[0], flip[1],
                          border, sharpness, invert, grid, filt])

        with m.If(debosd.btn_down):
            m.d.sync += osd_on.eq(~osd_on)

        with m.If(osd_on):
            with m.If(debsel.btn_down):
                m.d.sync += osd_sel.eq(~osd_sel)

            with m.If(debup.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(Mux(osd_val == 0, 11, osd_val-1))
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(1)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i]+1)

            with m.If(debdown.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(Mux(osd_val == 11, 0, osd_val+1))
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(0)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i]-1)

        # Show configuration values on leds
        with m.Switch(osd_val):
            for i in range(len(osd_vals)):
                with m.Case(i):
                    m.d.comb += leds.eq(osd_vals[i])

        # Generate VGA signals
        m.d.comb += [
            vga.i_clk_en.eq(1),
            vga.i_test_picture.eq(0),
            vga.i_r.eq(osd.o_r), 
            vga.i_g.eq(osd.o_g), 
            vga.i_b.eq(osd.o_b), 
            vga_r.eq(vga.o_vga_r),
            vga_g.eq(vga.o_vga_g),
            vga_b.eq(vga.o_vga_b),
            vga_hsync.eq(vga.o_vga_hsync),
            vga_vsync.eq(vga.o_vga_vsync),
            vga_blank.eq(vga.o_vga_blank),
        ]

        # VGA to digital video converter.
        tmds = [Signal(2) for i in range(4)]
        m.submodules.vga2dvid = vga2dvid = VGA2DVID(ddr=self.ddr, shift_clock_synchronizer=False)
        m.d.comb += [
            vga2dvid.i_red.eq(vga_r),
            vga2dvid.i_green.eq(vga_g),
            vga2dvid.i_blue.eq(vga_b),
            vga2dvid.i_hsync.eq(vga_hsync),
            vga2dvid.i_vsync.eq(vga_vsync),
            vga2dvid.i_blank.eq(vga_blank),
            tmds[3].eq(vga2dvid.o_clk),
            tmds[2].eq(vga2dvid.o_red),
            tmds[1].eq(vga2dvid.o_green),
            tmds[0].eq(vga2dvid.o_blue),
        ]

        # GPDI pins
        if (self.ddr):
            # Vendor specific DDR modules.
            # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended)
            # onboard GPDI.
            m.submodules.ddr0_clock = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[3][0],
                i_D1   = tmds[3][1],
                o_Q    = self.o_gpdi_dp[3])
            m.submodules.ddr0_red   = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[2][0],
                i_D1   = tmds[2][1],
                o_Q    = self.o_gpdi_dp[2])
            m.submodules.ddr0_green = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[1][0],
                i_D1   = tmds[1][1],
                o_Q    = self.o_gpdi_dp[1])
            m.submodules.ddr0_blue  = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[0][0],
                i_D1   = tmds[0][1],
                o_Q    = self.o_gpdi_dp[0])
        else:
            m.d.comb += [
                self.o_gpdi_dp[3].eq(tmds[3][0]),
                self.o_gpdi_dp[2].eq(tmds[2][0]),
                self.o_gpdi_dp[1].eq(tmds[1][0]),
                self.o_gpdi_dp[0].eq(tmds[0][0]),
            ]

        return m