terça-feira, 15 de abril de 2014

Embedded Linux Device Drivers

In this article I will talk about Linux driver development to embedded systems. There is a certain lack of documentation or tutorials on the subject. I hope with this article fill some of this gap.

Introduction


User applications cannot directly communicate with hardware because Linux does not allow. Linux divides RAM memory into two regions: kernel space and user space. The kernel space is where Linux runs and provide their services and where device drivers reside. User space is the area of memory where the user processes are executed. The kernel space can be accessed by user processes only through the use of system calls.
Thus, preferably the processes in kernel space can communicate with the hardware and access the peripherals. You can also use user space drivers to access the hardware. This mechanism allows developers to make software without worrying about hardware details. And protects the user from inadvertently accessing devices and somehow damage them. So far it has working fine.

What is Device Driver?


It is a program or process that runs on a special memory region and through which the user can access a device or resource of a processor. He serves as a mediator between software and hardware.

For example, when you take a photo on your Android phone, the camera driver interacts with the software and passes information to him regarding the captured images and other information. The end result is the photo. Or when you want to play your favorite game, but it is not possible without the driver for the video card, right? Through the driver, the game accesses features video card that allow amazing experience that games provide. This is idea, serve as mediator between the user and the hardware or between software and hardware.

Drivers as modules or built into the kernel


The drivers in the Linux kernel can be compiled as modules that can be loaded at runtime or embedded into kernel itself. The drivers in modules are known as Loadable Kernel Module and behave similarly to Windows DLLs. An LKM (Loadable Kernel Module) is composed of a single ELF object file, usually named as "serial.o" for the 2.4.x kernel or "serial.ko" to the kernel 2.6.x and later versions. A big advantage is that it can be loaded into memory at runtime by a simple command. And another advantage is that when you change the code LKM, it is not necessary to compile the whole kernel, just compile only the LKM.

The embedded or monolithic drivers are modules that are built as part of the kernel. They form, together with the Linux subsystems and other components, a single image, the end result is the kernel itself. Advantages of using monolithic drivers:
  • once accepted into the official Linux kernel, it will be maintained by developers;
  • free cost of maintenance, repair security flaws and improvements in code;
  • easy access to the source code by users;

Device Tree


Device tree is a data structure for describing hardware. Instead of including hardware code in the operating system, many aspects of the hardware can be described in a data structure that is passed to the kernel at boot time.

The Device Tree was used until recently only in systems with PowerPC and SPARC processors. But it was recently ported to ARM processors in the 3.7 kernel and its use is now mandatory in the development of new drivers. It is a great advantage for embedded systems, because we can easily describe the different types of boards that use the same processor or different processors.

The data structure itself is a simple tree of nodes and properties with names. The nodes contain properties and child nodes. Properties are a pair of name-value. Example description of an SPI controller:

spi@10115000 {
       compatible = "arm,pl022";
       
reg = <0x10115000 0x1000 >;
   };

With the Device Tree, it is now possible to boot any board with the same kernel! But this requires that the processor drivers have support to Device Tree.

Toolchain


If you do not know, the same way you need a cross compiler or toolchain to generate executables for a given platform, you need a cross compiler to generate device drivers. Nowadays many Linux distributions provide precompiled binaries of cross compilers and tools for easy installation for a variety of architectures. You can also compile a manually if you prefer.

The compiler used will depend on the architecture of the SoC (System-on-a-chip) chosen. The most commonly used architectures in Embedded Linux today are ARM, MIPS and PowerPC. It is also sometimes used the Intel x86. You need to compile or download a variant of gcc for the specified target. It's what we call cross-compiler or toolchain. Then we would have something to ARM as arm-linux-gcc. For MIPS, mips-linux-gcc. And so on.

Kernel version


The 2.5 kernel implements a unified device driver model that will make driver development for 2.6 easier.

The kernel version is very important when programming Linux device drivers. The Linux kernel API changes constantly over time. An I2C driver written for the 2.6.30 version, does not work for version 2.6.36 or greater. And the differences between version 2.4 and 2.6 are even greater. 

In version 2.5 of the Linux developers have created a Unified Device Driver Model and became effective on version 2.6 of the kernel. It consists of a number of structures and functions common to all device drivers. And includes support for power management, communication with the user space, hotplug devices, device classes, and more. Linux Device Driver Model is a complex data structure that resides in the / sys folder.


