Sunday, October 5, 2014

Speed up screen redraws with a BeagleBone Black and Adafruit TFT

In a previous post I wrote about experimenting with the BeagleBone Black and an Adafruit 2.2" TFT screen. The TFT screen communicates over SPI using a userspace library. Being a userspace library it is expected it will be slower than driver that is compiled into the kernel but something in the code seemed to be causing redraws to be unnecessarily slow.

Adafruit 2.2" TFT with a BeagleBone Black
To measure how long the screen draws were taking I modified the example image.py script to read the time right before and right after the screen draw function call. I also wrapped a while loop around it so it would redraw the screen repeatedly to give me an average of how long it took.

Code to measure screen redraw time

Depending on how much of the screen was being redrawn and the load on the BBB it would take between 0.7 seconds to 0.9 seconds to execute the disp.display(image) function. The following output is for the example image.py that draws the cat.jpg file to the screen:

Output measuring screen redraw time

One of the commenters on my previous post tracked down the slowness to one specific function named 'image_to_data' in the file ILI9341.py. He also supplied a modification that reduced his screen redraw time dramatically by using NumPy. I tried it out and it reduced my screen redraw times dramatically. Screen redraws went from 0.85 seconds to 0.17 seconds. That is an 80% improvement!

Screen redraw times when using NumPy

If you want to make this modification yourself here is what you need to do:

1. Install PyNum. This is easy to install as it is available as a pkg.

Install the python-numpy package


2. Edit the file Adafruit_Python_ILI9341/Adafruit_ILI9341/ILI9341.py

First add the import statement at the top

Add import statement for numpy

Next modify the image_to_data function. Here is the original function

Original image_to_data function

and here is the function after being modified to use NumPy

Modified image_to_data function

3. Save the file and then re-run the installation script.



If you don't want to manually make these modifications you can use my forked version of the library: https://github.com/matt448/Adafruit_Python_ILI9341

