[3mdeb blog]

Thoughts dereferenced from scratchpad noise

Directory scheme for multiple projects

| Comments

How to keep clean organization while working on multiple projects ?

Answer to this question depends on workflow and nature of projects itself.

Below I would like to present my approach to manage sanity while having multiple projects going simultaneously. This would be Embedded Systems Consultant view and will mostly show directory organization, but I think it can be adopted to other programmers workflow.

Directory organization

Usually I have up to 10 projects from external customer running and ~3 internal. Obviously better organization minimize overhead related to searching and wondering where to put recently obtained file. During last 3 years I collected over 60 projects for 45 customers.

Based on that experience I created directory structure that work pretty good for above numbers. Scheme looks like this:

1
${HOME}/projects/<year>/<customer>/<project-name>/{logs,images,releases,src}

Customer/year order

One flaw that this setup has is for project that last more then year. I don’t think making it <customer>/<year> improve things, because then I would have tens of even hundred of directories in projects. Splitting it by year makes searching focused. For now, when I deal with project longer then year I just copy relevant part from previous year. By relevant part I mean something that I really have to use, not one time reference. This can be for example particular SD card image that is still used as development base.

Customer

Customer part is trivial, although sometimes can cause confusion. There are situation where I start research not knowing what company I work for, because I was reached not from company domain. There are also cases when someone reach me over freelance portals (Upwork, Guru etc.) that information provided are outdated or simply invalid.

Having correct customer name is important only at invoicing stage, before that if I’m not clear I just place some made up string that can uniquely identify customer. Usually this is company name and contact person name, if company unknown.

Project name

Usually prototype projects doesn’t have marketing name, but project can be called by SoC/CPU/dev board + main feature ie. a20_camera, bbb_canbus_reader etc.

What most embedded projects needs ?

After couple years I found that couple thing are typically needed:

  • logs – this directory is used most of the times, I tend to run minicom in it with enabled logging, you never know when you will need information form this directory, naming convention for log files is something I still struggle

  • images – this is directory for OS images, typically I have here SD card images and ISO images of distros used in project, sometimes you may end up keeping multiple instance of the same OS in various projects, but with 1TB disc this should not be big concern, you can always search for duplicates, knowing where your OS is and avoiding downloading it again can save some time

  • releases – this directory contain all releases, developers usually use work in progress code, but customer receive release version of deliverables and usually will report bugs against particular release version

  • src – this directory keep all source code related to project, those are mostly git repositories cloned inside directory

Sample directory structure may look like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.
└── projects
    ├── 2015
    │   └── acme1
    │       ├── foo1
    │       │   ├── images
    │       │   ├── logs
    │       │   ├── releases
    │       │   └── src
    │       └── foo2
    │           ├── images
    │           ├── logs
    │           ├── releases
    │           └── src
    └── 2016
        └── acme2
            ├── foo1
            │   ├── images
            │   ├── logs
            │   ├── releases
            │   └── src
            └── foo2
                ├── images
                ├── logs
                ├── releases
                └── src

Summary

I hope this concept is somehow useful for you. I want to keep above information for self reference, because I was asked couple times how to organize multiple projects. Explaining this each time leads to this article. Of course whole organization is very subjective and may not work good for everyone.

Powering on LeMaker HiKey (ARMv8)

| Comments

Embedded Systems Consultants have chance to live in interesting times. ARM expansion touch server market and UEFI coming to non-x86 platforms. Firmware gaining its importance and because handling real development is harder and harder lot of things starting to happen in open source. Big players trying to address security and virtualization issues, what leads to really interesting features in recent SoCs.

Couple weeks ago I decided to recover my knowledge about UEFI and take a look how it is implemented for architecture that have its momentum – namely ARM in its 8 version (ARMv8). Short review of technology reveal universe that should be studied by every aspiring Embedded Systems adept.

Choosing ARMv8 dev board

First problem was to choose development board. Probably simpler solution is to use platforms like Raspberry Pi 3 which features Broadcom Cortex-A53 or very interesting alternative like PINE64 with Allwinner flavour.

Of course rush on this market bring other players like Amlogic with Odroic-C2. It is worth to mention that adaptation of new architecture is very slow. It was announced in 2012. First real product was released by Apple (iPhone S5), but despite various commercial products, since 2012 not much appeared on low end development board market, which is probably main area for makers and prototyping shops. Things start to change last year.

I have RPi3 on my desk but playing with its low level side is not encouraging because of limitation Broadcom put on releasing any information about BCM2837. My goal was to work on UEFI and ARM trusted firmware the only board except expensive ARM reference platforms that seems to work with UEFI was LeMaker HiKey.

Why 96boards ?

  • this is open specification – IIRC this is first of its kind and it is high chance to be widely accepted
  • its driven by Linaro, which in my opinion do a lot of great work for whole community
  • its standardized way with big players behind, so knowing it and having in portfolio cannot damage Embedded Systems Consultant career
  • IMO this approach in long term will have better return on investment, then custom quick shots made by not-so-community-friendly vendors

Power supply

Expected power input is 8-18V. I understand the need for higher and wider voltage range, but this is for sure not standard in makers/hackers community. I have ton of 5V/2A power supplies in stock, also for 5V I can use my active USB hub or even PC port for not power hungry devices.

Reasoning behind this choice can be found here.

Finally to not add more USD to my ARMv8 development environment I used my Zhaoxin DC power supply and unused plug from universal power supply.

1.8V UART

My second surprise was that board use 1.8V level for UART. Cables for that level are built with FT230XS or similar chips, which cost ~3USD. To my suprise cable that work with 1.8V UART level cost 30USD. There are 2 separated UART pins to connect on HiKey. One for low level bootloader development and one for Linux kernel development. So I would need to cables. Board cost 75USD, so you paying almost the same price for cables. It was not acceptable for me.

Linaro developers seems to use this which is out of stock for 5 months!

While searching for alternatives I found this TI converter on SparkFun page. Luckily availability of various SparkFun distributors made delivery possible in less then 48h.

After wiring up with TXB0104 everything seems to work ok.

Note that board use 2 UARTs. UART0 for bootloader development. This is connector with not typical pitch (2.0mm) and UART3 as debug port for Linux kernel output.

The only problem with wiring is that using one TI chip you can only have one reference Vcc for USB to serial UART, so you have to select one of them as reference and assume that second will have very similar level without much noise. I understand this is electronically probably not perfect, but I moved forward with that budget solution.

Booting OS

