Jul 022016
 
LED Clock + Arduino

4 years ago (time flies by!) I built a 6 digit 16 segment LED display. It’s using SPI and thus can be extended to many digits. It does not refresh all signals, so it’s limited in length, but it’s working for 6 digits. Which is enough for a clock.

Using Arduino as a quick check works well. Synchronizing the clock from a PC works too. There’s a problem though I did not expect: sending data to the Arduino via output redirection to /dev/ttyUSB0 fails to work. Reason is that the interface gets closes when done which breaks communication.

2 choices for the fix:

tail -f /dev/ttyUSB0 &

or

stty -F /dev/ttyUSB0 cs8 38400 ignbrk -brkint -icrnl -imaxbel \
-opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke \
noflsh -ixon -ixoff -crtscts -hupcl

The latter sets baurate too, but the important part is the -hupcl which does not close the interface when the shell is done.

So now I can synchronize the time from the PC to the Arduino via:

TZ_adjust=9;d=$(date +%s);t=$(echo "60*60*$TZ_adjust/1" | bc);echo T$(echo $d+$t | bc) >
/dev/ttyUSB0

Adjust TZ_adjust for your time zone. Also the Arduino clock is very inaccurate, so for a real clock, get a proper RTC with a good and more accurate crystal. The one I have is off by 900ppm (about 3s too fast per hour).

May 282016
 
nodemcu and web- or not-web-sockets

Got one of those neat ESP8266 modules with nodemcu and eLua on it. Running a web server is not recommended due to the limited amount of memory it has. The goal today was to make an LED on/off via a web page. A TCP socket would do fine (UDP too). Browser cannot (yet) use normal sockets, so websockets it is. Easy decision.

Found a library for nodemcu to do websockets but that did not work with the websocket clients I tried (Dark WebSocket Terminal among others): I could connect, but data never was sent. Wireshark confirmed that no data flows to the websocket listener. The opening and closing sequence seems to work fine. I have no idea what is missing, but since no actual data was sent at all and there was no other websocket implementation for nodemcu, I used TCP sockets on the ESP8266 side. That worked immediately.

But to make browser work with this, I need a websocket-to-tcp bridge. Which works just fine. The advantage is that the ESP8266 can connect as a client to a TCP socket on a gateway server on the Internet, and the client software can connect via websockets to that same server, which neatly works around NAT’ing routers.

So here I present all 2 pieces. The Lua part running on the ESP8266 (Pin 4 is a LED which turns on when you write LOW to the pin):

gpio.mode(4, gpio.OUTPUT)
led4=gpio.LOW

srv=net.createServer(net.TCP)
srv:listen(9001, function(conn)
  conn:on("receive", function(conn, payload)
    gpio.write(4, led4)
    led4=(led4==gpio.LOW) and gpio.HIGH or gpio.LOW
    -- print(payload)
    conn:send("ok\r\n")
    end)
  end)

and here the call for the websocket to TCP bridge:

./ws-tcp-bridge --lport 9000 --rhost 192.168.21.208:9001 --method ws2tcp

where port 9000 on the local host is where the websocket listener listens, and 192.168.21.208:9001 is the TCP listener on the ESP8266.

And that’s it. Now when connecting via e.g. Dark Websocket Terminal to 127.0.0.1:9000, and sending anything, the LED4 will change its state.

 

Next step: have a JavaScript front-end. DroidScript it’ll be. Then maybe a web page via node.js.

Mar 222015
 
Toggling LEDs

Here was a great start and given that I did not know Lua a lot (and I am sure I don’t still), it was a nice little challenge to expand the example to include all 6 LEDs.

Here the result:

 

myled={ 4, 3, 2, 1, 5, 0, 6, 7, 8 }
mystate={}

start_init = function()
local i
for i=1,6 do
 gpio.mode(myled[i], gpio.OUTPUT)
 gpio.write(myled[i],gpio.HIGH)
 mystate[i]=0
end 
end 
 
sendFileContents = function(conn, filename) 
    if file.open(filename, "r") then 
        --conn:send(responseHeader("200 OK","text/html"))
        repeat  
        local line=file.readline()  
        if line then  
            conn:send(line)
        end  
        until not line  
        file.close()
    else 
        conn:send(responseHeader("404 Not Found","text/html"))
        conn:send("Page not found")
            end 
end 
 
responseHeader = function(code, type) 
    return "HTTP/1.1 " .. code .. "\nConnection: close\nServer: nunu-Luaweb\nContent-Type: " .. type .. "\n\n";  
end 
 
