Countless times, I told my processor: "Slow the freak down!"

The easiest way to get started with a processor is writing a small program to blink a led. This can be done with some easy lines, switch the led on, delay 1 second, switch the led off, delay 1 second, and loop that forever.

Some starter-friendly processor like Arduino (well, technically, AVR) comes with an already-made, easy to use delay function, which is part of the friendly Arduino IDE. But, for example, the STM32 family does not have those luxuries built-in.

When I was new to the STM32 family, I was very frustrated every time I need a delay function. And recently, when I need a sub-millisecond delay function, I need to delay some microseconds, it took me quite some time to find an effective way to have one. So, I set out to compose a delay library, with all the delay functions I would ever need.

I take no credit for these codes. Some of them, I wrote them myself. But some, I take the ideas from various sources on the internet. Just like the writers of those code, who share them freely and publicly, I share my delay library here with the hope that someone will find it useful, that it would saves someone time when he look for these functions. You can use these in whatever way you want.


Remember to include the right "stm32fxxx.h" file in the "delay.h". Now, some quick words about the functions.

I configure SysTick Timer to trigger an interrupt every millisecond. Remember to call "SysTick_Init()" in your config code (before the main loop). From my experience, it is highly recommended to leave your SysTick Timer at 1kHz (1 trigger per ms). Having SysTick interrupt every 1 us could literally grind your processor to a halt. The interrupt handler "SysTick_Handler" is also in the file "delay.c".

"delay_ms(n)" and "delay_us(n)" are self-explained. AFAIK, the most effective way to delay some microseconds is to use a loop of assembly code.

Since I really like Arduino's "millis()" function, I get my own version here. Calling "millis()" will return the milliseconds that have passed since the SysTick Timer is configured.

And since I usually write my code to do a particular task periodically (every 100 ms, for example), I write a function called "on_period(old_millis, period_ms)". This functions will return 1 if period_ms ms have passed since old_millis, and the return value is 0 otherwise.

Example code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int main(void)
{
    SysTick_Init();
    while (1)
    {
        // Toggle led every 1 second
        toogle_led();
        delay_ms(1000);
    }
}

Example on how to plan your periodical tasks. This is like a simple task scheduler. Your program will only run tasks at specified intervals. No wasting time sitting on delay functions doing nothing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main(void)
{
    SysTick_Init();
    while (1)
    {
        // Call toggle_led every 1 second
        toggle_led_task(1000);
        // Another example task which will be executed every 70 ms
        another_task(70);
    }
}

