commit 83fd7cc826c235a1b2a287af82f2e4a7e9b80ce5
Author: Markus Birth <mbirth@gmail.com>
Date:   Sat Nov 14 23:29:59 2015 +0100

    Initial import

diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..21436e2
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Markus Birth <markus@birth-online.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..07833e1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+upcd8544
+========
+
+MicroPython module for the PCD8544 LCD, originally used for the Nokia 5110.
+
+[Datasheet](https://www.sparkfun.com/datasheets/LCD/Monochrome/Nokia5110.pdf)
+
+![](doc/wipy-lcd.jpg)
diff --git a/doc/wipy-lcd.jpg b/doc/wipy-lcd.jpg
new file mode 100644
index 0000000..03645aa
Binary files /dev/null and b/doc/wipy-lcd.jpg differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..349143d
--- /dev/null
+++ b/main.py
@@ -0,0 +1,18 @@
+# main.py -- put your code here!
+
+from machine import SPI, Pin
+
+# WiPy (on Exp board, SD and User-LED jumper have to be removed!)
+SPI    = machine.SPI(0)   # GP14 (CLK) + GP16 (MOSI->DIN), User-LED jumper removed!
+RST    = machine.Pin('GP24')
+CE     = machine.Pin('GP12')
+DC     = machine.Pin('GP22')
+LIGHT  = machine.Pin('GP23')
+# PWR    = directly from 3V3 pin of the WiPy
+
+import upcd8544
+
+lcd = upcd8544.PCD8544(SPI, RST, CE, DC, LIGHT)
+
+lcd.data([0xff])
+lcd.data([0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa])
diff --git a/upcd8544.py b/upcd8544.py
new file mode 100644
index 0000000..d404d27
--- /dev/null
+++ b/upcd8544.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*- 
+"""
+MicroPython PCD8544 driver
+(for Nokia 5110 displays)
+"""
+
+__author__     = "Markus Birth"
+__copyright__  = "Copyright 2015, Markus Birth"
+__credits__    = ["Markus Birth"]
+__license__    = "MIT"
+__version__    = "1.0"
+__maintainer__ ="Markus Birth"
+__email__      = "markus@birth-online.de"
+__status__     = "Production"
+
+# Datasheet: https://www.sparkfun.com/datasheets/LCD/Monochrome/Nokia5110.pdf
+# Inspiration from:
+#   - https://github.com/inaugurator/upyd5110
+#   - https://github.com/rm-hull/pcd8544/blob/master/src/lcd.py
+#
+# PINOUT
+# WiPy/pyBoard      display   function
+#
+# 3V3 or any Pin => VCC       3.3V logic voltage (0=off, 1=on)
+# MOSI           => DIN       data flow (Master out, Slave in)
+# SCK            => CLK       SPI clock
+# any Pin        => RST       Reset pin (0=reset, 1=normal)
+# any Pin        => CE        Chip Enable (0=listen for input, 1=ignore input)
+# any Pin        => DC        Data/Command (0=commands, 1=data)
+# any Pin        => LIGHT     Light (0=on, 1=off)
+# GND            => GND
+#
+# pyBoard "Y" side
+# SPI    = pyb.SPI(1)
+# RST    = pyb.Pin('Y4')
+# CE     = pyb.Pin('Y5')
+# DC     = pyb.Pin('Y3')
+# LIGHT  = pyb.Pin('Y2')
+# PWR    = pyb.Pin('Y1')
+#
+# pyBoard "X" side
+# SPI    = pyb.SPI(2)
+# RST    = pyb.Pin('X4')
+# CE     = pyb.Pin('X5')
+# DC     = pyb.Pin('X3')
+# LIGHT  = pyb.Pin('X2')
+# PWR    = pyb.Pin('X1')
+#
+# WiPy (on Exp board, SD and User-LED jumper have to be removed!)
+# SPI    = machine.SPI(0)   # GP14 (CLK) + GP16 (MOSI->DIN), User-LED jumper removed!
+# RST    = machine.Pin('GP24')
+# CE     = machine.Pin('GP12')
+# DC     = machine.Pin('GP22')
+# LIGHT  = machine.Pin('GP23')
+# PWR    = directly from 3V3 pin of the WiPy
+
+try:
+    import pyb as machine
+except:
+    # WiPy
+    import machine
+
+import struct
+import time
+
+class PCD8544:
+    def __init__(self, spi, rst, ce, dc, light, pwr=None):
+        self.width  = 84
+        self.height = 48
+
+        # init the SPI bus and pins
+        spi.init(spi.MASTER, baudrate=328125, bits=8, polarity=0, phase=1, firstbit=spi.MSB)
+        if "OUT_PP" in dir(rst):
+            # pyBoard style
+            rst.init(rst.OUT_PP, rst.PULL_NONE)  # Reset line
+            ce.init(ce.OUT_PP, ce.PULL_NONE)     # Chip Enable
+            dc.init(dc.OUT_PP, dc.PULL_NONE)     # Data(1) / Command(0) mode
+            light.init(light.OUT_PP, light.PULL_NONE)
+            if pwr:
+                pwr.init(pwr.OUT_PP, pwr.PULL_NONE)
+        else:
+            # WiPy style
+            rst.init(rst.OUT, None)
+            ce.init(ce.OUT, None)
+            dc.init(dc.OUT, None)
+            light.init(light.OUT, None)
+            if pwr:
+                pwr.init(pwr.OUT, None)
+
+        self.spi   = spi
+        self.rst   = rst
+        self.ce    = ce
+        self.dc    = dc
+        self.light = light
+        self.pwr   = pwr
+
+        self.light_off()
+        self.power_on()
+        self.ce.value(1)  # set chip to disable (don't listen to input)
+        self.reset()
+        self.set_contrast(0xba)
+        self.clear()
+
+    def set_contrast(self, value):
+        """ set LCD voltage, i.e. contrast """
+        assert 0x80 <= value <= 0xff, "contrast value must be between 0x80 and 0xff"
+        self.command([0x21, 0x06, 0x14, value, 0x20, 0x0c])
+        # 0x21 - enter extended instruction set (H=1)
+        # 0x06 - set temperature coefficient 2
+        # 0x14 - set BIAS system to n=3 (recomm. mux rate 1:40/1:34)
+        # value - (80-ff) - set Vop (80 = 3.00V, ff = 10.68V), 8b seems to work (0x3b/d70: 3.00+(70*0.06)=7.2V)
+        # 0x20 - back to basic instruction set
+        # 0x0c - normal display mode
+
+    def position(self, x, y):
+        """ goto to column x in seg y """
+        assert 0 <= x <= 83, "x must be between 0 and 83"
+        assert 0 <= y <=  5, "y must be between 0 and 5"
+        self.command([x + 0x80, y + 0x40])
+
+    def clear(self):
+        """ clear screen """
+        self.position(0, 0)
+        self.data([0] * (self.height * self.width // 8))
+        self.position(0, 0)
+
+    def sleep_ms(self, mseconds):
+        try:
+            time.sleep_ms(mseconds)
+        except AttributeError:
+            machine.delay(mseconds)
+
+    def sleep_us(self, useconds):
+        try:
+            time.sleep_us(useconds)
+        except AttributeError:
+            machine.udelay(useconds)
+
+    def power_on(self):
+        if self.pwr:
+            self.pwr.value(1)
+        self.reset()
+
+    def reset(self):
+        """ issue reset impulse to reset the display """
+        self.rst.value(0)  # RST on
+        self.sleep_us(100) # reset impulse has to be >100 ns and <100 ms
+        self.rst.value(1)  # RST off
+
+    def power_off(self):
+        self.clear()
+        self.command([0x20, 0x08])
+        # 0x20 - basic instruction set
+        # 0x08 - set display to blank (doesn't delete contents)
+        self.sleep_ms(10)
+        if self.pwr:
+            self.pwr.value(0) # turn off power
+
+    def command(self, arr):
+        """ send bytes in command mode """
+        self.bitmap(arr, 0)
+
+    def data(self, arr):
+        """ send bytes in data mode """
+        self.bitmap(arr, 1)
+
+    def bitmap(self, arr, dc):
+        self.dc.value(dc)
+        buf = struct.pack('B'*len(arr), *arr)
+        self.ce.value(0) # set chip to listening/enable
+        try:
+            self.spi.send(buf)
+        except AttributeError:
+            self.spi.write(buf)
+        self.ce.value(1) # set chip to disable
+
+    def light_on(self):
+        self.light.value(0)  # pull to GND
+
+    def light_off(self):
+        self.light.value(1)  # set to HIGH