TA的每日心情 | 怒 2019-11-20 15:22 |
|---|
签到天数: 2 天 [LV.1]初来乍到
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
; f6 v/ q) B8 S1 H" r4 i引言2 |9 I' M5 j. N5 H
( N3 k8 s |& g3 I! }" Y我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线inteRFace的ip,可以实现plug & work。) V Y, n8 ]3 h
G W9 }, h& A1 f9 O0 W: [# L2 F
所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。+ \; A4 ?1 w0 N3 g8 e r0 H
% a3 j( ^& y1 L/ A
本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。# B+ n5 N7 J2 Z7 f* p
7 r* L, b# F9 A# c5 v / ~; F/ W4 h9 V. s1 Y8 A$ w
) ~1 |; H3 X4 b6 k+ S# _
11.1 编写wishbone为interface的ip core(ip_mkg)1 l+ X. C/ E, f+ [* {* V
2 w" O! [% e" |0 X, x$ x/ }
1》这一步请参考:: n+ O( B& W( J- x7 Q, t, [* I
! ?, Q" H2 W( n- \linux学习之路_wishbone实验
% t$ B( p6 L- @; b
; _8 \: q1 V, L& R5 |9 {- ]4 }2》将其中的my_slave_module链接到ORPSoC的wishbone上。* K2 d6 A, t+ f6 N. |! ]
( r* u" c' i0 L2 ]
# O o, C6 W9 L9 H- d/ n# e
$ |4 Y, k+ u) U# J( n7 N' y
11.2 编写linux下的driver module) e3 B3 D. ^, N2 B& s
8 Z6 o; j. V, `/ n& g代码及makefile如下:- |# Y. f0 ` R- b) O
M R9 Q# i4 W9 d# f
1》ip_mkg.c: w7 \+ W0 l- S, x& z8 I: X
V$ ~1 r- V4 t- V5 A+ y
4 U8 k/ Y6 l" _
+ h! f4 |6 j, j/ L/ |4 Y
- /*
- *
- * 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");
0 a7 }: n( n! j
( B. a% B' S8 T5 m1 ]
: Z( n: p8 w' G4 M6 {; i
, q+ ]. Y7 m3 ~# q2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。
, W+ H+ @ H/ E( u9 j" G
0 R2 _2 u% u8 P V- #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;
- };
- #endif1 \ N5 h5 H+ y9 I4 o8 O ^
% j+ L4 \3 k: @7 f9 r5 @8 t
, o% u2 Y a3 u: O: r, q' Y) F* K
9 |9 w, Z9 G9 |6 C3 g3》Makefile5 A- f4 [8 Y8 N0 t6 f: x
# G: c! D% f% ^4 b/ [/ C7 @
- # 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! F2 `% h) P! b
" i) m: t' s9 Q7 B* i
, R1 ?: x' _% j8 r, ` ! }6 r* a8 D: A" P" J$ T4 g
11.3 遇到的问题3 A% _3 o% U$ o7 l. T* f8 j! b
: L8 M0 a: r4 u0 n; w% [0 O
1》当在执行make时会遇到如下警告:__ioremap undefined。- n3 D8 S; ~" ^& C7 H# O/ q
7 i0 Z7 m% L! Q: v+ z$ }; m
- C9 S+ c L7 D
% ~8 |; v$ h4 U# ^. V
, W' }! u6 L) v
: N7 h' }' u* S' B2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。9 P7 N2 s; A7 \6 U7 Q# @/ X- U1 ]/ @
. ]" @; v$ r9 D( Y
! I1 b3 D. c; D& ^1 l$ G1 v
7 ?/ T! v; t6 \) h( X; [. }/ U( F
. Y7 ^7 y5 X! a% ?/ j. p: i+ i" P3 v7 Y* K4 C
11.4 解决方法- _5 x4 l# R. d# w4 G) O
( h3 d" O6 O& r在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。4 D0 C, T8 d. o# g' t4 R
) T6 G9 q+ d3 r% Q d9 W$ B- #include <linux/module.h>
- EXPORT_SYMBOL(__ioremap);
. r0 P) R% w9 v* M8 z3 W
, V' M$ @( X) [: T* }3 F) g% k# C Q
% C/ W) g/ E5 n4 H, \5 D
11.5 小结% e9 g! b+ T: ?' ?/ t9 H7 w' s' e
" h5 E3 n; G: [" p% d' ^1 L实验步骤+ ~# Q3 p" Y V; u, E; b
% G6 J& `6 y1 F0 P7 A/ q& w
0》virtualbox虚拟机unbuntu上安装nfs服务
( C) Q" f( X7 ?% W1 L8 h7 E; c) z; m5 ~" X7 }* I+ g% A. L6 Y& b, I
0.0>确保virtualbox能上网& J2 D: ~& }. d' }
% P% b" g& N6 D i+ R% Z1 A0 U
0.1> apt-get install nfs-kernel-server
% k, f) R" p/ X7 U) a* T# a- o/ j0 t* v( ?5 c$ S
0.2>创建nfs共享目录:mkdir /home/openrisc/nfs# @& S' Y: F' `" T1 x4 D
, F5 y9 b8 k) G( M( i- \
0.3>vim /etc/exports,添加如下内容: [" m5 Q0 C) _; `0 I/ X2 U/ g) R
# U, \$ B7 V$ @1 l( Y& O
/home/openrisc/nfs *(rw,sync)# k( |7 m0 [7 V# f! B# [' H- }# t9 l
7 i v- w2 d5 e/ m0.4>重启nfs服务4 u1 T( d9 b" p$ Q/ N* c! e. Z' M
, T' F" j1 H9 s
sudo /etc/init.d/nfs-kernel-server restart
$ K, X4 _8 e. b( `8 C7 V4 Q5 s5 L- C# E
1》修改arch/openrisc/mm/ioremap.c
8 d; k! N7 ?) A( t8 l) @% q9 r; I; D' n( @& ^) V, C2 G+ R
2》cd /home/openrisc/soc-design/linux* o, T( v( G2 O/ D* V
6 S, Z5 P. E" o7 a( b- x7 c$ ]3 g
3》make ARCH=openrisc defconfig;make生成vmlinux4 x+ a( F* _1 R
X4 C9 ]' o% b1 B# G# X# ^
4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件/ Y! \# W7 ]0 c1 Z" h* {4 I! D4 {
) i8 f9 V' Y. F1 A" ]! m
5》在FPGA板子上运行linux(刚刚生成的vmlinux文件)
# n- g' `* O# K' F+ [
% E. U: ^" y6 U/ I6》配置virtualbox的ip: a8 X2 x) ]( s
% A7 f; q- `: U0 G; Msudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.2554 e9 f% x% S7 c9 O4 V
' ?( b+ T, y1 A: B3 d' X2 W
7》配置PC机的ip为192.168.1.102
% O, R& K% _; D: L9 o+ h9 s% @+ M& B5 H/ C. \
8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。' \( g0 C# o2 {3 E2 y6 F% c
% S. s5 H6 Y$ d9 r3 d) @+ p! G/ a9》板子上执行mkdir nfs,创建本地nfs共享目录
6 \; h# n3 O9 i @3 d4 j- _+ E1 z
! f/ [! {, t. G, ~, M3 }& Z10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs, H4 |+ l+ f5 @. h# ^) M1 O
5 h! H* Q+ K5 i$ E
11》在virtualbox里将ip_mkg.ko copy到nfs共享目录5 u; U+ P( A! e. h0 g# M
1 G4 _, d: N) o. P! B& N# T12》板子上cd nfs
1 Q+ P( V9 \# x: V% O [/ |0 u! @% o! ^: t7 {/ m
13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下
$ `+ z2 K4 n0 m
$ j+ a9 P# a0 R# |1 Y' H& b14》创建设备节点:mknod /dev/ip_mkg c 102 08 G# [8 r* w9 k. g! j
% v( T) K. q3 k, f. ]3 J15》测试:cat /dev/ip_mkg,看到如下结果:7 T! q6 y3 u6 d l$ I; }
$ s& N/ B0 Y# V) `4 a
16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下, K% i T3 L8 ^: C
' z N0 a* @; ?; o2 E' @& R
soc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS1 V5 {8 L% r6 y% j
3 _. O1 d: O$ |
\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。 7 @4 o/ }% r! d; K' c
3 a, `! w6 E, ~; P9 m8 E$ E5 x9 S
( ?$ T* ]9 L! s7 M8 `, q$ s
! i2 { K! y6 _
! v- t$ N) }! k6 ~& m+ }: r: E; ?$ P! W$ N
16》运行helloworld( N4 S, v2 \: \# m: E+ Y' q
9 z; J6 i+ A5 V! j6 ~
16.1>编写hello.c: \+ }+ K: h: f
' ~3 ?& f" I; |/ v7 s- #include <stdio.h>
- void main()
- {
- printf("rill helloworld!\n");
- }( K: x$ f% v" z9 [" K$ ?
7 K0 r4 O/ s0 R6 y7 E. q, B% P4 }4 D. R: j
; @* F8 o) n- X/ ^16.2>编译: or2-linux-gcc hello.c -o hello3 m- u" h0 N& C
2 O- P9 W& J8 Z
16.3>copy到板子上:cp hello /home/openrisc/nfs- s& s) }' f6 A1 X- _4 H3 O
' z! l) j- o& X; Y% @' T16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:9 v$ v* k. Y, r! \- U
/ @2 R5 E6 f# d
4 z* {3 ]4 }3 q% G, V# I: Y, l! \
. |5 n& N+ c# l* C, v7 U8 X |
|