UClinux Nios2 Custom Hardware

24
μClinux on NIOS2 with custom hardware and kernel module Johan Granath Applied Electronics for Embedded Systems AGSTU School of Higher Vocational Education Malm¨ o, Sweden [email protected] February 18, 2013 Abstract This document describes how to set up a NIOS2-CPU system with MMU for use with μClinux. It includes a simple custom hardware written in VHDL, connected to the Avalon bus, and a kernel module to be able to interface with the custom hardware from user-space. The custom hardware controls some LEDs on a Altera development board (DE2-115), and should be fairly simple to adapt to other circumstances. 1

description

MicroC linux document

Transcript of UClinux Nios2 Custom Hardware

  • Clinux on NIOS2 with custom hardware and

    kernel module

    Johan GranathApplied Electronics for Embedded Systems

    AGSTU School of Higher Vocational EducationMalmo, [email protected]

    February 18, 2013

    Abstract

    This document describes how to set up a NIOS2-CPU system with MMU foruse with Clinux. It includes a simple custom hardware written in VHDL,connected to the Avalon bus, and a kernel module to be able to interface withthe custom hardware from user-space. The custom hardware controls someLEDs on a Altera development board (DE2-115), and should be fairly simpleto adapt to other circumstances.

    1

  • Contents

    1 Specification 3

    2 QSys - building the system 42.1 OnChip RAMs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.2 CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 SDRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.4 UP clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.5 JTAG UART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.6 Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.7 MMC SPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.8 UART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.9 Custom LED component . . . . . . . . . . . . . . . . . . . . . . . 9

    2.9.1 Create new component . . . . . . . . . . . . . . . . . . . . 92.10 Set properties of led component . . . . . . . . . . . . . . . . . . . 112.11 Finishing the system . . . . . . . . . . . . . . . . . . . . . . . . . 112.12 Connecting wires . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

    3 Clinux - installation and configuration 133.1 Cloning the repositories . . . . . . . . . . . . . . . . . . . . . . . 133.2 Preparing the dts . . . . . . . . . . . . . . . . . . . . . . . . . . . 143.3 Configuring Clinux . . . . . . . . . . . . . . . . . . . . . . . . . 153.4 Building Clinux . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.5 Loading Clinux onto the board . . . . . . . . . . . . . . . . . . 18

    3.5.1 SD-card as root file system . . . . . . . . . . . . . . . . . 183.5.2 Boot from memory . . . . . . . . . . . . . . . . . . . . . . 18

    4 Custom hardware setup 204.1 Kernel configuration . . . . . . . . . . . . . . . . . . . . . . . . . 204.2 Add device files to root file system . . . . . . . . . . . . . . . . . 204.3 Adding the source . . . . . . . . . . . . . . . . . . . . . . . . . . 204.4 Building the kernel . . . . . . . . . . . . . . . . . . . . . . . . . . 204.5 Testing the driver . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

    A LED component VHDL code 21

    B LED component kernel driver C code 22

    2

  • 1 Specification

    The system should be based on NIOS2, more specifically the NIOS2(f) variant.It should use a MMU (Memory Management Unit) to be able to facilitate virtualmemory in Clinux. The following tasks are going to be implemented:

    Build a NIOS2-system with MMU and peripherals in QSys Build a custom hardware component that controls some LEDs, make it

    Avalon-ready

    Build and configure Clinux for NIOS2 with MMU Write a kernel driver (module) to control the LED-component.

    The hardware used in this project is Alteras DE2-115 board. However it shouldbe pretty easy to adapt to other development boards in the DE* range.

    3

  • 2 QSys - building the system

    In this project QSys is used instead of SOPC builder. QSys is the new wayof building NIOS2-based systems. The following features and components arerequired for this particular setup:

    NIOS2(f) CPU with MMU OnChip RAM (MMU) SDRAM JTAG-UART UART Timer UP Clocks MMC SPI (SD-card) Custom LED componentPlease note that the above specifies the requirements for this particular

    project. Clinux is able to function without some of the above (i.e customhardware, UART, MMC SPI).

    2.1 OnChip RAMs

    Two OnChip RAMs are used. One for the reset- and exception vectors and onefor the MMU TLB. The reset/exception OnChip RAM was made 4096 bytesbig and the MMU TLB OnChip 1024 bytes. Note that the MMU TLB OnChipRAM is a dual-port RAM. See figure 1 (reset/exception) and 2 (MMU TLB).

    Figure 1: OnChip RAM

    4

  • Figure 2: OnChip RAM TLB

    2.2 CPU

    The CPU is the fast variant (NIOS2(f)). Check that MMU is used and makesure that the reset-, exception vectors and TLB are located at their respectiveOnChip RAM. Connect data master to s1-port and instruction master to s2-porton TLB OnChip RAM. Also connect the instruction master and data master toport s1 of the regular OnChip RAM. See figure 3.

    Figure 3: CPU settings

    2.3 SDRAM

    To be able to function, Clinux needs some RAM. We make use of the SDRAMon the DE2-115 board. It has 128MB of SDRAM. It should be possible with

    5

  • less SDRAM (even SRAM) but at least 8MB is needed for a extremely minimalsystem. More RAM than that is recommended. Instanciate a SDRAM con-troller. Then choose custom and fill in the values as seen below in figure 4 and5. Please note that these settings are for the DE2-115 SDRAM, other settingsapply if you use another board.

    Figure 4: SDRAM profile

    Figure 5: SDRAM timing

    Also, export the wires from the SDRAM component. We will later connectthem to the SDRAM controller on the board.

    2.4 UP clocks

    This core will set up the clock that is needed for the SDRAM to functioncorrectly. It is found within Alteras University Program (UP). Instanciate thecore and select your board and then SDRAM clock. See figure 6.

    6

  • Figure 6: UP clocks

    Worth noting here is that the UP Clocks core provides us with a systemclock as well. Use this clock (sys clk) to all other components except the UPClocks component itself. I.e the other components should be clocked on sys clkfrom UP Clocks instead of directly from the 50Mhz clock provided by the board.

    2.5 JTAG UART

    This component is used for connecting to Clinux. The terminal so to speak.This project also includes a RS232 UART since the JTAG UART can be a bitflaky (it sends random characters when not supposed to, atleast on my system).Nevertheless, instanciate a JTAG UART and connect IRQ 1 to the CPU.

    2.6 Timer

    Clinux needs a timer to function. This timer needs to be full-featured. Seefigure 7. Connect the IRQ to the CPU.

    Figure 7: Timer settings

    2.7 MMC SPI

    This component is optional, but is needed if the system needs to make per-manent changes to the filesystem. It is basically a component that will makeit possible to use a filesystem on a SD-card (or MMC) as root filesystem in

    7

  • Clinux. Instanciate the component (called SPI 3-wire) and make changes ac-cording to figure 8.

    Figure 8: MMC (SD-card) SPI 3-wire

    Also, export the wires (Click to export). We will later connect them to theSD-card controller. Connect IRQ 2 to the CPU.

    2.8 UART

    For a more reliable terminal than JTAG UART, a real UART via RS232 willbe used. This component is also optional. Start by instanciating a UART andmake changes according to figure 9.

    8

  • Figure 9: UART RS323

    Export the wires and connect IRQ 3 to the CPU.

    2.9 Custom LED component

    The LED component is a proof-of-concept component, it has no real value exceptfor educational purposes. Its functionality is to take input from the Avalon busand output those values on the LEDG LEDs on the DE2-115 board. It is ofcourse also optional, and not needed for Clinux to operate. However if thereader is about to add some custom component to a Clinux system, theseguidelines might be useful. First, the component needs to be written in VHDL.See appendix A for the VHDL code.Next, it needs to be imported in QSys.

    Create a directory in your project directory called ip\led component\HDL.Next put the source code there (i.e led.vhd).

    2.9.1 Create new component

    In QSys choose File-New component. Fill in the boxes as seen in figure 10.

    9

  • Figure 10: New component settings

    Then add the led.vhd VHDL file and click Analyse Synthesis Files. Seefigure 11.

    Figure 11: New component files

    Then select the corresponding Avalon signals for each signal in the top-levelhierarchy. Note that LEDG has to be set to conduit. See figure 12.

    Figure 12: New component signals

    Finally, check that the clocks and reset signals are present (associated clock/reset).

    10

  • See figure 13.

    Figure 13: New component clocks/reset

    Then press finish. The component should be visible and the possiblility toinstanciate it will be present. Instanciate it and connect s1 to data master, andalso export the wires, which we will connect later.

    2.10 Set properties of led component

    To make our kernel driver recognize the led component it needs to have cor-rect properties in the DeviceTree. This can be accomplished by editing theled hw.tcl. Add the following sections to it.

    set_module_assignment embeddedsw.dts.vendor "ALTR"set_module_assignment embeddedsw.dts.name "led"set_module_assignment embeddedsw.dts.group "led"

    2.11 Finishing the system

    To finish, select Assign Base Addresses and press finish.

    2.12 Connecting wires

    For this project a BDF (Block Diagram) will connect the wires to the respectivecontrollers on the board. This is just a matter of reading the DE2-115 manual.See figure 14.

    11

  • Figure 14: Schematic pin connections

    12

  • 3 Clinux - installation and configuration

    To be able to build Clinux the following are required:

    Linux build box (Fedora 17 in our case) make version 3.81 or less Clinux distribution Toolchain (precompiled)This chapter explains installing and configuring Clinux without the custom

    hardware. We want to make sure it runs before we make those changes.

    3.1 Cloning the repositories

    There is a community git server that has all of the prerequisites. It is locatedat http://sopc.et.ntust.edu.tw/. Start by cloning the git repositories thatwe need.

    1. Clone the trunk branch of Clinux.git clone -b trunk git://sopc.et.ntust.edu.tw/git/uClinux-dist.git

    2. Clone the toolchain (MMU variant).git clone git://sopc.et.ntust.edu.tw/git/toolchain-mmu.git

    3. Clone the linux-2.6 repository.git clone git://sopc.et.ntust.edu.tw/git/linux-2.6.git

    4. We also need the sopc2dts tool.git clone git://sopc.et.ntust.edu.tw/git/tools.git

    Next, check that the correct branches are used. For Clinux, trunk shouldbe used, for toolchain-mmu, master is used and for linux-2.6, nios2 is used.

    # cd uClinux-dist# git branch* trunk...# cd toolchain-mmu# git branch* master...# cd linux-2.6# git branch* nios2

    13

  • 3.2 Preparing the dts

    DeviceTree is a way of describing the hardware in an embedded system. Thisinformation is passed to the kernel during build, so it is needed before we startto build Clinux. QSys provides a .sopcinfo file which has to be convertedto a .dts (DeviceTree). A boardinfo file can be created for later use. Readmore about boardinfo at http://www.alterawiki.com/wiki/Sopc2dts. Use thesopc2dts utility with the GUI feature.

    $ java -jar sopc2dts.jar --gui

    Next, select Choose file and open your .sopcinfo file from QSys. See figure15.

    Figure 15: sopc2dts GUI

    We have to add a mmc-spi-slot to the dts. Select Boardinfo, SPI andthen select your SPI component. Next click Add to add a mmc-spi-slot.See figure 16.

    14

  • Figure 16: sopc2dts GUI

    Finally, select Output and save your dts file.

    3.3 Configuring Clinux

    Before building the kernel some changes are needed. The first thing that needsto be done is to set the PATH environment variable so that the build system findsthe toolchain.

    # export PATH=$PATH:/path/to/nios2/toolchain/bin

    Some other changes in the kernel configuration is needed.

    Set start of SDRAM memory (CONFIG MEM BASE) Compile and link DTB into kernel image (CONFIG DTB SOURCE BOOL) Set DTB file to be used above (CONFIG DTB SOURCE) Set MMU support (CONFIG MMU) Set kernel commandline (CONFIG CMDLINE) Set link address offset (CONFIG BOOT LINK OFFSET) Set SPI support (if MMC SPI is used) (CONFIG SPI) Set SPI Altera support (if MMC SPI is used) (CONFIG SPI ALTERA) Set MMC support (if MMC SPI is used) (CONFIG MMC) Set MMC over SPI support (if MMC SPI is used) (CONFIG MMC SPI)

    15

  • These changes can be made with make menuconfig. Please note that makeversion 3.81 or less has to be used! The first configuration menu is for settingplatform and vendor. Choose libc - none here. See figure 15 and 16.

    Figure 17: Vendor/Platform selection

    Figure 18: Libc/Kernel configuration selection

    16

  • If the applications shipped with Clinux needs to change, select CustomizeApplication/Library Settings. For the purpose of this document, the de-fault application settings are used. If Customize Kernel Settings were cho-sen, the following menu is available (figure 17).

    Figure 19: Kernel configuration

    Here all the changes has to be made. The Start of SDRAM Memory needsto be set to whatever memory location QSys chose for the SDRAM. Have a lookin your DTS to find out. The kernel commandline can be one of two possiblesettings. It depends on if we want it to boot from SD-card or from memory, athird alternative is also possible - to use JTAG UART as console.

    1. To boot from memory with UART as serial console.

    debug console=ttyAL0,115200

    2. To boot from SD-card with UART as serial console.

    debug console=ttyAL0,115200 root=/dev/mmcblk0 rootdelay=2

    3. To boot from memory with JTAG UART as serial console.

    debug console=ttyJ0,115200

    The other settings also have to be made. To search and find where in theconfiguration menu tree a specific configuration option is, use / to search aftera CONFIG * option. Then do the appropriate changes.

    17

  • 3.4 Building Clinux

    After the configuration is done, the build can start. Hopefully without anycompilation errors. If you get compilation errors, there is most likely somepackage missing on your build machine. These packages are confirmed to beneeded (Fedora 17).

    git-all git-gui make gcc ncurses-devel bison byacc flex \gawk gettext ccache zlib-devel gtk2-devel lzo-devel \pax-utilslibglade2-devel uboot-tools

    To start the build (again with make version 3.81 or less):

    # make...Kernel: arch/nios2/boot/zImage is ready...

    When done, the above text is printed. This means your build was successful.

    3.5 Loading Clinux onto the board

    This can be done in two ways. Since we have configured MMC SPI support theinitramfs can be copied onto a SD-card, then use that as a root file system.

    3.5.1 SD-card as root file system

    The initramfs is located in the relative path (in uClinux-dist directory)linux-2.6/usr/initramfs data.cpio. First the SD-card has to be preparedto be able to copy the contents onto it. Please note that /dev/sdb could bedifferent in your system.

    $ mke2fs /dev/sdb$ mount /dev/sdb /mnt$ cd /mnt$ cat /path/to/initramfs_data.cpio | cpio -id$ umount /mnt

    The SD-card is now ready to be booted from. Proceed to Boot from memory.

    3.5.2 Boot from memory

    First, the board has to be loaded with the .sof file from Quartus.

    $ nios2-configure-sof /path/to/soffile.sof

    Next, we have to load the kernel into the memory.

    $ nios2-download /path/to/zImage

    To be able to see some output, use a terminal program, like minicom (or nios2-terminal if you chose JTAG UART as serial console). Note that ttyUSB0 couldbe different in your system.

    $ minicom -D /dev/ttyUSB0

    18

  • You should see Clinux boot up.

    ...Welcome to

    ____ _ _/ __| ||_|

    _ _| | | | _ ____ _ _ _ _| | | | | | || | _ \| | | |\ \/ /| |_| | |__| || | | | | |_| |/ \| ___\____|_||_|_| |_|\____|\_/\_/| ||_|

    For further information check:http://www.uclinux.org/

    BusyBox v1.18.4 (2013-02-13 19:40:16 CET) hush - the humble shellEnter help for a list of built-in commands.

    root:/>

    19

  • 4 Custom hardware setup

    Now that we have a functioning Clinux system up and running, its possible toadd support for the custom hardware that we added in QSys (LED component).We will do some changes to the kernel configuration and and a kernel driver forthis component.

    4.1 Kernel configuration

    There is a few changes that has to be made to include the code into the kernelbuild.

    1. Add option to Kconfig in linux-2.6\source\drivers\misc

    config LEDtristate "LED custom hardware"help

    LED custom hardware

    2. Add object file to Makefile in linux-2.6\source\drivers\misc

    obj-$(CONFIG_LED) += led.o

    4.2 Add device files to root file system

    The kernel driver will make use of a device file to communicate with the hard-ware, so a device file needs to be created. Add the following line to vendors\Altera\nios2\device table.txt/dev/led c 666 0 0 250 0 - - -

    4.3 Adding the source

    The source of the device driver needs to be put in linux-2.6\source\drivers\misc,and be called led.c. See source code in appendix B.

    4.4 Building the kernel

    To include the kernel driver, the kernel needs to be rebuilt. In the configurationchoose the CONFIG LED option and save your changes. The kernel should nowinclude the code in the build.

    $ make menuconfig$ make

    4.5 Testing the driver

    If the build was successful, the driver should be able to output some values onthe LEDG LEDs from user-space. To test the function type in the following.

    $ echo 1 > /dev/led

    The LEDG should now show 1, i.e the first LED should be lit.

    20

  • A LED component VHDL code

    library ieee;use ieee.std_logic_1164.all;

    entity led isport(

    clock_50 : in std_logic;reset_n : in std_logic;avalon_cs_n : in std_logic;avalon_addr : in std_logic_vector(0 downto 0);avalon_write_n : in std_logic;avalon_din : in std_logic_vector(7 downto 0);LEDG : out std_logic_vector(7 downto 0)

    );end entity led;

    architecture led_rtl of led isbegin

    led_p : process(clock_50, reset_n)begin

    if reset_n = 0 thenLEDG 0);

    elsif rising_edge(clock_50) thenif avalon_cs_n = 0 then

    if avalon_write_n = 0 and avalon_addr = "0" thenLEDG

  • B LED component kernel driver C code

    #include #include #include #include #include #include #include #include #include #include

    MODULE_AUTHOR("Johan Granath");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("LEDG[7..0] driver for Altera DE2-115");MODULE_SUPPORTED_DEVICE("none");

    #define LED_MAJOR 250

    static ssize_t led_write(struct file *, const char *, size_t, loff_t *);static char led_str[3];int *led_mem=0;

    static struct of_device_id led_of_match[] __devinitdata ={

    { .compatible = "ALTR,led-1.0", },{}

    };MODULE_DEVICE_TABLE(of, led_of_match);

    static struct file_operations fops_led ={

    .write = led_write,};

    static ssize_t led_write(struct file *fp, const char *buf, size_t len, \loff_t *offset)

    {int not_copied, led_value;

    not_copied=copy_from_user(led_str, buf, len);led_str[len] = \0;led_value = (int) simple_strtoul(led_str, NULL, 10);

    iowrite8(led_value, led_mem);

    return len-not_copied;}

    22

  • static int __devinit led_drv_probe(struct platform_device *op){

    struct resource *res;

    if(!of_match_device(led_of_match, &op->dev))return -ENODEV;

    res = platform_get_resource(op, IORESOURCE_MEM, 0);if(!res)

    return -ENODEV;

    if(!request_mem_region(res->start, resource_size(res), "led"))return -ENOMEM;

    led_mem = of_iomap(op->dev.of_node, 0);if(!led_mem)

    return -ENOMEM;

    if(register_chrdev(LED_MAJOR, "led", &fops_led)){

    printk("register_chrdev: led failed\n");return -EIO;

    }

    return 0;}

    static int __devinit led_drv_remove(struct platform_device *op){

    struct resource *res;

    res = platform_get_resource(op, IORESOURCE_MEM, 0);if(!res)

    return -ENODEV;

    release_mem_region(res->start, resource_size(res));

    return 0;}

    static struct platform_driver led_platform_driver ={

    .probe = led_drv_probe,

    .remove = led_drv_remove,

    .driver ={

    .name = "led",

    .owner = THIS_MODULE,

    .of_match_table = led_of_match,

    23

  • },};

    static int __init mod_init(void){

    int ret;ret = platform_driver_register(&led_platform_driver);return ret;

    }

    static void __exit mod_exit(void){

    platform_driver_unregister(&led_platform_driver);unregister_chrdev(LED_MAJOR, "led");

    }

    module_init(mod_init);module_exit(mod_exit);

    24

    SpecificationQSys - building the systemOnChip RAMsCPUSDRAMUP clocksJTAG UARTTimerMMC SPIUARTCustom LED componentCreate new component

    Set properties of led componentFinishing the systemConnecting wires

    Clinux - installation and configurationCloning the repositoriesPreparing the dtsConfiguring ClinuxBuilding ClinuxLoading Clinux onto the boardSD-card as root file systemBoot from memory

    Custom hardware setupKernel configurationAdd device files to root file systemAdding the sourceBuilding the kernelTesting the driver

    LED component VHDL codeLED component kernel driver C code