From book "Linux Device Drivers, 3rd Edition" - Figure 14-1 (A small piece of the device model)

You have to port a driver written for 2.4 if you intend to use it in version 2.6 or greater. And there are always changes in the kernel API over time. Why does kernel API change constantly? Read this document for more details: stable_api_nonsense.txt

One interesting thing about the evolution of the Linux kernel is that new versions always add new attributes and in recent years many specific attributes for embedded systems has been added. A good example is the IIO (Industrial I / O) subsystem. It was assigned to support ADC and DAC converters, accelerometer, light sensor, proximity sensor, magnetrômetro, etc.

For anyone who writes code for software does not matter the kernel version. An application written to version 2.4 runs on versions 2.6.x, 3.x and possibly later versions. Because Linux has always maintains backward compatibility at application level.


Peripherals on Embedded Systems


From device driver perspective, embedded software developers often deals with devices not commonly found on conventional computers. Examples of such devices: GSM modem, SPI, I2C, ADC, NAND memory, rádio, GPS and so on.

Under Linux, there are essentially three types of devices: network devices, block devices and character devices. Most devices fall into the category of character devices. However, nowadays, many device drivers are not implemented directly as character devices. They are developed under one specific framework for a given device. Examples of frameworks: framebuffer (graphics), V4L2 (video capture), IIO (Industrial I / O), etc.

For example, If you want to use a camera for which is not supported on Linux kernel, you have to write a device driver using Video4Linux2 framework.

Interruptions


If you already have some knowledge or experience with embedded systems, you probably know that interruptions is an important part in the development of firmware. However, unfortunately not as simple to use interrupts in Embedded Linux. You can only use interrupts in drivers, or in kernel space or by means of poll()/select() user space. But the use of poll()/select() offers few resources.

The form of interruption that we are accustomed to use in embedded systems is possible only in device drivers. You can not create a routine or function of treatment interruption in software. Another alternative is to use drivers in user space, through the use of UIO.

The form of interruption that we are accustomed to use in embedded systems is possible only in device drivers. You can not create a routine or function of treatment interruption in software. Another alternative is to use drivers in user space, through the use of UIO.

Writing Portable Device Drivers

Follow the kernel team's rules to make your drivers work on all architectures.

When dealing with embedded systems there is a good chance you use multiple types of processors along the career. It is important you keep in mind that you should always write portable device drivers. Almost all Linux kernel device drivers work on more than just one type of processor. So you have to know concepts like proper variable types, memory page sizes, endian issues, proper data alignment, etc.

For example, ARM processors have memory pages of 4K, 16K or 32K, but the i386 Intel has only 4K memory pages.

Memory Mapping


Some processors use the method of Port I/O and have special instructions to access ports, like intel x86. Other processors use the method of Memory-Mapped I/O, like ARM. Thus the family of functions in() and out() works only to x86. To ARM use family of functions write() and read().

For either method, or MMIO PMIO in order to access the RAM or the ports I/O on Linux, it is necessary to map physical memory to virtual memory. To access I/O memory in a portable manner, you must call ioremap() to gain access to a memory region and iounmap() to release access. However these functions are being replaced by devm_ioremap_resource() and eventually become obsolete. If the allocation of memory region does not return an error, then one can use the family of functions read()/write() to read and write memory mapped. This is the typical method for accessing registers of a processor that uses MMIO.


Conclusion

In this article I tried to address the most relevant topics in driver development for Embedded Linux and showing differences between programming drivers for Linux Desktop and Embedded Linux. These differences are most noticeable when drivers platform program.


References




sexta-feira, 11 de abril de 2014

What is Embedded Linux

Introduction 


Embedded Linux Systems is the application and usage of Linux kernel to a eletronic board whose main element is a System-on-a-chip (SoC). The Linux kernel in conjunction with a range of other software is written in FLASH memory or other storage media present on board. This combination constitutes a complete and functional operating system. 

The same Linux that runs on a supercomputer can run on a simple board! What makes this possible is the wide range of architectures and processors that Linux supports. But not all these architectures are actually used in embedded configurations. The most commonly used in embedded systems is ARM, PowerPC and MIPS. 

