{"id":8190,"date":"2013-01-19T17:01:03","date_gmt":"2013-01-19T22:01:03","guid":{"rendered":"http:\/\/scruss.com\/blog\/?p=8190"},"modified":"2022-07-01T16:10:28","modified_gmt":"2022-07-01T20:10:28","slug":"the-quite-rubbish-clock","status":"publish","type":"post","link":"https:\/\/scruss.com\/blog\/2013\/01\/19\/the-quite-rubbish-clock\/","title":{"rendered":"The Quite Rubbish Clock"},"content":{"rendered":"\n<p><span style=\"color: #ff0000;\"><em><strong>Hey! This article is really old and probably doesn&#8217;t work any more<\/strong><\/em><\/span>: <em>things have changed a <span style=\"text-decoration: underline;\">lot<\/span> in Raspberry Pi world since 2013<\/em> <em>\u2026<\/em><\/p>\n\n\n\n<p class=\"has-text-align-right\"><strong>Update 3<\/strong>: code for the demo video is <a href=\"http:\/\/scruss.com\/blog\/2013\/01\/25\/qrclock-the-demo-reel\/\">here<\/a>.<\/p>\n\n\n\n<p class=\"has-text-align-right\"><strong>Update 2<\/strong>: In which I actually post <a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/qrclock2.zip\">working code<\/a>.<\/p>\n\n\n\n<p class=\"has-text-align-right\"><strong>Update<\/strong>: <span style=\"color: #ff0000;\"><em>Eep!<\/em><\/span> This post was featured on the <a href=\"http:\/\/www.raspberrypi.org\/archives\/3109\">Raspberry Pi blog<\/a> today. Thanks, Liz!<\/p>\n\n\n\n<p>And now for something completely different:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"qrclock - the Quite Rubbish clock\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/PyvJUN5JRkM?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>&#8230; a clock that isn&#8217;t human readable. You&#8217;ll need a <a href=\"http:\/\/www.qrcode.com\/en\/index.html\">QR code<\/a> reader to be able to tell the time.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi-320x240.jpg\" alt=\"Nokia screen on Raspberry Pi\" class=\"wp-image-8203\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi-320x240.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi-160x120.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi-1024x768.jpg 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi-400x300.jpg 400w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-on-Raspberry-Pi.jpg 1280w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/figure>\n\n\n\n<p>This, however, is not the prime purpose of the exercise. I was looking for an excuse to try some direct hardware projects with the GPIO, and I remembered I had a couple of Nokia-style surplus LCDs lying about that could be pressed into service. These LCDs aren&#8217;t great: 84\u00d748 pixels, 3V3 logic, driven by <a title=\"Serial Peripheral Interface Bus\" href=\"http:\/\/scruss.com\/blog\/2013\/01\/19\/the-quite-rubbish-clock\/\">SPI<\/a> via an 8-pin header which includes PWM-controllable LED backlighting. They are cheap, and available almost everywhere: <a href=\"https:\/\/dx.com\/p\/arduino-1-6-lcd-display-screen-for-nokia-5110-red-silver-140226\">DealExtreme<\/a> ($5.36), <a href=\"https:\/\/www.sparkfun.com\/products\/10168\">SparkFun<\/a> ($9.95), <a href=\"https:\/\/www.adafruit.com\/products\/338\">Adafruit<\/a> ($10, but includes a level shifter, which you really need if you&#8217;re using a 5V logic Arduino), <a href=\"https:\/\/solarbotics.com\/product\/50408\/\">Solarbotics<\/a> ($10) and <a href=\"http:\/\/www.creatroninc.com\/index.php\/\">Creatron<\/a> (about $12; but you can walk right in and buy one). Despite being quite difficult to use, helpful people have written drivers to make these behave like tiny dot-addressable screens.<\/p>\n\n\n\n<p>I&#8217;d been following the discussion on the Raspberry Pi forum about <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;t=9814&amp;hilit=nokia&amp;sid=375a23c4a53a1524437a786ab6b09dba\">driving the Nokia LCD from a Raspberry Pi<\/a>. Only when user <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/memberlist.php?mode=viewprofile&amp;u=8878&amp;sid=0b3c6301ede8e135311d197876fdee68\">bgreat<\/a> posted some compact code that was supposed to run really fast did I dig out the LCD board and jumper wires. Building on bgreat&#8217;s <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;t=9814&amp;p=262274&amp;hilit=nokia#p261925\">nokiaSPI.py<\/a> class and a few other bits of code, here&#8217;s what I built to make this singularly pointless clock:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/python\n# -*- coding: utf-8 -*-\n# qrclock - The Quite Rubbish Clock for Raspberry Pi - scruss, 2013-01-19\n\nimport time\n# need to use git:\/\/github.com\/mozillazg\/python-qrcode.git\nimport qrcode\nfrom PIL import Image\nimport ImageOps\n# uses bgreat's SPI code; see\n# raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;amp;amp;amp;amp;t=9814&amp;amp;amp;amp;amp;p=262274&amp;amp;amp;amp;amp;hilit=nokia#p261925\nimport nokiaSPI\n\nnoki = nokiaSPI.NokiaSPI()              # create display device\nqr = qrcode.QRCode(version=1,           # V.1 QR Code: 21x21 px\n                   error_correction=qrcode.constants.ERROR_CORRECT_M,\n                   box_size=2, border=1)\nbg = Image.new('1', (84, 48))           # blank (black) image background\n\nwhile 1:\n    qr.clear()\n    newbg = bg.copy()                   # copy blank background\n    s = time.strftime('%Y-%m-%d %H:%M:%S')\n    qr.add_data(s)                      # make QR Code of YYYY-MM-DD HH:MM:SS\n    qr.make()\n    qrim = qr.make_image()              # convert qrcode object to PIL image\n    qrim = qrim.convert('L')            # make greyscale\n    qrim = ImageOps.invert(qrim)        # invert colours: B-&amp;amp;amp;amp;gt;W and W-&amp;amp;amp;amp;gt;B\n    qrim = qrim.convert('1')            # convert back to 1-bit\n    newbg.paste(qrim, (18, 0))          # paste QR Code into blank background\n    noki.show_image(newbg)              # display code on LCD\n    time.sleep(0.4)                     # pause before next display\n<\/pre><\/pre>\n\n\n\n<p>(Convenient archive of all the source: <a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/qrclock2.zip\">qrclock2.zip<\/a>, <em>really<\/em> including bgreat&#8217;s nokiaSPI class this time &#8230;)<\/p>\n\n\n\n<p>To get all this working on your Raspberry Pi, there&#8217;s a fair amount of configuration. The best references are bgreat&#8217;s own comments in the <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;t=9814&amp;p=262274&amp;hilit=nokia#p261925\">thread<\/a>, but I&#8217;ve tried to include everything here.<br><a name=\"spi\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enabling the SPI kernel module<\/h2>\n\n\n\n<p>As root, edit the kernel module blacklist file:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo vi \/etc\/modprobe.d\/raspi-blacklist.conf<\/pre>\n\n\n\n<p>Comment out the spi-bcm2708 line so it looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">#blacklist spi-bcm2708<\/pre>\n\n\n\n<p>Save the file so that the module will load on future reboots. To enable the module now, enter:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo modprobe spi-bcm2708<\/pre>\n\n\n\n<p>Now, if you run the <code>lsmod<\/code> command, you should see something like:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Module                  Size  Used by\nspi_bcm2708             4421  0<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Installing the WiringPi, SPI and other required packages<\/h2>\n\n\n\n<p><a href=\"https:\/\/projects.drogon.net\/raspberry-pi\/wiringpi\/\">WiringPi<\/a> by Gordon is one of the neater Raspberry Pi-specific modules, as it allows relatively easy access to the Raspberry Pi&#8217;s GPIO pins. For <a href=\"http:\/\/www.raspbian.org\/\">Raspbian<\/a>, there are a few other imaging libraries and package management tools you&#8217;ll need to install here:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo apt-get install python-imaging python-imaging-tk python-pip python-dev git\nsudo pip install spidev\nsudo pip install wiringpi<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Installing the Python QR code library<\/h2>\n\n\n\n<p>Finding a library that provided all the right functions was the hardest part here. I ended up using <a href=\"https:\/\/github.com\/mozillazg\">mozillazg<\/a>&#8216;s <a href=\"https:\/\/github.com\/mozillazg\/python-qrcode\">fork<\/a> of <a href=\"https:\/\/github.com\/lincolnloop\">lincolnloop<\/a>&#8216;s <a href=\"https:\/\/github.com\/lincolnloop\/python-qrcode\">python-qrcode<\/a> module. mozillazg&#8217;s fork lets you use most of the lovely <a title=\"Python Imaging Library\" href=\"http:\/\/www.pythonware.com\/products\/pil\/\">PIL<\/a> methods, while the original hides most of them. Since I had to do some image compositing and colour remapping to make the image appear correct on the Nokia screen, the new fork was very helpful.<\/p>\n\n\n\n<p>To install it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">git clone git:\/\/github.com\/mozillazg\/python-qrcode.git\ncd python-qrcode\/\nsudo python .\/setup.py install<\/pre>\n\n\n\n<p>The tiny 84\u00d748 resolution of the Nokia screen doesn&#8217;t give you many options for sizing QR codes. For the time display of the clock, a 21\u00d721 module <a href=\"http:\/\/www.qrcode.com\/en\/vertable1.html\">Version 1<\/a> code with two pixels per module and one module margin <em>just<\/em> fits into 48 pixels. Using a medium level of error correction, you can fit the 19-character message (such as &#8220;2013-01-19 18:56:59&#8221;) into this tiny screen with a very good chance of it being read by any QR code reader.<\/p>\n\n\n\n<p>(In the video, there&#8217;s a much larger QR code that&#8217;s a link to this blog post. That&#8217;s a Version 7 code [45\u00d745 modules] at one pixel per module and no margin. This doesn&#8217;t meet <a href=\"http:\/\/www.qrcode.com\/en\/qrgene3.html\">Denso Wave&#8217;s readability guidelines<\/a>, but the Nokia screen has large blank margins which seem to help. It won&#8217;t read on every phone, but you&#8217;re here at this link now, so you don&#8217;t need it &#8230;)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wiring it all up<\/h2>\n\n\n\n<p>(<span style=\"color: #ff0000;\"><em>Do I really need to say that you&#8217;ll be messing around with the inner delicate bits of your Raspberry Pi here, and if you do something wrong, you could end up with a dead Raspberry Pi? No? Okay. Just make sure you take some static precautions and you really should have the thing shut down and powered off.<\/em><\/span>)<\/p>\n\n\n\n<p>You&#8217;ll need 8 female-female <a href=\"<a href=&quot;https:\/\/solarbotics.com\/product\/45070\/&quot;>jumper wires<\/a>&#8220;>jumper wires<\/a>, and also some kind of pin header soldered in (I used <a href=\"http:\/\/www.pololu.com\/catalog\/product\/967\">right-angled<\/a> ones). Note that the thick border of the LCD is the <strong>top<\/strong> of the screen. These boards are made who-knows-where by who-knows-whom, and there&#8217;s a <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;t=9814&amp;hilit=nokia&amp;start=100#p262142\">huge<\/a> <a href=\"http:\/\/www.raspberrypi.org\/phpBB3\/viewtopic.php?f=32&amp;t=9814&amp;hilit=nokia&amp;start=100#p262269\">variety<\/a> of labels and layouts on the pins. My one appears to be yet another variant, and is labelled:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>VCC<\/li><li>GND<\/li><li>SCE<\/li><li>RST<\/li><li>D\/C<\/li><li>DNK(MOSI)<\/li><li>SCLK<\/li><li>LED<\/li><\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"240\" height=\"320\" src=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels-240x320.jpg\" alt=\"screen labels\" class=\"wp-image-8202\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels-240x320.jpg 240w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels-120x160.jpg 120w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels-768x1024.jpg 768w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels-225x300.jpg 225w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/screen-labels.jpg 960w\" sizes=\"auto, (max-width: 240px) 100vw, 240px\" \/><\/a><\/figure>\n\n\n\n<p>This is how I wired it (from comments in bgreat&#8217;s code and the <a href=\"http:\/\/elinux.org\/RPi_Low-level_peripherals#General_Purpose_Input.2FOutput_.28GPIO.29\">GPIO<\/a> reference):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> LCD Pin       Function      Pi GPIO Pin #   Pi Pin Name\n============= ============= =============== =============\n 1 VCC         Vcc            1              3.3 V\n 2 GND         Ground        25              GND\n 3 SCE         Chip Enable   24              GPIO08 SPI0_CE0_N\n 4 RST         Reset         11              GPIO17\n 5 D\/C         Data\/Command  15              GPIO22\n 6 DNK(MOSI)   Data In       19              GPIO10 SPI0_MOSI\n 7 SCLK        Serial Clock  23              GPIO11 SPI0_SCLK\n 8 LED         Backlight     12              GPIO18 PWM0<\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring-320x240.jpg\" alt=\"GPIO wiring\" class=\"wp-image-8201\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring-320x240.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring-160x120.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring-1024x768.jpg 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring-400x300.jpg 400w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/GPIO-wiring.jpg 1280w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"320\" height=\"240\" src=\"http:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen-320x240.jpg\" alt=\"back of screen\" class=\"wp-image-8200\" srcset=\"https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen-320x240.jpg 320w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen-160x120.jpg 160w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen-1024x768.jpg 1024w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen-400x300.jpg 400w, https:\/\/scruss.com\/wordpress\/wp-content\/uploads\/2013\/01\/back-of-screen.jpg 1280w\" sizes=\"auto, (max-width: 320px) 100vw, 320px\" \/><\/a><\/figure>\n\n\n\n<p>Wire it up, and fire up the program:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">sudo .\/qrclock.py<\/pre>\n\n\n\n<p>Yes, code that accesses GPIO needs to be run as root. Pesky, but helps you avoid running code that accidentally scrams the nuclear power station you&#8217;re controlling from your Raspberry Pi &#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a human-unreadable clock on a cheap Nokia LCD powered by a Raspberry Pi.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[2612,2613,2110,2540,2609,2510,2536,2617],"class_list":["post-8190","post","type-post","status-publish","format-standard","hentry","category-computers-suck","tag-lcd","tag-nokia","tag-pointless","tag-python","tag-qrcode","tag-raspberrypi","tag-raspbian","tag-spi"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pQNZZ-286","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/8190","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/comments?post=8190"}],"version-history":[{"count":25,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/8190\/revisions"}],"predecessor-version":[{"id":17043,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/8190\/revisions\/17043"}],"wp:attachment":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/media?parent=8190"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/categories?post=8190"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/tags?post=8190"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}