httpserver = function () 
    start_init(); 
    srv=net.createServer(net.TCP)  
    srv:listen(80,function(conn)  
      conn:on("receive",function(conn,request)  
        conn:send(responseHeader("200 OK","text/html")); 
        fflag, findex, pin=string.find(request, "gpio=(%d+)")
        pin=tonumber(pin)
        if fflag and pin>=1 and pin<=6 then
          print("Changing pin "..pin.." to ")
          if mystate[pin]==0 then
               mystate[pin]=1
               gpio.write(myled[pin], gpio.LOW)
               print("on\n")
          else
               mystate[pin]=0
                gpio.write(myled[pin],gpio.HIGH)
               print("off\n")
          end         
        else 
            sendFileContents(conn,"schead.htm")
            local i
            for i=1,6 do
             if mystate[i]==0 then
              preset=""
             else
              preset="checked=\"checked\""
             end
             conn:send("<div><input type=\"checkbox\" id=\"chbox"..i.."\" name=\"chbox"..i.."\" class=\"switch\" onclick=\"loadXMLDoc("..i..")\" "..preset.." />")
             conn:send("<label for=\"chbox"..i.."\">GPIO "..i.."</label></div>\n")
            end
            conn:send("</div>")            
        end 
        print(request); 
      end)  
      conn:on("sent",function(conn)  
        conn:close() 
        conn = nil  
 
      end) 
    end) 
end 
 
httpserver()

Note:

  1. I use only the 6 red LEDs on the dev board I have
  2. I had to shorten the text sent to the web client from “checkbox2” to “chbox2” as otherwise the last characters of those 6 lines were missing. That showed when some LEDs were on and I reloaded the page. Then toggle 6 went missing. Thus don’t send too much too fast.

 

Mar 222015
 
ESP8266 - IoT, here we come

The Internet of Things was for the longest time limited to bigger things. Costs of US$100 and more for a IP connected device was a given.

Arduino boards like this Ethernet Shield with a W5200 chip still needed a separate CPU. And it was not wireless, so add in a cable and a fraction of a switch. Newer possibilities are Raspberry Pi + USB WLAN stick (<US$40). Those were a bit expensive and quite large if all you want is switch on/off something small like a lamp.

Then came solutions like Spark Core which were relatively cheap (<US$40) and small. Slowly getting there.

And then the ESP8266 showed up, making most other solutions oversized and overpriced: About US$3 for the naked module (ESP-12) and US$11 for a small dev module. And you can program it in C or Lua or JavaScript. And not only is it cheap and quite capable, but it is also small, low-power and it’s easy to work with and connect it to various interfaces: GPIO, I2C, SPI, RS232, PWM etc.

Here an example of the blinking LED in Lua:

gpio.mode(4, gpio.OUTPUT)
led4=0

function switchled4()
 if led4==0 then
  gpio.write(4, gpio.LOW)
  led4=1
 else
  gpio.write(4, gpio.HIGH)
  led4=0
 end
end

tmr.alarm(0,1000,1,switchled4)

This leds the LED connected to GPIO4 (internal numbering, just like Arduino does) blink. And here a link to an example which uses a web page with AJAX to toggle 2 LEDs.

All in all, there is no reason to NOT allow pretty much anything to be connected to your WiFi network.

 

Jan 292014
 
Cubietruck

Got a Cubietruck as a small (literally) and low power (really) server. Main purpose is to have an off-site backup so I don’t need to continue to use CrashPlan. CrashPlan is nice generally, but it has show-stopper-quality problems. And those are not being addressed at an acceptable speed.

The solution is: boxbackup at a friend’s house. In return I host his off-site backup. BaaS we’d call this nowadays: Backup-as-a-Service.

Resources

  1. A small Internet connected PC with a disk which should be available 24/7
  2. boxbackup-server running on it
  3. some 500GB disk space being available

Implementation

Get a Cubieboard 3. Get a 500GB 2.5″ SATA disk. Set up forwarding rules for the Internet-facing router.

Configuration

OS is on an SD Card. Debian Wheezy in my case. Instructions see here and here. Worked like a charm. If using the serial console (highly recommended), make sure this is in the uEnv.txt file:

root=/dev/mmcblk0p2
extraargs=console=tty0 console=ttyS0,115200 hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1280x720p50 rootwait pan
ic=10 rootfstype=ext4 rootflags=discard

Note the “console=ttyS0,115200” part: without it, there is no serial console available.