Many kernel sub-communities maintain their own kernel, with usually newer but less stable features. In some cases, manufacturers maintain derived versions of the official Linux in order to provide support to your specific hardware. But, official Linux kernel is hosted in: https://www.kernel.org/.

Architecture of an Embedded Linux System

The basic components of embedded Linux are:
  1. Bootloader
  2. Kernel
  3. Rootfs
  4. Toolchain
A Bootloader resides in protected program memory on a SoC or storage media on board. It is usually the first software to run after power up or reset and is specific for each board. It is responsible for loading the kernel into main memory system. It can receive configuration parameters via file or command line. And you can also pass parameters and commands to the kernel through Bootloader.
The Kernel is Linux itself. As you should know the Kernel is responsible for managing all internal peripherals to SoC and outside it, the main and secondary memory system, besides offering access mechanisms hardware for software on user space(system calls). It coordinates all the processes so there are no conflicts or disputes over system resources. And many other tasks. The figure below shows the process of booting a Linux Embedded system and the basic elements that compose it:

Rootfs(root file system) is a set of softwares and libraries organized in a predefined hierarchy. Is closely related to the idea that we have about Distributions based on GNU/Linux. For this reason we have rootfs done by Distros like Debian, Ubuntu, Fedora, Arch and so on. Under Debian there is ports to ARMEL, ARMHF, MIPS, PowerPC, Sparc. 
Rootfs can be built with some sort of file system targeted to memory Nand like cramfs, JFFS2, squashfs and many others. Nowadays you can also use file systems designed for HDD like ext2, ext3 and ext4.

Toolchain


A toolchain is a set of software development tools. A cross toolchain (like arm-linux-gcc) run on a host system of a specific architecture (such as x86) but produce binary code (executables) to run on a different architecture (e.g. ARM). This is called cross compilation and is the typical way of building embedded software. 

Toolchain can be considered the central element of an embedded Linux. From it, all the other three elements will be generated. So, if you choose a armhf cross toolchain, bootloader, kernel and all software have to be compiled for armhf. You can compile your own toolchain or to download an existing. Debian toolchains are a good choice because they are stable and compact. On the other hand build your own toolchain is a complex task and sometimes can be frustrating. You can find the Debian toolchains here: http://www.emdebian.org/