Board is pre-installed with Debian, so +1 for choice. It boots smooth and you can also see bootloader logs.

On top there is bootloader on bottom booted Debian. Bootloader logs came from OP-TEE Trusted OS,

Summary

Setting up hardware to boot and having some debug output is initial step to start development. Once this point is passed I can start to deal with UEFI and(or) ARM Trusted Firmware (ATF). It is important to note that documentation on GitHub and in Hardware User Manual is very good and huge kudos should go to Linaro people for putting so much effort into that.

Things that I would like to write about in future posts:

  • UEFI setup for HiKey
  • UEFI capabilities and limitation
  • ATF development

As always please share if you think content maybe valuable to other.

PC Engines APU2 netboot Debian installation

| Comments

In previous post I described how to setup PXE server and boot Debian installer using it. I mentioned that provided setup is limited and some extensive configuration is needed to make it useful for real world example. Since that time I learned that there is chain command in iPXE, which give ability to use arbitrary TFTP server as boot file source.

Using RPi PXE server

For example by changing my test network topology from previous post to something like that:

In short Raspberry Pi contain our PXE server configured in previous post. TL-MR3420 is our DHCP server and PC Engines APU2A4 is our target box where we want to install Debian.

We need to change eth0 configuration, so our PXE server will get IP automatically from DHCP:

1
2
auto eth0
iface eth0 inet dhcp

Also disable udhcpd:

1
sudo update-rc.d udhcpd disable

Then reboot PXE server.

PXE booting

