Learning how to build an embedded Linux image for Raspberry Pi
- create a bootable SD card for Raspberry Pi Zero W from scratch
- no GUI, no manual package installation on the RPI
- be able to ssh into the RPI easily via USB (no wifi setup)
- use a simple Yocto recipe to create the SD card
- use a VM to run Yocto
- be able to run Yocto in VM on Windows host
- be able to write SD card image on Windows from VM
Maybe learn about device drivers.
The following applications need to be installed to use this project:
- VirtualBox - a free, widely used hypervisor
- Vagrant - a free tool for building and configuring VMs
The following hardware is required:
- a Raspberry Pi, preferably a Zero or Zero W
- host machine with SD Card reader
- spare SD Card 8 GB or greater
- micro USB cable
You'll also need a fast internet connection, as there are many downloads.
This Git project uses submodules to pull in the Yocto meta projects. After you've cloned this project, use the following in bring in the submodules:
git submodule update --init --recursive
You can repeat this later on the bring in subsequent updates to the "meta" projects.
By using a VM, all the required yocto tools are installed and updated. No worries about interference with other project toolchains. One shortcoming is that builds are reportedly about half as fast, but with a fast host processor, this is not a big issue.
This was developed and tested on Windows 7, but should work on Windows 10, Mac and Linux as well.
The Vagrant file specifies:
- the guest OS, bento/ubuntu-18.04
- the guest VM memory (4096 KB) and number of cores (4)
- the Chef provisioning recipe for the Yocto prerequisites
The Vagrant file and the Chef cookbook may be be modified to suit the circumstances.
Run vagrant box update to make sure the vm image is up to date
Run vagrant up
to create and provision the VM. This requires an internet connection and may take several minutes.
Run vagrant ssh
to access a shell on the VM. You will run the Yocto build and SD Card utilities from this shell.
The yocto build environment will be setup in the VM as follows:
- /vagrant/source - the yocto source and layers
- /home/vagrant/build-rover - the build workspace
Run the following to setup the Yocto build environment:
TEMPLATECONF=/vagrant/conf source /vagrant/sources/poky/oe-init-build-env build-rover
This will change the current directory to "build".
Tip: the template doesn't overwrite existing conf files. You may ned to
rm build-rover/conf/*
Building the image will take place in the build-rover directory. The sources directory is only used to update the yocto tool chain.
Before building the image with the "bitbake" command, check the build parameters.
- ./conf/bblayers.conf - specifies the modules that will go into the image
- ./conf/local.conf - has the desired machine, e.g. "raspberrypi0"
The conf/local.conf file should have:
MACHINE ?= "raspberrypi0-wifi"
ENABLE_I2C = "1"
Machine can also be "raspberrypi-wifi" for use with RPIWZ.
Now run
bitbake core-image-base
The first time you run bitbake, it will take several hours. It has to do the following:
- download source files and dependencies
- apply patches
- configure the builds
- compile the sources
- package the results
Subsequent builds will be faster, as the build caches intermediate files.
After a new image has been built with bitbake, it's time to put it on the SD Card for the Raspberry Pi. This process is not as simple as for the usual RPI images, such as Jessie. First, a blank SD Card needs to be properly partitioned. Then the files from the build need to be copied into their respective partitions. These tasks are automated with scripts included in this project.
Insert the SD card into the host system.
Verify access to the SD Card with the lsblk
command on the VM.
You should see a block device named sdf
.
On Windows, there's some setup required to see the SD Card in the VM. See the section "Access SD Card via VirtualBox on Windows" below.
This will create two partitions on the SD Card:
- a smallish 'boot' partition for the bootloader
- a large 'root' partition for the main file system
Run /vagrant/scripts/partition-sd.py
Create a mount point sudo mkdir /media/card
.
TODO: make the media/card part of VM
This step prepares an SD Card that the RPI can boot.
Look at the source code for an overview of what it does.
Run /vagrant/scripts/write-sd-image.py
When the process is successful, you should see a message like "Finished write of image raspberrypi0".
After inserting the SD card into the Raspberry Pi Zero W and booting, you should be able to get a remote shell.
Connect a USB cable between your desktop or laptop and the Raspberry Pi Zero W.
On Mac/Linux, start the remote shell with this command:
ssh root@raspberrypi0-wifi.local
On Windows, start the remote shell with this command:
putty root@raspberrypi0-wifi.local
Tips:
- on the RPI0, plug micro USB into the USB, not the PWR IN connector
- wait for the OS to finish boot - the green LED should flicker and then go solid
- you may need to clear the RSA fingerprint from ~/.shh/known_hosts
You can of course use the other related ssh commands to perform file copy and remote exec. On Mac, there's even a way to mount a remote directory over ssh. This can be very handy when you have an RPI application that you are developing. You can edit the application on your host computer with an IDE and SCM using the full resources of your host.
Debugging the image on Raspberry Pi Zero/Zero W:
- use a monitor with HDMI input, use an HDMI mini cable or adapter
- USB micro to USB A adapter to connect USB keyboard
- power via the power USB micro connector
- for RPI GUI, add a mouse with a cheap USB hub and Micro-USB adator
When LED flashes seven times, that indicates missing kernel.img
Target image bb files are in rpi/meta-rpi/images.
Windows: bitbake won't work on VM shared folder. Something about locking files. Kind of a shame, because it would have been nice to use IDE on host system to browse the yocto/poky/oe meta files. Might be possible to do a reverse share.
When you see 'bitbake command not found': source oe-init-build-env
Target SD card images ls -l ~/rpi/build/tmp/deploy/images/raspberrypi0-wifi
~/rpi/meta-rpi/images
ap-image: iot-image iot-image: console-basic-image audio-image: >image console-basic-image: >core-image console-image: >image flask-image: console-basic-image
~/rpi/build/conf/local.conf
There's some setup required to be able to access the SD Card from the VM.
Once this is done, you'll be able to see the inserted SD Card inside the VM with the lsblk
command.
Note: It seems to be better to halt and start the VM with the vagrant commands
vagrant halt
andvagrant up
. Vagrant seems to get a bit confused when you do this directly from VirtualBox GUI.
- Insert SD card in reader on Windows host machine
- Install the VirtualBox Extension Pack
- Restart VM
Only needs to be done once after VirtualBox is installed. If you've upgrdaed vb, update the ext as well, using File > Prefences > Extensions, etc
- Halt the VM
vagrant halt
- Open VirtualBox Manager
- Select the
yocto-rpi-vm
VM - Select Settings > USB
- Enable USB Controller
- Click the "+" tool button
- Select the host USB device for the CD card reader
- Start the VM
- Wait a while, and the SD card will appear with
lsblk
in the VM
Only needs to be done when a new VM is created with Vagrant.
Note: the following was useful. It required running cmd and VBox as admin, but still access errors. https://scribles.net/accessing-sd-card-from-linux-virtualbox-guest-on-windows-host/
One of the goals of this project is to be able to ssh into the RPI via a USB cable. The advantage of this over WiFi is that it requires no WiFi network nor access credentials. This would be especially useful in some demo situations, which may be hindered by lack of or difficulty of establishing WiFi connectivity.
https://www.thepolyglotdeveloper.com/2016/06/connect-raspberry-pi-zero-usb-cable-ssh/
During the course of getting this to work, I learned the following:
- the "ethernet gadget" module tunnels an ethernet IP link over USB
- the avahi daemon and Bonjour service provide for ad-hoc DNS lookup
- the ssh daemon is not configured by default on RPI
On a Mac, the following should be observed:
- in System Preferences > Network, the RNDIS/Ethernet Gadget should have connected status and an IP address
ping raspberrypi0.local
should resolvessh root@raspberrypi0.local
should open a shell on the RPI
On the RPI, the following should be observed:
- the avahi-daemon is running (two processes)
- the dropbear daemon is running (see note below)
- the g_ether module should appear in
lsmod
(there are a few other associated ones, as well) - the usb0 network interfacew should appear in
ifconfig
The are two options on RPI for ssh service:
Dropbear is a light-weight implementation.
(need to add to recipe)
The following are taken care of by yocto, correct?
In the /boot/cmdline.tx file add the following at the end after rootwait: modules-load=dwc2,g_ether
In the /boot/config.txt file, add the following at the end: dtoverlay=dwc2
It's handy to have sftp server on the RPI, so that you can easily upload files without having to setup full internet connection.
Supposed to be handled with openssh
Just use scp, instead!
It was very helpful to just connect the RPI via HDMI and USB keyboard to debug the boot process, look at log files, and test some assumptions.
A further goal is to run an app on the RPI that interacts with the hardware. An example is to drive a two-axis, servo-controlled arm. For expandability a servo hat was used. The RPI communicates with the servo hat via I2C.
The yocto overlays support I2C. The following should be added to ~/build/conf/local.conf:
ENABLE_I2C = "1"
This setting will add the following to boot:/config.txt:
dtparam=i2c1=on
dtparam=i2c_arm=on
There were some problems with the yocto-generated boot:/config.txt. Still using a short one from /vagrant/boot.
But still need to
modprobe i2c_dev
after boot to get /dev/i2c-1 to appear
It seems there's something missing in /etc/init.d, or in /etc/modprobe.d, or in thr udev configuration.
The solution is to add i2c_dev
to /etc/modules. because i2c is not in the device tree, unlike SPI.
This is taken care of by the sd card script, but ought to be in a Yocto recipe.
The /dev/i2c-1 file exists, but its permissions are 600 root root
. Need to create an "i2c" group so that a
non-root process can access it.
- create i2c group
- add udev rule to set the group and permissions on /dev/i2c-1 (see below)
- add any application users (such as "pi" or "rover") to the i2c group)
The udev rule can be created along the lines of echo 'KERNEL=="i2c-[0-9]*", GROUP="i2c"' >> /etc/udev/rules.d/10-local_i2c_group.rules
Some things left to explore:
RPI_USE_UBOOT
- remove dtoverlay=dwc2 from config.txt
- test VM and tooling on Mac
- be able to access the Pi Zero W as a Bluetooth peripheral
- which Ubuntu for VM, 16.04 or 18.04
This yocto-rpi-vm project only builds an embedded linux image for the Raspberry Pi suitable for adding an embedded application.
I have a fledging robotic application which I plan to run. The main focus would be to control the two-axis servo arm from a smart phone via bluetooth.
This project was developed and testing on the following platform:
- Windows 7 Professional
- Intel Xeon E3-1270 V2 @ 3.50 GHz
- 16 GB memory
- SSD main drive
- SATA 2 TB data drive
On this platform, the build took about 2 hr 45 min.
- MBP Core i7 @ 2.7 GHz
- macOS High Sierra 10.13.6
- 16 GB memory
The MCU is marked Elpida B4432BBPA. Supposed to be BCM2835?
ARM1176JZF-S
BCM43438/CYW43438 radio, connected via SDIO
https://www.yoctoproject.org/docs/2.6.1/brief-yoctoprojectqs/brief-yoctoprojectqs.html
https://github.com/jumpnow/meta-rpi
https://blog.gbaman.info/?p=791 Ethernet over USB
https://media.readthedocs.org/pdf/meta-raspberrypi/latest/meta-raspberrypi.pdf
http://www.circuitbasics.com/raspberry-pi-zero-ethernet-gadget/
https://elinux.org/Bitbake_Cheat_Sheet
https://www.virtualbox.org/wiki/Downloads
Detailed description of RPI Device Trees and Overlays
https://github.com/raspberrypi/linux/tree/rpi-4.14.y/drivers/net/wireless/broadcom/b43
http://linuxgizmos.com/the-best-way-to-build-with-yocto-project-and-bitbake/