UClinux Nios2 Custom Hardware
UClinux Nios2 Custom Hardware
UClinux Nios2 Custom Hardware
kernel module
Johan Granath
Applied Electronics for Embedded Systems
AGSTU School of Higher Vocational Education
Malmo, 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.
Contents
1 Specification
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
4
5
5
6
7
7
7
8
9
9
11
11
11
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
15
18
18
18
18
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
20
20
20
20
20
20
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
22
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 virtual
memory 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 should
be pretty easy to adapt to other development boards in the DE* range.
In this project QSys is used instead of SOPC builder. QSys is the new way
of building NIOS2-based systems. The following features and components are
required 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 component
Please note that the above specifies the requirements for this particular
project. Clinux is able to function without some of the above (i.e custom
hardware, UART, MMC SPI).
2.1
OnChip RAMs
Two OnChip RAMs are used. One for the reset- and exception vectors and one
for the MMU TLB. The reset/exception OnChip RAM was made 4096 bytes
big and the MMU TLB OnChip 1024 bytes. Note that the MMU TLB OnChip
RAM is a dual-port RAM. See figure 1 (reset/exception) and 2 (MMU TLB).
2.2
CPU
The CPU is the fast variant (NIOS2(f)). Check that MMU is used and make
sure that the reset-, exception vectors and TLB are located at their respective
OnChip RAM. Connect data master to s1-port and instruction master to s2-port
on TLB OnChip RAM. Also connect the instruction master and data master to
port s1 of the regular OnChip RAM. See figure 3.
2.3
SDRAM
To be able to function, Clinux needs some RAM. We make use of the SDRAM
on the DE2-115 board. It has 128MB of SDRAM. It should be possible with
less SDRAM (even SRAM) but at least 8MB is needed for a extremely minimal
system. More RAM than that is recommended. Instanciate a SDRAM controller. Then choose custom and fill in the values as seen below in figure 4 and
5. Please note that these settings are for the DE2-115 SDRAM, other settings
apply if you use another board.
2.4
UP clocks
This core will set up the clock that is needed for the SDRAM to function
correctly. It is found within Alteras University Program (UP). Instanciate the
core and select your board and then SDRAM clock. See figure 6.
Figure 6: UP clocks
Worth noting here is that the UP Clocks core provides us with a system
clock as well. Use this clock (sys clk) to all other components except the UP
Clocks component itself. I.e the other components should be clocked on sys clk
from UP Clocks instead of directly from the 50Mhz clock provided by the board.
2.5
JTAG UART
2.6
Timer
2.7
MMC SPI
This component is optional, but is needed if the system needs to make permanent changes to the filesystem. It is basically a component that will make
it possible to use a filesystem on a SD-card (or MMC) as root filesystem in
Clinux. Instanciate the component (called SPI 3-wire) and make changes according to figure 8.
2.8
UART
For a more reliable terminal than JTAG UART, a real UART via RS232 will
be used. This component is also optional. Start by instanciating a UART and
make changes according to figure 9.
2.9
In QSys choose File-New component. Fill in the boxes as seen in figure 10.
2.10
To make our kernel driver recognize the led component it needs to have correct properties in the DeviceTree. This can be accomplished by editing the
led 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
2.12
Connecting wires
For this project a BDF (Block Diagram) will connect the wires to the respective
controllers on the board. This is just a matter of reading the DE2-115 manual.
See figure 14.
11
12
3.1
There is a community git server that has all of the prerequisites. It is located
at http://sopc.et.ntust.edu.tw/. Start by cloning the git repositories that
we 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 should
be 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
14
3.3
Configuring Clinux
Before building the kernel some changes are needed. The first thing that needs
to be done is to set the PATH environment variable so that the build system finds
the 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 make
version 3.81 or less has to be used! The first configuration menu is for setting
platform and vendor. Choose libc - none here. See figure 15 and 16.
16
17
3.4
Building Clinux
After the configuration is done, the build can start. Hopefully without any
compilation errors. If you get compilation errors, there is most likely some
package missing on your build machine. These packages are confirmed to be
needed (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
This can be done in two ways. Since we have configured MMC SPI support the
initramfs can be copied onto a SD-card, then use that as a root file system.
3.5.1
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
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 nios2terminal if you chose JTAG UART as serial console). Note that ttyUSB0 could
be different in your system.
$ minicom -D /dev/ttyUSB0
18
19
Now that we have a functioning Clinux system up and running, its possible to
add 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 for
this component.
4.1
Kernel configuration
There is a few changes that has to be made to include the code into the kernel
build.
1. Add option to Kconfig in linux-2.6\source\drivers\misc
config LED
tristate "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
The kernel driver will make use of a device file to communicate with the hardware, so a device file needs to be created. Add the following line to vendors\Altera\nios2
\device table.txt
/dev/led
4.3
666
250
4.4
To include the kernel driver, the kernel needs to be rebuilt. In the configuration
choose the CONFIG LED option and save your changes. The kernel should now
include the code in the build.
$ make menuconfig
$ make
4.5
If the build was successful, the driver should be able to output some values on
the 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
library ieee;
use ieee.std_logic_1164.all;
entity led is
port(
clock_50
reset_n
avalon_cs_n
avalon_addr
avalon_write_n
avalon_din
LEDG
);
end entity led;
:
:
:
:
:
:
:
in std_logic;
in std_logic;
in std_logic;
in std_logic_vector(0 downto 0);
in std_logic;
in std_logic_vector(7 downto 0);
out std_logic_vector(7 downto 0)
21
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<linux/kernel.h>
<linux/module.h>
<linux/mod_devicetable.h>
<linux/platform_device.h>
<linux/of_device.h>
<linux/of_address.h>
<linux/fs.h>
<linux/ioport.h>
<asm/uaccess.h>
<asm/io.h>
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
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