Merge pull request #10 from nalzok/master

Added example for the PmodOLED module
This commit is contained in:
wuxx
2020-10-01 12:51:56 +08:00
committed by GitHub
19 changed files with 1035 additions and 0 deletions

View 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

View 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 |

View 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()

View 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()

View 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')

View 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View 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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

View 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

View File

@@ -0,0 +1,3 @@
cthulhu.svg
http://pcon.github.io/design/cthulhu/

View 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

View 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

View 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

View 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

View 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

View 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)

View 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

View 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