TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
: P" ^- Y) j, q6 m引言7 }$ t# K+ Q" x; T! ^2 M6 ^6 K
: G7 w, x" g: ?" u6 L+ D3 n" k
我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。% U; g+ S2 l7 D& F! q
- C1 ~9 F1 R6 O6 M; K) G所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。5 P; H; B2 q5 M+ @& N& m
4 R2 k1 ^3 A8 j6 Z
本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。% \" R8 W7 w+ c e% b
& I& O7 v2 q9 c0 p' \7 O 4 `5 e4 R4 S5 h
* v$ Q( D" K: N2 g* ?
11.1 编写wishbone为interface的ip core(ip_mkg)9 [6 Z" a/ C/ c- e D2 W7 j
0 E) }) E# A3 @) A1》这一步请参考:
' { w6 g- ]) u3 _- A- b, l4 U4 }& c! a ~
linux学习之路_wishbone实验7 x" C& Y0 G/ R7 e1 P% b7 J
3 A, c/ @0 m1 P% y6 K$ J, }
2》将其中的my_slave_module链接到ORPSoC的wishbone上。+ P# o4 A4 g. ~2 F, ~7 D5 L3 j
9 M2 x/ ^* l1 C; b7 {* i+ d# c+ h
7 ~$ K; }# O4 z" p8 X
' t/ b$ V+ c: l2 d/ A+ b2 O% i. K11.2 编写linux下的driver module' b& ~+ v( l' n) x! Z
" V( w7 x }% c0 u/ H8 Q1 G
代码及makefile如下:0 e$ O8 a8 d Q* W
, K- q* I" U- u6 n1》ip_mkg.c1 B" g6 o+ |/ k5 p
) w$ t, t* D) N4 w / b5 ~3 d& P9 y
1 B, a$ ]: \* r; L: D" l8 a+ J
- /*
- *
- * rill mkg driver
- *
- */
- #include <linux/vmalloc.h>
- #include <linux/slab.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <asm/uaccess.h> /* get_user and put_user */
- //#include <linux/clk.h>
- //#include <linux/ioport.h>
- #include <asm/io.h> /*ioremap*/
- #include <linux/platform_device.h> /*cleanup_module*/
- #include "ip_mkg.h"
- void __iomem *g_mkg_mem_base = NULL;
- static int device_open(struct inode *inode, struct file *file)
- {
- g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
- if(NULL == g_mkg_mem_base)
- {
- printk(KERN_ERR "mkg open ioremap error!\n");
- return -1;
- }
- else
- {
- printk("mkg ioremap addr:%d!\n",(int)g_mkg_mem_base);
- }
- return 0;
- }
- static int device_release(struct inode *inode, struct file *file)
- {
- return 0;
- }
- static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
- {
- return 0;
- }
- static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset)
- {
- return 0;
- }
- long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
- {
- int ret_val = 0;
- unsigned int ret = 0;
- struct reg_data *new_regs;
- switch(ioctl_num)
- {
- case IOCTL_REG_SET:
- {
- new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
- if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)
- {
- kfree(new_regs);
- printk(KERN_ERR " error copy line_datafrom user.\n");
- return -1;
- }
- iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr);
- kfree(new_regs);
- }
- break;
- case IOCTL_REG_GET:
- {
- new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);
- if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)
- {
- kfree(new_regs);
- printk(KERN_ERR " error copy line_datafrom user.\n");
- return -1;
- }
- ret = ioread16(g_mkg_mem_base+new_regs->addr);
- kfree(new_regs);
- return ret;
- }
- break;
- }
- return -1;
- }
- struct file_operations our_file_ops = {
- .unlocked_ioctl = device_ioctl,
- .read = device_read,
- .write = device_write,
- .open = device_open,
- .release = device_release,
- .owner = THIS_MODULE,
- };
- int init_module()
- {
- int ret_val;
- int ret;
- void __iomem *ret_from_request;
- //=== Allocate character device
- ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);
- if (ret_val < 0)
- {
- printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);
- return ret_val;
- }
- ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
- if (ret < 0)
- {
- printk(KERN_ERR "mkg check_mem_region bussy error!\n");
- return -1;
- }
- ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");
- //===ioremap mkg registers
- g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);
- if(NULL == g_mkg_mem_base)
- {
- printk(KERN_ERR "mkg ioremap error!\n");
- return -1;
- }
- else
- {
- ;//printk("mkg ioremap addr:%d!\n",g_mkg_mem_base);
- }
- printk("mkg module init done!\n");
- return 0;
- }
- void cleanup_module()
- {
- release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);
- unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
- }
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Rill zhen:rillzhen@gmail.com");
) R, w, K- u# {) Q, L9 {* l
+ _ A* ], E9 |% X' j$ J& d& x2 Q6 e3 Z 9 A+ _, J+ z `; K P
/ N; x! e4 B- d
2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。& M3 K: a8 Q; l8 t+ m9 m
1 N: @" ~* n! [- #ifndef __IP_MKG_H__
- #define __IP_MKG_H__
- #define MAJOR_NUM 102
- #define DEVICE_NAME "ip_mkg"
- #define MKG_MEM_BASE 0x10000001
- #define MKG_MEM_LEN 32
- #define IOCTL_REG_SET 0
- #define IOCTL_REG_GET 1
- struct reg_data
- {
- unsigned short addr;
- int value;
- };
- #endif
! f' t$ Z5 x/ ]1 y / \( T: ^; M; q4 \* k/ R
8 \7 f0 D& ]9 ], e2 ~) S" Z, j9 U$ i" d" a) D/ K
3》Makefile; i1 u; O8 u8 A0 C4 v
; K. b8 [ |0 e) b8 S- # To build modules outside of the kernel tree, we run "make"
- # in the kernel source tree; the Makefile these then includes this
- # Makefile once again.
- # This conditional selects whether we are being included from the
- # kernel Makefile or not.
- ifeq ($(KERNELRELEASE),)
- # Assume the source tree is where the running kernel was built
- # You should set KERNELDIR in the environment if it's elsewhere
- KERNELDIR ?= /home/openrisc/soc-design/linux
- # The current directory is passed to sub-makes as argument
- PWD := $(shell pwd)
- modules:
- make -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux-
- modules_install:
- make -C $(KERNELDIR) M=$(PWD) modules_install ARCH=openrisc CROSS_COMPILE=or32-linux-
- clean:
- rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
- .PHONY: modules modules_install clean
- else
- # called from kernel build system: just declare what our modules are
- obj-m := ip_mkg.o
- endif" w9 ?! j, ]5 @ n+ {
! h: [, L( l& R( D- u' N. I7 G( t; E: U+ g% S! ~- _* t
+ e* w. ]5 S8 ^# o- [, K2 Q11.3 遇到的问题 e3 [; i! `. G2 ^& H0 c: M
$ Q0 X! k b; U, y( k; `1》当在执行make时会遇到如下警告:__ioremap undefined。7 W* K$ K% A) A& V
+ \0 h! {; g6 H1 h4 A7 k: u
8 ?3 F) }. h3 j9 S
0 ]8 S' f+ |/ ~8 o! X* l% P" f P" r+ l
$ r' y6 ]5 \6 @7 E) H2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。; Q, p4 ~7 g) G0 F: w
! R1 E% k% T% m8 |4 ^
: _$ y' K" w6 w, B& [. p
9 a5 Z0 n M$ o" \$ v8 d
* @+ L5 o4 k! c( G2 c0 {& l) E
2 z' N ~; n/ ]! d. a8 Y, \11.4 解决方法
9 e% B& D2 a6 R- \8 M8 N/ f! W, |5 Z0 L4 Z/ L a
在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。. ^ Q0 x6 X$ f5 M8 z1 D4 p
* i- D4 q- U# u T+ u' Y) u1 t3 U- #include <linux/module.h>
- EXPORT_SYMBOL(__ioremap);
+ J3 {' _+ u7 ~. v
6 ]1 V) s' h5 t7 E! A/ `9 _: Z; b8 j4 h
+ P& J4 |1 b2 l' r! U, V0 J
11.5 小结
. R6 G f* r0 s9 |. ?% X; ]: A) p
实验步骤$ _' \% y$ R+ s
* ]8 ^! E$ ?* g& ^" _" u4 D1 w" Y0》virtualbox虚拟机unbuntu上安装nfs服务
' Q% f- @2 }* i! {8 ?+ d6 {4 \/ S( m0 X! p
0.0>确保virtualbox能上网
: w; C1 P8 q4 v
3 H( Z+ h3 u9 |4 e% D& H8 u0 B+ r0.1> apt-get install nfs-kernel-server
( _. i8 k. o, [, o6 S5 U# s8 J- F2 X+ E
0.2>创建nfs共享目录:mkdir /home/openrisc/nfs* L6 b7 }+ k: \1 x
C( p3 v" q% n$ {1 ]0.3>vim /etc/exports,添加如下内容8 ]* ^' I2 P5 a4 A
q2 j7 e; J7 @6 c
/home/openrisc/nfs *(rw,sync)* @5 X! {, }0 J1 h
% w) e# H4 O& L/ {; l" Y1 m% n0.4>重启nfs服务# s+ j0 q2 a4 U! ^7 m" q
' V+ E1 p9 b! d P' r
sudo /etc/init.d/nfs-kernel-server restart
5 o) g% Y# T1 _+ z' o5 o0 B* B) v
1》修改arch/openrisc/mm/ioremap.c" f' o% F, V9 z: j: y- V
; S \% }% A7 A( R- ^* W2》cd /home/openrisc/soc-design/linux4 ^/ y& N" h1 G
+ v$ U! k9 p$ Z. P. c% A) s; x
3》make ARCH=openrisc defconfig;make生成vmlinux
& ]6 c) o7 X% C; }8 s% s' l6 ?+ ]1 R
4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件
6 P( v2 X- Q3 s8 m
' _, A$ o4 k7 a9 e: F5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)
7 v' ^+ a Q/ h9 C
* V: b0 ?3 W3 ]0 c- e( d6》配置virtualbox的ip& M( `# h- s- q
" H% F- B$ n; A; lsudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255
( Q1 I: M- l. q' \$ z/ g2 |; T
4 T6 B8 L2 t4 X3 Y7》配置PC机的ip为192.168.1.1026 I0 _! c5 F; v
0 ~5 D' M8 Z0 g6 f5 C3 o2 J2 B3 D- w; S
8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。
+ o/ I; y" ^$ `+ ], z- f& t8 a; y5 {0 D$ ^
9》板子上执行mkdir nfs,创建本地nfs共享目录
) R8 P7 {$ k2 I5 q
$ ]" f1 t- R. [% i2 g10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs L" g) L; J8 D: d( |' t/ f$ B
) T4 Q6 g* q. N( Z1 M6 ]2 t' w
11》在virtualbox里将ip_mkg.ko copy到nfs共享目录
% _* Z( T5 ?% D
. |! ?3 b7 @# F12》板子上cd nfs( B# [! u5 S. K% B# N, Y3 q7 `4 E- B
; E( e; e7 I/ ?* c: J% u13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下1 n! l3 R8 @* o
, d s" g% [9 L- k
14》创建设备节点:mknod /dev/ip_mkg c 102 04 Q! x4 F- V8 |9 ?- E
1 p' I# _9 C+ ~7 C* y! {1 `15》测试:cat /dev/ip_mkg,看到如下结果:& y/ D8 y5 Y; {
) t5 q3 j+ k) c; l, R L1 j
16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下* H, Q8 g$ L; q9 F3 W+ W' T/ u( C
: f+ L7 a% v* c# Q9 wsoc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS
3 E/ o Z0 y `% j) J1 {+ M
5 O# d4 Y" l: n* i. H6 e8 W\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。
" D& R6 {* W- ~1 a* W3 G7 E* m3 a
# d5 Z' i% p) i( [+ u
( X' \/ I- Z0 A1 s& y4 g. G) u: a1 \% a' a6 k; \9 F, F
( [6 b( U+ l$ ~! I3 [% s( W16》运行helloworld- b) X! R. V& z/ \1 _; m
+ _7 ]7 U5 }5 P% l
16.1>编写hello.c
1 _; [. P1 n% K" ] R5 N
& {4 `& s1 a1 X. B8 Q7 X- #include <stdio.h>
- void main()
- {
- printf("rill helloworld!\n");
- }/ b) ?5 K" E" z2 x5 {8 ~& L
) G2 T# p( e& k7 Z
0 I1 C/ X/ H; B7 I5 K, T5 ~8 H4 e4 P' B- f6 h
16.2>编译: or2-linux-gcc hello.c -o hello
; o7 j6 w: \& \3 B7 s% C& ^ z5 }8 b7 w: C
16.3>copy到板子上:cp hello /home/openrisc/nfs) P( R: C% \% H/ P: r( _
7 \ m7 s2 q; s/ b( B+ S) N0 z
16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:
, q% |, l; c1 L ], B$ p1 f( v. T$ v
2 n, d3 k, X& L4 {
3 ~/ z( \! f k9 L# d
|
|