First enter iPXE on APU2 board by pressing <Ctrl-B> during boot. You should see something like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
iPXE (http://ipxe.org) 00:00.0 C100 PCI2.10 PnP PMMpmm call arg1=1
pmm call arg1=0
+DFF490B0pmm call arg1=1
pmm call arg1=0
+DFE890B0 C100


iPXE (PCI 00:00.0) starting execution...ok
iPXE initialising devices...ok



iPXE 1.0.0+ (e303) -- Open Source Network Boot Firmware -- http://ipxe.org
Features: DNS FTP HTTP HTTPS iSCSI NFS SLAM TFTP VLAN AoE ELF MBOOT NBI PXE SDI bzImage COMBOOT Menu PXEXT
iPXE>

Then obtain DHCP address:

1
2
iPXE> dhcp net0
Configuring (net0 00:0d:b9:3f:9e:58)............... ok

Now we can boot over the network using RPi PXE server:

1
2
3
iPXE> set filename /srv/tftp/pxelinux.0
iPXE> set next-server 192.168.0.100
iPXE> chain tftp://${next-server}/${filename}

Note that 192.168.0.100 is RPi PXE server and /srv/tftp/pxelinux.0 is path on RPi exposed through TFTP configuration.

Debian installer modification

Hit Tab in the main installer window:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
             +---------------------------------------+
             | Debian GNU/Linux installer boot menu |
             |---------------------------------------|
             | Install                               |
             | Advanced options                    > |
             | Help                                  |
             | Install with speech synthesis         |
             |                                       |
             |                                       |
             |                                       |
             |                                       |
             |                                       |
             |                                       |
             +---------------------------------------+



          Press ENTER to boot or TAB to edit a menu entry

Change boot command line to print output to serial:

1
> debian-installer/i386/linux vga=788 initrd=debian-installer/i386/initrd.gz --- console=ttyS0,115200 earlyprint=serial,ttyS0,115200

Then hit Enter. You will see complains about video mode like this:

1
Press <ENTER> to see video modes available, <SPACE> to continue, or wait 30 sec

Follow this instruction by waiting or hitting Space. Then you should have running installer.

Debian installation

This is typical installation except it happen over serial. As a storage I used 16GB USB stick with guided partitioning. At the end I also installed GRUB on USB stick MBR.

Be patient if serial console will be blank for some time it happen when installing over network.

After reboot you should be able to choose USB stick from boot menu (F10) and your Debian on APU2 should be ready:

1
2
3
4
5
6
7
8
9
10
11
12
13
Debian GNU/Linux 8 Maedhros ttyS0

Maedhros login: pietrushnic
Password: 
Linux Maedhros 3.16.0-4-686-pae #1 SMP Debian 3.16.7-ckt20-1+deb8u4 (2016-02-29) i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
pietrushnic@Maedhros:~$ 

Summary

Now when you have Debian installed on your system you can think about various improvements. For example:

  • Xen installation
  • Putting together automated installation using PXE server
  • Setup NFS and TFTP for Linux kernel development and testing

I hope this post was useful. If you think that it can be improved please comment. Thanks for reading.

PXE server with Raspberry Pi 1

| Comments

Recent days we get the announcement about releasing Raspberry Pi 3. Those of you who play with embedded systems or just try to make things probably still got good old Raspberry Pi (1). Because during time old platforms loose value as potential candidate for new projects I decided to sacrifice my old RPi and make test server from it.

One of my customer required testing his software against PXE server with various configurations. I realized that using my home network with my TP-Link router I have no way to create such configuration on server machine I usually use. I would need to connect directly to server and with one Ethernet port this was not the solution for me. My other platforms like A20 boards, Odroid or RPi2 are occupied by some projects. I recall that I have old RPi that can be used for that purpose.

Configuration described below is very limited because it test just PXE booting, there is no outside world connection. This connection can be added by adding wifi dongle to Raspberry Pi and modifying iptables and routing.

Prerequisites

  • download recent Raspberry Pi image and flash it to SD card. I used Raspbian Jessie Lite.
  • if you don’t have free keyboard and HDMI monitor use UART to connect serial console – you can use this post, if you don’t konw how to connect it
  • flash recent iPXE to your hardware or use what is already provided by vendor

Raspbian Jessie Lite – initial setup

Setup TFTP

Install server TFTP:

1
sudo apt-get install tftpd-hpa

Change configuration according to your needs. My looks like that:

1
2
3
4
5
6
7
# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
#TFTP_OPTIONS="--secure"
TFTP_OPTIONS=""

Download netboot files for Debian, which we will use for testing purposes:

1
wget http://ftp.nl.debian.org/debian/dists/jessie/main/installer-i386/current/images/netboot/netboot.tar.gz

Unpack netboot package in /srv/tftp:

1
2
cd /srv/tftp
sudo tar xvf /path/to/netboot.tar.gz

Setup udhcpd

Install udhcpd and remove conflicting packages:

1
2
sudo apt-get install udhcpd
sudo apt-get remove isc-dhcp-client 

At the end of /etc/udhcpd.conf add:

1
2
3
4
5
6
7
8
9
siaddr          192.168.0.1
boot_file       /srv/tftp/pxelinux.0
opt     dns     192.168.0.1 192.168.10.10
option  subnet  255.255.255.0
opt     router  192.168.0.1
opt     wins    192.168.0.1
option  dns     129.219.13.81
option  domain  local
option  lease   864000

You can also assign client MAC to given IP address by adding:

1
2
#static_lease 00:60:08:11:CE:4E 192.168.0.54
static_lease <mac> <ip>

Comment DHCPD_ENABLE in /etc/default/udhcpd:

1
2
3
4
5
6
7
8
9
# Comment the following line to enable
# DHCPD_ENABLED="no"

# Options to pass to busybox' udhcpd.
#
# -S    Log to syslog
# -f    run in foreground

DHCPD_OPTS="-S"

Change eth0 configuration to static IP:

1
2
3
4
5
auto eth0
iface eth0 inet static
        address 192.168.0.1
        netmask 255.255.255.0
        gateway 192.168.0.254

Then reboot device and connect your PXE client device.

Testing PXE server

When device boot press Ctrl-B to enter iPXE shell. If you cannot enter shell please replace iPXE with recent version using this instructions.

Entering iPXE you should see something like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
iPXE (http://ipxe.org) 00:00.0 C100 PCI2.10 PnP PMMpmm call arg1=1
pmm call arg1=0
+DFF490B0pmm call arg1=1
pmm call arg1=0
+DFE890B0 C100


iPXE (PCI 00:00.0) starting execution...ok
iPXE initialising devices...ok



iPXE 1.0.0+ (e303) -- Open Source Network Boot Firmware -- http://ipxe.org
Features: DNS FTP HTTP HTTPS iSCSI NFS SLAM TFTP VLAN AoE ELF MBOOT NBI PXE SDI bzImage COMBOOT Menu PXEXT
iPXE>  

First let’s configure interface:

1
2
3
4
iPXE> ifconf net0
Configuring (net0 00:0d:b9:3f:9e:58)............... ok
iPXE> dhcp net0
Configuring (net0 00:0d:b9:3f:9e:58)............... ok

And boot Debian installer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
iPXE> autoboot
net0: 00:0d:b9:3f:9e:58 using i210-2 on PCI01:00.0 (open)
  [Link:up, TX:20 TXE:0 RX:8 RXE:2]
  [RXE: 2 x "The socket is not connected (http://ipxe.org/380f6001)"]
Configuring (net0 00:0d:b9:3f:9e:58)............... ok
net0: 192.168.0.194/255.255.255.0 gw 192.168.10.2
net0: fe80::20d:b9ff:fe3f:9e58/64
net1: fe80::20d:b9ff:fe3f:9e59/64 (inaccessible)
net2: fe80::20d:b9ff:fe3f:9e5a/64 (inaccessible)
Next server: 192.168.0.1
Filename: /srv/tftp/pxelinux.0
tftp://192.168.0.1//srv/tftp/pxelinux.0... ok
pxelinux.0 : 42988 bytes [PXE-NBP]
PXELINUX 6.03 PXE 20150819 Copyright (C) 1994-2014 H. Peter Anvin et al+---------------------------------------+
| ^GDebian GNU/Linux installer boot menu |
|---------------------------------------|
| Install                               |
| Advanced options                    > |
| Help                                  |
| Install with speech synthesis         |
|                                       |
|                                       |
|                                       |
|                                       |
|                                       |
|                                       |
+---------------------------------------+Press ENTER to boot or TAB to edit a menu entry     

Summary

It took me some time to put this information together an correctly run this server, so for future reference and for those confused with udhcpd and other tools configuration this post should be useful. Thanks for reading and as always please share if you think this post is valuable. If anything is not clear or I messed something please let me know in comments.

Netcat - how to transfer files without scp or ftp

| Comments

One of my recent customers provided me hardware with custom Linux system. Distribution used on this hardware was very limited there was no developers tools, file transfer applications (like scp, ftp or even tftp) or communication clients like ssh. I had to deploy some firmware files to the system without modifying it. This was i386 machine. Of course I could compile something and add this software using usb stick or other stoarge, but what if I would not have direct access to hardware ? Also for development and testing purposes it would be much easier to use network transfer, then running with usb stick.

When looking for answer I found this. I heard before about netcat, but more in context of debugging then using it as file transfer application. Luckily nc as very small tool is in almost all distributions and it was also available in my small custom distro.

File transfer with netcat

nc by man page is described as TCP/IP swiss army knife , but can be used to transfer files.

What have to be done is setting receiving side ie.:

1
nc -l -p 2020 > my_file.bin

What tell nc to listen on inbound connection (-l) on port 2020 (-p 2020) and redirect content of incoming packages to my_file.bin.

On sender side we pipe my_file.bin to nc like that:

1
cat my_file.bin | nc <dest_ip_addr> 2020

Which cause nc to create TCP connection to <dest_ip_addr> on port 2020 and send everything it gets on standard input.

Known flaws

From what I saw sometimes nc doesn’t end at EOF and just hang waiting for next data, which never come. In that case I just break with Ctrl-C on both ends. Then check if all stuff was transfered correctly by verifying MD5 sum on sender and receiver side. In most cases files pass this integrity test.

Emulate Rapberry Pi 2 in QEMU

| Comments

In the process of planning system testing for one of my clients I found that someone from Microsoft published patches with BCM2836 support to QEMU mailing list. I thought it is very interesting, because if it is possible to setup emulated Raspberry Pi many use cases can be tested faster and in more automatic way. For example checking how application behave when running on more then one device at once, testing massive deployment process, stress testing and finally speed up debug-fix-test process.

So it looks like making RPi 2 working in emulated environment can add a lot of value to some products. In email Andrew mention github repo, which I would like to try in this post

Get QEMU and compile

1
2
3
4
5
git clone https://github.com/0xabu/qemu.git -b raspi
git submodule update --init dtc
./configure
make -j$(nproc)
sudo make install

Prepare to boot

QEMU requires kernel and device tree file to be given as parameters, because of that we have to extract those pieces from existing Raspbian image.

Get kernel and device tree

1
2
3
4
5
6
7
8
9
10
11
12
13
wget http://downloads.raspberrypi.org/raspbian/images/raspbian-2015-11-24/2015-11-21-raspbian-jessie.zip
unzip 2015-11-21-raspbian-jessie.zip
[23:35:23] pietrushnic:rpi2_qemu $ sudo /sbin/fdisk -lu 2015-11-21-raspbian-jessie.img 
Disk 2015-11-21-raspbian-jessie.img: 3.7 GiB, 3934257152 bytes, 7684096 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xea0e7380

Device                          Boot  Start     End Sectors  Size Id Type
2015-11-21-raspbian-jessie.img1        8192  131071  122880   60M  c W95 FAT32 (LBA)
2015-11-21-raspbian-jessie.img2      131072 7684095 7553024  3.6G 83 Linux

Check start of W95 FAT32 (LBA) partition. It is 8192. Sector size is 512. So calculate offset in bytes 8192 * 512 = 4194304.

1
2
3
4
5
mkdir tmp
sudo mount -o loop,offset=4194304 2015-11-21-raspbian-jessie.img tmp
mkdir 2015-11-21-raspbian-boot
cp tmp/kernel7.img 2015-11-21-raspbian-boot
cp tmp/bcm2709-rpi-2-b.dtb 2015-11-21-raspbian-boot

Then if you try to boot 2015-11-21 Rapbian with 0xabu code:

1
2
3
4
qemu-system-arm -M raspi2 -kernel 2015-11-21-raspbian-boot/kernel7.img \
-sd 2015-11-21-raspbian-jessie.img \
-append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2" \
-dtb 2015-11-21-raspbian-boot/bcm2709-rpi-2-b.dtb -serial stdio

You will experience kernel crash:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(...)
[    6.021989] Freeing unused kernel memory: 420K (80779000 - 807e2000)
[    7.366232] random: systemd urandom read with 7 bits of entropy available
[    7.383057] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
[    7.383057] 
[    7.384366] CPU: 0 PID: 1 Comm: systemd Not tainted 4.1.13-v7+ #826
[    7.384874] Hardware name: BCM2709
[    7.386615] [<80018444>] (unwind_backtrace) from [<80013e08>] (show_stack+0x20/0x24)
[    7.387307] [<80013e08>] (show_stack) from [<8055a188>] (dump_stack+0x98/0xe0)
[    7.387851] [<8055a188>] (dump_stack) from [<80556340>] (panic+0xa4/0x204)
[    7.388515] [<80556340>] (panic) from [<800293c8>] (do_exit+0xa0c/0xa64)
[    7.389074] [<800293c8>] (do_exit) from [<800294b8>] (do_group_exit+0x4c/0xcc)
[    7.389729] [<800294b8>] (do_group_exit) from [<80033f1c>] (get_signal+0x2b0/0x6e0)
[    7.390388] [<80033f1c>] (get_signal) from [<80013190>] (do_signal+0x98/0x3ac)
[    7.391021] [<80013190>] (do_signal) from [<8001368c>] (do_work_pending+0xb8/0xc8)
[    7.391665] [<8001368c>] (do_work_pending) from [<8000f9e4>] (work_pending+0xc/0x20)
[    7.393209] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
[    7.393209] 

To avoid this crash you have to comment /etc/ld.so.preload.

Changing ld.so.preload

First calculate offset in bytes to Raspbian root filesystem partition. According to fdisk output above partition starts with sector 131072, so offset would be 512*131072=67108864.

1
sudo mount -o loop,offset=67108864 2015-11-21-raspbian-jessie.img tmp

Use your favourite editor to change tmp/etc/ld.so.preload. Note that you have to edit as superuser. Content of file should looks like this:

1
#/usr/lib/arm-linux-gnueabihf/libarmmem.so

Sync and umount partition:

1
2
sync
sudo umount tmp

Final booting

1
2
3
4
qemu-system-arm -M raspi2 -kernel 2015-11-21-raspbian-boot/kernel7.img \
-sd 2015-11-21-raspbian-jessie.img \
-append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2" \
-dtb 2015-11-21-raspbian-boot/bcm2709-rpi-2-b.dtb -serial stdio

Summary

There are many problem with existing setup, but from my experience this is best approach and code that I saw during last years. Also it looks like this code is backed by huge corporation so it looks like they see value in providing this code to wide community. Rapid delivery of those patches probably would not be possible without previous work to which Andrew point in his email. It would be great to see community engagement in this effort.

Using PlatformIO with TI MSP430 LunchPads

| Comments

PlatformIO is very interesting project that aim to solve very important problem of configuring deployment environment for embedded systems. IMHO good approach is to focus on modularity (various IDE can be used, even Vim) and simplicity (in best case 2 command should be enough to deploy first code).

Recent years we have explosion of bootstraping applications (ie.vagrant, puppet). Most of them seems to follow git-like command line interface and getting a lot of attention from programmers community. PlatformIO is promising project for all Embedded Software developers who in the era of IoT came from Linux systems.

It take some time to try PlatformIO using real hardware. Luckily on my desk there are 2 supported boards gathering dust, which I would like to try in this post.

MSP-EXP430F5529LP on the left and MSP-EXP430FR5969 on the right.

Installation on Debian

I highly recommend using virtualenv for any custom python application.

At the beginning I simply follow Getting Started page.

1
2
pip install -U pip setuptools
pip install -U platformio

What configuration I should use for my boards ?

1
2
3
4
5
[13:38:34] pietrushnic:msp430 $ platformio boards|grep 5969
lpmsp430fr5969        msp430fr5969   8Mhz      64Kb    1Kb    TI LaunchPad w/ msp430fr5969
[13:38:41] pietrushnic:msp430 $ platformio boards|grep 5529
lpmsp430f5529         msp430f5529    16Mhz     128Kb   1Kb    TI LaunchPad w/ msp430f5529 (16MHz)
lpmsp430f5529_25      msp430f5529    25Mhz     128Kb   1Kb    TI LaunchPad w/ msp430f5529 (25MHz)

So it looks like 5529 have 2 flavours. According to Energia 16MHz option is for backward compatibility. Let’s use recent 25MHz config.

1
2
3
mkdir msp430
cd msp430
platformio init --board=lpmsp430fr5969 --board=lpmsp430f5529_25

PlatformIO first ask if we want auto-uploading successfully built project, so I answered y. Then inform about creating some directories and platformio.ini file. After confirming toolchain, downloading starts.

Problems with MSP430F5529LP

Lack of main.cpp

If you run PlatformIO without any source code in src directory you will get error message like this:

1
2
3
4
5
.pioenvs/lpmsp430f5529_25/libFrameworkEnergia.a(main.o): In function `main':
/home/pietrushnic/projects/3mdeb/msp430/.pioenvs/lpmsp430f5529_25/FrameworkEnergia/main.cpp:7: undefined reference to `setup'
/home/pietrushnic/projects/3mdeb/msp430/.pioenvs/lpmsp430f5529_25/FrameworkEnergia/main.cpp:10: undefined reference to `loop'
collect2: ld returned 1 exit status
scons: *** [.pioenvs/lpmsp430f5529_25/firmware.elf] Error 1

Of course adding main.cpp to src directory fix this issue. As sample code you may use MSP430F55xx_1.c

libmsp430.so: cannot open shared object file

Next problem is with libmsp430.so which is not visible by mspdebug, but was installed by PlatformIO in $HOME/.platformio/packages/toolchain-timsp430/bin/libmsp430.so.

Running:

1
export LD_LIBRARY_PATH=$HOME/.platformio/packages/toolchain-timsp430/bin/

before calling platformio fix problem. For some users even better would be to make libmsp430.so accessible system wide:

1
sudo cp $HOME/.platformio/packages/toolchain-timsp430/bin/libmsp430.so /usr/lib

tilib: device initialization failed

If you didn’t use your MSP430 for a while there can be problem like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$HOME/.platformio/packages/tool-mspdebug/mspdebug tilib --force-reset "prog .pioenvs/lpmsp430f5529_25/firmware.hex"
MSPDebug version 0.20 - debugging tool for MSP430 MCUs
Copyright (C) 2009-2012 Daniel Beer <dlbeer@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

MSP430_GetNumberOfUsbIfs
MSP430_GetNameOfUsbIf
Found FET: ttyACM0
MSP430_Initialize: ttyACM0
FET firmware update is required.
Re-run with --allow-fw-update to perform a firmware update.
tilib: device initialization failed
scons: *** [upload] Error 255

Fix for that according to error log should be like this:

1
$HOME/.platformio/packages/tool-mspdebug/mspdebug tilib --allow-fw-update

But this can cause additional problems that I reported here. I finally managed to fix problem using hints from Agla Blog.

Because gcc-msp430 was removed from Debian Sid we have to use compiler delivered by platformio to test blinky example from Agla blog:

1
$HOME/.platformio/packages/toolchain-timsp430/bin/msp430-gcc -mmcu=msp430f5529 -mdisable-watchdog blink.c

Problems with MSP430FR5969

I experienced very similar problems with FR5969. Unfortunately above procedure led me to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MSPDebug version 0.23 - debugging tool for MSP430 MCUs
Copyright (C) 2009-2015 Daniel Beer <dlbeer@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Chip info database from MSP430.dll v3.3.1.4 Copyright (C) 2013 TI, Inc.

Using old API
MSP430_GetNumberOfUsbIfs
MSP430_GetNameOfUsbIf
Found FET: ttyACM0
MSP430_Initialize: ttyACM0
Firmware version is 30301004
MSP430_VCC: 3000 mV
MSP430_OpenDevice
tilib: MSP430_OpenDevice: Unknown device (error = 5)
tilib: device initialization failed

Building libmsp430.so

This probably means that default libmsp430.so, downloaded probably from Energia project, doesn’t support FR5969. So I tried build libmsp430.so by myself:

1
2
3
4
5
6
7
8
9
10
11
12
sudo apt-get install libboost-system-dev libboost-filesystem-dev
git clone https://github.com/pietrushnic/MSPDebugStack_OS_Package.git -b libmsp430-fr5969
git clone https://github.com/signal11/hidapi.git
cd hidapi
./bootstrap
./configure --with-pic
make
cp ./libusb/hid.o ../MSPDebugStack_OS_Package/ThirdParty/lib64
cp ./hidapi/hidapi.h ../MSPDebugStack_OS_Package/ThirdParty/include
cd ../MSPDebugStack_OS_Package
make
sudo cp libmsp430.so /usr/lib

This improved situation, but give:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
MSPDebug version 0.23 - debugging tool for MSP430 MCUs
Copyright (C) 2009-2015 Daniel Beer <dlbeer@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Chip info database from MSP430.dll v3.3.1.4 Copyright (C) 2013 TI, Inc.

Using new (SLAC460L+) API
MSP430_GetNumberOfUsbIfs
MSP430_GetNameOfUsbIf
Found FET: ttyACM0
MSP430_Initialize: ttyACM0
FET firmware update is required.
Starting firmware update (this may take some time)...
Initializing bootloader...
Programming new firmware...
    75 percent done
    84 percent done
    84 percent done
    91 percent done
    96 percent done
    99 percent done
   100 percent done
   100 percent done
Initializing bootloader...
Programming new firmware...
     4 percent done
    20 percent done
    36 percent done
    52 percent done
    68 percent done
    84 percent done
   100 percent done
Update complete
Done, finishing...
tilib: MSP430_FET_FwUpdate: MSP-FET / eZ-FET legacy module update failed (error = 75)
tilib: device initialization failed

I’m not sure why this message appear, but when tried 2nd time I finally get debugger prompt, what means that process finished correctly and we can access FR5969.

Final test

MSP430F5529LP

Please download MSP430F55xx_1.c and save it as src/main.c. Then run:

1
platformio run -e lpmsp430f5529_25

If you see blinking red P1.0 LED1 then everything works as expected.

MSP430FR5969

Please download msp430fr59xx_1.c and save it as src/main.c. Then run:

1
platformio run -e lpmsp430fr5969

If you see blinking green LED2 then everything works as expected.

Summary

I hope that this post was useful for you and you learn some things. If you feel that this knowledge was valuable please share, if you experienced some other problems please let me know, so I can improve content of this post.

UEFI Application development in OVMF

| Comments

OVMF (Open Virtual Machine Firmware) is a project that aim is to enable UEFI support in various virutal machines. According to whitepaper various projects have interest in supporting OVFM ie. VirtualBox, Xen, BHyVe and of course QEMU. Why someone may be interested in OVMF ?

  • IMHO the most important reason is that OVMF give ability to develop UEFI applications without using real hardware. This speeds up development cycle by giving ability to start before hardware prototype arrive. There are also cases when hardware is available only remotely, dealing with remote setup is usually annoying, so part of development can be performed locally.

  • It also improve testing and debugging, because we have full control over execution environment internals. Error injection and corner case analysis can be ineffective in real world. OVMF and qemu open debugging to new levels.

  • It enables training and learning environment. Not every one can obtain UEFI PC and mess with it when there is risk of destroying sth.

  • Many other reason like ability to test/develop UEFI support for various OSes, simplified debugging, lack of dependencies on legacy address space and devices. This and other interesting reasons can be found in Laszlo Ersek whitepaper

What I want to show below is procedure for setting up development environment for UEFI applications and show how to compile and deploy Hello World application in that environment.

QEMU

Let’s use upstream version of QEMU:

1
2
3
4
5
6
git clone https://github.com/qemu/qemu.git 
cd qemu
git submodule init
git submodule update
./configure --target-list=x86_64-softmmu
make -j$(nproc)

Prepare application image

Of course size depends on you application requirements. Usually 128MB is way too much.

1
2
3
dd if=/dev/zero of=app.disk bs=1 count=1 seek=$(( (128 * 1024 * 1024) - 1))
sudo mkfs.vfat app.disk
cd ..

EDK2

First build UEFI firmware with shell:

1
2
3
4
git clone https://github.com/tianocore/edk2.git
cd edk2
nice OvmfPkg/build.sh -a X64 -n $(nproc)
cp Build/OvmfX64/DEBUG_GCC4?/FV/OVMF.fd ovmf.flash

Now we need some application that can be delivered over app.disk to virtual machine. There are couple examples of UEFI applications in edk2 source code, but let’s start with classical Hello World. Source code can be found in MdeModulePkg/Application/HelloWorld. This module is built in MdeModulePkg because of that we can built it as follows:

1
2
source edksetup.sh
build -a X64 -p MdeModulePkg/MdeModulePkg.dsc -t GCC49 -n$(nproc)

Let’s put it into app.disk:

1
2
3
4
5
mkdir mnt_app
cp ../qemu/app.disk .
sudo mount app.disk mnt_app
sudo cp Build/MdeModule/DEBUG_GCC49/X64/HelloWorld.efi mnt_app
sudo umount mnt_app

OVMF configuration

When we develop UEFI application best way would be to run OVMF to UEFI Shell for test purposes. This is not default option. How to change boot order so we every time will lend in shell ?

On booting screen hit <Esc>.

You should be in main menu of UEFI setup:

Go through Boot Maintenance Manager -> Boot Options -> Change Boot Order, select Change Boot Order and hit <Enter>. Then using +/- keys move EFI Internal Shell to the top.

Do not forget to save configuration with <F10>.

Run HelloWorld.efi

To boot OVMF I’m using Laszlo’s slightly modified script which can be found here.

After booting to UEFI Shell we should look something like this:

Note FS0: in mapping table list – this is our app.disk.

Type:

1
2
fs0:
HelloWorld.efi

Result should look like this:

NOTE: If your result is different then make sure to check last lines of app.ovmf.log it can give you some hints.

Summary

Hopefully at least part of above article was useful somehow. There are many ways to extend this sample presentation. In example application delivery can be achieved by network transfer. If you have any question or need UEFI support please do not bother to ping me in comments or using any other medium.

Linux, RPi and USB over IP updated

| Comments

Because of increasing interesting in USB over IP topic I decided to refresh my old post. I will focus on doing the same thing with more recent version of Raspabian. If you need more information please read my previous post.

Setup SD card

First get recent version of Raspbian, then unzip and dd it to SD card:

1
sudo dd bs=4M if=2015-09-24-raspbian-jessie.img of=/dev/sdc

If you are impatient and want to know what happen in background you can use this method of tracking dd progress:

1
sudo sh -c "while true; do killall -USR1 dd; sleep 1; done"

Before removing card we have to be sure that all data were wrote to card:

1
sync

If this operation takes time you can watch progress work writeback and dirty kilobytes using:

1
watch grep -e Dirty: -e Writeback: /proc/meminfo

When sync will finish you can remove SD card and sanity check booting on RPi.

Kernel for RPi

After booting you should be able to ssh to your RPi and check if USBIP was compiled in your kernel.

1
2
3
4
5
6
pi@raspberrypi ~ $ sudo modprobe configs
pi@raspberrypi ~ $ zcat /proc/config.gz |grep USBIP
CONFIG_USBIP_CORE=m
CONFIG_USBIP_VHCI_HCD=m
CONFIG_USBIP_HOST=m
# CONFIG_USBIP_DEBUG is not set

Great! It looks like both server and client support was compiled as modules in recent Raspbian.

Run server side of usbip

Unfortunately usbip user space tools are not available from scratch and have to be installed:

1
sudo apt-get install usbip

Then you can run server:

1
2
3
pi@raspberrypi ~ $ sudo modprobe usbip-core
pi@raspberrypi ~ $ sudo modprobe usbip-host
pi@raspberrypi ~ $ sudo usbipd -D

Without connecting anything we get only internal Ethernet device when listing:

1
2
3
pi@raspberrypi ~ $ usbip list -l
 - busid 1-1.1 (0424:ec00)
    Standard Microsystems Corp. : SMSC9512/9514 Fast Ethernet Adapter (0424:ec00)

Let’s put some memory stick and check again:

1
2
3
4
5
6
pi@raspberrypi ~ $ usbip list -l
 - busid 1-1.1 (0424:ec00)
   Standard Microsystems Corp. : SMSC9512/9514 Fast Ethernet Adapter (0424:ec00)

 - busid 1-1.2 (0951:1666)
   Kingston Technology : unknown product (0951:1666)

Good usbip see our storage device. Let’s try to bind it:

1
2
3
pi@raspberrypi ~ $ sudo usbip --debug bind -b 1-1.2
usbip: debug: /build/linux-tools-06nnfo/linux-tools-3.16/drivers/staging/usbip/userspace/src/usbip.c:141:[run_command] running command: `bind'
usbip: info: bind device on busid 1-1.2: complete

Client side

Let’s check if device was correctly exposed by server on RPi. Of course we need usbip package installed.

1
2
3
4
5
6
7
[13:28:50] pietrushnic:~ $ sudo usbip list -r 192.168.0.105
Exportable USB devices
======================
 - 192.168.0.105
      1-1.3: Toshiba Corp. : TransMemory-Mini / Kingston DataTraveler 2.0 Stick (2GB) (0930:6544)
           : /sys/devices/platform/soc/20980000.usb/usb1/1-1/1-1.3
           : (Defined at Interface level) (00/00/00)

Information is even more accurate then on RPi. Of course 192.168.0.105 have to be replaced with you IP address.

Quickly check if client support correct modules:

1
2
3
4
5
[13:18:36] pietrushnic:~ $ grep USBIP /boot/config-`uname -r`
CONFIG_USBIP_CORE=m
CONFIG_USBIP_VHCI_HCD=m
CONFIG_USBIP_HOST=m
# CONFIG_USBIP_DEBUG is not set

Everything looks ok. Let’s load hos module:

1
sudo modprobe vhci-hcd

Now we can attach remote storage:

1
sudo usbip attach -r 192.168.0.105 -b 1-1.3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[13:29:15] pietrushnic:~ $ sudo fdisk -l /dev/sdd 
GPT PMBR size mismatch (13695 != 3911615) will be corrected by w(rite).
Disk /dev/sdd: 1.9 GiB, 2002747392 bytes, 3911616 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 2164228A-0AD4-43A8-9478-0E94701363B1

Device     Start   End Sectors  Size Type
/dev/sdd1   2048 13662   11615  5.7M EFI System
[13:29:27] pietrushnic:~ $ sudo mount /dev/sdd1 tmp
[13:29:39] pietrushnic:~ $ ls tmp 
EFI  shellia32.efi  shellx64.efi  shellx64-refind-signed.efi

Let’s left some signs:

1
2
3
[13:30:55] pietrushnic:~ $ sudo sh -c "echo DEADBEEF > tmp/foobar"
[13:31:08] pietrushnic:~ $ cat tmp/foobar 
DEADBEEF

Detach and see if we will see this file on server side:

1
2
3
4
5
6
7
8
[13:33:31] pietrushnic:~ $ sudo usbip port
Imported USB devices
====================
Port 00: <Port in Use> at High Speed(480Mbps)
       unknown vendor : unknown product (0930:6544)
       5-1 -> usbip://192.168.0.105:3240/1-1.3
           -> remote bus/dev 001/005
[13:33:39] pietrushnic:~ $ sudo usbip detach -p 0

First let’s unbind:

1
2
pi@raspberrypi ~ $ sudo usbip unbind -b 1-1.3
usbip: info: unbind device on busid 1-1.3: complete

Then mount partition on which we placed out test file:

1
2
3
pi@raspberrypi ~ $ sudo mount /dev/sda1 tmp/
pi@raspberrypi ~ $ cat tmp/foobar 
DEADBEEF

Summary

This is quick refresh for those struggling with running usbip. There many topics to cover in this area I think about writing posts related to below topics:

  • usbip on Raspberry Pi 2
  • passing frames for RS232 to USB converter using usbip
  • A20-OLinuXino-MICRO/Cubietruck and usbip

If you any other preference or topics that would like to see on this blog please let me know in comments. If you think this post can be useful for others please share.

Thanks for reading.

Building Android 4.2 LiveSuit image for Cubietruck (Allwinner A20)

| Comments

Treating A20 boards like outdated piece of HW by vendors makes building Android for Cubietruck not trivial task. Finding documentation, mailing list or blog post that clearly describe steps is almost impossible. Most of links to SDK are broken and instructions outdated. Because of that I decided to leave couple notes for me and all of you lost in this madness.

Hopefully below steps can build foundation for future development and improvements.

Get the code

It took me couple of googling hours to realize that key was to carefully search cubietech sever. Finally I found this.

So I cloned repos with code:

1
2
git clone https://bitbucket.org/cubietech/a20-android4.2_android.git lichee
git clone https://bitbucket.org/cubietech/a20-android4.2_android.git

Based on other instruction that I hit previously (but download link was broken) I run build process:

1
2
cd lichee
./build.sh -p sun7i_android

Lichee compilation error

World would be too beautiful if everything would work right out of the box, so I hit this very informative build error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
make: Entering directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali'
/home/pietrushnic/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4
make -C DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump CONFIG=ca8-virtex820-m400-1 BUILD=release KDIR=/home/pietrushnic/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4
make[1]: Entering directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump'
make -C /home/pietrushnic/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4 M=/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump modules
make[2]: Entering directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4'
  CC [M]  /home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/common/ump_kernel_common.o
arm-linux-gnueabi-gcc: error: directory: No such file or directory
arm-linux-gnueabi-gcc: error: directory": No such file or directory
scripts/Makefile.build:307: recipe for target '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/common/ump_kernel_common.o' failed
make[3]: *** [/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/common/ump_kernel_common.o] Error 1
Makefile:1365: recipe for target '_module_/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump' failed
make[2]: *** [_module_/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump] Error 2
make[2]: Leaving directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4'
Makefile:60: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump'
Makefile:15: recipe for target 'build' failed
make: *** [build] Error 2
make: Leaving directory '/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_lichee/linux-3.4/modules/mali'
ERROR: build kernel Failed

After some digging I managed to narrow down issue to piece of smart code, that injected version string through define, which generated above mess. Without thinking much about fix I just changed incorrectly generated define to driver version string. This string will be presented in UMP modinfo. Patch which fix above looks like that:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
diff --git a/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/Kbuild b/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/Kbuild
index 042745d0c757..608a7ba97f95 100755
--- a/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/Kbuild
+++ b/linux-3.4/modules/mali/DX910-SW-99002-r3p2-01rel2/driver/src/devicedrv/ump/Kbuild
@@ -26,10 +26,10 @@ endif
 UDD_FILE_PREFIX = ../mali/
 
 # Get subversion revision number, fall back to 0000 if no svn info is available
-SVN_REV := $(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //')
+# SVN_REV := $(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //')
 
-ccflags-y += -DSVN_REV=$(SVN_REV)
-ccflags-y += -DSVN_REV_STRING=\"$(SVN_REV)\"
+#ccflags-y += -DSVN_REV=$(SVN_REV)
+ccflags-y += -DSVN_REV_STRING=\"r3p2-01rel2\"
 
 ccflags-y += -I$(src) -I$(src)/common -I$(src)/linux -I$(src)/../mali/common -I$(src)/../mali/linux -I$(src)/../../ump/include/ump
 ccflags-y += -DMALI_STATE_TRACKING=0

After above change repeated build command finish without errors.

1
./build.sh -p sun7i_android

Android

I assume you directory layout looks like this:

1
2
3
.
├── a20-android4.2_android
└── lichee

Go to Android directory and source environment setup script. Android do not like shells other then bash, so change you shell if you using something different:

1
2
3
4
cd a20-android4.2_android
bash
source build/envsetup.sh
lunch

You will get menu which will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
You're building on Linux

Lunch menu... pick a combo:
     1. full-eng
     2. full_x86-eng
     3. vbox_x86-eng
     4. full_mips-eng
     5. full_grouper-userdebug
     6. full_tilapia-userdebug
     7. mini_armv7a_neon-userdebug
     8. mini_armv7a-userdebug
     9. mini_mips-userdebug
     10. mini_x86-userdebug
     11. full_maguro-userdebug
     12. full_manta-userdebug
     13. full_toroplus-userdebug
     14. full_toro-userdebug
     15. sugar_cubieboard2-eng
     16. sugar_cubietruck-eng
     17. sugar_evb-eng
     18. sugar_ref001-eng
     19. sugar_standard-eng
     20. wing_evb_v10-eng
     21. full_panda-userdebug

Of course our target is sugar_cubietruck-eng, so type 16. Then copy kernel and modules using extract-bsp function and start build:

1
2
extract-bsp
make -j$(nproc)

Wrong make version

Android expects make in version 3.81 or 3.82 and recent distros (like my Debian stretch/sid) have make>=4.0. Problem signature looks like this:

1
2
3
4
5
6
build/core/main.mk:45: ********************************************************************************
build/core/main.mk:46: *  You are using version 4.0 of make.
build/core/main.mk:47: *  Android can only be built by versions 3.81 and 3.82.
build/core/main.mk:48: *  see https://source.android.com/source/download.html
build/core/main.mk:49: ********************************************************************************
build/core/main.mk:50: *** stopping.  Stop.

You can workaround this problem using below patch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
diff --git a/build/core/main.mk b/build/core/main.mk
index 87488f452a9d..ce366bee6ced 100644
--- a/build/core/main.mk
+++ b/build/core/main.mk
@@ -40,8 +40,7 @@ endif
 # Check for broken versions of make.
 # (Allow any version under Cygwin since we don't actually build the platform there.)
 ifeq (,$(findstring CYGWIN,$(shell uname -sm)))
-ifeq (0,$(shell expr $$(echo $(MAKE_VERSION) | sed "s/[^0-9\.].*//") = 3.81))
-ifeq (0,$(shell expr $$(echo $(MAKE_VERSION) | sed "s/[^0-9\.].*//") = 3.82))
+ifeq (0,$(shell expr $$(echo $(MAKE_VERSION) | sed "s/[^0-9\.].*//") = 4.0))
 $(warning ********************************************************************************)
 $(warning *  You are using version $(MAKE_VERSION) of make.)
 $(warning *  Android can only be built by versions 3.81 and 3.82.)
@@ -50,7 +49,6 @@ $(warning **********************************************************************
 $(error stopping)
 endif
 endif
-endif
 
 # Absolute path of the present working direcotry.

Java SE 1.6 required

If your distro is not prepared you can hit something like this:

1
2
3
4
5
6
7
8
9
10
************************************************************
You are attempting to build with the incorrect version
of java.
 
Your version is: java version "1.7.0_85".
The correct version is: Java SE 1.6.
 
Please follow the machine setup instructions at
    https://source.android.com/source/download.html
************************************************************

To fix this issues add this repo to your /etc/apt/sources.list

1
2
deb http://ppa.launchpad.net/webupd8team/java/ubuntu precise main
deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu precise main

Then update and install required Java SDK.

1
2
sudo apt-get update
sudo apt-get install sun-java6-jdk

You also may need to update alternatives if Java SE 1.6 was installed previously:

1
2
sudo update-alternatives --config java  #correct is /usr/lib/jvm/java-6-oracle/jre/bin/java
sudo update-alternatives --config javac #correct is /usr/lib/jvm/java-6-oracle/bin/javac

Missing dependencies

If you will hit some weird compiler errors like this:

1
2
3
4
5
6
7
8
9
10
11
12
In file included from /usr/include/endian.h:60:0,
                 from /home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_android/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/bin/../sysroot/usr/include/sys/types.h:217,
                 from cts/suite/audio_quality/lib/src/FileUtil.cpp:18:
/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_android/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/bin/../sysroot/usr/include/bits/byteswap.h:22:3: error: #error "Never use <bits/bytesw
ap.h> directly; include <byteswap.h> instead."
In file included from frameworks/native/include/utils/RefBase.h:24:0,
                 from frameworks/native/include/utils/Thread.h:31,
                 from frameworks/native/include/utils/threads.h:35,
                 from cts/suite/audio_quality/lib/include/FileUtil.h:24,
                 from cts/suite/audio_quality/lib/include/Log.h:24,
                 from cts/suite/audio_quality/lib/src/FileUtil.cpp:21:
/usr/include/stdlib.h:760:34: fatal error: bits/stdlib-bsearch.h: No such file or directory

This mean that you have missing dependencies. On Debian you can fix this with:

1
sudo apt-get install bison g++-multilib git gperf libxml2-utils make python-networkx zip xsltproc

After all above fixes running make again should build the image:

1
make -j$(nproc)

It took some time, so you can go for coffee. Final messaged for passed build should look like this:

1
2
3
4
5
6
7
8
9
10
11
Running:  simg2img out/target/product/sugar-cubietruck/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/sugar-cubietruck/obj/PACKAGING/systemimage_intermediates/unsparse_system.img
Running:  e2fsck -f -n out/target/product/sugar-cubietruck/obj/PACKAGING/systemimage_intermediates/unsparse_system.img
e2fsck 1.41.14 (22-Dec-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
out/target/product/sugar-cubietruck/obj/PACKAGING/systemimage_intermediates/unsparse_system.img: 1506/32768 files (0.0% non-contiguous), 100004/131072 blocks
Install system fs image: out/target/product/sugar-cubietruck/system.img
out/target/product/sugar-cubietruck/system.img+out/target/product/sugar-cubietruck/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=548110464 blocksize=4224 total=403588136 reserve=5537664

Pack image

1
pack

In output it will tell you where your image is:

1
2
3
4
5
6
----------image is at----------

/home/pietrushnic/storage/wdc/projects/3mdeb/cubietruck/cubietruck_android/lichee/tools/pack/sun7i_android_sugar-cubietruck.img

pack finish
/home/pietrushnic/projects/3mdeb/cubietruck/cubietruck_android/a20-android4.2_android

Image installation

Image can be installed using LiveSuit. Flashing instructions can be found on sunxi wiki.

Summary

As you can see Android boots to initial screen and it looks like we have working prcedure for building Cubietech Android SDK. This gives good ground for future experimentation.

Hopefully above instructions works for you and will not outdate soon. If you found any problems/errors please let me know in comment. I you think content can be useful to others please share.

Thanks for reading.