Next steps

  1. Connect 2.5″ disk to the Cubietruck with the supplied cables.
  2. Configure boxbackup-server
  3. Set up network connectivity to the remote backup (port forwarding, tunnel, etc.)
  4. Do a backup

 

Jan 152012
 
Programming AVRs - Part 2

I used to use the FT245R chip to program my AVRs but I was looking for something more comfortable. Like the Bus Pirate. Works great. No special configuration needed for avrdude. Simply say it’s using now a Bus Pirate and which USB port it shows at.

 

Update: It’s too slow, so I flashed the STK500v2 firmware, which means I tell avrdude I got an STK500v2. While it loses all the features of the real Bus Pirate, it’s magnitudes faster (and I have the AVR extended patches and updated the Bus Pirate firmware to 6.1, but it was still too slow for larger programs).

Jan 032012
 
More 16 Segment LED Fun

I continued to look for a 16 Segment Font, alas, there seems to be none. The best I found are two videos on YouTube. So I finally made my own one, and for the benefit of the world, here the code for all printable 96 ASCII characters:

#include <avr/pgmspace.h>

// Segment bit order is (MSB) A1 A2 B C D1 D2 E F G1 G2 H I J K L M (LSB)
const uint16_t uiCharacterMap[96] PROGMEM =
{
 // SPACE ! " # $ % & '
 0x0000, 0x0300, 0x0110, 0x0fd2, 0xddd2, 0x95db, 0x8eb4, 0x0010,
 // ( ) * + , - . /
 0x000c, 0x0021, 0x00ff, 0x00d2, 0x0001, 0x00c0, 0x0004, 0x0009,
 // 0 1 2 3 4 5 6 7
 0xff09, 0x3008, 0xec41, 0xdc48, 0x01d2, 0xcd84, 0x1fc0, 0xc00a,
 // 8 9 : ; < = > ?
 0xffc0, 0xf1c0, 0x8080, 0x8081, 0x0c09, 0xc0c0, 0x0c24, 0xe142,
 // @ A B C D E F G
 0xfe83, 0x3049, 0xfc52, 0xcf00, 0xfc12, 0xcfc0, 0xc3c0, 0xdf40,
 // H I J K L M N O
 0x33c0, 0xcc12, 0x3e00, 0x038c, 0x0f00, 0x3328, 0x3324, 0xff00,
 // P Q R S T U V W
 0xe3c0, 0xff04, 0xe3c4, 0xddc0, 0xc012, 0x3f00, 0x0309, 0x3305,
 // X Y Z [ | ] ^ _
 0x002d, 0x002a, 0xcc09, 0x8b00, 0x0024, 0x7400, 0x0120, 0x0c00,
 // ` a b c d e f g
 0x0020, 0x8e92, 0x0b82, 0x0a80, 0x0e92, 0x0a81, 0x40d2, 0x8992,
 // h i j k l m n o
 0x0382, 0x0a00, 0x0812, 0x001e, 0x0412, 0x12c2, 0x0282, 0x0a82,
 // p q r s t u v w
 0x8390, 0x8192, 0x0280, 0x0444, 0x04d2, 0x0e02, 0x0201, 0x1e02,
 // x y z { | } ~ DEL
 0x002d, 0x3450, 0x0881, 0x4492, 0x0012, 0x8852, 0x0128, 0x00ff
 };

Note the PROGMEM extra attribute which is helpful on a Harvard CPU like the ATmega are. Without it, the table will be copied and used in RAM. 192 Byte in total does not sound too bad, unless you use an ATmega168 which has only 1 kByte. To access this type of special memory, you need the include file and to access the array, a special function is needed:

a=pgm_read_word_near(&(uiCharacterMap[i]));

It’s all documented here. On a normal CPU (more RAM, no Harvard architecture) you would not bother.

I thought about adding “spinning things”, but those are trivial to make and I thus leave those as an exercise to the reader.

Nov 232011
 
EAGLE - First Impression

EAGLE is probably the most common software used for PCB creation. Many years ago I saw a professional using it on DOS. Looked good and not simple at all. Back then creating PCBs was quite expensive too, so I never thought about making them myself. For most of my purposes a breadboard works well enough. For a bit more permanent things I have those which is just the same layout and connections, but for soldering.

For a bit more complex things though the problems of breadboards become an issue:

Distressing as it may sound, solderless breadboards can be very flakey, especially as they age. If you’re having problems with your circuit, it could be that the little metal clips on the inside aren’t working well. Try poking it with your finger, or moving it to a different section.

It’s still great for small tests, but for permanent things, expect a  low reliability.

