Today we are going to build custom Yocto Linux image for embedded IoT computer called Intel Edison. My main aim why I need to build image was enabling mobile internet USB dongles support, but this guide can be also used if you want to do any other image tuning. To achieve USB modems support we need:

1. Include USB to Serial drivers for modem (to have /tty/USBx ports which will allow communicating with GSM/CDMA module inside of our USB Dongle)

2. Most of the dongles plugged in the system as USB storage Device. But to enable internet connection we need to switch dongle in USB Modem mode. This will lead to changing USB Vendor ID and appearing /tty/USBx ports (of course only if USB serial drivers will be installed). To implement switching, we need to include usb_modeswitch package in our Linux.

3. We need to enable PPP kernel drivers for creating PPP data connection to our mobile provider. 

4. We will also install pppd which will make a call to the mobile operator, create connection and create network interface (e.g. ppp0) which will connect our device to big world of the internet!

Ok. Let's do this.

Preparing for build

I will use Ubuntu 14.04.4 LTS 32-bit, Trusty Tahr on VirtualBox and flash from Windows 10. Newer versions of Ubuntu might have some issues with apt packages, for fixes look for Intel Communities.

We need next packages on Ubuntu:

sudo apt-get install build-essential git diffstat gawk chrpath texinfo unzip

I will use iot-devkit-yp-poky-edison-20160315.zip source package (sources for Release 3.0 Yocto* complete image). Achieve md5: ee6ef7a6514e7c2c1bb9c085e165ced7, modified 06 May 2016. It can be downloaded here: http://iotdk.intel.com/src/3.0/edison/ .

This guide is related to latest 3.0 Image sources so it is mostly based on README from the root of iot-devkit-yp-poky-edison-20160315.zip and some topics from Intel Communities. It has some differences from official "Intel® Edison Board Support Package, May 2015 Revision 006", which now looks a bit obsolete.

After downloading sources, we need to do the following:

mkdir -p /home/user/yocto/
cd /home/user/yocto/
unzip iot-devkit-yp-poky-edison-20160315.zip

Note that if you will sometimes see /home/user/yocto/ in the guide, know that it is my absolute base path, so you need to replace it with yours!

Building image without tuning

It is a good idea to build image before changing any settings. This will help us to ensure that source package and build environment is ok and when we will start to adjust sources and have some errors we will exactly know the reason.

cd iot-devkit-yp-poky-edison-20160315/poky/
source oe-init-build-env ../build_edison/
bitbake edison-image u-boot

The build process is pretty long (5-6 hours according to BSP manual), but when it will be done once next rebuilds after some changes will be considerably faster.

In my case on VirtualBox Ubuntu it took exactly5 hours (Host processor Intel Core i7-6700 Skylake, VirtualBox started from Windows 10, HDD file placed on non SSD drive, virtual machine was provided by 8 Gb RAM and 4 cores)

Please consider the information about image in output of bitbake:

Build Configuration:
BB_VERSION = "1.24.0"
BUILD_SYS = "i686-linux"
NATIVELSBSTRING = "Ubuntu-14.04"
TARGET_SYS = "i586-poky-linux"
MACHINE = "edison"
DISTRO = "poky-edison"
DISTRO_VERSION = "1.7.3"
TUNE_FEATURES = "m32 core2"
TARGET_FPU = ""

Most important thing here is DISTRO_VERSION which is 1.7.3. This means that actual Yocto version is 1.7.*. Pay attention that this is not "Yocto complete image" version that is 3.0 in our case. Yocto complete image version is terminology which Intel uses when issues new images. But these images based on certain Yocto versions. For example, several Intel images can use same Yocto version but have differences in kernel or packages.

A bit of theory

While you waiting for Bitbake finish lets discover some terminology about Yocto and packages in Yocto that will be used in next sections.

  • Yocto Project - infrastructure (set of scripts, binaries, repositories etc) for creating custom Linux images for embedded hardware with different architectures. There is some very similar project named OpenEmbedded (OE) developed by another community. Both Yocto and OE use same build system named Bitbake.
  • Recipe - text file with .bb extension which used by Bitbake to build binary files and other stuff for the complete package.
  • Package - binary file with .ipk extension which created after compiling recipe. IPK packages managed by opkg package manager. Opkg can delete/install/show version etc. This package manager used in some other operation systems like OpenWRT.
  • Layer - is a group of recipes which is the folder in the terminology of the filesystem. There are standard Yocto layers with recipes supplied by Yocto community (for recipes list see link number №3 from "Useful links" section at the end of this article). We can also attach another layer (for example we will use layers from OE project which have a lot of useful software). Or we can even create custom layers with custom recipes.