I have submitted a pull request to Adafruit for this change so maybe in the future this will be included there. [UPDATE: Adafruit has pulled these changes into the master branch of their library. If you download the latest version here https://github.com/adafruit/Adafruit_Python_ILI9341 you will get the improved screen drawing speed.]


Here are videos before and after I made the change. It's quite noticeable when making quick changes. Before making the code changes the display would lag behind when adjustments were made to the pot.
BEFOREAFTER



[Updated 2014-10-08: Added before and after videos.]
[Updated 2015-03-11: Added note about my pull request being included in the main library.]


Thursday, September 25, 2014

Using the Seeed CAN-BUS shield with an Arduino Mega


The Seeed Studio CAN-BUS shield is designed specifically to be used with an Arduino Uno but with a simple modification you can use it with several other Arduino boards. I sourced this info from a few different forums and thought I would write up a complete post on exactly how to do this. The Seeed website had some info on how to use the shield with a Mega but their info was not complete and did not work for me. In this post I am going to show how to use the Seeed CAN-BUS shield with an Arduino Mega 2560.

The CAN-BUS shield incompatibility with Arduino boards other than the Uno arises from where Seeed chose to access the SPI pins. They used pins 11,12,13 to access SPI on the Uno. On the Mega the SPI pins are 50,51,52. A better design would have been to use the SPI pins on the ICSP header which is consistent on the Uno, Mega, Due and Leonardo but such is life and we have to work with what is available right now. Seeed's site does mention they are working on a 1.1 version of the board that moves SPI to the ICSP header.

Here is an Arduino Uno with the SPI pins labeled
Arduino Uno SPI pins


And here is an Arduino Mega 2560 with the SPI pins labeled
Arduino Mega 2560 SPI pins


Here is what the Seeed Studio CAN-BUS Shield looks like if you don't already own one
Seeed Studio CAN-BUS Shield v1.0


The mod

Here is how to modify the CAN-BUS Shield to work with a Mega. The basic overview of the mod is that we need to change the SPI pins that the CAN-BUS Shield is using. There are two ways to do this modification. One one is reversible and the other is more permanent. First the reversible method.

The reversible method is to bend three pins on the CAN-BUS Shield like this:


When you plug the shield into the Mega it will look like this:


With bent pins I was able to bend them back use the shield with an Uno again.

Now you need to use three jumper wires to connect the SPI pins on the shield to the SPI pins on the Arduino board. In my example I connected the wires to pins 50,51,52 on the Arduino because I only had male-male jumper wires. If you have male-female jumper wires you can connect to the ICSP header instead.

Jumper wire connections
Mega Pin Shield Pin SPI Desc
50 12 MISO
51 11 MOSI
52 13 SCK


Here is what it looks like with the jumper wires installed




I would recommend you use coryjfowler's MCP2515 library instead of the Seeed's because his fork of the library has a configureable SS pin but Seeed's version will work with this mod because they hard coded the SS pin as digital pin 10.

I then loaded up one of the examples and the shield started up correctly.


If you want to make this modification more permanent you can simply snip off the three pins instead of bending them.



I found some male-female jumper wires at Fry's Electronics yesterday. Here is what it looks like when using the ICSP headers


ICSP Pin Shield Pin SPI Desc
1 12 MISO
4 11 MOSI
3 13 SCK


Sources
http://arduino.cc/en/Reference/SPI
http://forum.arduino.cc/index.php?topic=123367.0
http://www.seeedstudio.com/forum/viewtopic.php?f=23&t=5172
http://www.seeedstudio.com/wiki/Talk:CAN-BUS_Shield
http://www.seeedstudio.com/wiki/CAN-BUS_Shield


[Updated 2014-09-29] - Added photos of shield with the pins snipped off. Also added photo showing the male-female jumpers with the ICSP header.

[Updated 2014-10-23] - Added table with pinouts for connecting the shield to the ICSP header.

Friday, September 19, 2014

Trouble installing PyCrypto on Mac OSX 10.9


This afternoon I was trying to install the PyCrypto Python library on my Mac running OSX 10.9.4 with the built in Python. To install the library I was using the command 'sudo pip install pycrypto' but it kept failing when trying to compile parts of the library with the C compiler. This is the error I was getting:

checking for gcc... gcc

checking whether the C compiler works... no

configure: error: in `/private/tmp/pip_build_root/pycrypto':

configure: error: C compiler cannot create executables

See `config.log' for more details

Grrr... I searched around and read a bunch of stackoverflow questions but it seemed like I had everything in place that I needed to compile this library. Xcode was installed, I have the Command Line Tools installed, I have a recent version of pip installed. Why won't the C compiler work??

Well the answer turned out to be something really dumb. I recently updated Xcode but I had not launched the Xcode application since it was updated. Turns out the command line C compiler won't compile anything until you accept the license agreement for the updated Xcode. I opened the Xcode gui and clicked Accept. After that I was able to install PyCrypto. I also found you can accept the agreement from the command line using the command 'sudo xcodebuild -license' but you have to page through all the text and type agree.



Friday, September 5, 2014

Experimenting with BeagleBone Black and a userspace TFT library

This post is part of a series of posts I have done about the Adafruit 2.2" TFT display. You can check out those previous posts here and here. In those previous posts I was using this display with an Arduino and ran into issues with the refresh rate. To get a decent refresh rate I had to do some extra coding to determine what data needed updating and then only redraw the sections of the screen that actually needed to change. In this post I am going to take a look at using this display with the BeagleBone Black single board computer. My hope going into this is that the CPU horsepower of the BBB will allow quicker screen redraws which would eliminate the need to selectively redraw sections of the screen.

Since the BBB is a full computer there is a Linux operating system sitting between the code and the hardware. This quite a bit different from an Arduino where you have direct access to the hardware. My BBB came with Angstrom Linux on it but I am more familiar with Ubuntu and the Adafruit tutorials were written assuming you have Ubuntu installed. So I swapped the OS to Ubuntu 14.04 following Adafruit's tutorial. To control the TFT display with a BBB Adafruit created a user space library in Python. To install the library and wire up the display I followed the instructions on learn.adafruit.com. The instructions were written for the 2.8 inch display but they worked just fine for my 2.2 inch display. I think these instructions would probably work for most ILI9341 based TFT displays.

The wiring for the 2.2" display is slightly different than the 2.8" display. Here is how I wired it up.

  • BeagleBone Black SCLK pin P9_22 to TFT SCK.
  • BeagleBone Black MOSI pin P9_18 to TFT MOSI.
  • BeagleBone Black CE0 pin P9_17 to TFT CS.
  • BeagleBone Black pin P9_12 to TFT RST.
  • BeagleBone Black pin P9_15 to TFT D/C.
  • BeagleBone Black 3.3V power pin P9_3 to TFT Vin.
  • BeagleBone Black ground pin P9_2 to TFT GND.

Then I ran the sample image.py application to make sure everything worked correctly



Now that we have all that stuff out of the way let's get to the real point of this post, how fast can the BBB update this display! To test it I took one of Adafruit's example scripts that came with the library and modified it so it read the value of an analog pin (P9_40) and then display that value on the TFT screen with a custom font. I connected a 10k pot to the analog pin so I could adjust the value.

The first time I ran the test script I ran into problem with the bottom the text being clipped off. Turns out it was a bug with a Python library. I detailed the fix for that here.

In the script I also recorded a time stamp before drawing the TFT screen and immediately after to measure how long it took to actually draw the screen.

Here is a video of the testing



If you made it to the end of the video you saw that it was taking approximately 0.6 seconds for the draw command to complete but the screen itself appears to update nearly instantly. This is a huge improvement compared to when I tested this display with an Arduino. On the Arduino you could see the screen slowly painting the image onto the screen.

Here is a video of the same exact test with an Arduino:



I'm not sure what is taking 0.6 seconds with the BBB. The screen redraws seem to happen faster than that. Maybe it's the data transfer over SPI plus the screen redraw (Update: See this post to learn how to speed up the redraws). In any case I am quite pleased with it. Another advantage of using the BBB is I'm able to use any TrueType font to display text. The library on the Arduino only had one font which became very blocky when using large characters. As you saw in the first video I used an Arial font which looked very smooth.

I originally wanted to use this TFT display for my speedometer project but abandoned it for a 7 segment display because the refresh rate was so slow with the Arduino. Based on these BBB results I think I'm going to make a v2.0 digital speedometer using both an Arduino and a BBB. The BBB isn't great at doing real time things like counting pulses so I think I will continue to use the Arduino to count the VSS pulses and then feed the speed data into the BBB over I2C or CAN. I'm already brainstorming other data to display on the screen...

Oh here is the python code I used to test this display if you are interested:





Helpful Links

https://learn.adafruit.com/user-space-spi-tft-python-library-ili9341-2-8/
https://learn.adafruit.com/beaglebone-black-installing-operating-systems
http://elinux.org/Beagleboard:Ubuntu_On_BeagleBone_Black


[Updated 2014-09-05]
This is in reference to my statement about about the BBB not being great at real time tasks. I've been doing some reading and the BBB does have a hardware counter on it but it looks like you have to be a NASA engineer to get it to work. This post discusses the PRU on the BBB. When he started talking about having to write Assembly code I tuned out. I'll just use an Arduino to do the accurate pulse counting, thanks.

[Updated 2014-10-04]
Added Fritzing wiring diagram and pin outs.

[Updated 2014-10-08]
Added link to post that shows how to speed up display redraws.



Monday, August 25, 2014

Font issues with BeagleBone Black and ILI9341 TFT display

In my continuing quest to build a really cool digital speedometer for my car I have been experimenting with an Adafruit 2.2" color TFT display. This past weekend I loaded up Ubuntu 14.04 on my BeagleBone Black and wired up the TFT display to it. Adafruit has a python library that works on both the BeagleBone Black and a Raspberry Pi. After trying out the example code I decided I wanted to try using a nicer font than the default one in the example code. The first font I tried seemed to look fine but the second font I tried had the bottom third of the characters not displayed. To figure out which fonts were affected I wrote a python script that cycled through displaying a bunch of fonts on the screen. Here is a video of the results:


As you can see some fonts are affected more than others. A few have over half the line cut off. I started digging into the code that displays the text. I figured out the code is determining the height and width of the text and then turning the text into an image to be displayed on the screen. This is done so text can easily be rotated on the display.

Line number 17 in this snippet of code is where the height and width is determined before making the image.
The Adafruit library is using PIL (Python Image Library) to create an image from the text. Ubuntu 14.04 actually uses a fork of PIL called Pillow. I did some google searches and discovered that the textsize function has a bug that does not account for the font offsets which causes the clipping on some fonts. The Ubuntu 14.04 I installed on my BBB came with Pillow 2.3.0 which was broken. I updated it to latest available package which was Pillow 2.5.3 and it was still broken. I looked at the bug fix on the master branch of Pillow and it was just a small change to one file, PIL/ImageFont.py, so I decided to apply that change to my 2.5.3 install of Pillow.

Here is how I fixed it.

cd /usr/local/lib/python2.7/dist-packages/PIL
sudo vi ImageFont.py

At about line 142 look for the getsize function. Here is what it looked like before the change.




And here it is after the change.


Save the file and then you need to compile it into python byte-code.
sudo pycompile ImageFont.py

This creates an ImageFont.pyc file. Now to test it again.



All fixed! I'm sure that fix to getsize will be pushed out soon so this won't be a problem in the future but until then this will let me continue my experimentation.



Thursday, August 7, 2014

Arduino - TFT LCD display refresh rate part 2

Since January I have been thinking about how to reduce the flashing effect of redrawing characters on the Adafruit 2.2" TFT display running off of an Arduino. Initially I thought I was doing something wrong but then I saw that other projects experience the same slow screen redraw performance. This post isn't about rewriting/optimizing the ILI9340 library that talks to the display. I'm not a good enough programmer to even think about digging into that code. Also I don't think it really is a problem with the library or the display itself. I've seen videos with this display hooked up to a Raspberry Pi smoothly playing video files. I suspect the limitation is the CPU and/or RAM of the Arduino. For my speedometer project I wanted to use an Arduino because it starts up almost instantly and I don't have to worry about shutting it down which is not the case with a Raspberry Pi.

So my goal was to optimize the refresh rate by reducing the amount of screen redraw to the smallest amount possible. To do this I first draw the static elements on the screen (the red box and the mph text). These are never redrawn. Redrawing static items causes a flashing effect. Then the speed value is only updated if it changes. When it does change only digits that have changed are redrawn. For example say the speed is 35 mph and then on the next loop the speed is 36 mph. The 5 would be drawn over with black and then the 6 is drawn in white. This performs the least amount of screen drawing possible.

Here is a video of the progress so far. The code is below the video.



Here is the code


Thursday, July 31, 2014

LED light up bicycle

The city of Round Rock, Texas has an annual night time bike ride event at the end of July. It starts at 9pm with a ride through the downtown area to a city park where they have music, free hotdogs and free shaved ice. After the event everyone rides back to the starting point. It sounded like fun to me so I decided I wanted to participate along with my two older kids. As the event approached I started to think it would be fun to decorate my bike for the event. I didn't want to spend much money because this was going to be a pretty temporary thing. I started scrounging my plastic storage bins of electronics for parts. I found a 12 volt LED light strip that had originally been purchased to be used as under cabinet lighting (which I never installed). I had an old unused UPS battery backup that came with our AT&T Uverse service. I tore that UPS open and found a nice 12 amp hour SLA battery. I also had four extra TIP120 transistors and an Arduino Uno. Seemed like enough ingredients to make something cool.

I started by measuring how many amps the full strip of LED's drew at full brightness. It measured 1.3 amps so the battery should give me about 9 hours of run time between charges which is obviously more than enough for a long night ride.

The spool had just enough LED's to light up each of the tubes of the frame on both sides of the bike. The LED strips have a cut line every three LED's. I cut the LED strips into sections that would fit each of the tubes on the frame of my bike.


Then I soldered power and ground leads onto each of the strips and covered the connections with heat shrink.



I attached the LED strips to my bike using zip ties and black electrical tape.


Next I wired up the TIP120 transistors on some scrap proto board. I soldered on a row of right angle headers so I could plug the Arduino right onto the board. Please keep in mind I was just throwing this together at the last minute so it isn't very pretty. The only real goal was to make it fit on top of the battery and stay out of my way while pedaling the bike. I used a scrap barrel connector pigtail for the main power to the board and another to power the Arduino. I added a 12 volt regulator to the Arduino power circuit because the battery was putting out a little over 13 volts and I didn't want to damage the voltage regulator on the Arduino. The transistors connect to four different LED segments and are controlled by four PWM digital pins on the Arduino. I used a different color wire for each transistor and LED segment so I could keep track of them when I wrote the software for animating the segments.


The transistor circuit is very simple. The TIP120 isn't the best way to do this but I had them laying around. A N-channel Power MOSFET is better for this because it can handle high amperage without generating heat. 

Example of TIP120 used with an Arduino.
Image taken from here


I couldn't wait anymore to see what the bike looked like in action so I just taped the battery to the frame and took it out for a quick test ride. At this point the Arduino software just faded the LED's to full brightness and didn't do anything else.


Now I turned my attention to making a proper mount for the battery. I wanted to make sure the battery was mounted solidly so it didn't fall off the bike when I hit a bump. I started with an old L bracket I had laying around the garage and drilled some holes in it so it matched up with the water bottle mounts on the seat post tube of the bike. I bent the L bracket down a bit so the battery would sit level on the bike. Next I took a piece of scrap sheet metal and created a short metal box for the battery to sit in. I made another tab out of sheet metal so the battery box could also bolt to the other water bottle mount on the down tube. I spot welded everything together and ground down the welds on the battery box so it didn't scratch or cut my legs while pedaling.


After the welding and grinding was all done I mounted the battery box on the bike.


I did a test fit of the battery and it was a little loose in the box but I had planned on putting something on the top edge of the sheet metal to cover any sharp edges.


I scrounged around the garage a bit more and found some extra automotive vacuum tubing. I made a slit down the entire length of the vacuum tubing and then pushed it on the top edge of the battery box.


Now the battery fit very snug in the box.


Next I made two velcro straps out of 1" webbing. I cut the webbing to length and sewed on some velcro with the sewing machine. These straps will hold the battery in box.


Here is the battery with the straps in place and then the control board installed on top of the battery.


Here is how the overall bike looks with everything installed.


The last thing I needed was some way to charge the battery. I searched around on Amazon and found this SLA battery charger. I paid about $18 US dollars for it. It has an automatic shutoff once the charging is complete. It only comes with screw terminals so I had to make my own cable. I used yet another barrel connector and some 18 gauge wire to make a cable. (seriously how many barrel connectors can one person have? I may have used up my stockpile on this project.) I triple checked the polarity of the connecters on my charger and my battery with the voltmeter and then charged up the battery.


I finished writing the code for the Arduino the night before the event. Here is a video showing the animations. Since I only had four TIP120 transistors I could only control four sections of the LED's. The fork and the seat tube just stay on full brightness.




Here are my kiddos at the starting line a few hours before the event.


The night ride event was really fun and my kids enjoyed the ride. I'll go ahead say I had the coolest bike at the night ride. This bike has inspired me to get some exercise and I have been riding about 4 miles every night since the event. Maybe for next year's event I will step up to some Adafruit NeoPixels.