{"id":1440,"date":"2013-11-28T00:53:12","date_gmt":"2013-11-28T00:53:12","guid":{"rendered":"http:\/\/www.daveakerman.com\/?p=1440"},"modified":"2013-12-02T12:36:44","modified_gmt":"2013-12-02T12:36:44","slug":"driving-a-scrolling-led-badge-from-a-raspberry-pi","status":"publish","type":"post","link":"http:\/\/www.daveakerman.com\/?p=1440","title":{"rendered":"Driving a scrolling LED badge from a Raspberry Pi"},"content":{"rendered":"<p>For a while I&#8217;ve wanted to build a &#8220;Flight Readiness&#8221; unit that I can have near me when filling a balloon, and will show me if the tracker is running OK or if there&#8217;s a problem with the tracker or receiver (e.g. it may have drifted out of tune). To build this I needed a WiFi-connected computer (a Raspberry Pi is an obvious choice) plus a display that is easily visible in a variety of lighting conditions. I opted for an &#8220;LED badge&#8221; which is a small scrolling message board, purchased on ebay for \u00a313 (about $20).<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-1441\" alt=\"badge\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge.jpg\" width=\"428\" height=\"148\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge.jpg 428w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge-300x103.jpg 300w\" sizes=\"(max-width: 428px) 100vw, 428px\" \/><\/a><\/p>\n<p>These displays typically have a USB socket for charging and programming, and appear to a PC or Pi as a virtual serial port. They come with Windows drivers and software to download messages to the device, the intention being that you download your message then unplug and run the display from its internal battery. Messages are stored internally in flash memory so the device can be powered off and it will retain the message.<\/p>\n<p>For my purposes, I want to be able to send a message from a Pi, and have the device display that message (scrolling if necessary) until I replace the message with another one. I can then get the Pi to display the current tracker status &#8211; e.g. &#8220;All OK&#8221;, or &#8220;No GPS Lock&#8221;, etc.<\/p>\n<p>So the first job was to get the device running on my Windows PC. The device installed as a serial device (the common Prolific PL2303 driver) and the supplied software successfully sent messages to it:<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/colour.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-1442\" alt=\"colour\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/colour.jpg\" width=\"906\" height=\"381\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/colour.jpg 906w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/colour-300x126.jpg 300w\" sizes=\"(max-width: 906px) 100vw, 906px\" \/><\/a><\/p>\n<p>So with the software working, the next job was to have a look at what it was sending to the device. For this I downloaded a serial monitor program from <a href=\"http:\/\/www.hhdsoftware.com\/serial-monitor\">HHD Software<\/a>. This is an excellent program and runs for 14 days in trial mode with nag screens. For the above message and settings it showed this packet being sent, at 1200 baud:<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/packet.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-1443\" alt=\"packet\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/packet.jpg\" width=\"715\" height=\"263\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/packet.jpg 715w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/packet-300x110.jpg 300w\" sizes=\"(max-width: 715px) 100vw, 715px\" \/><\/a><\/p>\n<p>Perhaps surprisingly, the &#8220;hello world&#8221; text doesn&#8217;t appear. In fact, this is because the PC is rendering the text and sending it as a 1-bit bitmap pattern. By sending different messages with different parameters (brightness, scroll speed, direction and &#8220;loop&#8221; which is a marquee effect) I gleaned the following about the protocol:<\/p>\n<ul>\n<li>The first item is a 6-byte startup packet &#8220;Ahello&#8221;<\/li>\n<li>This\u00a0<strong>must<\/strong> be followed by a short delay (10ms works well)<\/li>\n<li>The next 48 bytes contain the message parameters and the number of bitmap\u00a0packets.<\/li>\n<li>This\u00a0<strong>must<\/strong> be followed by a delay of at least 800ms<\/li>\n<li>The bitmap packets follow, 11 bytes each, with a delay of at least 100ms separating each from the next.<\/li>\n<\/ul>\n<p>The parameter section can be adjusted as follows:<\/p>\n<ul>\n<li>Byte 0 (the first byte of the parameter packet) has the brightness in bits 2-0. \u00a0Value 0 is the brightest and 3 the dimmest.<\/li>\n<li>Byte 2 has the following:\n<ul>\n<li>Bit 7 is set for the marquee effect<\/li>\n<li>Bits 6-4 contain the speed from 0 (slow) to 7 (fast)<\/li>\n<li>Bits 2-0 contain the direction (0 is &#8220;move to left&#8221;)<\/li>\n<\/ul>\n<\/li>\n<li>Byte 14 contains the number of bitmap packets. \u00a0For some strange reason, this value is repeated in bytes 16, 18, 20, 22, 24, 26 and 28.<\/li>\n<\/ul>\n<p>The bitmap packets are 11 bytes each. \u00a0The first byte of the first such packet represents the first 8 dots starting at the top-left of the image being sent, with a &#8220;1&#8221; representing a lit LED. \u00a0Bit 7 in that byte is the top-left dot, and bit 6 is the one to its right, etc. \u00a0The next byte in the packet is for the next 8 dots\u00a0to the right of the first 8, assuming the image is wider than 8 bytes. \u00a0in other words, the image is scanned one row at a time from top to bottom, and is sent in 11-byte packets. \u00a0The smallest possible image then would consist of 1 bitmap packet, representing 11 rows (the display is 11 rows high) of 8 dots each.<\/p>\n<p>So, with the protocol understood, I needed to port this functionality to Linux on the Raspberry Pi. \u00a0I investigated some Linux programs that can render text as suitable binary dot patterns, such as the strangely named &#8220;toilet&#8221; program, but the resulting images weren&#8217;t as easy to read as ones generated from the Windows program. \u00a0So, I opted for a 2-stage approach; I wrote a Delphi Windows program to build a nice clear character set and then copied the result into a C program on the Pi that can use it to render text before sending it to the display. \u00a0To make the job slightly easier, I had the Delphi program generate actual C source code, like so:<\/p>\n<p><!-- code formatted by http:\/\/manoli.net\/csharpformat\/ --><\/p>\n<pre class=\"csharpcode\"><span class=\"kwrd\">struct<\/span> TCharacter\r\n{\r\n    <span class=\"kwrd\">char<\/span> Character;\r\n    <span class=\"kwrd\">int<\/span> Width;\r\n    <span class=\"kwrd\">int<\/span> Pattern[11];\r\n};\r\n\r\n<span class=\"kwrd\">struct<\/span> TCharacterSet\r\n{\r\n    <span class=\"kwrd\">int<\/span> Count;\r\n    <span class=\"kwrd\">struct<\/span> TCharacter Characters[95];\r\n} CharacterSet = {95,\r\n                  <span class=\"str\">' '<\/span>, 4, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,\r\n                  <span class=\"str\">'!'<\/span>, 4, 0x000, 0x000, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x000, 0x004, 0x000,\r\n                  <span class=\"str\">'\"'<\/span>, 3, 0x000, 0x002, 0x002, 0x002, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,\r\n                  <span class=\"str\">'#'<\/span>, 9, 0x000, 0x000, 0x050, 0x050, 0x0FC, 0x028, 0x028, 0x07E, 0x014, 0x014, 0x000,\r\n                  <span class=\"str\">'$'<\/span>, 7, 0x000, 0x008, 0x008, 0x03C, 0x00A, 0x00A, 0x01C, 0x028, 0x028, 0x01E, 0x008,<\/pre>\n<p>I put this in a .h file and included it in a new program that:<\/p>\n<ul>\n<li>Accepts command-line parameters to set the scroll speed etc.<\/li>\n<li>Renders text using the above character set information<\/li>\n<li>Sends the header packet, parameter packet, and bitmap packets to the LED badge at 1200 baud and with the appropriate delays as above.<\/li>\n<\/ul>\n<p>Initially I did this with the badge connected to the Pi&#8217;s USB port. \u00a0The badge appears as \/dev\/ttyUSB0 and it&#8217;s a simple task to open that port, set the baud rate, switch off output processing (we&#8217;re sending binary data so we don&#8217;t want CR\/LF conversions etc!) and to send the data. \u00a0However, this particular badge only displays the message once, and then switches to &#8220;charge mode&#8221; where it dims the display and shows a battery charge graphic; it only shows the message continuously when unplugged from USB! \u00a0This behaviour is not useful for any application that wants to update the message and then display it for a while before changing the message.<\/p>\n<p>So, I took the display apart to see what I could find:<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge2.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-large wp-image-1448\" alt=\"badge2\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge2-1024x319.jpg\" width=\"640\" height=\"199\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge2-1024x319.jpg 1024w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge2-300x93.jpg 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p>Unsurprisingly, there&#8217;s a Prolific USB-serial converter, with the serial Rx and Tx pins connecting to Tx and Rx on the LPC1113\u00a0ARM Cortex-Mo processor. \u00a0There&#8217;s also a Microchip LiPo charge controller, and of course a large matrix of SMD LEDs.<\/p>\n<p>The first thing I wanted to do was bypass the USB interface, since it&#8217;s ugly to have a large USB plug sticking out the side of a fairly small display. \u00a0Pin 1 on the PL2303 is the Tx pin that sends data to the CPU, so I carefully lifted that pin with a scalpel and soldering iron. \u00a0Conveniently, the track goes to a relatively large pad labelled &#8220;Rx&#8221; so I soldered a wire to that for connection to the serial Tx line on the Pi GPIO header. \u00a0With this and a GND wire connected I could happily program the badge from the Pi. \u00a0Finally, I connected 5V from the Pi to the 5V USB line on the badge (the pad for a missing D4 component was ideal for this).<\/p>\n<p>However, there was a problem. \u00a0As mentioned earlier, the badge&#8217;s firmware &#8220;knows&#8221; whether the device is externally powered or not. \u00a0It does this by taking the USB 5V line, passing it through a potential divider to drop to about 3V, and then takes that to a digital input pin on the ARM processor. \u00a0The firmware then does one of the following 2 things, both undesirable, depending on the state of that pin:<\/p>\n<ul>\n<li>High (USB connected) &#8211; Displays the message once, then enters charge mode<\/li>\n<li>Low (Disconnected) &#8211; Resets, displaying a startup logo, then displays the message continuously<\/li>\n<\/ul>\n<p>So the second scenario is better, but means that every time the Pi changes the message, there&#8217;s a delay whilst the startup logo is shown. \u00a0However, a combination of the above would be good &#8211; pretend that USB is connected so the message appears quickly and then, before it stops scrolling and enters charge mode, pretend that USB is disconnected.<\/p>\n<p>To do this, I removed the potential divider and connected the ARM&#8217;s input pin directly to a GPIO pin on the Pi. \u00a0Here&#8217;s the modified board with all 4 wires (5V, 0V, Serial Data, GPIO) connected:<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge3.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge3-1024x566.jpg\" alt=\"badge3\" width=\"640\" height=\"353\" class=\"aligncenter size-large wp-image-1449\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge3-1024x566.jpg 1024w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/badge3-300x165.jpg 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p>The required sequence is then:<\/p>\n<ol>\n<li>Raise that pin high<\/li>\n<li>Send the message<\/li>\n<li>Wait a moment for the message to appear<\/li>\n<li>Drop that pin low<\/li>\n<\/ol>\n<p>I used the <a href=\"https:\/\/projects.drogon.net\/raspberry-pi\/wiringpi\/the-gpio-utility\/\">Wiring Pi<\/a> GPIO program to test this, and I&#8217;ll soon integrate the pin control into my program with the WiringPi library.<\/p>\n<p>Here&#8217;s a short video showing the badge in operation, with the Pi updating the message:<\/p>\n<p><iframe loading=\"lazy\" width=\"640\" height=\"480\" src=\"http:\/\/www.youtube.com\/embed\/78BuavRR7uo?feature=oembed\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>And finally, here&#8217;s the badge mounted on a Pi case with an <a href=\"http:\/\/uk.rs-online.com\/web\/p\/product\/7757504\/?grossPrice=Y&#038;cm_mmc=UK%7CShopping-_-Google+PLA-_-RS%7CPower+Banks-_-7757504&#038;kpid=&#038;istCompanyId=f7e7b05b-2daf-4c0e-8825-3633baf8113b&#038;istItemId=xitlrqxal&#038;istBid=tztx&#038;gclid=CIPYr8XCkbsCFTMftAodEnwAZg\">RS USB Power Bank<\/a>:<\/p>\n<p><a href=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/P1080954.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/P1080954-1024x682.jpg\" alt=\"P1080954\" width=\"640\" height=\"426\" class=\"aligncenter size-large wp-image-1453\" srcset=\"http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/P1080954-1024x682.jpg 1024w, http:\/\/www.daveakerman.com\/wp-content\/uploads\/2013\/11\/P1080954-300x200.jpg 300w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For a while I&#8217;ve wanted to build a &#8220;Flight Readiness&#8221; unit that I can have near me when filling a balloon, and will show me if the tracker is running OK or if there&#8217;s a problem with the tracker or receiver (e.g. it may have drifted out of tune). To [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[5,4],"tags":[],"_links":{"self":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/1440"}],"collection":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1440"}],"version-history":[{"count":8,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/1440\/revisions"}],"predecessor-version":[{"id":1454,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=\/wp\/v2\/posts\/1440\/revisions\/1454"}],"wp:attachment":[{"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1440"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.daveakerman.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}