There are three concepts associated with toolchains which you will see constantly:

  • the build machine, on which the toolchain is built
  • the host machine, on which the toolchain is executed
  • the target machine, target for which the toolchain generates executables


  • Typically we use something like a x86 build machine, a x86 host machine and some target(ARM, PowerPC, MIPS). The build/host machine could be Windows or Mac OS, however it is more recommended to use Linux as Workstation. The reason is simple: to gain experience with Linux, there really is no substitute for actually using a Linux system for your own development. My personal recommendation is: use Linux!

    Builder Systems


    There are software that can build of automated manner a whole embedded Linux system. Using the same scheme of construction of Linux, through a .config file. The most systems allows building using the toolchain indicated by you or build everything from scratch, including the toolchain. Good choices to builder systems are BuildrootYoctoproject and PtxdistYou can also manually build a embedded linux system from scratch, but it takes a long time. The book Building Embedded Linux Systems explains step by step how to build the entire system from scratch.

    Boards with embedded Linux


    In 2013 one avalance of new boards appeared on the market. Many with attractive prices. Before it was difficult to buy a board due to high prices. There were few boards with affordable prices. For example, Friendly ARM. 

    Nowadays there are many options and settings of boards. Among the cheapest and with great cost benefit are OLinuXino, Cubieboard, BeagleBone Black, Raspberry pi, Wandboard... They are made by independent companies from different parts of the world. Of the new boards that have emerged recently, Beaglebone Black spread very fast. 

    The choice will depend on project requirements and its available budget. The boards whose target audience is the hobbyists are generally cheaper. You can buy them under $100. Boards with greater availability of peripherals and more RAM memory are usually more expensive.

    Programming languages


    The availability of ports done by distributions like Debian, Fedora, Arch, becomes programming possible in any available language in Linux Desktop. Language C, C++, java, perl, python. Many projects have been made ​​in python. However most of it is still done in C language.

    Applications


    Linux has expanded greatly in the world of electronics in recent years. Largely due to Android. Not only that, but also for its maturity and improvements to ports used in embedded systems like ARM, MIPS and PowerPC. It seems that the developers of the kernel is giving more attention to embedded systems and new features have been added.


    Today Linux is used in many electronics devices, even where it was not used before. Examples like TVs, refrigerators, smartphones, tv satellite receivers, automation car and so on. It is likely that there is further growth.

    Reference

    http://www.embarcados.com.br/arm-para-hobbyistas-parte-1-de-3-placas-de-desenvolvimento/

    domingo, 6 de abril de 2014

    Configuring the WIFI chipset rtl8188cu

    Building Linux sunxi with WIFI Realtek support



    The first step to configure the wifi module is to load a driver support this chipset. There is a legacy driver called 8188cu.ko and other newer called rtl8192cu.ko. This driver support both chiptsets rtl8192cu and rtl8188cu, but it is necessary a firmware to work.

    Before doing these steps, first test if there is already WIFI Realtek support in Linux board:
    modprobe rtl8192cu (linux board)

    If the message is: modprobe: FATAL: Module rtl8192cu not found, do next steps. If no, go to section Configuring the interface.


    Warning: this step is to be done on PC! You can enable the driver in kernel config:
    Device Drivers --> [*] Network device support -->[*] Wireless LAN --> <M> Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter


    Now compile the kernel with Realtek support enabled. You could read: Compiling linux for sunxi.


    You can also download the source code RTL8192CU and build it manually. For the Wifi works it is necessary to have the firmware rtl8192cufw.bin. In the Debian repo there is the package firmware-realtek that contains the firmware. Download here debian-repo and tranfer to uSD or media used and install it:
    dpkg -i firmware-realtek
    In my case (Debian 6), even installing the package firmware-realtek, rtl8192cufw.bin was not present. Verify the /lib/firmware/rtlwifi and look for it. If this is your case, download here rtl8192cufw.bin and tranfer to uSD or media used. Then copy the firmware to /lib/firmware/rtlwifi of target. This debian-rootfs already have all the necessary packages. Choose your preferred Linux distribution!


    In Linux with WIFI Realtek support enabled and the firmware in right place just type:
    modprobe rtl8192cu (linux board)
    
    You should see something like:
    rtl8192cu: MAC address: 48:02:2a:ea:8c:3e
    rtl8192cu: Board Type 0
    rtl8192cu: rx_max_size 15360, rx_urb_num 8, in_ep 1
    ieee80211 phy0: Selected rate control algorithm 'rtl_rc'
    usbcore: registered new interface driver rtl8192cu

    Configuring the interface (linux board)



    All commands and actions performed in that section is to be done on board. That is, in linux that is running on the board!
    In order to configure the wlanN(N can be any interger) interface download from your PC and transfer to uSD the packages wireless-tools and wpasupplicant and install them, if your system does not have them! These packages are to Debian wheezy armhf. Download the appropriate packages for your system!
    Thereafter check if your wifi interface is active:
    ifconfig
    
    If you see only the lo interface,  we find out the number of interface wlanN(N can be any integer). Type:
    iwconfig
    lo        no wireless extensions.
    
    tunl0     no wireless extensions.
    
    wlan0     IEEE 802.11bgn  ESSID:off/any  
              Mode:Managed  Access Point: Not-Associated   Tx-Power=0 dBm   
              Retry  long limit:7   RTS thr=2347 B   Fragment thr:off
              Encryption key:off
              Power Management:on
    Ok, my N is 0. Edit the file /etc/network/interfaces and change as your network(dhcp or static):
    auto wlan0 
    iface wlan0 inet dhcp
        wpa-driver wext
        wpa-ssid YOUR_WIFI_SSID (change as your network)
        wpa-key-mgmt WPA-PSK
        wpa-psk YOUR_WIFI_PASSWORD (change as your network)
    Now we can type:
    ifup wlan0 (replace with the number you found)
    From that point everything already works in the current kernel!


    Verifying the Wifi functionality (linux board)

    Type ifconfig and a similar result should appear:
    ifconfig
    
    lo        Link encap:Loopback Local  
              inet end.: 127.0.0.1  Masc:255.0.0.0
              endereço inet6: ::1/128 Escopo:Máquina
              UP LOOPBACKRUNNING  MTU:16436  Métrica:1
              RX packets:16 errors:0 dropped:0 overruns:0 frame:0
              TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
              colisões:0 txqueuelen:0 
              RX bytes:1000 (1000.0 B)  TX bytes:1000 (1000.0 B)
    
    wlan0     Link encap:Ethernet  Endereço de HW 00:0d:f0:a2:63:74  
              inet end.: 192.168.1.3  Bcast:192.168.1.255  Masc:255.255.255.0
              endereço inet6: fe80::20d:f0ff:fea2:6374/64 Escopo:Link
              UP BROADCASTRUNNING MULTICAST  MTU:1500  Métrica:1
              RX packets:604836 errors:0 dropped:0 overruns:0 frame:0
              TX packets:343723 errors:0 dropped:0 overruns:0 carrier:0
              colisões:0 txqueuelen:1000 
              RX bytes:898817015 (857.1 MiB)  TX bytes:31367981 (29.9 MiB)
    
    Make sure you are connected on the wireless network:
    iwconfig
    
    lo        no wireless extensions.
    
    wlan0     IEEE 802.11bgn  ESSID:"GVT-9EE1"  
              Mode:Managed  Frequency:2.447 GHz  Access Point: 84:C9:B2:C9:9E:E2   
              Bit Rate=72.2 Mb/s   Tx-Power=20 dBm   
              Retry  long limit:7   RTS thr=2347 B   Fragment thr:off
              Encryption key:off
              Power Management:off
              Link Quality=51/70  Signal level=-59 dBm  
              Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
              Tx excessive retries:0  Invalid misc:1   Missed beacon:0
    
    One way to improve the connectivity is downloading the network-manager. Test your internet connection and type:
    apt-get update
    
    apt-get install 'any package'
    If these two commands to work, the configuration is ok!

    sexta-feira, 4 de abril de 2014

    Using GPIOs from userspace

    GPIO usage for linux sunxi


    What I'll state here applies to many boards on the market today. However, it is targeted specifically for boards with Allwinner processors. In this article we will use GPIO Sysfs Interface for Userspace.

    In order to you can to use GPIOs signals of your board, you have to determine if there is a GPIO driver for your platform. Besides, you must know if this driver follows the standard GPIO Linux framework. Check under the folder /drivers/gpio/xxxx.c whether there is a GPIO driver. If so, this driver uses the standard GPIO framework. If not, you have to look in other folders.

    For the case of processors Allwinner, there was a driver called sun4i-gpio, but was removed in favor of the new gpio-sunxi. This new driver uses GPIO Linux framework. This means that you can manipulate the pins I/O through the entries in the /sys directory. In addition, there are many other benefits to using the standard framework.

    Since you have found the driver of the GPIO to board processor, how can we use it in user space? You either can access the GPIO signals through command line or by software. The second option is obviously more interesting for those who make projects. I will present both.

    Defining the pin number


    First you must determine the number corresponding to the pin you want to use. The number that kernel "see". In Linux there is a standard to define this number. For example, if your CPU have a GPIO with 2 ports, each port containing 32 pins, so GPIO1.5 will be 5, GPIO1.32 will be 32 and GPIO2.1 will be 33. Do the calculation according to the number of pins and ports of your GPIO.

    You can also get information about number pin by GPIO controller, referenced in the kernel as gpiochipN. GPIO controllers have paths like /sys/class/gpio/gpiochip42 (for the controller implementing GPIOs starting at #42) and have the following read-only attributes under /sys/class/gpio/gpiochipN: base, label and ngpio.

    See the manufacturer's documentation to know the correct number for your platform. On Allwinner, the correct number is in script.fex file. For example, if we want to use pin PG9 on A13-OLinuxino:
    
    
    [gpio_para]
    gpio_used = 1
    gpio_num = 6
    gpio_pin_1 = port:PB03<1><0>
    gpio_pin_2 = port:PB04<1><0>
    gpio_pin_3 = port:PB05<1><0>
    gpio_pin_4 = port:PB06<1><0>
    gpio_pin_5 = port:PB07<1><1>
    gpio_pin_6 = port:PG09<1><1>
    
    
    you will pass the number 6 as parameter. This suits to commands and software. Let's see!

    GPIO Example usage via command line


    Usage via command is only useful for testing. Perhaps with a script you can do something more dynamic. For more complex tasks, the method for software is the preferred.
    GPIO=6
    cd /sys/class/gpio
    echo $GPIO > export
    
    If export was successful, you should see a new folder. Get in.
    cd gpio$GPIO
    
    Set the direction of the pin using the strings "in" or "out". They are self-explanatory. Example of reading:
    echo "in" > direction
    cat value
    
    Example of writing:
    echo "out" > direction
    echo 1 > value

    GPIO Example usage via software


    In case the software is interesting to create a library with functions as such export, set direction, read, write, etc. I did a library based on RidgeRun's code.  I just rearranged the code!
    https://www.dropbox.com/sh/gaqxgasjuixmnr3/7rHxvPxdoC
    We can set a pin at high level and low level as follows:
    gpio = atoi(argv[1]); // take pin as parameter
    gpio_export(gpio);
    gpio_set_dir(gpio, 1);
    gpio_set_value(gpio, 1); // Set high level
    sleep(1);
    gpio_set_value(gpio, 0); // set low level
    Please, always keep the license and credit to the original author!

    The code shown above will only work if you apply this patch: gpio-sunxi.patch, created by Emilio Lopes.

    Video on Youtube: https://www.youtube.com/watch?v=iN3mEWqaf1s

    References


    http://www.softwarelivre.blog.br/2014/05/usando-gpio-partir-do-userspace.html
    https://github.com/torvalds/linux/blob/master/Documentation/gpio/sysfs.txt
    https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals
    http://sergioprado.org/user-space-device-drivers-no-linux-parte-2/

    quarta-feira, 2 de abril de 2014

    Compiling linux for sunxi A13/A10

    Toolchain
    First you need to download all the tools and the cross compiler in order to compile a linux kernel for sunxi. These softwares are downloaded in your PC! The cross compiler installed in PC, will generate an image that will run in board. The same compiler also generates software and drivers that can run in board.
    If you have not installed toolchain, folow these steps.
    Add this link into your /etc/apt/sources.list:
    Note: Emdebian's armhf-toolchain is only available for Debian/unstable at the moment.
    It is important to use armhf because most software currently is compiled for armhf. If you use armel, you must get software compatible with armel!
    Run these commands in order to get cross compiler:
    apt-get install emdebian-archive-keyring
    apt-get update
    apt-get install gcc-4.7-arm-linux-gnueabihf
    Choose the same version of the compiler's distro, thus you avoid incompatibilities and broken packages. Type 'gcc -v' and check your version.
    Create a symbolic link to arm-linux-gnueabihf-gcc:
    ln -s arm-linux-gnueabihf-gcc-4.7 arm-linux-gnueabihf-gcc
    You need extra tools to compile linux kernel:
    apt-get install build-essential git debootstrap u-boot-tools libncurses5-dev

    Clone the repository
    git clone -b sunxi-3.4 https://github.com/linux-sunxi/linux-sunxi.git
    The kernel linux-sunxi is provided by sunxi community, but it is not included in the official linux kernel. The official linux kernel with support sunxi can be found in these links:
    https://github.com/mripard/linux
    https://github.com/jwrdegoede/linux-sunxi/tree/sunxi-devel

    But still is not usable, for now use linux-sunxi.

    Configure
    For A10 use:
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun4i_defconfig
    
    For A13 use:
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun5i_defconfig

    Configure additional parameters, such as drivers or debug options:
    make ARCH=arm menuconfig
    To A13-OLinuXino-Wifi enable Realtek's driver:
    Device drivers --> Network device support --> Wireless LAN --> <M> Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter

    Build
    make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
    
    Choose -jN according to the number of cores of your CPU. Four cores -j4, two cores -j2...

    This command will copy all enabled modules in the specified folder by INSTALL_MOD_PATH:
    make ARCH=arm INSTALL_MOD_PATH=output modules_install
    
    Install
    As a final result we will have kernel and modules:
    arch/arm/boot/uImage
    output/lib/modules/3.4.XXX/
    
    The uImage file needs to be started by u-boot, and the modules directory needs to be copied to the /lib/modules on the target rootfs. So copy kernel image uImage to SD partition 1 and modules to partition 2, into rootfs.

    Videos on Youtube:
    Part 1: https://www.youtube.com/watch?v=3xNdH9SquL4
    Part 2: https://www.youtube.com/watch?v=ilDhOzmkORY
    Part 3: https://www.youtube.com/watch?v=LWJ11nJ_0-k