void toggle_led_task(uint16_t period)
{
    // Remember that old_millis need to be static
    static uint32_t old_millis = 0;
    // old_millis will be updated if on_period return 1
    if (on_period(&old_millis, period)
    {
        toggle_led();
    }
}

Make your debugging life easier with preprocessor marcos

These tips maybe useful for you when you need to debug your code without a real debugger. Typically, you will push variables's value to some displays such as the console on Windows/ Linux or the "Serial monitor" on Arduino. And when you don't want to see those outputs anymore, you delete those "cout"/ "print" lines, or better to comment them out.

You can save yourself from manually comment/ uncomment those lines (maybe scattered all over the place) repeatedly. Simple put this at the start of your source file:

1
#define DEBUG

And wrap your debugging lines with this:

1
2
3
4
5
6
7
#ifdef DEBUG
...
Serial.print(x);
or ...
cout << x << endl;
...
#endif

From now on, you can quickly toggle debugging output by comment/ uncomment the #define line.

There's also the inverted version. For example, only output PWM to motors when not debugging:

1
2
3
#ifndef DEBUG
motor_set(pwm)
#endif

You can have as many flags as you want. 1 flag for each module, 1 flag to toggle timing function execution...

1
2
3
#define DEBUG_SPEED
#define DEBUG_POSITION
#define TIME

You can also execute "or" operation. For example, on Arduino, we need to enable Serial to push out debugging values:

1
2
3
#if defined(DEBUG) || defined(TIME)
Serial.begin(115200);
#endif

Hope these tips can help you.

Headless Hard-float BeagleBone Black - Part 2: Installing LXDE Desktop and Autostart VNC Server

Welcome to Part 2 of my guide on "Headless Hard-float BeagleBone Black". Make sure you did not miss Part 1: Installing Hard-float Ubuntu.

Let's get started. Why do we need to install LXDE Desktop? Well, armhf ubuntu only comes with terminal interface, and for some applications, you need a Desktop GUI. Ubuntu have its default Desktop (Unity), but it's too heavy. You can't fit ubuntu with its desktop on BBB's eMMC. And even on spacious uSD card, the GUI is too slow to provide acceptable user experience. If I remember it right, clean armhf ubuntu takes about 300 MBs, and LXDE takes another 300 MBs, so you will still have more than 1 GB for other stuff (most likely dependencies for development).

Make sure your BBB is updated and upgraded before proceeding:

1
2
sudo apt-get update
sudo apt-get upgrade

Those 2 commands will do the job. Now, to install LXDE, type:

1
sudo apt-get -y install lxde lxde-core lxde-icon-theme

You can skip the "-y" if you want to confirm the installation yourself. After it's done, reboot. If you have a monitor, you can connect it to BBB and you're greeted by LXDE log in screen.

With LXDE install, we will go on and install an autostart VNC server. First, you need x11vnc server:

1
sudo apt-get install x11vnc

Use this command to start VNC server:

1
x11vnc -bg -o %HOME/.x11vnc.log.%VNCDISPLAY -auth /var/run/lxdm/lxdm-\:0.auth -display :0 -forever

Then use a VNC viewer to connect to your BBB. If you haven't got one, you can try this.

Now, we want to setup your BBB to run that command every time it boots. Luckily, LXDE makes this very easy. Use your favorite text editor to edit /etc/lxdm/LoginReady with root privilege. The easiest way is to use WinSCP, connect to your BBB as root, navigate to that file and open it. You are now editing it on your friendly Windows environment. Just copy and paste the command:

1
x11vnc -bg -o %HOME/.x11vnc.log.%VNCDISPLAY -auth /var/run/lxdm/lxdm-\:0.auth -display :0 -forever

at the end of LoginReady and save it.

Some explanations:
  • LXDM's LoginReady is a shell script file, and it will be executed with root privilege when LXDM is ready to show the login window.
  • The flag "-forever" in the VNC server command is to tell the server to not go down. Without that flag, your VNC server will accept the first connection. And when that first client disconnect, the server is shutdown too (just the VNC server, not your whole BBB). 

Headless Hard-float BeagleBone Black - Part 1: Installing Hard-float Ubuntu

Hi everyone! This time, I want to show you how to get a headless hard-float BBB running. These steps are the actual steps that I did to get my BBB working. As usual, if you have any question and/or suggestion, please let me know.

In this post, I will refer your Windows powered desktop/laptop as "Host", and BBB as "Kit". Of course you could use a Linux powered host, but my steps here are for Windows.

What is headless and why? Headless means you run your kit without a monitor, even without mouse and keyboard. Why do we want to do this? The first benefit is that we don't need another monitor, another mouse, and another keyboard. And the most important benefit is that we can use our current mouse and keyboard, to control the kit via a window on out host (as a regular program), which helps multitasking easier.

What is hard-float? Our kit have powerful floating-point capability. In order to fully utilize that power, you need to compile your programs with "float-abi=hard" flag. The Angstrom distribution that comes with the kit DOES support hard-float, but you have to change some settings, see this thread for more details. The easier way to fully utilize hard-float is using armhf-ubuntu. Those images are prepackaged with hardware floating point enabled and are easy to install. One more important benefit of armhf-ubuntu is that libjpeg-turbo is the default libjpeg. You could find more information about libjpeg-turbo and why we want it.

OK, let's get started.

Get an image from here. I used Ubuntu 12.04 LTS image, and you should also use this if you want to install LXDE (more on this on Part 2). You should read the instruction on armhf page too, but I will also give detailed step-by-step to install Ubuntu 12.04 LTS on your kit's eMMC. If you follow armhf's instruction to install to eMMC, you will use your host to install ubuntu to your uSD card, then while running on uSD card, install ubuntu to your eMMC

And now, my steps to directly install ubuntu to your eMMC. You need 7-zip, and SDFormatter.

  • Download "ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img.xz" (~65MB) from armhf
  • Use 7-zip to extract it, you will get "ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img" (~1.78GB)
  • Use SDFormatter to format your uSD card, default settings are good
  • Visit http://elinux.org/BeagleBone_Black_Extracting_eMMC_contents, read it, get the zip, do as instructed there. But change the autorun.sh to:

1
2
3
4
5
#!/bin/sh
echo timer > /sys/class/leds/beaglebone\:green\:usr0/trigger
dd if=/mnt/ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img of=/dev/mmcblk1 bs=10M
sync
echo default-on > /sys/class/leds/beaglebone\:green\:usr0/trigger

  • Copy the extracted image ("ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img") to the root of uSD card
  • Insert uSD card to kit and boot kit up, the script will install ubuntu to your eMMC
  • Once it's done, poweroff the kit (disconnect power), remove uSD card and reconnect power to boot it up
Now you have fresh ubuntu 12.04 installed on your kit. Use PuTTy, connect to your kit, username & password is "ubuntu" (without quotes, of course). The first thing you want to do is setting a root password:

1
sudo passwd

Then update your installation:

1
2
3
sudo apt-get update
sudo apt-get upgrade
sudo apt-get clean

The last command, "sudo apt-get clean" is to delete download cache, to regain precious disk space on your kit.

Starting a new life with embedded linux system

I am a long time Windows user, and I have just started playing with embedded linux system. It's like having found a whole new world, too many new concepts, too many new "ways" to get things done. I have had a hard time getting started, so now I want to share some apps that make my life with embedded linux easier.

All of the apps I share here are free. And this post is based on my experience with BeagleBone Black, but it should be applicable to most embedded linux system.

What you have just bought is a tiny computer, like the credit-card-size BBB. And having another set of monitor and mouse and keyboard to work with it is not convenient. Those embedded computer could be operated headlessly with no difficulty. Just a power cord and a LAN cable then you're good to go.

First of all, you need a SSH terminal to connect to your embedded system's SSH server. BBB come with Angstrom installed on it, and Angstrom has both a GUI desktop and a SSH server. Many people, including me, then install Ubuntu onto BBB. Ubuntu doesn't come with a GUI desktop, but still has SSH server installed. So basically, it's a good chance that your embedded system comes with a SSH server. My recommendation here is PuTTy:

Figure 1: PuTTy main screen
And once you got yourself a terminal to your embedded system, you can do literally everything with your new system. For example, install a GUI desktop and a VNC server. If you plan on using GUI on your embedded system, then VNC is the solid way to go. You can read more about VNC here. You can also download a VNC Viewer. Basically, VNC lets you see your embedded system's GUI desktop in a window, and you can control your embedded system with your mouse and keyboard, just as you are working with a windows app:
Figure 2: My BBB's LXDE desktop as a window on my Windows PC
We had terminal access, we had remote desktop control. Now, we need a way to quickly transfer files from/to our embedded system. Linux systems has a very strong command: scp. It allows computers to exchange data easily and securely over network. And now, we can use scp on windows, with GUI thanks to WinSCP:

Figure 3: My PC's C:\ drive and BBB's root in WinSCP window
With PuTTy, VNC and WinSCP, you can easily manage your embedded system.

A special note here for my fellow BBB users. If you want to backup/restore your embedded system (before trying something messy, or recover from disaster), you can use this script. It save my day countless time.

You may also want to give VirtualBox a look. A linux PC (or at least a virtual linux machine) will help you tremendously when dealing with embedded linux.

And if you need to deal with some disk format that windows doesn't support like ext2, ext3, ext4, ... you may need MiniTool Partition Wizard Home Edition.

If you have any correction and/or suggestion, please feel free to let me know.

An updated guide to get hardware-accelerated OpenCV on BeagleBone Black

If you're interested in BBB and OpenCV, you must have known Michael Darling's guide. Seriously, if you have not read it, go read it please to understand the hard works that people have done to make our life with BBB much much easier. These two blog posts about BBB and OpenCV are also very interesting [1] & [2].

That guide is dated to September 24, 2013. Since then, many things have changed, and fortunately, things are much easier now. I will point out steps that need to be changed from the guide (due to links changes, sources changes, ...). I will also include some steps that I hope will make things easier new comers.

My steps assume that your main operating system is Windows.

This is is intended to be used side by side with Michael Darling's guide. Michael Darling wrote a really excellent guide, I just want to update and add some steps.

You have to install Ubuntu onto your BBB. Go to here, I recommend getting Ubuntu Precise 12.04. I also recommend flash it directly to your eMMC, as your eMMC is much faster than any uSD card. You can do that by:
  1. Download ubuntu-precise-12.04.3-armhf-3.8.13-bone30.img.xz to your desktop
  2. Extract it (you need 7-zip, it's a free and very powerful archive manager)
  3. Copy it to the root of your uSD card
  4. Go to here, download it, and do as instructed to perform flashing
We need to install dependencies, tons of them. Make an "install.sh" file with the following content is the easiest and most automatic way to do so:

1
2
3
4
5
6
7
sudo apt-get -y install build-essential checkinstall cmake cmake-curses-gui pkg-config yasm
sudo apt-get -y install libtiff4-dev libjpeg-dev libjasper-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libxine-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev
sudo apt-get -y install python-dev python-numpy
sudo apt-get -y install libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev
sudo apt-get -y install x264 v4l-utils ffmpeg
sudo apt-get -y install libgtk2.0-dev

And one tip for you, doing "sudo apt-get clean" after installing packages will clean the download cache and free up disk space (it can free 200-400MB, which matters much on BBB).

Recently, libjpeg-turbo have been choose to be default libjpeg-dev package for armhf distro, so you don't have to built it from source like in the guide.

I highly recommend doing this step. Building OpenCV on a single core ARM board takes 3-4 hours and will make your little ARM CPU hot as hell. Setting up distcc and configure OpenCV correctly, we can build it in 15 minutes, and BBB CPU is not even warm.

About the compiler, you can use the one in the guide, version 4.8-2013.08 or use the updated here.

The new commands for installing distcc are:

1
2
3
4
wget https://distcc.googlecode.com/files/distcc-3.1.tar.bz2
tar xjf distcc-3.1.tar.bz2
cd distcc-3.1
./configure --with-gtk --disable-Werrormakesudo make install

Get a USB flash drive, and use MiniTool Partition Wizard Home Edition (free) to format it to Ext2. Remember to give it a name when doing so, the name must contain no space, for example "myusb". Plug it in your BBB.

The new commands for building OpenCV:

1
2
3
4
5
6
7
8
su
cd /media/myusb
wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.8/opencv-2.4.8.zip
unzip opencv-2.4.8.zip
cd opencd-2.4.8
mkdir build
cd build
cmake -D CMAKE_C_FLAGS='-O3 -mfpu=neon -mfloat-abi=hard' -D CMAKE_CXX_FLAGS='-O3 -mfpu=neon -mfloat-abi=hard' -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -DENABLE_VFPV3=ON -DENABLE_NEON=ON ..

We need to disable some part of the build to speed it up:

1
ccmake .

Remember the dot "." after ccmake command. Check to make sure that ENABLE_NEON and ENABLE_VFPV3 are ON. Now we disable BUILD_PERF_TESTS, BUILD_TESTS, and ENABLE_PRECOMPILED_HEADERS. Some explanations:

  • ENABLE_NEON and ENABLE_VFPV3: to enable hardware acceleration
  • BUILD_PERF_TESTS and BUILD_TESTS: set these 2 to OFF to disable the building of these 2 test suites of OpenCV. Why do we want to not build the tests? Building these tests takes lots lots of time, and I'm sure that you don't have enough patient to run those tests. There is an individual executable for each module of OpenCV, and I tried running the test for opencv_core myself just to see me interrupted the test after waiting for ~20 minutes.
  • ENABLE_PRECOMPILED_HEADERS: by theory, using precompiled headers speed up compilation. But that's not in this case. Our BBB CPU will have to compile those headers alone, as distcc can't do this. And doing this takes BBB CPU lots of time. The precompiled headers in this case will only speed up compilation on host machine, which is already powerful. Less work for BBB = faster overall compilation :).

Follow the on-screen instructions, press "c" to reconfigure and then "g" to regenerate. Finally, we can begin compilation:

1
make -j6

The "-jX" after make command allow parallelization, set X to the number of jobs your host allow.

My distcc host is a virtual machine running Ubuntu 12.04. My desktop is powered by an AMD Phenom II X4 and 4GB RAM so I give my virtual Ubuntu 3 cores and 1.5GB RAM. Therefore the number of jobs is 6. My setup built OpenCV in just 15 minutes.

Some final notes:

  • Environmental variables in Unix systems are only temporary, they got wiped out after reboot or even on session exit. So if you plan to keep using distcc, you will have to edit the ".profile" file in your home folder. Just paste the export commands at the end of that file. The variables will be created every time you log in using that username.
  • Don't forget to tell your system where to look for OpenCV runtime libraries. Edit /etc/ld.so.conf and add "/usr/local/lib" and the end of it. Then run "sudo ldconfig".
  • The easiest way to edit those files from Windows is using WinSCP (free). Using WinSCP, you just need to navigate to the needed file, double click it, a text editor will open it up, and when you save, WinSCP will put the updated version in the right place. Nice and clean. Log in as your username to edit the ".profile" file, and as root to edit /etc/ld.so.conf.

This "guide" lacks lots of stuffs. That's my intention, so you have to read this guide in combination with Michael Darling's one.

Feel free to leave suggestions and/or questions :).

Update: Watch the Final test run of my Thesis on YouTube

Welcome to my blog!

Some words about me and this blog :).

I'm an Electric and Electronic Engineering student. I'm in my final year. On my recent projects, I received lots of help from community. Those help maybe just some posts that people posted on their pages, their blogs, but some people even helped me via direct meeting, phone calls, emails conversations.

I realize that I owe the community a lot. So I decide that I should make this blog, to spread what I have learned, and to help those who need.

Please understand that my native language is not English, so feel free to notice me about spelling and grammar mistakes. All the posts here will be in English, and if you need to ask me via comments or mails (I recommend doing so via comments so that others can learn from your problems too), feel free to use English.