Fixing Errors

During build process, most package sources are downloaded from web. So from time to time some urls may become broken. In most cases missed urls may point to optional no needed packages and some warnings may be showed (e.g. "Failed to fetch URL..."). In most cases it is no need to fix them becouse broken urls have some mirrors, for example after end of building in the end of output I have:

NOTE: Tasks Summary: Attempted 3777 tasks of which 2071 didn't need to be rerun and all succeeded.

Summary: There were 50 WARNING messages shown.

But if all urls to sources that are important become broken error will appear. If you have errors when perform a first build you should google it and if there are no results ask on Intel Communities.

Tuning image

Now we come to most interesting part. First of all, we will consider how to add kernel drivers to image, which are needed for dongle support.

Kernel modules

We need  to open menuconfig:

bitbake virtual/kernel -c menuconfig

Now we are going to turnon PPP modules support. It is needed for setup internet connection between Edison and mobile provider via mobile data connection.  In menuconfig window go to Device Drivers section:

Go to Network Device Support:

 Go to PPP (point-to-point protocol) Support:, press Space to set "M" on this item and then also check items marked with red arrows:

Note that some drivers may be included as build-in (you need to mark them <*>) and as modules (marked as <M>), and this difference is important sometimes so I take your Attention what Character (<*> or <M>) you use when mark item . 

Ok PPP modules are ready, now let's add USB serial drivers for GSM modem. Return to Device Drivers pressing ESC.

Go to USB support:

Go to USB Serial Converter support:

Mark with <M> item named USB driver for GSM and CDMA modems:

As I know this driver (it also named option in lsmod list) can be used for most of USB GSM/CDMA dongles like Huawei or ZTE, but sometimes very rare dongles may need other drivers, so you need to google it.

Saving kernel configuration

Let's save the result navigating to Save button and pressing it. Default suggested filename is .config, let's leave it and press OK. In current build Yocto release saved file will be in ./tmp/work/edison-poky-linux/linux-externalsrc/1.0-r2/linux-externalsrc-1.0/.config (you could see this during several first seconds on menuconfig launch).

