(原创)uCLinux在NiosII平台上的移植(基于Nios II的SOPC软硬件系统)(DE2)
uCLinux在NiosII平台上的移植
一、编译环境搭建
VMware上安装Ubuntu9.04*1
配置一些比较快的源
默认情况下,Ubuntu中的vi编辑器并不好用,左右键不正常,需先安装vim-full,但ubuntu-9.04-desktop-i386.iso中的默认的源无法访问了。sudo apt-get install 命令全都是“failed to fetch”的错误。
需要修改/etc/apt/sources.list源文件。可用gedit命令。
输入用户密码。
但若把源地址一项一项添加很费事,易出错,从windows环境下又无法向VMware中粘贴。
sshd,vsftpd没有安装,share-folder在Ubuntu环境下无法使用。
现在,还有一种方法,可在VMware环境下,从外部的ftp服务器上把事先已传上去的sources.list文件下载下来。
先配置网络
sudo vi /etc/network/interfaces
配置域名服务器
sudo vi /etc/resolv.conf
sudo /etc/init.d/networking restart
从ftp上下载source.list文件,然后执行sudo mv sources.list /etc/apt 命令
之后,
sudo apt-get update //升级安装的软件包。
sudo apt-get install vim-full //安装vim-full,便于以后的编辑
sudo apt-get install openssh-server //安装sshd,便于远程登录
sudo apt-get install vsftpd //安装vsftpd,便于以后与物理机间传送文件
sudo apt-get install chkconfig //安装chkconfig,便于服务器的管理
接下来就参照http://www.nioswiki.com上所讲继续安装了。
在进行移植工作之前,可以先下载现成的配置文件和内核映像文件,下载到板子上看看效果。
从nioswiki网站上下载DE2平台上已经编译好的DE2_NIOS_HOST_MOUSE_VGA.sof,DE2_NIOS_HOST_MOUSE_VGA.ptf 以及zImage_DE2_NIOS_HOST_MOUSE_VGA_v1.6文件。
Configure the FPGA
[NiosII EDS]$ nios2-configure-sof DE2_NIOS_HOST_MOUSE_VGA.sof
Download and run the kernel image,
[NiosII EDS]$ nios2-download -g zImage_DE2_NIOS_HOST_MOUSE_VGA_v1.6
Open nios2 terminal
[NiosII EDS]$ nios2-terminal
安装或下载源码和编译工具。
在编译工具链之前,先安装以上这些工具。如若不安装完全,在后面的编译工具链和编制内核的时候可能出现错, Ncurses是一个能提供基于文本终端窗口功能的动态库。在Ubuntu安装的时候应注意,安装ncurses-dev库时可能会显示 “ncurses-dev has no installation candidate”,如下图所示:
此时,可以安装libncurses5-dev。
$ sudo apt-get install libncurses5-dev
在完成了上述库的安装后,可按下一条命令检查是否安装完全。
检查默认的shell是否是bash
如若不是,需改成bash
$ sudo rm /bin/sh
$ sudo ln -s bash /bin/sh
注销重新登录,检查’cc’是否链接向了’gcc’
如若不是,则需修改:
$ cd /usr/bin
$ ln -s gcc cc
20090703 需要gcc 4.2或者更高版本*2。
从ftp上下载nios2-linux-20090730.tar
sha1sum校验
把nios2-linux-20090730.tar解压到指定的目录:
$ sudo tar nios2-linux-20090730.tar –C /media/sdb1/
切换到nios2-linux 目录,check out the source
nios2-linux中各个目录的作用。Nios2 uClinux 的源文件和gnu工具链。
以下这些命令是编译nios2-gcc工具链的整个过程
Ubuntu中编译需要注意的是:Ubuntu中并没有root用户,需用sudo的方式执行管理员操作,但是即使用sudo make仍会产生’permission denied’的错误。可能是sudo的有效区域的问题。可用以下方式解决:
出现的错误:
在安装好上文中所说的那些库后,在make的过程中仍有各种错误,便切换到nios2-linux目录update了一下。
再进行上述操作,会出现以下错误
cp: cannot stat `doc/gcc.1': No such file or directory
在google上寻找解决方法如下,需修改gcc3目录下的Make-lang.in中的一句代码。
至此,在编译就没有错误了,tools chain的编译时间比较长,大概用了1个小时10分钟左右的时间。toolchain终于编译成功了。
也可以用编译好的BinaryToolchain,
然后设一下PATH变量
$ vi ~/.bashrc
本文中,把编译好的BinaryToolchain放到/opt/nios2/bin目录下,把自行编译的tools-chain设在/media/sdb1/nios2-linux/toolchain-build/build/nios2/bin目录下。
重新登录后,查看nios2-linux-uclibc-gcc 是否可用
$ nios2-linux-uclibc-gcc -v
现在把编译环境完全在nios2-linux-20090929上来做。我在Ubuntu虚拟机上新加了一块8G的硬盘,在tar xf,./checkout,make toolchain之后居然空间不够了,还得把nios2-linux-20090929.tar的包删掉才行。由于nios2-linux项目使用git来管理的,所以在用的时候需要注意查看分支。如若不是在test-nios2分支上,切换过来吧。
依次检查每一个目录。其它与7月30的版本相同,而且不会出现编译工具链时的错误。
编一个测试程序:hello world
编译与检测
接下来,就可以配置和编译内核了。
切换到uClinux-dist目录下,执行
$ make menuconfig
回车进入Vendor/Product Selection,Vendor选择Altera,Product选择Altera Products(nios2)。
Exit。选择Kernel/Library/Defaults Selection,单击回车进入。
选择Default all settings (lose changes),Exit,Exit。
显示 Do you wish to save your new kernel configuration? 选择 Yes
可先从nioswiki网站上下载一个已配置好的系统 DE2_NIOS_HOST_MOUSE_VGA.ptf 和
DE2_NIOS_HOST_MOUSE_VGA.sof先做一下实验。
运行vendor_hwselect
$ make vendor_hwselect SYSPTF=/home/lunix/uclinux/DE2_NIOS_HOST_MOUSE_VGA.ptf
选择要使用的cpu,设置程序运行的存储器。
编译内核和程序
$ make
把生成的zImage文件cp到vftpd配置的目录,在Windows环境中从虚拟机上下载。
启动nios2 command shell
$ nios2-configure-sof DE2_NIOS_HOST_MOUSE_VGA.sof
$ nios2-download –g zImage
-g 选项代表着是 下载后立即运行。
$ nios2-terminal
四、配置SOPC硬件系统平台
下面将配置一个SOPC系统,并自行裁剪linux内核
后记:没有认真阅读http://www.nioswiki.com/OperatingSystems/UClinux上的说明文档,想当然的配了个系统,浪费了大量的时间。
它的基本的硬件要求或建议是
- Nios II f型core,带Hardware multipler
- sdram(最小8M)
- 一个full feature的定时器timer
- 一个jtag或者serial的UART
除了定时器timer不要把中断号0(irq 0)分配给任何器件
硬件设计
建立一个工程,名字为DE2_uClinux。器件设置如下。
加入一个Verilog HDL文件,文件名为DE2_uClinux.v,Set as Top-Level Entity。此时可先不管DE2_uClinux.v中的内容,先建立一个SOPC系统。
调用Sopc Builder 建立一个nios系统。起名字为DE2_lab1
添加On chip Memory,在Memorie and Memory Controllers->On-Chip->On-Chip Memory(RAM or ROM)。
添加cpu,选择Nios II/e型,设置 复位和异常 向量。更正:此处应选Nios II/f型
加入定时器timer,选择full-featured,在Peripherals->Microcontroller Peripherals->Interval Timer
加入JTAG_UART和UART,在Interface Protocols->Serial中
加入sdram控制器,在Memories and Memory Controller->SDRAM->SDRAM Controller
加入sram,此处需注意
将DE2光盘中找到demo工程的SRAM_16Bits_512K copy到DE2-uClinux工程目录下,执行file->refresh system,可看到左侧system content栏中多了一个Terasic Technologies Inc组,组中的SRAM_16Bits_512K就是要加入的DE2上的sram控制器。
将DM9000A和SRAM_16Bit_512K加入
后记:
SOPC Component for DM9000
把dm9000a_hw.tcl文件存放到工程目录,打开SOPC Builder,可看到一个新的“dm9000a”组件。
添加一个新的Avalon-MM tristate bridge,添加”dm9000a”组件,重命名为”dm9000”,连接到Avalon tristate bridge master,不需要Verilog或者VHDL文件,因为SOPC Builder会自动生成。不要把中断号0(irq 0)分配给dm9000。
DM9000A模块加入后,应命名为dm9000,并通过tristate-bridge与连接到系统上,且中断号不能为0。以下图的中未作修改,所有的dm9000a都应为dm9000。
加入flash controller,Memories and Memory Controller->Flash->Flash Memeory Interface(CFI)
CFI flash通过tristate-bridge与Avalon MM总线连接,它是个速度较慢的器件。
配些开关和灯。开关和红灯18个,绿灯8个,按钮4个。
绿灯和按钮类似
先选这么多吧,最后结果
执行一些地址对齐,中断号分配的工作。注意中断号0。点击next,generate。
把新生成的系统加到DE2_uCLinux工程中。
配置引脚
Assignments->Import Assignments, 选中DE2光盘中的DE2_pin_assignments.csv文件,导入。
Assignment->Device->Device and Pin Options->Unused pin 设为 As input tri-stated。
Dual-purpose pin->nCEO 设置为Use as regular I/O
修改顶层文件DE2_uClinux。
打开DE2光盘中的一个比较齐全的的Demo,此处用\DE2\DE2_demonstrations\DE2_NET。把里面的DE2_NET.v文件的内容考出,把内容copy到DE2_uClinux.v中,把顶层module名改为DE2_uClinux。把不需要的部分进行裁剪。本文中裁剪如下。
//////////////////// Clock Input ////////////////////
CLOCK_27, // On Board 27 MHz
CLOCK_50, // On Board 50 MHz
//////////////////// Push Button ////////////////////
KEY, // Pushbutton[3:0]
//////////////////// DPDT Switch ////////////////////
SW, // Toggle Switch[17:0]
//////////////////////// LED ////////////////////////
LEDG, // LED Green[8:0]
LEDR, // LED Red[17:0]
//////////////////////// UART ////////////////////////
UART_TXD, // UART Transmitter
UART_RXD, // UART Receiver
///////////////////// SDRAM Interface ////////////////
DRAM_DQ, // SDRAM Data bus 16 Bits
DRAM_ADDR, // SDRAM Address bus 12 Bits
DRAM_LDQM, // SDRAM Low-byte Data Mask
DRAM_UDQM, // SDRAM High-byte Data Mask
DRAM_WE_N, // SDRAM Write Enable
DRAM_CAS_N, // SDRAM Column Address Strobe
DRAM_RAS_N, // SDRAM Row Address Strobe
DRAM_CS_N, // SDRAM Chip Select
DRAM_BA_0, // SDRAM Bank Address 0
DRAM_BA_1, // SDRAM Bank Address 1
DRAM_CLK, // SDRAM Clock
DRAM_CKE, // SDRAM Clock Enable
//////////////////// Flash Interface ////////////////
FL_DQ, // FLASH Data bus 8 Bits
FL_ADDR, // FLASH Address bus 20 Bits
FL_WE_N, // FLASH Write Enable
FL_RST_N, // FLASH Reset
FL_OE_N, // FLASH Output Enable
FL_CE_N, // FLASH Chip Enable
//////////////////// SRAM Interface ////////////////
SRAM_DQ, // SRAM Data bus 16 Bits
SRAM_ADDR, // SRAM Address bus 18 Bits
SRAM_UB_N, // SRAM High-byte Data Mask
SRAM_LB_N, // SRAM Low-byte Data Mask
SRAM_WE_N, // SRAM Write Enable
SRAM_CE_N, // SRAM Chip Enable
SRAM_OE_N, // SRAM Output Enable
//////////////////// USB JTAG link ////////////////////
TDI, // CPLD -> FPGA (Data in)
TCK, // CPLD -> FPGA (Clock)
TCS, // CPLD -> FPGA (CS)
TDO, // FPGA -> CPLD (Data out)
//////////// Ethernet Interface ////////////////////////
ENET_DATA, // DM9000A DATA bus 16Bits
ENET_CMD, // DM9000A Command/Data Select, 0 = Command, 1 = Data
ENET_CS_N, // DM9000A Chip Select
ENET_WR_N, // DM9000A Write
ENET_RD_N, // DM9000A Read
ENET_RST_N, // DM9000A Reset
ENET_INT, // DM9000A Interrupt
ENET_CLK//, // DM9000A Clock 25 MHz
文件中其它的部分与上些部分无关的代码去掉。
在生成的DE2_lab.v文件中把,把顶层模块DE2_lab复制到DE2_uClinux.v中修改如下
DE2_lab1 de2(
// 1) global signals:
.clk(CPU_CLK),
.reset_n(CPU_RESET),
// the_button_pio
.in_port_to_the_button_pio(KEY),
// the_dm9000a
.cmd_to_the_dm9000(cmd_dm9000),
.cs_n_to_the_dm9000(ENET_CS_N),
.data_to_and_from_the_dm9000(ENET_DATA),
.irq_from_the_dm9000(ENET_INT),
.ior_n_to_the_dm9000(ENET_RD_N),
.rst_n_to_the_dm9000(ENET_RST_N),
.iow_n_to_the_dm9000(ENET_WR_N),
// the_led_green
.out_port_from_the_led_green(LEDG),
// the_led_red
.out_port_from_the_led_red(LEDR),
// the_sdram
.zs_addr_from_the_sdram(DRAM_ADDR),
.zs_ba_from_the_sdram({DRAM_BA_1,DRAM_BA_0}),
.zs_cas_n_from_the_sdram(DRAM_CAS_N),
.zs_cke_from_the_sdram(DRAM_CKE),
.zs_cs_n_from_the_sdram(DRAM_CS_N),
.zs_dq_to_and_from_the_sdram(DRAM_DQ),
.zs_dqm_from_the_sdram({DRAM_UDQM,DRAM_LDQM}),
.zs_ras_n_from_the_sdram(DRAM_RAS_N),
.zs_we_n_from_the_sdram(DRAM_WE_N),
// the_sram_16bit_512k
.SRAM_ADDR_from_the_sram_16bit_512k(SRAM_ADDR),
.SRAM_CE_N_from_the_sram_16bit_512k(SRAM_CE_N),
.SRAM_DQ_to_and_from_the_sram_16bit_512k(SRAM_DQ),
.SRAM_LB_N_from_the_sram_16bit_512k(SRAM_LB_N),
.SRAM_OE_N_from_the_sram_16bit_512k(SRAM_OE_N),
.SRAM_UB_N_from_the_sram_16bit_512k(SRAM_UB_N),
.SRAM_WE_N_from_the_sram_16bit_512k(SRAM_WE_N),
// the_switch_pio
.in_port_to_the_switch_pio(SW),
// the_tri_state_bridge_avalon_slave
.address_to_the_cfi_flash(FL_ADDR),
.data_to_and_from_the_cfi_flash(FL_DQ),
.read_n_to_the_cfi_flash(FL_OE_N),
.select_n_to_the_cfi_flash(FL_CE_N),
.write_n_to_the_cfi_flash(FL_WE_N),
// the_uart
.rxd_to_the_uart(UART_RXD),
.txd_from_the_uart(UART_TXD)
)
关于dm9000的一些修改
// the_dm9000a
.cmd_to_the_dm9000(cmd_dm9000),
.cs_n_to_the_dm9000(ENET_CS_N),
.data_to_and_from_the_dm9000(ENET_DATA),
.irq_from_the_dm9000(ENET_INT),
.ior_n_to_the_dm9000(ENET_RD_N),
.rst_n_to_the_dm9000(ENET_RST_N),
.iow_n_to_the_dm9000(ENET_WR_N),
为dm9000产生一个25MHz的时钟
// the_dm9000a
reg ENET_CLK;
always @(posedge CLOCK_50) ENET_CLK<= ~ENET_CLK;
wire [1:0] cmd_dm9000;
assign ENET_CMD = cmd_dm9000[1];
从DE2_NET例子的目录下把两个文件Reset_Delay.v和SDRAM_PLL.v两个文件复制到当前工程目录下。并加上下两句代码。
Reset_Delay delay1 (.iRST(KEY[0]),.iCLK(CLOCK_50),.oRESET(CPU_RESET));
SDRAM_PLL PLL1 (.inclk0(CLOCK_50),.c0(DRAM_CLK),.c1(CPU_CLK),.c2(CLK_25));
Reset_Delay是个复位延迟文件。为了给Nios2提供有效宽度的复位信号。
SDRAM_PLL为系统及SDRAM提供时钟。可以自己配置。
SDRAM的时钟必须和SDRAM Controller的时钟频率相同,必须保证当时钟上升沿到来时,SDRAM芯片上的data,address,和Control信号已经稳定,这就需要SDRAM时钟和SDRAM Controller时钟之间有一个clock skew(SDRAM的时钟上升沿到来的晚一些),所以需要PLL产生一个phase shift,SDRAM Controller core的说明文档中有计算公式,此处取demo中的经验值即可。
Inclk0 50M
Clk c0: output clock frequency: 50MHz, Clock phase shift -3.00 ns, Clock duty cycle %:50
为sdram提供时钟
Clk c1: output clock frequency: 100MHz, Clock phase shift 0.00 ns, Clock duty cycle %:50
为nios2系统提供时钟
Clk c2可以不设,在本系统中没有用到。
编译。显示Full Compilation was Successful!
生成DE2_uClinux.sof和DE2_uClinux.ptf文件(成功后可以先用Nios II IDE编写一个小程序测试一下所生成的系统是否有错误),用这两个文件重做上面的实验。
五、配置编译uClinux内核
此次自定制裁剪uClinux内核,实现3个目的
Ø 用hyperterminal作为控制终端
Ø 在uClinux中运行hello world程序
Ø 调通网络
将上文中生成的hw文件cp到$NIOS2LINUX/nios2-linux/uClinux-dist/romfs/下
基本步骤与上文相同,仅列出需要注意的不同的步骤。
在Kernel/Library/Defaults Selection à下选择Custom Kernel Setting向,其它不变,退出。
其实没有什么可以修改的,基本上默认即可
Processor type and features à Platform (Altera DE2 Development board support)
Device DriversàCharacter devicesàSerial driversàAltera UART console support
一定要把Altera JTAG UART console support关掉,不能用两个控制终端,这一点没有认真看文档,浪费了不少时间。
关于网络,默认即可
Network SupportàNetwork Optionsà选择如下
Device DriversàNetwork Device SupportàEthernet (10 or 100 Mbit)àDM9000 support
一路exit,yes。
root@lunix-desktop:/media/sdc1/nios2-linux/uClinux-dist# make
配置超级终端UART
打开超级终端,将新核下载到板子上。
[Nios II EDS]$ nios2-confige-sof hw/DE2_uClinux.sof
[Nios II EDS]$ nios2-download –g zImage_net
[Nios II EDS]$ nios2-terminal
在超级终端上显示:
执行ls命令,可看到文件系统中多了hw文件,这就是我们刚才加进去的。
执行./hw显示hello world!!!,运行成功了。
下面配一下网络
/> ifconfig eth0 down
/> ifconfig eth0 hw ether 00:00:11:22:33:44
/> ifconfig eth0 192.168.135.250 up
配置MAC地址时,前2个字节应该是00:00,其它随便配。
实验一下ftp
就到这吧
一点感触:之所以在这个实验上浪费了大量时间,是因为以前做过,以为很快就会做完。但现在的环境已经很多不一样了,一开始没仔细阅读nioswiki上关于uClinux的文档,导致一些配置不符合要求,死磕了不少时间。
*1 Ubuntu起源于debian,debian被认为是最“free”的,但实际上,很少被大企业采用作为标准平台,使用中会碰到各种各样的兼容性问题,建议以RHEL(CentOS)为基准,Ubuntu/fedora之类的,个人玩玩是可以的,但要与他人合作工作,不太合适
*2 有这种说法?一般讲,目前gcc稳定版本还是3.4.6,大多数系统特别是嵌入式系统,不会采用新版gcc特性;我跟着git服务器更新过,用的3.4.6编译工具链,没有任何问题