Anyway, for a large clock using those quite large 16 segment LEDs, breadboards don’t work well: a single digit is too large and needs 2 breadboards, with some gap between. The next digit will have a lot of gap between the previous digit. All in all, not optimal.

In the end, and because that clock will be permanent, some soldering is needed. Soldering without PCB is not fun: lots of burned fingers, a messy layout and errors are my experiences. A PCB would be sooo much nicer.

Enter the world of low-cost PCB manufacturing. The low price is done by merging small PCBs onto one larger one, which splits the setup costs by many users. In the end, a 5cm by 5cm board with 2 layers of copper, solder stop mask, silk screen is amazingly US$10. Larger ones get a bit more expensive, but it’s still cheap. And I get 10 boards. There is some extra delay of course as all those small boards needs to get pooled to one large PCB.

What does it have to do with EAGLE? EAGLE is the program which is recommended to create the PCBs from. Other programs work too (e.g. KiCAD), but most tutorials are for EAGLE and most services can handle EAGLE files, either directly or indirectly. EAGLE also runs on Linux.

So I downloaded EAGLE v5.1 as

aptitude install eagle

did not work.

And then the steep learning curve of EAGLE started. At first I could not do anything at all; this is an old program and it shows: hardly anything works as expected. This tutorial helped me to get started. It stops where the layout starts though, so here my additions:

  • If you want to fill a plane (e.g. with GND), make a polygon on the board layout of where you want it. RMB (right mouse button) will show the properties of it. Add Isolate to have a distance from signals. 0 is a stupid default value.
  • Use the name command (RMB on the polygon) to merge it with the GND signal (of whatever signal you want to have connected).
  • To start the autorouter, click on the autorouter button (yeah, it sounds very straightforward). Any signals which could not be connected will be air-wires (thin yellow lines).
  • To rip up one trace, use RMB and delete.
  • To rip up all traces, click on the ripup button, then on the go icon (the traffic light next to the STOP icon).
  • Click on ratsnest to see the polygon being poured.
  • It’s fun to watch the autorouter on slightly complex layouts. If your design is complex or space is too limited, you might end up with some air wires. Try to relocate some components.
  • The rules file document dictate what the manufacturer can do. E.g. available drill sizes or capabilities like thinnest possible traces etc. The default values are quite conservative. To load, click on Edit/Design rules and load the rules for your service.
  • The CAM file creates the layers (copper per layer, silk screen, solder stop masks). It creates all the needed Gerber files.
  • gerbv is a nice utility to display those created Gerber files layer for layer. Use it recommended. While you’ll unlikely stop small errors (e.g. a single traces missing), you’ll find layers completely missing.
  • Never only open schematics or board view. Always have both open, as otherwise you create inconsistencies which are not fun to manually fix. As long as both are open, any modification on one window will update the other one.
  • The free version of EAGLE is limited to 8cm by 10cm and 2 layers. Good for small stuff. For hobby use (non-commercial) you can get the standard edition (10cm by 16cm, 6 layers) for modest US$125. I doubt I’ll need those capabilities, but if I do, I know there’s a cheap upgrade path.
TODO on my side:
  • Understand the bus feature. That will clean up the schematics a lot.
  • Name signals
  • Create library items (e.g. for the MCP23017 I found no usable library so I had to use a generic 28 pin DIL socket with no proper names and no knowledge of what is input or output or GND or Vcc.
Oct 012011
 
16 Segment LED

16 Segment LEDs are (obviously) somewhere between 7 segment LED and graphical displays. Quite micro-controller friendly as they do not need a lot of memory or CPU performance or external hardware, but they look better and can display the full range of alphanumerical characters.

For those using these type of displays, a lot of time is spent trying to find “bitmap” data for characters. Some special ICs contain those already, but that I have none of those. After searching for font data and coming up empty-handed, I created my own:

// Segment bit order is A1 A2 B C D1 D2 E F G1 G2 H I J K L M

const unsigned int uiCharacterMap[0x40] =
	{
//	0	1	2	3	4	5	6	7   8   9
	0xff09, 0x3008, 0xec41, 0xdc48, 0x01d2, 0xcd84, 0x1fc0, 0xc00a,	0xffc0, 0xf1c0,
	0x7712, 0x3300, 0x6742, 0x7740, 0x3350, 0x5750, 0x1752, 0x7300, 0x7752, 0x7350
};

Those are digits 0 to 19 (yes, not just 0 to 9). Unfortunately 20 does not work, and neither do 22 or 23. Here a video of the 20 numbers: http://www.youtube.com/watch?v=pI8WTVAadiA