Saved file is not that one that will be used when building, so we need to make backup of original file (named i386_edison_defconfig, it placed at ../poky/linux-kernel/arch/x86/configs/i386_edison_defconfig and replace with saved .config. Just do it:

cp ../poky/linux-kernel/arch/x86/configs/i386_edison_defconfig /home/user/yocto/i386_edison_defconfig_orig
cp ./tmp/work/edison-poky-linux/linux-externalsrc/1.0-r2/linux-externalsrc-1.0/.config ../poky/linux-kernel/arch/x86/configs/i386_edison_defconfig

To compare original and edited file we can use:

diff ../poky/linux-kernel/arch/x86/configs/i386_edison_defconfig /home/user/yocto/i386_edison_defconfig_orig

Now we need to reconfigure kernel and rebuild image:

bitbake virtual/kernel -c configure -f -v
bitbake edison-image u-boot

If you have some errors after experiments you could simply restore backup:

cp /home/user/yocto/i386_edison_defconfig_orig ../poky/linux-kernel/arch/x86/configs/i386_edison_defconfig

and then rebuild again.

Adding packages

Let's add usb-modeswitch, ppp and screen package to our image. Screen provides simple UART terminal and will be used only for test /dev/ttyXXXx port.

For this we need to edit file ../../iot-devkit-yp-poky-edison-20160315/poky/meta-intel-edison/meta-intel-edison-distro/recipes-core/images/edison-image.bb

And add there lines:

IMAGE_INSTALL += "ppp"
IMAGE_INSTALL += "screen"
IMAGE_INSTALL_append += "usb-modeswitch"

Then we need to rebuild all using bitbake edison-image u-boot.

Preparing image for flash

../poky/meta-intel-edison/utils/flash/postBuild.sh .
zip -r toFlash.zip toFlash

After this, we have toFlash.zip which can be used for flashing from linux or windows operation system. 

Flashing

From Windows

If you build Yocto in VirtualBox then most likely you can't boot into Edison USB bootloader through VirtualBox USB forwarding (VirtualBox USB detection is slow so bootloader timeout will be exceeded). So you need to copy toFlash.zip to windows with shared folder or with openssh scp or in other way.

On Windows you need to unpack zip and run flashall.bat.  But before running flashall.bat you need to place dfu-util.exe into folder near flashall.bat, get it here

Now run flashall.bat then connect board to USB and reboot it to enter in bootloader. On minibreakout board it is possible to perform reboot by pressing power button for 10 seconds untill led will turn off and then pressing this button again for several seconds until led will blink. After several seconds flashing process should begin. Also if you use minibreakout, instead of rebooting, you can simply replug usb cable and module will be repowered.

Also you may need drivers from here.

Flashing process should look like this:

>flashall.bat
Using U-boot target: edison-blankrndis
Now waiting for dfu device 8087:0a99
Please plug and reboot the board
Dfu device found
Flashing IFWI
Download        [=========================] 100%      4194304 bytes
Download done.
Download        [=========================] 100%      4194304 bytes
Download done.
Flashing U-Boot
Download        [=========================] 100%       237568 bytes
Download done.
Flashing U-Boot Environment
Download        [=========================] 100%        65536 bytes
Download done.
Flashing U-Boot Environment Backup
Download        [=========================] 100%        65536 bytes
Download done.
Rebooting to apply partiton changes
Dfu device found
Flashing boot partition (kernel)
Download        [=========================] 100%      6127616 bytes
Download done.
Flashing rootfs, (it can take up to 5 minutes... Please be patient)
Download        [=========================] 100%   1226589184 bytes
Download done.
Rebooting
U-boot & Kernel System Flash Success...
Your board needs to reboot to complete the flashing procedure, please do not unplug it for 2 minutes.

From Linux

If you want flash Edison from Linux you need dfu-util. Ubuntu version is old and not suitable (DFU 1.0, but needed 1.1) so we can build it:

git clone git://git.code.sf.net/p/dfu-util/dfu-util
cd dfu-util/
./autogen.sh 
sudo apt-get install libusb-1.0-0-dev
./configure 
make && sudo make install

Next actions are same as in Windows flashing (run flashall.sh and reboot board).

Connecting to Internet

This section is not Edison or even Yocto specific so you can also use any other guide, check "usefull links bellow". As an example I will connect Huawei E156g:

Checking modem

After plugging modem via USB Otg converter to Edison we should check lsusb:

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 12d1:1003 Huawei Technologies Co., Ltd. E220 HSDPA Modem / E230/E270/E870 HSDPA/HSUPA Modem
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Also there are two USB serial ports:

ls /dev/ttyUSB*
/dev/ttyUSB0 /dev/ttyUSB1

This means that our dongle already in "modem state" that is exactly what we need. We can also ensure that USB serial driver works properly with screen:

screen /dev/ttyUSB0

If you have Huawei dongle you can enter AT+CSQ and press Enter, if all right you will see signal quality: 

AT+CSQ
+CSQ: 11,99

OK

other dongles may have different AT commands, for example most of ZTE dongles has AT+ZRSSI command in their GSM modules instead of AT+CSQ command .

To exit from screen use Ctrl+A,k,y.

Please note that if you have several /dev/ttyUSBx interfaces some of thes may not work, so if you have issues with first try other.

Configuring PPPD

Ok, we are ready to create configs for pppd

nano /etc/ppp/peers/mts

Replace mts with your mobile provider name. If you will have several providers, you will need to create a copy of this file. Add content:

/dev/ttyUSB0
921600
usepeerdns
crtscts
lock
noauth
local
persist
modem
nopcomp
novjccomp
#bsdcomp
nobsdcomp
nodeflate
noaccomp
ipcp-accept-local
ipcp-accept-remote
noipdefault
defaultroute
noipdefault
user ""
password ""
connect "/usr/sbin/chat -v -t15 -f /etc/ppp/mts.chat"

My cell operator don't use authentification so I use noauth option. If you need one - comment it and fill user and password sections with your data.

Next one file will be /etc/ppp/mts.chat which contains AT-commands for modem.

ABORT BUSY
ABORT 'NO CARRIER'
ABORT VOICE
ABORT 'NO DIALTONE'
ABORT 'NO DIAL TONE'
ABORT 'NO ANSWER'
ABORT DELAYED

REPORT CONNECT

# modeminit
'' ATZ
OK 'ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0'
OK 'AT+CGDCONT=1,"IP","internet"'

# ispnumber
OK-AT-OK "ATDT*99#"
# ispconnect
CONNECT \d\c

Note that Aсcess Point Name, APN (internet) and dialing number (*99#) are cell operator specific.

Connect the line!

killall pppd ; pppd call mts

Here, mts is filename in peers folder.

Now let's read real-time logs:

journalctl -xf -n1000 | grep -e "\(pppd\|chat\)"

Here is my result:

Jun 26 22:39:09 edison pppd[727]: pppd 2.4.6 started by root, uid 0
Jun 26 22:39:10 edison chat[730]: abort on (BUSY)
Jun 26 22:39:10 edison chat[730]: abort on (NO CARRIER)
Jun 26 22:39:10 edison chat[730]: abort on (VOICE)
Jun 26 22:39:10 edison chat[730]: abort on (NO DIALTONE)
Jun 26 22:39:10 edison chat[730]: abort on (NO DIAL TONE)
Jun 26 22:39:10 edison chat[730]: abort on (NO ANSWER)
Jun 26 22:39:10 edison chat[730]: abort on (DELAYED)
Jun 26 22:39:10 edison chat[730]: report (CONNECT)
Jun 26 22:39:10 edison chat[730]: send (ATZ^M)
Jun 26 22:39:10 edison chat[730]: expect (OK)
Jun 26 22:39:10 edison chat[730]: ATZ^M^M
Jun 26 22:39:10 edison chat[730]: OK
Jun 26 22:39:10 edison chat[730]: -- got it
Jun 26 22:39:10 edison chat[730]: send (ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0^M)
Jun 26 22:39:10 edison chat[730]: expect (OK)
Jun 26 22:39:10 edison chat[730]: ^M
Jun 26 22:39:10 edison chat[730]: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0^M^M
Jun 26 22:39:10 edison chat[730]: OK
Jun 26 22:39:10 edison chat[730]: -- got it
Jun 26 22:39:10 edison chat[730]: send (AT+CGDCONT=1,"IP","internet"^M)
Jun 26 22:39:11 edison chat[730]: expect (OK)
Jun 26 22:39:11 edison chat[730]: ^M
Jun 26 22:39:11 edison chat[730]: AT+CGDCONT=1,"IP","internet"^M^M
Jun 26 22:39:11 edison chat[730]: OK
Jun 26 22:39:11 edison chat[730]: -- got it
Jun 26 22:39:11 edison chat[730]: send (ATDT*99#^M)
Jun 26 22:39:11 edison chat[730]: expect (CONNECT)
Jun 26 22:39:11 edison chat[730]: ^M
Jun 26 22:39:11 edison chat[730]: ATDT*99#^M^M
Jun 26 22:39:11 edison chat[730]: CONNECT
Jun 26 22:39:11 edison chat[730]: -- got it
Jun 26 22:39:11 edison chat[730]: send (\d)
Jun 26 22:39:12 edison pppd[727]: Serial connection established.
Jun 26 22:39:12 edison pppd[727]: Using interface ppp0
Jun 26 22:39:12 edison pppd[727]: Connect: ppp0 <--> /dev/ttyUSB0
Jun 26 22:39:15 edison pppd[727]: Could not determine remote IP address: defaulting to a.b.c.d
Jun 26 22:39:15 edison pppd[727]: local IP address x.y.z.y
Jun 26 22:39:15 edison pppd[727]: remote IP address a.b.c.d
Jun 26 22:39:15 edison pppd[727]: primary DNS address d1.d2.d3.d4
Jun 26 22:39:15 edison pppd[727]: secondary DNS address d5.d6.d7.d8

Note that if you have any issues here try to use other ttyUSBx port - some of them may not support data link connections.

Also, as mentioned earlier AT commands for non-Huawei vendors or even different Huawei models may have other AT commands, so try to google it. Also, I have one chat file example for ZTE MF190S modem:

TIMEOUT 6
ABORT 'BUSY'
ABORT 'ERROR'
ABORT '+CME ERROR:'
TIMEOUT 6
'' 'AT'
OK 'ATV1'
OK 'ATE0'
OK 'AT&F&D2&C1S0=0'
OK 'ATS7=60S30=0'
OK 'ATS0=0'
OK 'AT'
OK 'ATV1'
OK 'ATE0'
OK 'AT&F&D2&C1S0=0'
OK 'ATS7=60S30=0'
OK 'AT+ZSNT=2,0,0'
OK 'AT+ZPAS?'
OK 'AT+ZRSSI'
OK 'AT+CGDCONT=1,"IP","internet"'
OK 'ATDT*99#'
CONNECT ''

That is all. Thanks for reading. Please write in comments if this was useful for you. 

 

Useful links:

  1. Main guide about building Yocto for Edison:
    Intel® Edison Board Support Package, User Guide, May 2015, Revision 006
    http://www.intel.com/content/www/us/en/support/boards-and-kits/000005616.html
  2. Very useful article about configuring pppd for 3G USB modes. There are examples for configuring Huawei Dongles.
    https://wiki.archlinux.org/index.php/3G_and_GPRS_modems_with_pppd
  3. List of recipes and it versions from standard yocto layer. Drawyout attention that you need to select your version on top dropdown before search.
    http://recipes.yoctoproject.org/rrs/recipes/1.7/All/
  4. List of Yocto versions and it's code names:
    https://wiki.yoctoproject.org/wiki/Releases