Mostrando postagens com marcador toolchain. Mostrar todas as postagens
Mostrando postagens com marcador toolchain. Mostrar todas as postagens

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/

    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