mirror of
https://github.com/wuxx/icesugar.git
synced 2026-01-03 10:23:02 +08:00
Merge pull request #10 from nalzok/master
Added example for the PmodOLED module
This commit is contained in:
31
src/basic/verilog/pmodoled2/Makefile
Normal file
31
src/basic/verilog/pmodoled2/Makefile
Normal file
@@ -0,0 +1,31 @@
|
||||
all: pmodoled2.bin
|
||||
|
||||
ICELINK_DIR=$(shell df | grep iCELink | awk '{print $$9}')
|
||||
${info iCELink path: $(ICELINK_DIR)}
|
||||
|
||||
pmodoled2.bin: pmodoled2.v uart.v pmodoled2.pcf
|
||||
yosys -p "synth_ice40 -top top -json $(@:.bin=).json" $(filter %.v,$^)
|
||||
nextpnr-ice40 \
|
||||
--up5k \
|
||||
--package sg48 \
|
||||
--json $(@:.bin=).json \
|
||||
--pcf $(filter %.pcf,$^) \
|
||||
--asc $(@:.bin=).asc
|
||||
icepack $(@:.bin=).asc $(@:.bin=).bin
|
||||
|
||||
clean:
|
||||
rm -f pmodoled2.json pmodoled2.asc pmodoled2.bin
|
||||
|
||||
prog_flash: pmodoled2.bin
|
||||
@if [ -d '$(ICELINK_DIR)' ]; \
|
||||
then \
|
||||
cp -R pmodoled2.bin $(ICELINK_DIR); \
|
||||
else \
|
||||
echo "iCELink not found"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: subdirs
|
||||
.PHONY: subdirs $(SUBDIRS)
|
||||
.PHONY: clean
|
||||
.PHONY: prog_flash
|
||||
54
src/basic/verilog/pmodoled2/README.md
Normal file
54
src/basic/verilog/pmodoled2/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Courtesy of https://github.com/laanwj/yosys-ice-experiments
|
||||
|
||||
- Display: Digilent PmodOLED 128x32 grid SSD1306 module
|
||||
- Connected to iCEstick evaluation board
|
||||
- Using 4-wire SPI 10MHz max
|
||||
- iCE40HX-1k FPGA, programmed using open source FPGA toolchain Yosys + Arachne-pnr + IceStorm
|
||||
- Image generated using Python script, sent from PC through FTDI serial-over-USB 1000000 baud
|
||||
|
||||
```
|
||||
+------+ +------------+ +------+ +---------+
|
||||
| Host |<------->| FTDI 2232H |------->| FPGA |----->| Display |
|
||||
+------+ USB +------------+ Serial +------+ SPI +---------+
|
||||
1M baud (pmod conn)
|
||||
```
|
||||
|
||||
PmodOLED
|
||||
------------
|
||||
|
||||
Connector Pmod
|
||||
|
||||
Pin | Signal | Description
|
||||
------|-----------|---------------------------------
|
||||
1 | CS | SPI Chip Select (Slave Select)
|
||||
2 | SDIN | SPI Data In (MOSI)
|
||||
3 | None | Unused Pin
|
||||
4 | SCLK | SPI Clock
|
||||
7 | D/C | Data/Command Control
|
||||
8 | RES | Power Reset
|
||||
9 | VBATC | V BAT Battery Voltage Control
|
||||
10 | VDDC | V DD Logic Voltage Control
|
||||
5, 11 | GND |
|
||||
6, 12 | VCC | Power Supply G
|
||||
|
||||
Pins on FPGA
|
||||
--------------
|
||||
|
||||
Connecting PMODoled: on module: when connector is to the left, pin 1 is at the top right.
|
||||
Pin 1 is clearly indicated on the iCEstick itself.
|
||||
|
||||
Pin | Signal | Pkgpin
|
||||
-----|---------|---------
|
||||
1 | PIO1_02 | 78
|
||||
2 | PIO1_03 | 79
|
||||
3 | PIO1_04 | 80
|
||||
4 | PIO1_05 | 81
|
||||
5 | GND |
|
||||
6 | VCC |
|
||||
7 | PIO1_06 | 87
|
||||
8 | PIO1_07 | 88
|
||||
9 | PIO1_08 | 90
|
||||
10 | PIO1_09 | 91
|
||||
11 | GND |
|
||||
12 | VCC |
|
||||
|
||||
9
src/basic/verilog/pmodoled2/clear.py
Executable file
9
src/basic/verilog/pmodoled2/clear.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''Clear screen'''
|
||||
from __future__ import division,print_function
|
||||
from oleddisplay import OledDisplay
|
||||
|
||||
disp = OledDisplay()
|
||||
42
src/basic/verilog/pmodoled2/cursestest.py
Executable file
42
src/basic/verilog/pmodoled2/cursestest.py
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''Typing directly to display'''
|
||||
from __future__ import division,print_function
|
||||
import sys,time
|
||||
from imagefont import ImageFont
|
||||
from util import bin8,load_bw_image,tile_image
|
||||
from oleddisplay import OledDisplay,DC
|
||||
import time
|
||||
import curses
|
||||
|
||||
font = ImageFont("fonts/oddball.png")
|
||||
disp = OledDisplay()
|
||||
|
||||
stdscr = curses.initscr()
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
stdscr.keypad(1)
|
||||
|
||||
try:
|
||||
disp.update(on=DC) # send display data
|
||||
ofs = 0
|
||||
while True:
|
||||
ch = stdscr.getch()
|
||||
if ch == 27:
|
||||
break
|
||||
elif ch == 10:
|
||||
n = 16 - (ofs % 16)
|
||||
disp.spi(font.glyphs_bw[0x20] * n)
|
||||
ofs += n
|
||||
elif ch < len(font.glyphs_bw):
|
||||
disp.spi(font.glyphs_bw[ch])
|
||||
ofs += 1
|
||||
disp.update(off=DC) # back to command mode
|
||||
finally:
|
||||
curses.nocbreak()
|
||||
stdscr.keypad(0)
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
46
src/basic/verilog/pmodoled2/display.py
Normal file
46
src/basic/verilog/pmodoled2/display.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''
|
||||
Base classes for Display, console-based emulation
|
||||
'''
|
||||
from __future__ import division,print_function
|
||||
import sys
|
||||
|
||||
class BaseDisplay:
|
||||
'''
|
||||
Base class for external grid displays.
|
||||
'''
|
||||
width = None
|
||||
height = None
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def set_image(self, data):
|
||||
'''
|
||||
Send image to display.
|
||||
Input: width * height 2D array of 0,1 values.
|
||||
'''
|
||||
pass
|
||||
|
||||
class ConsoleDisplay(BaseDisplay):
|
||||
'''
|
||||
Simple console based 'display'.
|
||||
'''
|
||||
def __init__(self):
|
||||
sys.stdout.write('\x1b[H\x1b[J')
|
||||
self.width = 128
|
||||
self.height = 32
|
||||
|
||||
def set_image(self, data):
|
||||
sys.stdout.write('\x1b[H')
|
||||
for y in range(0,self.height):
|
||||
s = []
|
||||
for x in range(0,self.width):
|
||||
if data[y][x]:
|
||||
s.append('x')
|
||||
else:
|
||||
s.append(' ')
|
||||
sys.stdout.write((''.join(s)) + '\n')
|
||||
|
||||
|
||||
6
src/basic/verilog/pmodoled2/fonts/credits.md
Normal file
6
src/basic/verilog/pmodoled2/fonts/credits.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Font: oddball.png
|
||||
http://forums.tigsource.com/index.php?topic=8834.0
|
||||
Topic: Oddball's small offerings
|
||||
David Williamson
|
||||
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
|
||||
|
||||
BIN
src/basic/verilog/pmodoled2/fonts/oddball.png
Normal file
BIN
src/basic/verilog/pmodoled2/fonts/oddball.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
56
src/basic/verilog/pmodoled2/imagefont.py
Normal file
56
src/basic/verilog/pmodoled2/imagefont.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''
|
||||
Simple image font
|
||||
'''
|
||||
# TODO: support different image formats than RGBA
|
||||
from __future__ import division,print_function
|
||||
from PIL import Image
|
||||
|
||||
THRESHOLD=128 # pixel values >= this are considered hi, else lo
|
||||
ALPHA_COMP=3 # component to use for b/w extraction
|
||||
|
||||
class ImageFont:
|
||||
def __init__(self, imgname, glyph_w=8, glyph_h=8):
|
||||
self.glyph_w = glyph_w
|
||||
self.glyph_h = glyph_h
|
||||
|
||||
img = Image.open(imgname)
|
||||
|
||||
self.chars_w = img.size[0]//glyph_w
|
||||
self.chars_h = img.size[1]//glyph_h
|
||||
self.numchars = self.chars_w * self.chars_h
|
||||
|
||||
self._extract_glyphs(img)
|
||||
self._convert_to_bw()
|
||||
|
||||
def _extract_glyphs(self,img):
|
||||
'''Extract RGBA glyphs'''
|
||||
data = list(img.getdata())
|
||||
self.glyphs = []
|
||||
for ch in range(self.numchars):
|
||||
basex = (ch % self.chars_w) * self.glyph_w
|
||||
basey = (ch // self.chars_w) * self.glyph_h
|
||||
baseaddr = basey*img.size[0] + basex
|
||||
glyph_data = []
|
||||
for yy in range(self.glyph_h):
|
||||
glyph_data.append(data[baseaddr:baseaddr+self.glyph_w])
|
||||
baseaddr += img.size[0]
|
||||
self.glyphs.append(glyph_data)
|
||||
|
||||
def _convert_to_bw(self):
|
||||
'''Extract b/w binary glyphs'''
|
||||
self.glyphs_bw = []
|
||||
for ch in range(self.numchars):
|
||||
glyph_in = self.glyphs[ch]
|
||||
glyph_data = []
|
||||
for xx in range(self.glyph_w):
|
||||
glyph_col = 0
|
||||
for yy in range(self.glyph_h):
|
||||
if glyph_in[yy][xx][ALPHA_COMP] >= THRESHOLD:
|
||||
glyph_col |= 1<<yy
|
||||
glyph_data.append(glyph_col)
|
||||
self.glyphs_bw.append(glyph_data)
|
||||
|
||||
|
||||
BIN
src/basic/verilog/pmodoled2/images/cthulhu.png
Normal file
BIN
src/basic/verilog/pmodoled2/images/cthulhu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 590 B |
105
src/basic/verilog/pmodoled2/images/cthulhu.svg
Normal file
105
src/basic/verilog/pmodoled2/images/cthulhu.svg
Normal file
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="540"
|
||||
height="540"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="cthulhu.svg"
|
||||
inkscape:export-filename="/home/pcon/Dropbox/Art/cthulhu.png.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="-16.708253"
|
||||
inkscape:cy="177.91599"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer2"
|
||||
showgrid="false"
|
||||
units="in"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1059"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Layer"
|
||||
style="display:inline">
|
||||
<g
|
||||
id="g3065">
|
||||
<path
|
||||
sodipodi:nodetypes="sssssssccsssssssaass"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3067"
|
||||
d="m 261.9375,54.0625 c -1.27261,0.01551 -2.5561,0.219546 -3.78125,0.4375 -18.71955,3.330193 -36.50792,11.632093 -53,21.09375 -8.34901,4.789907 -10.58745,6.814271 -14.65625,15.84375 -8.88547,19.71865 -16.24305,44.52107 -21.40625,61.25 -2.77039,8.97614 -0.83902,10.52359 2,14.28125 29.95621,39.64929 68.10908,82.91549 88.21875,117.34375 1.88883,3.23372 4.35165,9.33111 10.45809,-2.05871 0.67116,-1.58413 0.81289,-1.11245 1.45492,0.10896 6.06362,11.24181 8.51672,5.17311 10.39949,1.94975 20.10967,-34.42826 58.26254,-77.69446 88.21875,-117.34375 2.83902,-3.75766 4.77039,-5.30511 2,-14.28125 -5.1632,-16.72893 -12.52078,-41.53135 -21.40625,-61.25 -4.0688,-9.029479 -6.30724,-11.053843 -14.65625,-15.84375 -16.49208,-9.461657 -34.28045,-17.763557 -53,-21.09375 -2.4503,-0.435908 -5.17262,-0.772599 -7.46875,0.1875 -1.44544,0.604394 -2.46348,2.201359 -3.97284,2.778964 -0.5022,0.192185 -1.0808,0.328474 -1.60145,0.194067 -1.63802,-0.422858 -2.59585,-2.338567 -4.11321,-2.973031 -1.14807,-0.480051 -2.41489,-0.640506 -3.6875,-0.625 z"
|
||||
style="opacity:1;color:#000000;fill:#000000;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3880"
|
||||
d="M 270,3.28125 C 122.69627,3.28125 3.28125,122.69627 3.28125,270 3.28125,417.30373 122.69627,536.71875 270,536.71875 417.30373,536.71875 536.71875,417.30373 536.71875,270 536.71875,122.69627 417.30373,3.28125 270,3.28125 z M 270,24.75 C 405.44853,24.75 515.25,134.55147 515.25,270 515.25,405.44853 405.44853,515.25 270,515.25 134.55147,515.25 24.75,405.44853 24.75,270 24.75,134.55147 134.55147,24.75 270,24.75 z"
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
id="rect3091-4-1"
|
||||
d="M 153.9375 75.5625 C 151.47667 75.628808 149.01192 76.05563 146.71875 76.78125 C 140.32828 78.803363 130.15027 88.893611 129.53125 97.96875 C 128.95613 106.40028 133.04595 101.41431 135.5625 98.0625 C 139.91975 92.259047 148.77073 89.836105 152.15625 91.90625 C 158.4914 95.779996 156.48783 107.0233 154.21875 114.09375 C 152.58544 119.18316 146.62954 125.31055 139.0625 131.65625 C 143.35042 135.8515 147.0507 140.61214 150.375 145.625 C 160.68126 136.27942 169.72724 126.0617 174.28125 113.3125 C 177.48117 104.35417 177.06272 93.190773 172.5 84.84375 C 170.25107 80.729572 165.62528 77.949674 161.15625 76.53125 C 158.86372 75.803623 156.39833 75.496192 153.9375 75.5625 z M 120.0625 146.1875 C 110.0571 153.45269 100.53453 160.19837 95.6875 165.09375 C 82.21555 178.70006 69.22414 193.56513 60.84375 210.78125 C 51.40301 230.17571 49.93192 268.67337 73 288.09375 C 92.18219 304.24272 120.24559 319.72068 188.6875 310.21875 C 243.20382 301.82908 243.80057 340.32076 242.96875 380.03125 C 239.46365 420.45849 231.0934 432.8027 226.59375 440 C 209.87711 458.25284 198.99168 457.85564 191.90625 449.90625 C 185.14845 453.48985 178.13972 456.69643 170.8125 458.84375 C 173.88306 464.20555 177.32129 467.61092 180.75 470.34375 C 192.09384 479.38526 215.43347 483.93448 235.34375 464.8125 C 243.19839 457.26885 253.23541 439.81245 258.90625 414.84375 C 265.21823 387.05207 272.11624 336.02944 266.96875 315.15625 C 258.69956 281.6245 256.62635 282.20434 237.78125 274.0625 C 232.7467 271.88736 218.70284 267.78135 210.71875 250.5 C 207.70547 243.97783 214.94198 237.51071 224.25 245.625 C 228.02199 248.91325 227.95204 247.08149 226.53125 244.40625 C 216.50734 225.53198 205.0731 214.84041 193.46875 200.84375 C 191.0891 197.97352 188.98398 198.40108 190.75 202.875 C 193.83932 210.70128 198.48666 222.22069 189.21875 236.5 C 187.66371 238.89589 187.97775 236.72061 188.53125 235.75 C 191.83753 229.95211 192.20795 229.2922 192.65625 225.59375 C 192.99471 222.80142 192.05656 221.46077 189.5 223.78125 C 187.24516 225.82788 172.03409 219.97817 172.875 199.625 C 173.0545 195.28039 171.9806 195.44105 169.21875 197.65625 C 146.76203 215.66808 139.70446 253.46944 160.25 273.53125 C 163.18798 276.40006 164.53337 278.17363 166.78125 272.65625 C 167.54753 270.77544 172.23876 262.0555 183.15625 261.6875 C 187.64645 261.53615 205.44692 270.53778 182.5 283.15625 C 164.24935 293.19225 102.58165 295.26009 84.4375 267.78125 C 53.01319 220.18994 114.45163 176.68847 120.96875 170.6875 C 123.99464 167.90125 127.18658 165.18131 130.4375 162.46875 C 128.33735 156.2533 125.08838 150.35575 120.0625 146.1875 z M 131.59375 323.53125 C 131.00505 323.52701 130.41746 323.54362 129.84375 323.5625 C 124.33615 323.74377 119.59241 324.94028 116.65625 326.15625 C 107.0109 330.15076 108.01782 345.46741 108.75 349.625 C 110.19955 357.85598 118.07408 362.58154 118.5 351.5 C 118.65551 347.45392 120.47927 341.43797 123.375 339.96875 C 125.14854 339.0689 133.79042 337.08903 142.25 344.78125 C 143.89392 346.27605 145.44704 348.0478 146.90625 350.09375 C 151.1989 345.81265 155.57738 341.62181 160.15625 337.625 C 159.66158 336.99393 159.17653 336.36943 158.65625 335.75 C 150.79982 326.39635 140.42426 323.59487 131.59375 323.53125 z M 173.03125 361.9375 C 167.34166 366.64746 162.00181 371.66065 157.125 377.1875 C 157.12683 377.1973 157.12317 377.20895 157.125 377.21875 C 158.47835 384.46423 159.37739 392.8616 159.71875 402.5 C 160.19991 416.08558 161.34014 426.81949 162.96875 435.4375 C 169.95415 435.03352 176.63396 431.81555 182.375 427.8125 C 182.09962 426.59096 181.82697 425.37531 181.59375 424.15625 C 179.48288 413.12258 181.52488 386.87966 173.03125 361.9375 z "
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
id="rect3961"
|
||||
d="M 209.96875 311.65625 C 203.09514 311.50727 196.03697 313.30547 189.15625 313.25 C 185.40727 313.2198 184.12095 314.31349 184.375 317.125 C 184.47541 318.23629 184.02795 320.13934 183.59375 320.5 C 156.63864 342.8894 155.94124 343.80377 142.875 357.03125 C 133.21167 366.81382 126.416 376.06831 122 384.84375 C 129.17702 387.96164 136.89811 389.63914 144.71875 390.375 C 147.36428 386.09828 150.47283 382.12428 153.375 378.53125 C 166.82595 361.8783 186.01508 349.6657 204 336.5 C 209.95023 332.14419 214.211 329.3029 228.78125 327.59375 C 234.56562 326.91522 231.40586 323.80946 229.71875 321.6875 C 223.51713 313.88738 216.84236 311.80523 209.96875 311.65625 z M 227.5 409.0625 C 217.51048 409.13476 204.15303 413.97975 185.3125 428.1875 C 176.01741 435.19698 159.62323 442.98011 148.625 432.125 C 143.06813 426.64044 140.07484 421.20671 138.84375 415.9375 C 130.79008 414.77742 122.92524 412.58648 115.375 409.5625 C 115.04324 421.84941 119.30936 432.97448 126.21875 443.03125 C 143.42848 468.08037 169.63828 459.96096 193.53125 446.71875 C 205.06812 440.32467 214.58663 426.70985 229.84375 430.28125 C 232.84326 423.94164 234.87181 417.22757 236.4375 410.40625 C 233.77389 409.53728 230.82984 409.03841 227.5 409.0625 z M 257.875 426.5 C 255.84969 433.13102 253.38582 439.63354 250.375 445.875 C 254.13749 452.93087 255.57356 462.02343 250.71875 469.375 C 248.27438 473.07647 245.6062 477.5232 240.09375 481.21875 C 231.91518 486.70167 236.83994 487.51412 246.71875 486.1875 C 258.4979 484.60569 262.33782 471.62582 264.09375 466.75 C 269.1202 452.79272 267.03181 435.53364 257.875 426.5 z "
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3961-9"
|
||||
d="m 330.75,311.65625 c -6.87361,0.14898 -13.57963,2.23113 -19.78125,10.03125 -1.68711,2.12196 -4.84687,5.22772 0.9375,5.90625 14.57025,1.70915 18.83102,4.55044 24.78125,8.90625 10.15259,7.43211 20.6758,14.58787 30.34375,22.375 2.70782,-7.38909 6.38755,-14.41897 11,-20.78125 -4.7286,-4.10222 -11.05,-9.38101 -20.9375,-17.59375 -0.4342,-0.36066 -0.88166,-2.26371 -0.78125,-3.375 0.25405,-2.81151 -1.03227,-3.9052 -4.78125,-3.875 -6.88072,0.0555 -13.90764,-1.74273 -20.78125,-1.59375 z M 394.3125,353.5 c -4.28206,7.21475 -6.59299,15.3451 -8.21875,23.5625 0.40724,0.48437 0.82133,0.97672 1.21875,1.46875 11.15096,13.80545 25.32148,33.28997 4.75,53.59375 -3.77207,3.72298 -8.18133,5.25367 -12.71875,5.375 -5.5e-4,0.002 -0.0307,-0.002 -0.0312,0 -1.60656,6.91197 -3.8085,13.64506 -6.96875,19.9375 15.78053,4.13837 30.87505,1.96828 42.125,-14.40625 15.67322,-22.81271 17.78259,-51.13619 -16.65625,-86 -1.41342,-1.43086 -2.32707,-2.34568 -3.5,-3.53125 z m -81.46875,55.53125 c -14.65645,0.0433 -22.01983,10.44173 -29,16.53125 -10.00865,8.73157 -12.45657,26.73008 -7.25,41.1875 1.75593,4.87582 5.59585,17.85569 17.375,19.4375 9.87881,1.32662 14.80357,0.51417 6.625,-4.96875 -5.51245,-3.69555 -8.18063,-8.14228 -10.625,-11.84375 -7.34651,-11.12472 -0.33416,-26.3146 7.4375,-32.25 23.80107,-18.17745 35.16471,1.51014 49.75,9.59375 0.42551,0.23583 0.85434,0.45508 1.28125,0.6875 4.12047,-5.35225 6.55947,-11.75277 8.0625,-18.40625 -0.38086,-0.27287 -0.76474,-0.54083 -1.125,-0.8125 -19.05629,-14.37046 -32.50315,-19.18589 -42.53125,-19.15625 z"
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
id="rect3982"
|
||||
d="M 110.0625 120.78125 C 99.387573 120.92699 90.820211 126.26065 86.6875 129.84375 C 70.89183 143.53875 70.66733 154.3184 70.65625 163.6875 C 70.64175 175.98002 75.68897 170.99955 77.125 164.40625 C 79.72745 152.45752 85.803113 141.36781 103.09375 139.46875 C 135.09121 135.95441 147.76639 188.17959 118.9375 230.21875 L 90.40625 271.8125 C 95.35589 276.55253 101.55219 279.93706 108.03125 282.3125 C 110.06233 278.98439 112.26613 275.65025 114.65625 272.3125 C 128.29318 253.2688 138.66431 236.35241 145.59375 222.15625 C 160.47598 191.6674 156.23226 158.9325 151.03125 150.34375 C 136.95794 127.10362 122.16075 120.61607 110.0625 120.78125 z M 77.0625 293.90625 C 70.414905 309.08021 63.617404 335.18594 74.09375 365.625 C 80.63308 384.62504 95.418353 402.06096 125.9375 411.125 C 134.08179 413.54382 145.70035 415.40572 158.375 414.75 C 157.86408 407.28272 157.69269 399.77547 157.125 392.3125 C 153.73517 392.63619 150.37695 392.72304 147.125 392.53125 C 97.823356 389.62354 79.761764 350.94494 96.65625 305.46875 C 89.695465 302.37771 83.155809 298.46358 77.0625 293.90625 z M 230.28125 330.84375 C 229.6669 330.82496 228.95833 330.83228 228.15625 330.875 C 225.30643 331.02678 222.16411 331.02769 219.6875 332.90625 C 218.69688 333.65766 215.24855 333.87607 215.84375 338.15625 C 218.83631 359.67607 201.70676 377.36385 180.53125 386.3125 C 181.5276 394.22349 182.03941 402.1846 182.4375 410.15625 C 190.30114 407.42695 198.02032 403.35428 205.0625 397.46875 C 216.72663 387.72041 231.65574 373.12665 235.65625 371.1875 C 238.21678 369.94634 240.47572 367.07298 240.1875 359.125 C 239.89484 351.05427 239.50412 342.70557 235.78125 334.9375 C 234.64691 332.57061 234.58167 330.97526 230.28125 330.84375 z "
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3982-5"
|
||||
d="m 428.46875,120.78125 c -7.30286,0.22736 -15.5132,2.97647 -23.90625,10.28125 5.05336,4.38913 10.61455,8.24824 16.09375,12.15625 4.58586,-3.01849 10.0557,-4.43033 16.25,-3.75 17.29064,1.89906 23.33505,12.98877 25.9375,24.9375 1.43603,6.5933 6.5145,11.57377 6.5,-0.71875 -0.0111,-9.3691 -0.26683,-20.14875 -16.0625,-33.84375 -4.13271,-3.5831 -12.70007,-8.91676 -23.375,-9.0625 -0.47868,-0.007 -0.95064,-0.0152 -1.4375,0 z m -37.9375,27.09375 c -0.52634,0.82017 -1.06923,1.60258 -1.59375,2.46875 -5.20101,8.58875 -9.44473,41.32365 5.4375,71.8125 6.92944,14.19616 17.30057,31.11255 30.9375,50.15625 34.15773,47.70062 31.5056,95.46456 -4.0625,113.1875 3.07212,6.56908 5.21325,13.60557 5.90625,20.8125 21.79707,-9.7143 33.19589,-24.6408 38.71875,-40.6875 14.54594,-42.26328 -4.20232,-76.155 -9.625,-84.0625 L 421.03125,230.21875 C 405.06371,206.93439 401.83088,180.51667 407.5625,162.1875 401.83594,157.46628 396.05932,152.8036 390.53125,147.875 z M 309.6875,330.84375 c -4.29951,0.13328 -4.36566,1.72686 -5.5,4.09375 -3.72287,7.76807 -4.11359,16.11677 -4.40625,24.1875 -0.28822,7.94798 1.97072,10.82134 4.53125,12.0625 4.00051,1.93915 18.92962,16.53291 30.59375,26.28125 20.40205,17.05109 46.42436,19.05839 65.40625,16.53125 0.96873,-7.50971 -1.52456,-15.05502 -5.375,-21.625 -0.69656,0.0566 -1.38424,0.1144 -2.09375,0.15625 -31.89163,1.8809 -73.23658,-21.88685 -68.71875,-54.375 0.5952,-4.28018 -2.85313,-4.49859 -3.84375,-5.25 -2.47661,-1.87856 -5.61893,-1.87947 -8.46875,-2.03125 -0.80208,-0.0427 -1.51078,-0.0503 -2.125,-0.0312 z"
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect3091-4"
|
||||
d="m 387.28125,75.34375 c -2.46083,-0.06631 -4.92622,0.241123 -7.21875,0.96875 -4.46903,1.418424 -9.09482,4.198322 -11.34375,8.3125 -4.56272,8.347023 -4.98117,19.54167 -1.78125,28.5 8.77926,24.57799 34.16759,39.74378 53.28125,57.34375 6.51712,6.00098 67.95556,49.50244 36.53125,97.09375 -1.1899,1.80207 -2.55401,3.47723 -4.09375,5.03125 4.18264,6.01157 8.14492,12.16006 11.3125,18.71875 1.469,-1.13559 2.88282,-2.28651 4.25,-3.4375 23.06808,-19.42038 21.56574,-57.91804 12.125,-77.3125 -8.38039,-17.21612 -21.3718,-32.04993 -34.84375,-45.65625 -12.1575,-12.27877 -53.74261,-36.10979 -58.53125,-51.03125 -2.26908,-7.07045 -4.27265,-18.313754 2.0625,-22.1875 3.38552,-2.070145 12.2365,0.352797 16.59375,6.15625 2.51655,3.3518 6.63762,8.33778 6.0625,-0.09375 -0.61902,-9.075139 -10.79703,-19.165387 -17.1875,-21.1875 -2.29317,-0.72562 -4.75792,-1.152442 -7.21875,-1.21875 z M 369.3125,195.9375 c -0.77093,0.0354 -1.06972,1.05616 -0.96875,3.5 0.84091,20.35317 -14.40141,26.17163 -16.65625,24.125 -2.55656,-2.32048 -3.46346,-0.94858 -3.125,1.84375 0.4483,3.69845 0.78747,4.35836 4.09375,10.15625 0.5535,0.97061 0.86754,3.14589 -0.6875,0.75 -9.26791,-14.27931 -4.62057,-25.79872 -1.53125,-33.625 1.76602,-4.47392 -0.30785,-4.90148 -2.6875,-2.03125 -11.60435,13.99666 -23.06984,24.65698 -33.09375,43.53125 -1.42079,2.67524 -1.45949,4.507 2.3125,1.21875 9.30802,-8.11429 16.54453,-1.64717 13.53125,4.875 -7.98409,17.28135 -22.02795,21.41861 -27.0625,23.59375 -18.8451,8.14184 -20.91831,7.53075 -29.1875,41.0625 -5.14749,20.87319 1.71927,71.89582 8.03125,99.6875 0.61051,2.68809 1.26455,5.2703 1.96875,7.78125 5.50414,-5.26676 11.04423,-10.87157 18.15625,-13.53125 -1.65941,-7.63983 -3.11885,-17.09731 -4.15625,-29.0625 -0.83182,-39.71049 -0.26632,-78.17092 54.25,-69.78125 42.50413,5.90094 69.43557,2.14536 88.34375,-5.40625 -2.69112,-6.84843 -5.96695,-13.4328 -9.71875,-19.78125 -25.51511,8.23023 -59.64351,5.12914 -72.4375,-1.90625 -22.94692,-12.61847 -5.1152,-21.58885 -0.625,-21.4375 10.91749,0.368 15.60872,9.05669 16.375,10.9375 2.24788,5.51738 3.59327,3.74381 6.53125,0.875 20.54554,-20.06181 13.48797,-57.86317 -8.96875,-75.875 -1.20831,-0.96915 -2.08789,-1.5275 -2.6875,-1.5 z m 39.21875,127.40625 c -8.59386,0.28448 -18.45783,3.23924 -26,12.21875 -12.55037,14.94215 -17.54618,33.37399 -19.78125,49.9375 6.30437,2.3627 12.81826,3.94942 19.5,4.71875 2.24121,-23.60817 8.38079,-38.04335 16.71875,-45.625 8.45958,-7.69222 17.07021,-5.71235 18.84375,-4.8125 2.89573,1.46922 4.75074,7.45392 4.90625,11.5 0.42592,11.08154 8.2692,6.35598 9.71875,-1.875 0.73218,-4.15759 1.77035,-19.47424 -7.875,-23.46875 -3.42552,-1.41863 -9.34714,-2.81502 -16.03125,-2.59375 z M 360.625,413.25 c -0.23375,4.32388 -0.51076,7.99811 -1.03125,10.71875 -4.36763,22.82994 -15.84822,47.64322 -45,15.8125 -1.20303,-1.92428 -2.69509,-4.24531 -4.28125,-7.34375 -7.06639,2.14495 -13.31333,6.70454 -17.5,12.78125 4.33627,8.88816 8.99544,15.46896 13.0625,19.375 19.91028,19.12198 43.24991,14.60401 54.59375,5.5625 8.60628,-6.85956 17.18624,-18.07058 20.15625,-53.4375 -6.78755,-0.43888 -13.48303,-1.57743 -20,-3.46875 z"
|
||||
style="opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
3
src/basic/verilog/pmodoled2/images/source.md
Normal file
3
src/basic/verilog/pmodoled2/images/source.md
Normal file
@@ -0,0 +1,3 @@
|
||||
cthulhu.svg
|
||||
http://pcon.github.io/design/cthulhu/
|
||||
|
||||
90
src/basic/verilog/pmodoled2/mandelbrot.py
Executable file
90
src/basic/verilog/pmodoled2/mandelbrot.py
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''
|
||||
Smooth Mandelbrot rendering using numpy.
|
||||
'''
|
||||
from __future__ import division,print_function
|
||||
from display import ConsoleDisplay
|
||||
from oleddisplay import OledDisplay
|
||||
import numpy as np
|
||||
|
||||
def mandelbrot(c, iterations=20):
|
||||
'''
|
||||
Compute mandelbrot set at coordinate c,
|
||||
return True if inside or False if outside.
|
||||
'''
|
||||
z = 0+0j
|
||||
i = 0
|
||||
while abs(z) < 2 and i < iterations:
|
||||
z = (z * z) + c
|
||||
i += 1
|
||||
return i >= iterations
|
||||
|
||||
def find_edge(c1, c2, func):
|
||||
'''
|
||||
Find edge of mandelbrot set using bisection method.
|
||||
Input: c1, a point on the set, c2 a point not on the set.
|
||||
Returns: (c1',c2')
|
||||
'''
|
||||
midpoint = (c1 + c2) / 2
|
||||
if func(midpoint):
|
||||
return (midpoint, c2) # midpoint on set, c2 not on set
|
||||
else:
|
||||
return (c1, midpoint) # c1 on set, midpoint not on set
|
||||
|
||||
def random_point():
|
||||
'''Find random point on Mandelbrot set'''
|
||||
import random
|
||||
ofs1 = complex(0,0) # on mandelbrot set
|
||||
ofs2 = (1j ** (random.random()*4)) * 2 # not on mandelbrot set
|
||||
#ofs1 = complex(0.02996, 0.80386) # on mandelbrot set
|
||||
#ofs2 = complex(0.02997, 0.80386) # not on mandelbrot set
|
||||
for i in range(64):
|
||||
(ofs1, ofs2) = find_edge(ofs1, ofs2, mandelbrot)
|
||||
return ofs1
|
||||
# what are interesting points?
|
||||
# https://en.wikipedia.org/wiki/Misiurewicz_point
|
||||
|
||||
#disp = ConsoleDisplay()
|
||||
disp = OledDisplay()
|
||||
|
||||
WW = disp.width
|
||||
HH = disp.height
|
||||
fovy = HH/WW
|
||||
|
||||
xx,yy = np.meshgrid(np.linspace(-1.0, 1.0, WW), np.linspace(-1.0, 1.0, HH))
|
||||
ii = xx + 1j*yy*fovy
|
||||
iterations_outer = 2
|
||||
iterations_inner = 20
|
||||
|
||||
while True:
|
||||
ofs = random_point()
|
||||
#ofs = -0.77568377 + 0.13646737j # M23,2
|
||||
#ofs = -1.54368901269109 # M3,1
|
||||
#ofs = -0.1010 + 0.9562j # M4,1
|
||||
#ofs = 0.3994999999988 + 0.195303j
|
||||
|
||||
frame = 0
|
||||
while True:
|
||||
zoom = 2.0**((frame-600)/200.0)
|
||||
|
||||
# Compute mandelbrot in parallel with numpy
|
||||
c = ii / zoom + ofs
|
||||
z = np.zeros((HH,WW),dtype=complex)
|
||||
for i in range(iterations_inner):
|
||||
if i == iterations_outer: # for showing outer boundary
|
||||
zb = z
|
||||
z = (z * z) + c
|
||||
data = np.abs(z) < 2
|
||||
boundary = np.abs(zb) < 2
|
||||
|
||||
# Boundary
|
||||
disp.set_image(np.invert(data) & boundary)
|
||||
|
||||
if np.all(data) or not np.any(data):
|
||||
# stop if there is nothing to see anymore
|
||||
break
|
||||
frame += 1
|
||||
|
||||
102
src/basic/verilog/pmodoled2/oleddisplay.py
Normal file
102
src/basic/verilog/pmodoled2/oleddisplay.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''
|
||||
Serial OLED display driving logic.
|
||||
'''
|
||||
from __future__ import division,print_function
|
||||
import serial,sys,time
|
||||
from imagefont import ImageFont
|
||||
from util import bin8,load_bw_image,tile_image,detect_serial
|
||||
from display import BaseDisplay
|
||||
|
||||
# Flag bits
|
||||
CS = (1<<4) # chip select if low
|
||||
DC = (1<<3) # command if low, data if high
|
||||
RES = (1<<2) # reset if low
|
||||
VBATC= (1<<1) # power control display; active-low
|
||||
VDDC = (1<<0) # power control logic; active-low
|
||||
|
||||
class OledDisplay(BaseDisplay):
|
||||
width = 128
|
||||
height = 32
|
||||
def __init__(self, port=None):
|
||||
if port is None:
|
||||
ports = detect_serial()
|
||||
if len(ports) == 0:
|
||||
raise IOError('No iCEStick devices detected')
|
||||
if len(ports) > 1:
|
||||
raise IOError('Multiple possible iCEStick devices detected. Need to specify which one to use')
|
||||
port = ports[0]
|
||||
self.conn = serial.serial_for_url(port, 1000000,
|
||||
parity=serial.PARITY_NONE, rtscts=False, xonxoff=False, timeout=1)
|
||||
|
||||
self.value = 0
|
||||
|
||||
# Send 33 NOPs to reset and sync serial
|
||||
self.conn.write(bytearray([0x00] * 33))
|
||||
|
||||
# Select chip, go to command mode, turn off reset and power
|
||||
self.update(off=CS|DC,on=RES|VBATC|VDDC)
|
||||
# 1. Apply power to VDD.
|
||||
self.update(off=VDDC)
|
||||
# 2. Send Display Off command (0xAE)
|
||||
self.spi(0xAE)
|
||||
# Reset
|
||||
self.update(off=RES)
|
||||
time.sleep(0.000003) # at least 3us
|
||||
self.update(on=RES)
|
||||
# 3. Initialize display to desired operating mode.
|
||||
self.spi([0x8D,0x14]) # charge pump
|
||||
self.spi([0xD9,0xF1]) # precharge
|
||||
# 4. Clear screen.
|
||||
self.spi([0x20,0x00]) # horizontal addressing mode
|
||||
self.spi([0x22,0x00,0x03]) # page start and end address (create wraparound at line 32)
|
||||
self.set_image([[0]*self.width for x in range(self.height)])
|
||||
# 5. Apply power to VBAT.
|
||||
self.update(off=VBATC)
|
||||
# Misc configuration
|
||||
self.spi([0x81,0x0F]) # contrast
|
||||
self.spi([0xA1,0xC8]) # invert display
|
||||
self.spi([0xDA,0x20]) # comconfig
|
||||
|
||||
# 6. Delay 100ms.
|
||||
time.sleep(0.1)
|
||||
# 7. Send Display On command (0xAF).
|
||||
self.spi(0xAF)
|
||||
|
||||
# Debugging:
|
||||
#spi(0xA5) # full display
|
||||
#spi(0xA4) # display according to memory
|
||||
#spi([0x20,0x01]) # vertical addressing mode
|
||||
|
||||
def update(self, off=0, on=0):
|
||||
self.value &= ~off
|
||||
self.value |= on
|
||||
self.conn.write(bytearray([0b00100000 | self.value]))
|
||||
#print('Write %s SCLK=%i SDIN=%i' % (bin8(value), bool(value&SCLK), bool(value&SDIN)))
|
||||
#print('OUT %02x' % (0b00100000 | value))
|
||||
|
||||
def spi(self, data_values):
|
||||
'''Clock 8-bit value(s) to SPI'''
|
||||
import binascii
|
||||
if not isinstance(data_values, list):
|
||||
data_values = [data_values]
|
||||
# Value of SDIN is sampled at SCLK's rising edge
|
||||
# so put in new bit at falling edge
|
||||
# Data is clocked from bit 7 (MSB) to bit 0 (LSB)
|
||||
ptr = 0
|
||||
while ptr < len(data_values):
|
||||
n = min(len(data_values)-ptr, 16)
|
||||
self.conn.write(bytearray([0b00010000 | (n-1)] + data_values[ptr:ptr+n]))
|
||||
# print('SPI %02x %s' % (0b00010000 | (n-1), binascii.b2a_hex(bytearray(data_values[ptr:ptr+n]))))
|
||||
ptr += n
|
||||
|
||||
def set_image(self, data):
|
||||
'''Send 128x32 image to display.
|
||||
Input must be 128x32 array of booleans or 0/1.
|
||||
'''
|
||||
self.update(on=DC) # send display data
|
||||
self.spi(tile_image(data))
|
||||
self.update(off=DC) # back to command mode
|
||||
|
||||
21
src/basic/verilog/pmodoled2/pmodoled2.pcf
Normal file
21
src/basic/verilog/pmodoled2/pmodoled2.pcf
Normal file
@@ -0,0 +1,21 @@
|
||||
set_io TXD 6
|
||||
set_io RXD 4
|
||||
set_io clk 35
|
||||
set_io resetq 18
|
||||
|
||||
# LEDs (PMOD 3)
|
||||
set_io LED0 27
|
||||
set_io LED1 25
|
||||
set_io LED2 21
|
||||
set_io LED3 23
|
||||
set_io LED4 26
|
||||
|
||||
# PMOD OLED module connected
|
||||
set_io PMOD_CS 46
|
||||
set_io PMOD_SDIN 44
|
||||
set_io PMOD_SCLK 37
|
||||
set_io PMOD_DC 45
|
||||
set_io PMOD_RES 43
|
||||
set_io PMOD_VBATC 38
|
||||
set_io PMOD_VDDC 36
|
||||
|
||||
73
src/basic/verilog/pmodoled2/pmodoled2.py
Executable file
73
src/basic/verilog/pmodoled2/pmodoled2.py
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''Implementation of pmodoled2a in terms of OledDisplay'''
|
||||
from __future__ import division,print_function
|
||||
import serial,sys,time
|
||||
from imagefont import ImageFont
|
||||
from util import bin8,load_bw_image,tile_image
|
||||
from oleddisplay import OledDisplay,DC
|
||||
|
||||
font = ImageFont("fonts/oddball.png")
|
||||
disp = OledDisplay()
|
||||
|
||||
screen = 0
|
||||
while True:
|
||||
#disp.spi([0xB0,0x00,0x10]) # reset write location (alt: set end address appropriately)
|
||||
disp.update(on=DC) # send display data
|
||||
# Build image
|
||||
#screen = 3
|
||||
if screen == 0:
|
||||
data = [0]*(128*32//8)
|
||||
ptr = 0
|
||||
for ch in u"\u0157 \u0158 \u0157 Ph'nglui Mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn \u0157 \u0158 \u0157":
|
||||
for col in font.glyphs_bw[ord(ch)]:
|
||||
data[ptr] = col
|
||||
ptr += 1
|
||||
elif screen == 1:
|
||||
data = load_bw_image('images/cthulhu.png', ofsy=8)
|
||||
elif screen == 2:
|
||||
scratch = [[0] * 128 for y in range(32)]
|
||||
for l in range(16):
|
||||
for y in range(32):
|
||||
scratch[y][l*8+4] = 1
|
||||
for l in range(4):
|
||||
for x in range(128):
|
||||
scratch[l*8+4][x] = 1
|
||||
data = tile_image(scratch)
|
||||
elif screen == 3:
|
||||
import random
|
||||
shuffle = [x for x in range(64)]
|
||||
'''
|
||||
bs = [5,1,2,3,4,0]
|
||||
for x in range(64):
|
||||
bits = [((x>>b)&1) for b in range(6)]
|
||||
shuffle[x] = sum(bits[bs[b]]<<b for b in range(6))
|
||||
'''
|
||||
for x in range(64):
|
||||
if (x % 3)==0:
|
||||
a = shuffle[x]
|
||||
shuffle[x] = 63-x
|
||||
shuffle[63-x] = a
|
||||
|
||||
data = [0]*(128*32//8)
|
||||
ptr = 0
|
||||
for x in range(64):
|
||||
x_ = shuffle[x]
|
||||
for l in range(8):
|
||||
vv = 0
|
||||
for i in range(8):
|
||||
bit = random.randint(0, 64) < x_
|
||||
vv |= bit << i
|
||||
data[ptr] = vv
|
||||
ptr += 1
|
||||
|
||||
# Send image
|
||||
disp.spi(data)
|
||||
|
||||
disp.update(off=DC) # back to command mode
|
||||
|
||||
time.sleep(5)
|
||||
screen = (screen + 1)% 4
|
||||
|
||||
114
src/basic/verilog/pmodoled2/pmodoled2.v
Normal file
114
src/basic/verilog/pmodoled2/pmodoled2.v
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2015 Wladimir J. van der Laan
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
/* Very simple interface to PMOD SPI. Serial port accepts bytes in the
|
||||
* form:
|
||||
* 0001zzzz Followed by z+1 bytes. Transfer data to SPI.
|
||||
* 001abcde Set parallel control flags: a CS, b DC, c RES, e VBATC, f VDDC
|
||||
* */
|
||||
`timescale 1 ns / 1 ps
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module top(input clk,
|
||||
|
||||
output TXD, // UART TX
|
||||
input RXD, // UART RX
|
||||
|
||||
input resetq,
|
||||
|
||||
output LED0, // Led
|
||||
output LED1, // Led
|
||||
output LED2, // Led
|
||||
output LED4, // Center led
|
||||
|
||||
output PMOD_CS,
|
||||
output PMOD_SDIN,
|
||||
output PMOD_SCLK,
|
||||
output PMOD_DC,
|
||||
output PMOD_RES,
|
||||
output PMOD_VBATC,
|
||||
output PMOD_VDDC,
|
||||
);
|
||||
localparam MHZ = 12;
|
||||
|
||||
// ###### UART ##########################################
|
||||
//
|
||||
reg uart0_valid, uart0_busy;
|
||||
wire [7:0] uart0_data_in;
|
||||
wire [7:0] uart0_data_out = 0;
|
||||
wire uart0_wr = 0;
|
||||
wire uart0_rd = 1;
|
||||
wire [31:0] uart_baud = 1000000;
|
||||
buart #(.CLKFREQ(MHZ * 1000000)) _uart0 (
|
||||
.clk(clk),
|
||||
.resetq(resetq),
|
||||
.baud(uart_baud),
|
||||
.rx(RXD),
|
||||
.tx(TXD),
|
||||
.rd(uart0_rd),
|
||||
.wr(uart0_wr),
|
||||
.valid(uart0_valid),
|
||||
.busy(uart0_busy),
|
||||
.tx_data(uart0_data_out),
|
||||
.rx_data(uart0_data_in));
|
||||
|
||||
reg led0;
|
||||
reg led4;
|
||||
reg [4:0] outcount;
|
||||
reg halfclk;
|
||||
reg [3:0] spi_count; /* number of data bits */
|
||||
reg [7:0] spi_data_out;
|
||||
reg uart_processed; /* UART input byte processed */
|
||||
|
||||
always @(posedge clk) begin
|
||||
// Acme clock divider 12MHz -> 6MHz (to get under max 10MHz)
|
||||
halfclk <= ~halfclk;
|
||||
// Handle SPI output
|
||||
if (halfclk) begin
|
||||
// rising edge
|
||||
PMOD_SCLK <= 1;
|
||||
end else begin
|
||||
// falling edge
|
||||
if (|spi_count) begin
|
||||
// if active - load new data bit on falling edge
|
||||
{PMOD_SDIN,spi_data_out} <= {spi_data_out[7:0],1'b1};
|
||||
PMOD_SCLK <= 0;
|
||||
spi_count <= spi_count - 1;
|
||||
end
|
||||
LED1 <= spi_count; // Just for fun
|
||||
end
|
||||
// Handle UART input, if not processed yet
|
||||
if (uart0_valid && !uart_processed) begin
|
||||
uart_processed <= 1;
|
||||
if (|outcount) begin
|
||||
// SPI transmission in progress
|
||||
outcount <= outcount - 1;
|
||||
spi_data_out <= uart0_data_in;
|
||||
spi_count <= 8;
|
||||
led0 <= ~led0; // Blinkenlights just for fun
|
||||
end else begin
|
||||
// Handle opcodes
|
||||
casez (uart0_data_in)
|
||||
8'b0001zzzz: begin
|
||||
// Send next N+1 bytes to SPI
|
||||
outcount <= (uart0_data_in & 5'b01111) + 1;
|
||||
end
|
||||
8'b001zzzzz: begin
|
||||
// Set flags
|
||||
{PMOD_CS,PMOD_DC,PMOD_RES,PMOD_VBATC,PMOD_VDDC} <= uart0_data_in[4:0];
|
||||
end
|
||||
default: ;
|
||||
endcase
|
||||
led4 <= ~led4; // Blinkenlights
|
||||
end
|
||||
end
|
||||
// New data word coming in, reset processed flag
|
||||
if (~uart0_valid)
|
||||
uart_processed <= 0;
|
||||
end
|
||||
assign LED0 = led0;
|
||||
assign LED4 = led4;
|
||||
|
||||
endmodule // top
|
||||
38
src/basic/verilog/pmodoled2/rawbench.py
Executable file
38
src/basic/verilog/pmodoled2/rawbench.py
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
'''Benchmark rendering'''
|
||||
from __future__ import division,print_function
|
||||
import serial,sys,time
|
||||
from imagefont import ImageFont
|
||||
from util import bin8,load_bw_image,tile_image
|
||||
from oleddisplay import OledDisplay,DC
|
||||
import time
|
||||
|
||||
font = ImageFont("fonts/oddball.png")
|
||||
disp = OledDisplay()
|
||||
|
||||
time_start = time.time()
|
||||
frames = 0
|
||||
fps_str = ''
|
||||
while True:
|
||||
data = [0]*(128*32//8)
|
||||
ptr = 0
|
||||
for ch in str(frames):
|
||||
data[ptr:ptr+8] = font.glyphs_bw[ord(ch)]
|
||||
ptr += 8
|
||||
ptr = 16*8
|
||||
for ch in fps_str:
|
||||
data[ptr:ptr+8] = font.glyphs_bw[ord(ch)]
|
||||
ptr += 8
|
||||
|
||||
disp.update(on=DC) # send display data
|
||||
disp.spi(data)
|
||||
disp.update(off=DC) # back to command mode
|
||||
frames += 1
|
||||
if (frames%1000)==0:
|
||||
curtime = time.time()
|
||||
fps_str = '%.1f FPS' % (frames/(curtime-time_start))
|
||||
print(fps_str)
|
||||
|
||||
187
src/basic/verilog/pmodoled2/uart.v
Normal file
187
src/basic/verilog/pmodoled2/uart.v
Normal file
@@ -0,0 +1,187 @@
|
||||
// Copyright (c) 2015 James Bowman
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
// Borrowed from https://github.com/jamesbowman/swapforth/blob/master/j1a/icestorm/uart.v
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module baudgen(
|
||||
input wire clk,
|
||||
input wire resetq,
|
||||
input wire [31:0] baud,
|
||||
input wire restart,
|
||||
output wire ser_clk);
|
||||
parameter CLKFREQ = 1000000;
|
||||
/* needs to be (CLKFREQ).bit_length() + 1 */
|
||||
parameter RWIDTH = 25;
|
||||
|
||||
wire [RWIDTH-1:0] aclkfreq = CLKFREQ;
|
||||
reg [RWIDTH-1:0] d;
|
||||
wire [RWIDTH-1:0] dInc = d[RWIDTH-1] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq);
|
||||
wire [RWIDTH-1:0] dN = restart ? 0 : (d + dInc);
|
||||
wire fastclk = ~d[RWIDTH-1];
|
||||
assign ser_clk = fastclk;
|
||||
|
||||
always @(negedge resetq or posedge clk)
|
||||
begin
|
||||
if (!resetq) begin
|
||||
d <= 0;
|
||||
end else begin
|
||||
d <= dN;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
/*
|
||||
|
||||
-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
|
||||
| | | | | | | | | | | |
|
||||
|start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2|
|
||||
| | | | | | | | | | | ? |
|
||||
+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +
|
||||
|
||||
*/
|
||||
|
||||
module uart(
|
||||
input wire clk,
|
||||
input wire resetq,
|
||||
|
||||
output wire uart_busy, // High means UART is transmitting
|
||||
output reg uart_tx, // UART transmit wire
|
||||
|
||||
input wire [31:0] baud,
|
||||
input wire uart_wr_i, // Raise to transmit byte
|
||||
input wire [7:0] uart_dat_i
|
||||
);
|
||||
parameter CLKFREQ = 1000000;
|
||||
|
||||
reg [3:0] bitcount; // 0 means idle, so this is a 1-based counter
|
||||
reg [8:0] shifter;
|
||||
|
||||
assign uart_busy = |bitcount;
|
||||
wire sending = |bitcount;
|
||||
|
||||
wire ser_clk;
|
||||
|
||||
wire starting = uart_wr_i & ~uart_busy;
|
||||
baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
|
||||
.clk(clk),
|
||||
.resetq(resetq),
|
||||
.baud(baud),
|
||||
.restart(1'b0),
|
||||
.ser_clk(ser_clk));
|
||||
|
||||
always @(negedge resetq or posedge clk)
|
||||
begin
|
||||
if (!resetq) begin
|
||||
uart_tx <= 1;
|
||||
bitcount <= 0;
|
||||
shifter <= 0;
|
||||
end else begin
|
||||
if (starting) begin
|
||||
shifter <= { uart_dat_i[7:0], 1'b0 };
|
||||
bitcount <= 1 + 8 + 1; // 1 start, 8 data, 1 stop
|
||||
end
|
||||
|
||||
if (sending & ser_clk) begin
|
||||
{ shifter, uart_tx } <= { 1'b1, shifter };
|
||||
bitcount <= bitcount - 4'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module rxuart(
|
||||
input wire clk,
|
||||
input wire resetq,
|
||||
input wire [31:0] baud,
|
||||
input wire uart_rx, // UART recv wire
|
||||
input wire rd, // read strobe
|
||||
output wire valid, // has data
|
||||
output wire [7:0] data); // data
|
||||
parameter CLKFREQ = 1000000;
|
||||
|
||||
reg [4:0] bitcount;
|
||||
reg [7:0] shifter;
|
||||
|
||||
// On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter
|
||||
|
||||
wire idle = &bitcount;
|
||||
wire sample;
|
||||
reg [2:0] hh = 3'b111;
|
||||
wire [2:0] hhN = {hh[1:0], uart_rx};
|
||||
wire startbit = idle & (hhN[2:1] == 2'b10);
|
||||
wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter;
|
||||
|
||||
wire ser_clk;
|
||||
baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
|
||||
.clk(clk),
|
||||
.baud({baud[30:0], 1'b0}),
|
||||
.resetq(resetq),
|
||||
.restart(startbit),
|
||||
.ser_clk(ser_clk));
|
||||
|
||||
assign valid = (bitcount == 18);
|
||||
reg [4:0] bitcountN;
|
||||
always @*
|
||||
if (startbit)
|
||||
bitcountN = 0;
|
||||
else if (!idle & !valid & ser_clk)
|
||||
bitcountN = bitcount + 5'd1;
|
||||
else if (valid & rd)
|
||||
bitcountN = 5'b11111;
|
||||
else
|
||||
bitcountN = bitcount;
|
||||
|
||||
// 3,5,7,9,11,13,15,17
|
||||
assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk;
|
||||
assign data = shifter;
|
||||
|
||||
always @(negedge resetq or posedge clk)
|
||||
begin
|
||||
if (!resetq) begin
|
||||
hh <= 3'b111;
|
||||
bitcount <= 5'b11111;
|
||||
shifter <= 0;
|
||||
end else begin
|
||||
hh <= hhN;
|
||||
bitcount <= bitcountN;
|
||||
shifter <= shifterN;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module buart(
|
||||
input wire clk,
|
||||
input wire resetq,
|
||||
input wire [31:0] baud,
|
||||
input wire rx, // recv wire
|
||||
output wire tx, // xmit wire
|
||||
input wire rd, // read strobe
|
||||
input wire wr, // write strobe
|
||||
output wire valid, // has recv data
|
||||
output wire busy, // is transmitting
|
||||
input wire [7:0] tx_data,
|
||||
output wire [7:0] rx_data // data
|
||||
);
|
||||
parameter CLKFREQ = 1000000;
|
||||
|
||||
rxuart #(.CLKFREQ(CLKFREQ)) _rx (
|
||||
.clk(clk),
|
||||
.resetq(resetq),
|
||||
.baud(baud),
|
||||
.uart_rx(rx),
|
||||
.rd(rd),
|
||||
.valid(valid),
|
||||
.data(rx_data));
|
||||
uart #(.CLKFREQ(CLKFREQ)) _tx (
|
||||
.clk(clk),
|
||||
.resetq(resetq),
|
||||
.baud(baud),
|
||||
.uart_busy(busy),
|
||||
.uart_tx(tx),
|
||||
.uart_wr_i(wr),
|
||||
.uart_dat_i(tx_data));
|
||||
endmodule
|
||||
58
src/basic/verilog/pmodoled2/util.py
Normal file
58
src/basic/verilog/pmodoled2/util.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2015 Wladimir J. van der Laan
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
from __future__ import division,print_function
|
||||
from PIL import Image
|
||||
|
||||
def bin8(value):
|
||||
svalue = bin(value)[2:]
|
||||
svalue = '0'*(8-len(svalue)) + svalue
|
||||
return svalue
|
||||
|
||||
def load_bw_image(filename, ofsx=0, ofsy=0):
|
||||
data = [0]*(128*32//8)
|
||||
i = Image.open(filename)
|
||||
for y in range(32):
|
||||
for x in range(128):
|
||||
page = y // 8
|
||||
bit = y % 8
|
||||
ofs = x
|
||||
if i.getpixel((ofsx+x,ofsy+y)):
|
||||
data[page*128+ofs] |= 1<<bit
|
||||
return data
|
||||
|
||||
def tile_image(ingrid):
|
||||
'''
|
||||
Convert image to tiled SSD1306 representation
|
||||
'''
|
||||
data = [0]*(128*32//8)
|
||||
for y in range(32):
|
||||
for x in range(128):
|
||||
page = y // 8
|
||||
bit = y % 8
|
||||
ofs = x
|
||||
if ingrid[y][x]:
|
||||
data[page*128+ofs] |= 1<<bit
|
||||
return data
|
||||
|
||||
def detect_serial():
|
||||
'''Detect serial port for iCEStick.
|
||||
Based on 'findserial' in swapforth.
|
||||
'''
|
||||
import glob, subprocess
|
||||
return glob.glob('/dev/tty.usbmodem*')
|
||||
# options = []
|
||||
# for dev in glob.glob('/dev/ttyUSB*'):
|
||||
# info = subprocess.check_output(['/sbin/udevadm', 'info', '-a', '-n', dev])
|
||||
# info = info.split(b'\n')
|
||||
# vendor_matches = False
|
||||
# product_matches = False
|
||||
# for line in info:
|
||||
# if b'ATTRS{idVendor}=="0403"' in line:
|
||||
# vendor_matches = True
|
||||
# if b'ATTRS{idProduct}=="6010"' in line:
|
||||
# product_matches = True
|
||||
# if vendor_matches and product_matches:
|
||||
# options.append(dev)
|
||||
# return options
|
||||
|
||||
Reference in New Issue
Block a user