{"id":1310,"date":"2016-09-24T19:14:35","date_gmt":"2016-09-24T19:14:35","guid":{"rendered":"http:\/\/blog.paranoidprofessor.com\/?p=1310"},"modified":"2016-09-24T19:14:35","modified_gmt":"2016-09-24T19:14:35","slug":"just-making-it-a-4x4x4-led-cube","status":"publish","type":"post","link":"https:\/\/blog.paranoidprofessor.com\/index.php\/2016\/09\/24\/just-making-it-a-4x4x4-led-cube\/","title":{"rendered":"just making it &#8211; a 4x4x4 led cube"},"content":{"rendered":"<p>Some time back, I had a fair amount lot of free time and did watch things on you tube. \u00a0A friend of mine showed a number of cool LED cubes that were trending at that time.<\/p>\n<p>It seemed so cool and considering our combined backgrounds a natural that we should try and create our own\u00a0control board for our own LED cube. \u00a0He was the hardware engineer so I left him to that task while I thought about patterns and programming the cube.<\/p>\n<p>Yet, despite not being the hardware type I thought I could create my own, albeit less sophisticated cube, with only a small bit of effort.<\/p>\n<p><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/HpUvgoLtos0\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p>Come on just how hard could it really be?<\/p>\n<h2>Bring in the pie&#8217;s<\/h2>\n<p>Part of the reason I thought this would be so simple is that I was also playing around with the &#8220;Raspberry Pi&#8221;. \u00a0The specifications for the pi \u00a0were not all that impressive when compared to my laptop but it was a truly amazingly affordable and small computer that also offered a comfortable\u00a0Linux distribution for running it.<\/p>\n<p>The Raspberry Pi that I was using is basically just a small computer with the power of a smart phone from 6\u00a0years ago.<\/p>\n<div style=\"margin-left: 1cm;\">\n<ul>\n<li>ARM11 700 mhz<\/li>\n<li>SoC is a Broadcom BCM2835<\/li>\n<li>512MB RAM<\/li>\n<li>2 USB ports<\/li>\n<li>Ethernet port<\/li>\n<li>3.5mm jack for audio out<\/li>\n<li>HDMI<\/li>\n<\/ul>\n<\/div>\n<p>The operating system is a derivative of Debian. \u00a0Communicating with the Raspberry Pi can be done just like any other computer over the Ethernet or perhaps by using a WiFi dongle.<\/p>\n<p>Communication between the Raspberry Pi and other external peripherals is done via the general purpose I\/O pins. \u00a0The GPIO is the break out of the functionality in the Broadcom BCM2835 system on a chip which in additional to other functionality also includes the support for I2C and SPI as well as UHF transmission.<\/p>\n<p>I2C and SPI are two different but common communication bus protocols for communication between micro-controllers and other components or peripherals. \u00a0The protocol allows a\u00a0component to send commands to a\u00a0receiving component. \u00a0This is a really convenient way to delegate tasks to other devices, but inter-device\u00a0communication is not the only advantage of the GPIO.<\/p>\n<p>The other advantage of the GPIO pins is that it is possible to use it to turn on or off something connected to one of these pins. \u00a0This can be used to enable or disable other devices or even simple things like turning on a motor or a LED.<\/p>\n<h2>How LED\u00a0cubes work<\/h2>\n<p>LED cubes create neat images by turning on LED&#8217;s in rapid succession in order to creates letters or patterns. \u00a0The power required to turn on all the lights becomes more and more considerable as the cubes get larger and larger. \u00a0A 3<a href=\"https:\/\/www.amazon.de\/Velleman-Mini-Kit-BAUSATZ-MK193-LED-W%C3%BCrfel\/dp\/B008SOWGOI\/ref=pd_sim_107_1?ie=UTF8&amp;psc=1&amp;refRID=SZ50V5TZ8HSW71W006BE\" target=\"_blank\">x3x3<\/a>\u00a0cube can easily be powered by a 9 volt battery but a <a href=\"https:\/\/www.amazon.de\/DAOKAI%C2%AE-Light-8x8x8-Cube-Blue\/dp\/B01JD38PUG\/ref=sr_1_1?s=ce-de&amp;ie=UTF8&amp;qid=1474461667&amp;sr=1-1&amp;keywords=led+cube\" target=\"_blank\">8x8x8<\/a> or <a href=\"http:\/\/www.iphoneness.com\/cool-finds\/l3d-cube-kit\/\" target=\"_blank\">16x16x16<\/a> cube would require a an actual power supply.<\/p>\n<p>The thing that is the same no matter of the size is that the cubes only turn on a single led at a time and rely on persistence of vision to fool the eye into believing that all the LED&#8217;s in the pattern are on at the same time.<\/p>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Persistence_of_vision\">Persistence of vision principle<\/a> is essentially the same concept underpinning\u00a0&#8220;moving pictures&#8221; aka cartoons. \u00a0The eye cannot distinguish between changes that occur too quickly and so it will see it as a single picture. \u00a0Thus when the different LED&#8217;s in a cube switch rapidly on and off the eye simply sees the LED&#8217;s were on.<\/p>\n<h2>My own cubes logic<\/h2>\n<p>The first thing that I needed to be consider was how to power each led. \u00a0Four levels of 16 LED&#8217;s\u00a0gives a total of 64 LED&#8217;s or 128 legs (anode and cathode) for the cube. \u00a0 The\u00a0total number of GPIO pins available on my Raspberry Pi <span style=\"color: #000000;\">is<\/span><span style=\"color: #ff0000;\"><span style=\"color: #000000;\"> 26. \u00a0Even if I could use every single one of these pins this would be nowhere near enough pins for this small project.<\/span><\/span><\/p>\n<p>This is a very important point as not every one of these pins is even available to be used. Some of these pins are used for I2C or power or ground which leaves me severely lacking if the goal is that the Raspberry Pi is to drive everything directly.<\/p>\n<p>Yet, I cannot be the only person or manufacturer to have encountered this problem and indeed I was\u00a0not.<\/p>\n<h2>23017 IO Extender<\/h2>\n<p>The 23017 IO extender has 16 data legs which can be turned on or off. \u00a0One of these chips alone won&#8217;t be enough to deal with 128 legs but there are some clever simplifications to the overall design that will allows me to use two of these chips to drive the rest of the cube.<\/p>\n<p>Because we only need to turn on one led at a time, I can use the IO extender for each of the LED columns. \u00a0Thus if I provide power for each level, as needed, and allow the current to flow through the led controlled by each column then I can turn on or off any led at any spot on the cube.<\/p>\n<p>This means that I will need to use one of the 23017&#8217;s only to control the columns but then I need a way to control which levels get the power. \u00a0This is done by using a second 23017 to control which level will receive the power.<\/p>\n<p>How this works is as follows. \u00a0A light bulb or a LED cannot light unless it receives a path to power and ground. \u00a0When this happens the electricity flows through lighting up the element. \u00a0Controlling a light bulb is done using a normal wall switch, and this can be done for a LED as well. \u00a0However, for a LED in a circuit another possibility is to prevent the power from flowing.<\/p>\n<p>This is done if either no current is provided for the input (anode) of the LED or no ground (cathode) provided to complete the circuit. \u00a0If both of these pins are set to ground or both are provided voltage the current will not flow and the LED will not light up.<\/p>\n<p>This how my cube controls the individual\u00a0LED&#8217;s. \u00a0Once the program decides which LED to light up, it will provide current to that level and will set the cathode for that LED to ground.<\/p>\n<p>Well, this is how my circuit behaves, but the Raspberry Pi is not toggling the state of the LED&#8217;s directly but actually using I2C to send a command to both of my 23017&#8217;s to enable each LED. \u00a0Each 23017 is given a different address so it can be controlled directly. \u00a0This is done by setting the pins 15 &#8211; 17 to a unique value for the 23017 chips that you are using.<\/p>\n<p>MCP 23017<\/p>\n<table class=\"w3-table-all\" style=\"height: 1533px;\">\n<tbody>\n<tr>\n<th>Pin<\/th>\n<th>Name<\/th>\n<th>Description<\/th>\n<\/tr>\n<tr>\n<td>1<\/td>\n<td>GPB0<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>GPB1<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>GPB2<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>GPB3<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>GPB4<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>6<\/td>\n<td>GPB5<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>7<\/td>\n<td>GPB6<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>8<\/td>\n<td>GPB7<\/td>\n<td>I\/O port B<\/td>\n<\/tr>\n<tr>\n<td>9<\/td>\n<td>VDD<\/td>\n<td>5 volt power<\/td>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>VSS<\/td>\n<td>ground<\/td>\n<\/tr>\n<tr>\n<td>11<\/td>\n<td>NC<\/td>\n<td>unused<\/td>\n<\/tr>\n<tr>\n<td>12<\/td>\n<td>SCL<\/td>\n<td>Clock pin<\/td>\n<\/tr>\n<tr>\n<td>13<\/td>\n<td>SDA<\/td>\n<td>Data pin<\/td>\n<\/tr>\n<tr>\n<td>14<\/td>\n<td>NC<\/td>\n<td>unused<\/td>\n<\/tr>\n<tr>\n<td>15<\/td>\n<td>A0<\/td>\n<td>Address<\/td>\n<\/tr>\n<tr>\n<td>16<\/td>\n<td>A1<\/td>\n<td>Address<\/td>\n<\/tr>\n<tr>\n<td>17<\/td>\n<td>A2<\/td>\n<td>Address<\/td>\n<\/tr>\n<tr>\n<td>18<\/td>\n<td>Reset<\/td>\n<td>Reset<\/td>\n<\/tr>\n<tr>\n<td>19<\/td>\n<td>INTB<\/td>\n<td>Interrupt B<\/td>\n<\/tr>\n<tr>\n<td>20<\/td>\n<td>INTA<\/td>\n<td>Interrupt A<\/td>\n<\/tr>\n<tr>\n<td>21<\/td>\n<td>GPA0<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>22<\/td>\n<td>GPA1<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>23<\/td>\n<td>GPA2<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>24<\/td>\n<td>GPA3<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>25<\/td>\n<td>GPA4<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>26<\/td>\n<td>GPA5<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>27<\/td>\n<td>GPA6<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<tr>\n<td>28<\/td>\n<td>GPA7<\/td>\n<td>I\/O port\u00a0A<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h6>This table is intended to give a brief overview. \u00a0To have a full understanding you will need to reference the specification sheet for this chip.<\/h6>\n<p>Reading through the I2C specification of how exactly the bus functions is fascinating but perhaps a small it intimidating at the same time. \u00a0The nice thing for the application developer is that, more likely than not, this is a low level function that you call with some parameters.<\/p>\n<p>In my case I was able to find a <a href=\"http:\/\/www.airspayce.com\/mikem\/bcm2835\/\">open source library <\/a>on the internet which supported the BMC2835 chip which included an I2C support.<\/p>\n<h2>Circuit diagram<\/h2>\n<p>Despite how complex this circuit may appear it is simply two IO extender\u00a0chips, three capacitors and twenty resisters.<\/p>\n<p><a href=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-1339\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit.png\" alt=\"ledcube-circuit\" width=\"1054\" height=\"478\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit.png 1054w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit-300x136.png 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit-768x348.png 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-circuit-1024x464.png 1024w\" sizes=\"(max-width: 1054px) 100vw, 1054px\" \/><\/a><\/p>\n<p>Somewhat contrary to what you might think, the circuit diagram wasn&#8217;t created so we could create the following board.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-1338 size-medium aligncenter\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-board-300x218.png\" alt=\"ledcube-board\" width=\"300\" height=\"218\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-board-300x218.png 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-board-768x558.png 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-board.png 922w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>We created the board layout in order to design an optimal layout for the individual connections.<\/p>\n<p><a href=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-solder.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-1361 size-medium aligncenter\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-solder-300x207.jpg\" alt=\"ledcube-solder\" width=\"300\" height=\"207\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-solder-300x207.jpg 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-solder-768x531.jpg 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-solder-1024x708.jpg 1024w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>There is really very little needs to be described for this circuit. \u00a0 \u00a0On the left side of the circuit is a simple five line connector connector. \u00a0These lines will connect to the Raspberry Pi which will provide power, ground and the SCL and SDA in order to use I2C to communicate with the 23017 chips.<\/p>\n<h2>Building the cube<\/h2>\n<p>Building the actual LED cube is both the easiest and the hardest part of this project.<\/p>\n<h3><strong>layers<\/strong><\/h3>\n<p>On one hand it should not be overly difficult to solder together the LED&#8217;s. \u00a0It is just a matter of soldering each LED to a wire. \u00a0This should be made even easier by creating a template to hold all of\u00a0the LED&#8217;s still in the proper relative positions to each other.<\/p>\n<p><a href=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-1333 size-full\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl.jpg\" width=\"3181\" height=\"2349\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl.jpg 3181w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl-300x222.jpg 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl-768x567.jpg 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-plane-tmpl-1024x756.jpg 1024w\" sizes=\"(max-width: 3181px) 100vw, 3181px\" \/><\/a><\/p>\n<p>Indeed this template makes it relatively easy to create a plane of LED&#8217;s. \u00a0You can take as much time as you need and there is no need of any additional tools or assistants to make these planes. \u00a0One minor inconvenience is to find your own way to create straight wires.<\/p>\n<p>If the wires are not straight then the rows or columns won&#8217;t be either. \u00a0While preparing for this I have hit upon three different manners to prepare the wires.<\/p>\n<div style=\"margin-left: 1cm;\">\n<ol>\n<li>pull the wires<\/li>\n<li>use a drill<\/li>\n<li>use a couple of boards<\/li>\n<\/ol>\n<\/div>\n<p>The first two methods pretty much require a vice. \u00a0Simply connect the wire to the vice and either pull the wire ever so slightly or put the other end into a drill and briefly run the drill. \u00a0Both of these methods actually stretch the wire slightly which is what causes it to straighten out.<\/p>\n<p>I only saw a single video on the topic of using boards to straighten wires, and somehow I lost that link. \u00a0The idea is pretty simple, you need a flat board and a small thin board that is at least as long as the wire and approximately six cm wide.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-1332 size-medium aligncenter\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-boards-300x197.jpg\" alt=\"dav\" width=\"300\" height=\"197\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-boards-300x197.jpg 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-boards-768x504.jpg 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-boards-1024x672.jpg 1024w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Just place the wire on the flat board and set the smaller board on top of it. \u00a0Rub the wire left and right as many times as it takes for it to straighten out. \u00a0This is a very convenient method as long as the wires don&#8217;t need to be too long.<\/p>\n<h3><strong>Assemble the layers<\/strong><\/h3>\n<p>The most challenging part is the assembly of the different layers. \u00a0 I don&#8217;t think using the word trivial is correct for creating the layers but you can work and re-work them until you are happy. \u00a0The hard task is the assembly.<\/p>\n<p>The reason this is so difficult is that this method of assembly requires that you use your soldering iron for each layer and you need to solder in the middle. \u00a0This is fairly easy for the first one but gets more complex as more layers are added.<\/p>\n<p>In addition, you have to be extremely careful not to accidentally touch any of the wires with your soldering iron otherwise too much heat may be transmitted to the nearest solder joint. \u00a0If the LED&#8217;s or wires have any pressure pushing them apart this heat may be all it takes to cause a previously soldered part to either come loose or become a weak joint \/ loose connection. It is very difficult to re-solder these connections once the cube is built. This would become even more problematic the larger the cube is.<\/p>\n<p>The level of difficulty assembling in this manner due in part to how densely packed the cube should be. \u00a0This is both the horizontal and the vertical density. \u00a0Two difficulties present themselves.<\/p>\n<p>The first difficulty is how much spacing to keep between each plane. \u00a0The second and related problem is ensuring that the spacing is kept uniformly for each layer and for all subsequent layers.<\/p>\n<p>I didn&#8217;t do it with my cube, I used wires for most of the structure, but quite a few other cubes are built using the actual cathodes and anodes to build up the cube structure. \u00a0If this were done it would help considerably with the spacing problems.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-1342\" src=\"http:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-full.jpg\" alt=\"dav\" width=\"2952\" height=\"2768\" srcset=\"https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-full.jpg 2952w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-full-300x281.jpg 300w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-full-768x720.jpg 768w, https:\/\/blog.paranoidprofessor.com\/wp-content\/uploads\/2016\/09\/ledcube-full-1024x960.jpg 1024w\" sizes=\"(max-width: 2952px) 100vw, 2952px\" \/><\/p>\n<h2>Drawbacks of this design<\/h2>\n<p>My father always said that you should use the correct\u00a0tool for the job. \u00a0In this case, I imagine that the\u00a0right tool would have been an electrical engineer.<\/p>\n<p>As long as you already have a Raspberry Pi, my design is a low cost, low component count that can easily be put together either with a breadboard or with a small amount of soldering. Yet, the Raspberry Pi is not a power plant, there are limitations to how much power it can produce.<\/p>\n<p>The power required to turn on all the lights becomes more and more considerable as the cubes get larger . \u00a0A 3<a href=\"https:\/\/www.amazon.de\/Velleman-Mini-Kit-BAUSATZ-MK193-LED-W%C3%BCrfel\/dp\/B008SOWGOI\/ref=pd_sim_107_1?ie=UTF8&amp;psc=1&amp;refRID=SZ50V5TZ8HSW71W006BE\" target=\"_blank\">x3x3<\/a>\u00a0cube can easily be powered by a 9 volt battery but a <a href=\"https:\/\/www.amazon.de\/DAOKAI%C2%AE-Light-8x8x8-Cube-Blue\/dp\/B01JD38PUG\/ref=sr_1_1?s=ce-de&amp;ie=UTF8&amp;qid=1474461667&amp;sr=1-1&amp;keywords=led+cube\" target=\"_blank\">8x8x8<\/a> or <a href=\"http:\/\/www.iphoneness.com\/cool-finds\/l3d-cube-kit\/\" target=\"_blank\">16x16x16<\/a> cube would require a an actual power supply.<\/p>\n<p>My solution is using I2C for communication with the LED&#8217;s via the 23017. The only problem is that I found this communication to be pretty slow. My LED&#8217;s were not as bright as a lot of the other LED cubes that you can see on youtube.<\/p>\n<p>It was because of the power limitations on how much current can be channeled through the MPC23017 that caused me in the end to take a conservative view and cause\u00a0me to pick the low power LED&#8217;s. The good news is that if I turn on every LED in my cube at the same time it is pretty much within the limitations of the power that can be driven by the 23017. The cube looks good in a dark room but you cannot hardly see it in normal lighting conditions.<\/p>\n<p>I was also a bit disappointed in exactly how symmetrical my cube was. Not bad for a first attempt but I was hoping for better. Unfortunately, the actual LED cube is the product of its creator and the result is unrelated to using a kit or creating everything from scratch. The best results are most likely to be attributed to slow and steady work and a great deal of thought and preparation.<\/p>\n<p>In retrospect the biggest flaw in my design was originally\u00a0its biggest strength. The nice thing about using the Raspberry Pi was I simply used secure shell to connect to the computer and wrote, compiled, and debugged the code\u00a0in one easy step.<\/p>\n<p>The only problem is that the Raspberry Pi is a computer not some off the shelf device with a micro-controller. \u00a0This means that when you turn it on, it takes a while before the computer is booted up and the application can start.<\/p>\n<p>The startup isn&#8217;t the problem, the problem when it comes down to shutting down the cube. \u00a0The Raspberry Pi doesn&#8217;t doesn&#8217;t have an on \/ off button so to shut it off I need to open up a secure shell to the Raspberry Pi and then issue a shutdown. \u00a0Once the device is shutdown then unplug the power supply.<\/p>\n<p>Because the Raspberry Pi isn&#8217;t really doing anything special it could have been replaced with either an Arduino or a smaller Arduino and my custom controller board.<\/p>\n<h2>Alternatives<\/h2>\n<p>The internet is full of instructional videos, instructions and photos of how to make your own LED cube.<\/p>\n<p>One of the difficulties that I mentioned was that building a cube from horizontal layers. The next cube that I would make would take a one of two different alternatives. \u00a0The first is to simply solder together an entire column of LED&#8217;s and then start to solder them to the board and to each other.\u00a0 The second alternative is somewhat similar. \u00a0Simply solder together vertical panels and solder them together.<\/p>\n<div id=\"code-link-1310\" class=\"sh-link code-link sh-hide\"><a href=\"#\" onclick=\"showhide_toggle('code', 1310, 'Show code (2,519 More Words)', 'Hide code'); return false;\" aria-expanded=\"false\"><span id=\"code-toggle-1310\">Show code (2,519 More Words)<\/span><\/a><\/div><div id=\"code-content-1310\" class=\"sh-content code-content sh-hide\" style=\"display: none;\"><\/p>\n<h2>Code<\/h2>\n<h3><strong>picube.c <\/strong><\/h3>\n<div class=\"sbody-code\">\n<pre><code>#include &lt;bcm2835.h&gt;\r\n\r\ncat picube.c\r\n#include &lt;bcm2835.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;signal.h&gt;\r\n#include \"picube.h\"\r\n\r\nuint cathode = 0x20;\r\nuint anode = 0x21;\r\nuint IOCON = 0x0A;\r\nuint IODIRA = 0x00;\r\nuint IODIRB = 0x01;\r\nuint OLATA = 0x14;\r\n\r\nint mapping[4][4];\r\nint zmapping[4];\r\n\r\nint debug = 0;\r\nint verbose = 0;\r\n\r\nvoid sigint_handler()\r\n{\r\n printf(\"unexpected request, shutting down program\\n\");\r\n final_bcm2835();\r\n}\r\n\r\nvoid init_mapping()\r\n{\r\n mapping[0][1] = 3;\r\n mapping[0][0] = 7;\r\n mapping[0][3] = 11;\r\n mapping[0][2] = 15;\r\n\r\n mapping[1][1] = 2;\r\n mapping[1][0] = 6;\r\n mapping[1][3] = 10;\r\n mapping[1][2] = 14;\r\n\r\n mapping[2][1] = 1;\r\n mapping[2][0] = 5;\r\n mapping[2][3] = 9;\r\n mapping[2][2] = 13;\r\n\r\n mapping[3][1] = 0;\r\n mapping[3][0] = 4;\r\n mapping[3][3] = 8;\r\n mapping[3][2] = 12;\r\n\r\n if (debug != 0)\r\n {\r\n int x,y;\r\n for (x = 0; x &lt; 4; x++)\r\n {\r\n for (y = 0; y &lt; 4; y++)\r\n printf(\"%02d \",mapping[x][y]);\r\n printf(\"\\n\");\r\n }\r\n }\r\n\r\n zmapping[0] = ZDIM0;\r\n zmapping[1] = ZDIM1;\r\n zmapping[2] = ZDIM2;\r\n zmapping[3] = ZDIM3;\r\n}\r\n\r\n\/*\r\n** a bit of checking of return codes\r\n*\/\r\nvoid check_retcode(int status)\r\n{\r\n switch (status)\r\n {\r\n case BCM2835_I2C_REASON_OK:\r\n \/\/printf(\"Code: Ok\\n\");\r\n break;\r\n case BCM2835_I2C_REASON_ERROR_NACK:\r\n printf(\"Code: Received a NACK\\n\");\r\n break;\r\n case BCM2835_I2C_REASON_ERROR_CLKT:\r\n printf(\"Code: Received Clock Stretch Timeout\\n\");\r\n break;\r\n case BCM2835_I2C_REASON_ERROR_DATA:\r\n printf(\"Code: Not all data is sent \/ received\\n\");\r\n break;\r\n default:\r\n printf(\"Code: unknown\\n\");\r\n break;\r\n }\r\n}\r\n\r\n\/\/ more for debugging than anything else.\r\nvoid turn_on_entire_cube()\r\n{\r\n if (verbose != 0)\r\n printf(\"turning on whole cube\\n\");\r\n\r\n \/\/ turn on all cathodes\r\n bcm2835_i2c_setSlaveAddress(cathode);\r\n char cmd7[] = { OLATA, 0x00, 0x00};\r\n check_retcode(bcm2835_i2c_write(cmd7,sizeof(cmd7)));\r\n\r\n \/\/ turn on all layers (anodes)\r\n char cmd9[] = { OLATA, 0xF0 };\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n check_retcode(bcm2835_i2c_write(cmd9,sizeof(cmd9)));\r\n sleep(1);\r\n}\r\n\r\nvoid turn_off_entire_cube()\r\n{\r\n if (debug != 0)\r\n printf(\"turning off whole cube\\n\");\r\n\r\n \/\/ turn off all layers\r\n char cmd10[] = { OLATA, 0x00 };\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n check_retcode(bcm2835_i2c_write(cmd10,sizeof(cmd10)));\r\n}\r\n\r\nvoid init_bcm2835()\r\n{\r\n if (!bcm2835_init())\r\n {\r\n printf(\"failed on init\\n\");\r\n exit(1);\r\n }\r\n\r\n bcm2835_i2c_begin();\r\n\r\n bcm2835_i2c_set_baudrate(400000);\r\n}\r\n\r\nvoid init_cathode()\r\n{\r\n \/\/ point library to cathode\r\n bcm2835_i2c_setSlaveAddress(cathode);\r\n\r\n \/\/ set bit 7 = 0 use consecutive mapping\r\n \/\/ set bit 5 = 1 (address increment) to on\r\n \/\/ all others dont care.\r\n char cmd[] = { IOCON, 0x20 };\r\n check_retcode(bcm2835_i2c_write(cmd,sizeof(cmd)));\r\n\r\n \/\/ all pins output\r\n char cmd2[] = { IODIRA, 0x00, 0x00 };\r\n check_retcode(bcm2835_i2c_write(cmd2,sizeof(cmd2)));\r\n\r\n#if 0\r\n \/\/ all pins output\r\n char cmd3[] = { IODIRB, 0x00 };\r\n check_retcode(bcm2835_i2c_write(cmd3,sizeof(cmd3)));\r\n#endif\r\n}\r\n\r\nvoid init_anode()\r\n{\r\n \/\/ point library to anode\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n\r\n char cmd6[] = { IOCON, 0x20 };\r\n check_retcode(bcm2835_i2c_write(cmd6,sizeof(cmd6)));\r\n\r\n \/\/ all pins output\r\n char cmd4[] = { IODIRA, 0x00, 0x00 };\r\n check_retcode(bcm2835_i2c_write(cmd4,sizeof(cmd4)));\r\n\r\n#if 0\r\n \/\/ all pins output\r\n char cmd5[] = { IODIRB, 0x00 };\r\n check_retcode(bcm2835_i2c_write(cmd5,sizeof(cmd5)));\r\n#endif\r\n}\r\n\r\nvoid init_microprocessor()\r\n{\r\n init_cathode();\r\n init_anode();\r\n}\r\n\r\nvoid light_mask_z(int mask, int zmask)\r\n{\r\n int bitmask, invertmask, lowerx, upperx;\r\n\r\n \/*\r\n ** first deal with setting up the cathodes\r\n *\/\r\n\r\n if (debug != 0 )\r\n printf(\"mask %04x z%2d\\n\",mask,zmask);\r\n\r\n \/\/ which bits should be on\r\n bitmask = mask;\r\n\r\n \/\/ then we invert bits\r\n invertmask = ~bitmask &amp; 0xffff;\r\n\r\n \/\/ break it up for microprocessor\r\n lowerx = invertmask &amp; 0x00ff;\r\n upperx = (invertmask &amp; 0xff00) &gt;&gt; 8;\r\n\r\n bcm2835_i2c_setSlaveAddress(cathode);\r\n\r\n char cmd7[] = { OLATA, upperx, lowerx};\r\n check_retcode(bcm2835_i2c_write(cmd7,sizeof(cmd7)));\r\n\r\n \/*\r\n ** now deal with setting up the anodes\r\n *\/\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n\r\n \/\/ setup our layer\r\n \/\/ set which layers should be on\r\n\r\n bitmask = zmask;\r\n char cmd8[] = { OLATA, bitmask &amp; 0xff };\r\n check_retcode(bcm2835_i2c_write(cmd8,sizeof(cmd8)));\r\n}\r\n\r\n\/\/ x is 0 - 3\r\n\/\/ y is 0 - 3\r\n\/\/ z is 0 - 3\r\nvoid light_x_y_z(int X, int Y, int Z)\r\n{\r\n int bitmask, invertmask, lowerx, upperx;\r\n int mappedpin;\r\n\r\n \/*\r\n ** first deal with setting up the cathodes\r\n *\/\r\n mappedpin = mapping[X][Y];\r\n\r\n if (debug != 0)\r\n printf(\"x%2d(%d) y%2d z%2d\\n\",X,mappedpin,Y,Z);\r\n\r\n \/\/ first set the bit\r\n bitmask = ( 1 &lt;&lt; mappedpin );\r\n\r\n \/\/ then we invert bits\r\n invertmask = ~bitmask &amp; 0xffff;\r\n\r\n \/\/ break it up for microprocessor\r\n lowerx = invertmask &amp; 0x00ff;\r\n upperx = (invertmask &amp; 0xff00) &gt;&gt; 8;\r\n\r\n\/\/ printf(\"%2d %04x %04x %02x %02x\\n\",mappedpin,bitmask,invertmask,upperx,lowerx);\r\n\r\n bcm2835_i2c_setSlaveAddress(cathode);\r\n\r\n char cmd7[] = { OLATA, upperx, lowerx};\r\n check_retcode(bcm2835_i2c_write(cmd7,sizeof(cmd7)));\r\n\r\n \/*\r\n ** now deal with setting up the anodes\r\n *\/\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n\r\n \/\/ setup our layer\r\n \/\/ set which layers should be on\r\n\r\n bitmask = ( 0x10 &lt;&lt; Z );\r\n char cmd8[] = { OLATA, bitmask &amp; 0xff };\r\n check_retcode(bcm2835_i2c_write(cmd8,sizeof(cmd8)));\r\n}\r\n\r\nvoid rotate_layers()\r\n{\r\n if (verbose != 0)\r\n printf(\"rotate layers\\n\");\r\n\r\n \/\/ enable\r\n int idx;\r\n bcm2835_i2c_setSlaveAddress(anode);\r\n for (idx = 0; idx &lt; 4; idx++)\r\n {\r\n \/\/ actually write something out, will turn on\r\n \/\/ one layer for any leds that are setup\r\n\r\n char cmd8[] = { OLATA, 0x10 &lt;&lt; idx };\r\n\r\n if (debug != 0)\r\n printf(\"cmd8 %x %x\\n\",idx, 0x10 &lt;&lt; idx);\r\n check_retcode(bcm2835_i2c_write(cmd8,sizeof(cmd8)));\r\n sleep(2);\r\n }\r\n}\r\n\r\nvoid circle_chase_base(int speed, double divisor)\r\n{\r\n int x,y;\r\n int z = 1;\r\n int iterations;\r\n\r\n for (iterations = 0; iterations &lt; 10; iterations++)\r\n {\r\n\/\/printf(\"speed %d\\n\",speed);\r\n for (z = 0; z &lt; 4; z++)\r\n {\r\n for (x = 0; x &lt; 4; x++)\r\n {\r\n light_x_y_z(x,0,z);\r\n delay(speed);\r\n }\r\n for (y = 1; y &lt; 4; y++)\r\n {\r\n light_x_y_z(3,y,z);\r\n delay(speed);\r\n }\r\n\r\n for (x = 2; x &gt; 0;x--)\r\n {\r\n light_x_y_z(x,3,z);\r\n delay(speed);\r\n }\r\n for (y = 3; y &gt; 0; y--)\r\n {\r\n light_x_y_z(0,y,z);\r\n delay(speed);\r\n }\r\n }\r\n speed = (int)(divisor * (double)speed);\r\n }\r\n}\r\n\r\nvoid fast_circle_chase()\r\n{\r\n if (verbose != 0)\r\n printf(\"fast circle chase\\n\");\r\n\r\n circle_chase_base(15,1);\r\n}\r\n\r\nvoid circle_chase()\r\n{\r\n if (verbose != 0)\r\n printf(\"normal circle chase\\n\");\r\n\r\n circle_chase_base(200,0.65);\r\n}\r\n\r\nvoid one_after_another()\r\n{\r\n int count,x,y,z;\r\n\r\n if (verbose != 0)\r\n printf(\"one led after another\\n\");\r\n\r\n for (count = 0; count &lt; 1; count++)\r\n {\r\n for (z = 0; z &lt; 4; z++)\r\n for (y = 0; y &lt; 4; y++)\r\n for (x = 0; x &lt; 4; x++)\r\n {\r\n light_x_y_z(x,y,z);\r\n delay(30);\r\n }\r\n }\r\n}\r\n\r\nvoid top_bottom_rotate_side()\r\n{\r\n int counter;\r\n\r\n if (verbose != 0)\r\n printf(\"top bottom rotate\\n\");\r\n\r\n for (counter = 0; counter &lt; 5; counter++)\r\n {\r\n light_mask_z(YCOL0,ZDIM_TOPBOT); delay(250);\r\n light_mask_z(XROW3,ZDIM_TOPBOT); delay(250);\r\n light_mask_z(YCOL3,ZDIM_TOPBOT); delay(250);\r\n light_mask_z(XROW0,ZDIM_TOPBOT); delay(250);\r\n }\r\n}\r\n\r\nvoid side_corkscrew()\r\n{\r\n int counter;\r\n if (verbose != 0)\r\n printf(\"side corkscrew\\n\");\r\n\r\n for (counter = 0; counter &lt; 5; counter++)\r\n {\r\n \/\/ sides\r\n light_mask_z(YCOL0,ZDIM0); delay(250);\r\n light_mask_z(XROW3,ZDIM1); delay(250);\r\n light_mask_z(YCOL3,ZDIM2); delay(250);\r\n light_mask_z(XROW0,ZDIM3); delay(250);\r\n\r\n \/\/ column CA7\r\n light_mask_z(CA07,ZDIM_ALL); delay(250);\r\n }\r\n}\r\n\r\nvoid rotate_takeoff()\r\n{\r\n if (verbose != 0)\r\n printf(\"rotate take off\\n\");\r\n\r\n light_x_y_z(3, 0, 0); \/\/ A\r\n light_x_y_z(2, 1, 0);\r\n light_x_y_z(1, 2, 0);\r\n light_x_y_z(0, 3, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(2, 0, 0); \/\/ B\r\n light_x_y_z(2, 1, 0);\r\n light_x_y_z(2, 2, 0);\r\n light_x_y_z(2, 3, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(1, 0, 0); \/\/ C\r\n light_x_y_z(1, 1, 0);\r\n light_x_y_z(1, 2, 0);\r\n light_x_y_z(1, 3, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(0, 1, 0); \/\/ D\r\n light_x_y_z(1, 1, 0);\r\n light_x_y_z(2, 1, 0);\r\n light_x_y_z(3, 1, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(0, 2, 0); \/\/ E\r\n light_x_y_z(1, 2, 0);\r\n light_x_y_z(2, 2, 0);\r\n light_x_y_z(3, 2, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(0, 0, 0); \/\/ F\r\n light_x_y_z(1, 1, 0);\r\n light_x_y_z(2, 2, 0);\r\n light_x_y_z(3, 3, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(1, 1, 0); \/\/ G\r\n light_x_y_z(2, 1, 0);\r\n light_x_y_z(1, 2, 0);\r\n light_x_y_z(2, 2, 0);\r\n sleep (200);\r\n\r\n light_x_y_z(1, 1, 0); \/\/ G\r\n light_x_y_z(2, 1, 0);\r\n light_x_y_z(1, 2, 0);\r\n light_x_y_z(2, 2, 0);\r\n sleep (200);\r\n\r\n \/\/ H\r\n light_mask_z(OUTERRING,0); delay(250);\r\n\r\n \/\/ I\r\n light_mask_z(CORNERS,0); delay(250);\r\n}\r\n\r\nvoid fireworks()\r\n{\r\n int x, y;\r\n\r\n if (verbose != 0)\r\n printf(\"fireworks\\n\");\r\n\r\n for (x = 1; x &lt;= 2; x++)\r\n for (y = 1; y &lt;= 2; y++)\r\n {\r\n light_x_y_z(x, y, 0);\r\n delay(100);\r\n\r\n light_x_y_z(x, y, 0);\r\n light_x_y_z(x, y, 1);\r\n delay(100);\r\n\r\n light_x_y_z(x, y, 0);\r\n light_x_y_z(x, y, 1);\r\n light_x_y_z(x, y, 2);\r\n delay(100);\r\n\r\n light_x_y_z(x, y, 0);\r\n light_x_y_z(x, y, 1);\r\n light_x_y_z(x, y, 2);\r\n light_x_y_z(x, y, 3);\r\n delay(100);\r\n\r\n light_x_y_z(x, y, 3);\r\n delay(25);\r\n\r\n light_mask_z(INNERRING,ZDIM3);\r\n delay(150);\r\n light_mask_z(OUTERRING,ZDIM3);\r\n delay(150);\r\n\r\n \/\/ falling pieces\r\n int zdim ;\r\n for (zdim = 3; zdim &gt;= 0; zdim--)\r\n {\r\n if (zdim % 2 == 1)\r\n light_mask_z( CA05 | CA12 | CA09 ,zmapping[zdim]);\r\n else\r\n light_mask_z(CA07 | CA04 | CA08 | CA11 ,zmapping[zdim]);\r\n delay(75 + zdim * 25);\r\n }\r\n turn_off_entire_cube();\r\n }\r\n}\r\n\r\nvoid helicopter()\r\n{\r\n int smallwait[] = {110, 90, 65, 40 };\r\n int zdim,idx;\r\n\r\n if (verbose != 0)\r\n printf(\"helicopter\\n\");\r\n\r\n for (zdim = 0; zdim &lt; 4; zdim++)\r\n {\r\n for (idx = 0; idx &lt;= zdim+4; idx++)\r\n {\r\n light_mask_z(PATTERN_A,zmapping[zdim]); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_B,zmapping[zdim]); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_C,zmapping[zdim]); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_F,zmapping[zdim]); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_D,zmapping[zdim]); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_E,zmapping[zdim]); delay(smallwait[zdim]);\r\n }\r\n }\r\n\r\n for (zdim = 0; zdim &lt; 4; zdim++)\r\n {\r\n light_mask_z(PATTERN_G,zmapping[zdim]); delay(1000\/(zdim+1));\r\n light_mask_z(PATTERN_H,zmapping[zdim]); delay(750\/(zdim+1));\r\n }\r\n\r\n for (zdim = 3; zdim &gt;= 0; zdim--)\r\n {\r\n light_mask_z(PATTERN_I,zmapping[zdim]); delay(300);\r\n }\r\n}\r\n\r\nvoid x_rotating_plate()\r\n{\r\n int idx,rep,smallwait = 10;\r\n if (verbose != 0)\r\n printf(\"x rotating plate\\n\");\r\n\r\n for (idx = 0; idx &lt; 10; idx++)\r\n {\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW3,ZDIM3); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW0,ZDIM0); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW3,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW0,ZDIM1); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW3,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW0,ZDIM2); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW0,ZDIM3); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW3,ZDIM0); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW1,ZDIM3); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW1,ZDIM0); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(XROW2,ZDIM3); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM2); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM1); delay(smallwait);\r\n light_mask_z(XROW2,ZDIM0); delay(smallwait);\r\n }\r\n turn_off_entire_cube();\r\n }\r\n}\r\n\r\nvoid y_rotating_plate()\r\n{\r\n int idx,rep,smallwait = 10;\r\n if (verbose != 0)\r\n printf(\"y rotating plate\\n\");\r\n\r\n for (idx = 0; idx &lt; 10; idx++)\r\n {\r\n\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL3,ZDIM3); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL0,ZDIM0); delay(smallwait);\r\n\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL3,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL0,ZDIM1); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL3,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL0,ZDIM2); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL0,ZDIM3); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL3,ZDIM0); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL1,ZDIM3); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL1,ZDIM0); delay(smallwait);\r\n }\r\n for (rep = 0; rep &lt; 5; rep++)\r\n {\r\n light_mask_z(YCOL2,ZDIM3); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM2); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM1); delay(smallwait);\r\n light_mask_z(YCOL2,ZDIM0); delay(smallwait);\r\n }\r\n turn_off_entire_cube();\r\n }\r\n}\r\n\r\n\/\/ rotates around the z axis\r\nvoid z_rotating_plate()\r\n{\r\n int smallwait[] = {250, 200, 150, 100 };\r\n int zdim,idx;\r\n if (verbose != 0)\r\n printf(\"z rotating plate\\n\");\r\n\r\n for (idx = 0; idx &lt; 4; idx++)\r\n for (zdim = 0; zdim &lt; 4; zdim++)\r\n {\r\n for (idx = 0; idx &lt;= zdim; idx++)\r\n {\r\n light_mask_z(PATTERN_A,ZDIM_ALL); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_B,ZDIM_ALL); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_C,ZDIM_ALL); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_F,ZDIM_ALL); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_D,ZDIM_ALL); delay(smallwait[zdim]);\r\n light_mask_z(PATTERN_E,ZDIM_ALL); delay(smallwait[zdim]);\r\n }\r\n }\r\n}\r\n\r\nvoid wire_frame()\r\n{\r\n int iter;\r\n\r\n if (verbose != 0)\r\n printf(\"wire frame\\n\");\r\n\r\n for (iter = 0; iter &lt; 200; iter++)\r\n {\r\n light_mask_z(OUTERRING,ZDIM0); delay(10);\r\n light_mask_z(CORNERS,ZDIM1); delay(10);\r\n light_mask_z(CORNERS,ZDIM2); delay(10);\r\n light_mask_z(OUTERRING,ZDIM3); delay(10);\r\n }\r\n}\r\n\r\nvoid shrinking_cube()\r\n{\r\n int iter,idx;\r\n int redraw = 20;\r\n\r\n if (verbose != 0)\r\n printf(\"shrinking cube\\n\");\r\n\r\n for (idx = 0; idx &lt; 5; idx++)\r\n {\r\n \/\/ bigest cube\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(XROW0 | XROW3 | YCOL0 | YCOL3, ZDIM0); delay(10);\r\n light_mask_z(CA07 | CA11 | CA08 | CA04,ZDIM1); delay(10);\r\n light_mask_z(CA07 | CA11 | CA08 | CA04,ZDIM2); delay(10);\r\n light_mask_z(XROW0 | XROW3 | YCOL0 | YCOL3, ZDIM3); delay(10);\r\n }\r\n\r\n \/\/ next bigest cube\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(CA05 | CA06 | CA07 | CA03 | CA01 | CA15 | CA14 | CA13, ZDIM0);\r\n delay(10);\r\n\r\n light_mask_z(CA03 | CA06 | CA01 | CA14, ZDIM1);\r\n delay(10);\r\n\r\n light_mask_z(CA05 | CA06 | CA07 | CA03 | CA01 | CA15 | CA14 | CA13, ZDIM2);\r\n delay(10);\r\n }\r\n\r\n \/\/ next biggest\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(CA07 | CA06 | CA03 | CA02, ZDIM0); delay(10);\r\n light_mask_z(CA07 | CA06 | CA03 | CA02, ZDIM1); delay(10);\r\n }\r\n\r\n \/\/ smallest cube, actually just a point\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(CA07, ZDIM0); delay(10);\r\n }\r\n\r\n delay(100);\r\n\r\n \/\/ next biggest\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(CA07 | CA06 | CA03 | CA02, ZDIM0); delay(10);\r\n light_mask_z(CA07 | CA06 | CA03 | CA02, ZDIM1); delay(10);\r\n }\r\n\r\n \/\/ next bigest cube\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(CA05 | CA06 | CA07 | CA03 | CA01 | CA15 | CA14 | CA13, ZDIM0);\r\n delay(10);\r\n\r\n light_mask_z(CA03 | CA06 | CA01 | CA14, ZDIM1);\r\n delay(10);\r\n\r\n light_mask_z(CA05 | CA06 | CA07 | CA03 | CA01 | CA15 | CA14 | CA13, ZDIM2);\r\n delay(10);\r\n }\r\n\r\n \/\/ bigest cube\r\n for (iter = 0; iter &lt; redraw; iter++)\r\n {\r\n light_mask_z(XROW0 | XROW3 | YCOL0 | YCOL3, ZDIM0); delay(10);\r\n light_mask_z(CA07 | CA11 | CA08 | CA04,ZDIM1); delay(10);\r\n light_mask_z(CA07 | CA11 | CA08 | CA04,ZDIM2); delay(10);\r\n light_mask_z(XROW0 | XROW3 | YCOL0 | YCOL3, ZDIM3); delay(10);\r\n }\r\n }\r\n}\r\n\r\nvoid floating_cube(int pause)\r\n{\r\n int iter;\r\n int count = 2;\r\n int cubes[] = { CA04 | CA00 | CA05 | CA01, \/\/ 0\r\n CA05 | CA01 | CA06 | CA02, \/\/ 1\r\n CA06 | CA02 | CA07 | CA03, \/\/ 2\r\n CA02 | CA14 | CA03 | CA15, \/\/ 3\r\n CA14 | CA10 | CA15 | CA11, \/\/ 4\r\n CA13 | CA09 | CA14 | CA10, \/\/ 5\r\n CA12 | CA08 | CA13 | CA09, \/\/ 6\r\n CA00 | CA12 | CA01 | CA13, \/\/ 7\r\n CA01 | CA13 | CA02 | CA14, \/\/ 8\r\n };\r\n int lvls[] = { ZDIM0 | ZDIM1, ZDIM1 | ZDIM2, ZDIM2 | ZDIM3 };\r\n\r\n \/\/ next biggest\r\n for (iter = 0; iter &lt; count; iter++)\r\n {\r\n light_mask_z(cubes[0],lvls[0]); delay(pause);\r\n light_mask_z(cubes[1],lvls[0]); delay(pause);\r\n light_mask_z(cubes[1],lvls[1]); delay(pause);\r\n light_mask_z(cubes[2],lvls[1]); delay(pause);\r\n light_mask_z(cubes[8],lvls[1]); delay(pause);\r\n light_mask_z(cubes[8],lvls[2]); delay(pause);\r\n light_mask_z(cubes[3],lvls[2]); delay(pause);\r\n\r\n light_mask_z(cubes[4],lvls[2]); delay(pause);\r\n light_mask_z(cubes[5],lvls[1]); delay(pause);\r\n light_mask_z(cubes[8],lvls[1]); delay(pause);\r\n\r\n light_mask_z(cubes[6],lvls[0]); delay(pause);\r\n light_mask_z(cubes[7],lvls[1]); delay(pause);\r\n light_mask_z(cubes[8],lvls[0]); delay(pause);\r\n\r\n light_mask_z(cubes[0],lvls[0]); delay(pause);\r\n light_mask_z(cubes[8],lvls[1]); delay(pause);\r\n light_mask_z(cubes[4],lvls[2]); delay(pause);\r\n light_mask_z(cubes[3],lvls[2]); delay(pause);\r\n light_mask_z(cubes[2],lvls[1]); delay(pause);\r\n light_mask_z(cubes[1],lvls[1]); delay(pause);\r\n light_mask_z(cubes[0],lvls[0]); delay(pause);\r\n\r\n }\r\n}\r\n\r\nvoid final_bcm2835()\r\n{\r\n \/\/ make sure we turn off the leds\r\n turn_off_entire_cube();\r\n\r\n \/\/ shutdown in an orderly manner\r\n bcm2835_i2c_end();\r\n bcm2835_close();\r\n}\r\n\r\nint main(int argc, char **argv)\r\n{\r\n signal(SIGINT,sigint_handler);\r\n init_mapping();\r\n\r\n init_bcm2835();\r\n\r\n init_microprocessor();\r\n\r\n int loopcounter ;\r\n for (loopcounter = 0; loopcounter &lt; 10; loopcounter++)\r\n {\r\n\/\/#if 0\r\n\r\nloopcounter = 1;\r\n turn_on_entire_cube();\r\n sleep(2);\r\n\r\n one_after_another();\r\n sleep(1);\r\n\r\n floating_cube(700);\r\n sleep(1);\r\n\r\n circle_chase();\r\n sleep(1);\r\n\r\n side_corkscrew();\r\n sleep(1);\r\n\r\n wire_frame();\r\n\r\n top_bottom_rotate_side();\r\n sleep(1);\r\n\r\n fast_circle_chase();\r\n sleep(1);\r\n\r\n helicopter();\r\n sleep(1);\r\n\r\n fireworks();\r\n sleep(1);\r\n\r\n x_rotating_plate();\r\n floating_cube(250);\r\n\r\n y_rotating_plate();\r\n shrinking_cube();\r\n\r\n z_rotating_plate();\r\n\r\n\/\/printf(\"%d\\n\",loopcounter);\r\n\/\/#endif\r\n shrinking_cube();\r\n }\r\n\r\n final_bcm2835();\r\n return 0;\r\n}\r\n<\/code><\/pre>\n<\/div>\n<p>picube.h<\/p>\n<div class=\"sbody-code\">\n<pre>#ifndef _PICUBE_H_\r\n#define _PICUBE_H_\r\n\r\nextern void final_bcm2835();\r\n\r\n#define CA07 0x0080\r\n#define CA06 0x0040\r\n#define CA05 0x0020\r\n#define CA04 0x0010\r\n#define CA03 0x0008\r\n#define CA02 0x0004\r\n#define CA01 0x0002\r\n#define CA00 0x0001\r\n\r\n#define CA15 0x8000\r\n#define CA14 0x4000\r\n#define CA13 0x2000\r\n#define CA12 0x1000\r\n#define CA11 0x0800\r\n#define CA10 0x0400\r\n#define CA09 0x0200\r\n#define CA08 0x0100\r\n\r\n#define YCOL0 CA07 | CA03 | CA15 | CA11\r\n#define YCOL1 CA06 | CA02 | CA14 | CA10\r\n#define YCOL2 CA05 | CA01 | CA13 | CA09\r\n#define YCOL3 CA04 | CA00 | CA12 | CA08\r\n\r\n#define XROW0 CA07 | CA06 | CA05 | CA04\r\n#define XROW1 CA03 | CA02 | CA01 | CA00\r\n#define XROW2 CA15 | CA14 | CA13 | CA12\r\n#define XROW3 CA11 | CA10 | CA09 | CA08\r\n\r\n#define ZDIM_BOTTOM 0x10\r\n#define ZDIM_TOP 0x80\r\n#define ZDIM_TOPBOT 0x90\r\n\r\n#define ZDIM0 0x10\r\n#define ZDIM1 0x20\r\n#define ZDIM2 0x40\r\n#define ZDIM3 0x80\r\n\r\n\/\/ a few patterns that can be used\r\n#define CORNERS CA07 | CA11 | CA04 | CA08\r\n#define OUTERRING XROW0 | XROW3 | YCOL0 | YCOL3\r\n#define INNERRING CA01 | CA02 | CA13 | CA14\r\n\r\n#define PATTERN_A CA04 | CA01 | CA14 | CA11\r\n#define PATTERN_B YCOL2\r\n#define PATTERN_C YCOL1\r\n#define PATTERN_D XROW1\r\n#define PATTERN_E XROW2\r\n#define PATTERN_F CA07 | CA02 | CA13 | CA08\r\n#define PATTERN_G INNERRING\r\n#define PATTERN_H OUTERRING\r\n#define PATTERN_I CORNERS\r\n\r\n#define ZDIM_ALL 0xF0\r\n#endif<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<h3><strong>watchdog.sh<\/strong><\/h3>\n<p>This script actually shouldn&#8217;t be necessary at all. \u00a0Occasionally the program stops. \u00a0I had not been able to trace it down to either my libraries or my code, but in the end decided to simply write a small watchdog to ensure that if the program stops, it is restarted.<\/p>\n<div class=\"sbody-code\">\n<pre><code>#!\/bin\/bash\r\n\r\nPGM=\/home\/pi\/picube\/picube\r\n\r\nwhile [ 1 == 1 ]\r\ndo\r\n\r\n CNT=`ps -ef | grep $PGM | grep -v grep | grep -v sudo | awk '{ print $8 }' | wc -l`\r\n NAME=`ps -ef | grep $PGM | grep -v grep | grep -v sudo | awk '{ print $8 }' `\r\n ID=`ps -ef | grep $PGM | grep -v grep | grep -v sudo | awk '{ print $2 }' `\r\n\r\n if [ $CNT -ne 1 ]\r\n then\r\n echo restarting\r\n $PGM &amp;\r\n fi\r\n\r\n sleep 60\r\ndone\r\n<\/code><\/pre>\n<\/div>\n<h2>Makefile<\/h2>\n<div class=\"sbody-code\">\n<pre>PGM=picube\r\n\r\nSRC=$(PGM).c\r\nOBJ=$(SRC:.c=.o)\r\nCFLAGS=-Wall\r\nINCDIR=-I.\r\nLIBS=-lbcm2835 -lm\r\nLIBDIR=\r\n\r\nall:    $(PGM)\r\n\r\n$(PGM): $(OBJ) $(PGM).h\r\n        @echo building $(PGM)\r\n        gcc $(INCDIR) $(OBJ) $(LIBS) $(LIBDIR) -o $(PGM)\r\n\r\n.c.o:\r\n        @echo \"compling $@\"\r\n        @gcc -c $(CFLAGS) $&lt; -o $@\r\n\r\nclean:\r\n        @echo cleaning up build env\r\n        @rm -f $(OBJ) $(PGM)\r\n\r\n.phony: run\r\nrun:    all\r\n        sudo .\/$(PGM)\r\n\r\n#dependancies\r\n$(PGM).o: $(PGM.h)\r\n<\/pre>\n<\/div>\n<p><\/div>\n<h2><\/h2>\n","protected":false},"excerpt":{"rendered":"<p>Some time back, I had a fair amount lot of free time and did watch things on you tube. \u00a0A friend of mine showed a number of cool LED cubes that were trending at that time. It seemed so cool &hellip; <a href=\"https:\/\/blog.paranoidprofessor.com\/index.php\/2016\/09\/24\/just-making-it-a-4x4x4-led-cube\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[20,3],"tags":[79,80],"_links":{"self":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/1310"}],"collection":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/comments?post=1310"}],"version-history":[{"count":35,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/1310\/revisions"}],"predecessor-version":[{"id":1366,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/posts\/1310\/revisions\/1366"}],"wp:attachment":[{"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/media?parent=1310"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/categories?post=1310"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.paranoidprofessor.com\/index.php\/wp-json\/wp\/v2\/tags?post=1310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}