|
|
|
@ -6,9 +6,10 @@
|
|
|
|
|
- [6.1.1 pynq开发板介绍](#subsec_pynq)
|
|
|
|
|
- [6.1.2 设备树](#subsec_device_tree)
|
|
|
|
|
- [6.1.3 内存映射I/O(MMIO)](#subsec_MMIO)
|
|
|
|
|
- [6.1.4 轮询I/O控制方式](#subsec_polling)
|
|
|
|
|
- [6.1.5 中断驱动I/O控制方式](#subsec_plic)
|
|
|
|
|
- [6.1.6 设备文件](#subsec_file)
|
|
|
|
|
- [6.1.4 riscv-fesvr原理](#subsec_fesvr)
|
|
|
|
|
- [6.1.5 轮询I/O控制方式](#subsec_polling)
|
|
|
|
|
- [6.1.6 中断驱动I/O控制方式](#subsec_plic)
|
|
|
|
|
- [6.1.7 设备文件](#subsec_file)
|
|
|
|
|
- [6.2 lab4_1 POLL](#polling)
|
|
|
|
|
- [给定应用](#lab4_1_app)
|
|
|
|
|
- [实验内容](#lab4_1_content)
|
|
|
|
@ -34,7 +35,15 @@
|
|
|
|
|
|
|
|
|
|
本实验中,我们所使用的pynq-z2开发板上搭载两块芯片,一块为Arm架构32位芯片,称为PS端,我们能在上面运行Ubuntu;另一块为FPGA可编程芯片,称为PL端,通过烧录Rocket chip电路,使它能够运行Riscv架构的操作系统,即riscv-pke。
|
|
|
|
|
|
|
|
|
|
在前面的实验中,Spike模拟器负责执行PKE的机器指令和为PKE分配内存,并通过HTIF协议和PKE进行通信为PKE分配主机的其他资源(如文件等)。在开发板上运行时,执行PKE的机器指令和为PKE分配内存由PL端的电路负责,负责和PKE通信的则是我们在PS端运行的程序riscv-fesvr,PKE借此可以访问PL端的用户程序等文件,这是实验4的基础。
|
|
|
|
|
![](pictures/fig6_4.png)
|
|
|
|
|
|
|
|
|
|
如上图,在开发板上运行的时候,PKE在PL端运行,一方面它可以通过Rocket Chip电路的连线访问PL端的设备(device),如蓝牙、小车电机等;另一方面,在PS端运行的riscv-fesvr程序可以和PKE通过HTIF协议通信,使得PKE可以读写PS端Linux操作系统下的设备文件(host device),比如摄像头、声卡等。也就是说,PKE除了可以访问本身的设备,还可以利用PS端操作系统的功能访问更复杂的设备,这就是代理内核的特点。
|
|
|
|
|
|
|
|
|
|
实验四和前三个实验的关系如下:
|
|
|
|
|
|
|
|
|
|
![](pictures/fig6_5.png)
|
|
|
|
|
|
|
|
|
|
可见除了部分硬件相关的操作外,PKE在Spike和开发板上的运行是完全等价的,代理内核一方面让我们可以用最简单的方法访问两端的设备,另一方面在不同地方运行基本不用改太多代码,非常优越。
|
|
|
|
|
|
|
|
|
|
<a name="subsec_device_tree"></a>
|
|
|
|
|
|
|
|
|
@ -58,9 +67,28 @@
|
|
|
|
|
|
|
|
|
|
在本章节中,修改后的RocketChip将蓝牙控制寄存器和小车电机端接到固定的内存地址,因此可以通过对这些地址进行读写控制蓝牙和小车电机。
|
|
|
|
|
|
|
|
|
|
<a name="subsec_fesvr"></a>
|
|
|
|
|
|
|
|
|
|
### 6.1.4 riscv-fesvr原理
|
|
|
|
|
|
|
|
|
|
riscv-fesvr是PKE在PYNQ开发板上使用的重要工具,它是ARM端系统上运行的程序,控制PKE的启动。除了启动功能,riscv-fesvr程序主要分为两个模块,系统调用模块块负责接受PKE对ARM端的系统调用请求,在ARM端执行这些函数;内存模块负责读写RISCV端的内存,和PKE交换数据。
|
|
|
|
|
|
|
|
|
|
PKE调用宿主机/开发板ARM端的系统调用函数使用的是HTIF协议。协议要求内核保留两个地址,作为和riscv-fesvr共享数据的地方。PKE要使用系统调用函数,就需要将系统调用函数的编号和参数通过这个地址发送给riscv-fesvr,方法是定义一个数组magic_mem,该数组存储了调用号和参数,再将数组的起始地址按一定的格式填入这个地址中,如下图。
|
|
|
|
|
|
|
|
|
|
![](pictures/fig6_7.png)
|
|
|
|
|
|
|
|
|
|
打个比方,我通过HTIF协议调用ARM端的write函数,那么我先定义一个数组magic_mem,magic_mem[0]为write的系统调用号,magic_mem[1]为文件描述符,magic_mem[2]为缓冲区地址,magic_mem[3]为写入长度。然后把一个数写入共享地址,这个数高8位和中间8位都是0,低48位为magic_mem的地址。riscv-fesvr会首先读出magic_mem里的数据,然后根据magic_mem[0]决定要调用write函数,这时需要注意magic_mem[2]里的缓冲区地址是RISCV端内存的地址,所以先把RISCV端内存里的这段数据读到外面内存,再以外面内存地址为参数调用write函数。
|
|
|
|
|
|
|
|
|
|
riscv-fesvr的内存模块用来读写RISCV端的内存,从而可以读取系统调用参数以及读写PKE的缓冲区。Pynq开发板把RISCV端的内存抽象成设备文件/dev/mem,所以内存模块可以通过在固定偏移量读写该文件,从而实现读写内存。
|
|
|
|
|
|
|
|
|
|
另外,控制摄像头需要用到的ioctl、mmap、munmap三个系统调用函数是原版的riscv-fesvr不支持的,所以我们对riscv-fesvr的系统调用模块进行了修改:
|
|
|
|
|
|
|
|
|
|
* ioctl函数比较简单,可以直接用PKE传过来的参数调用系统调用函数
|
|
|
|
|
* mmap函数比较麻烦,因为ARM端通过mmap映射的是ARM端的内存,RISCV端无法访问。所以再添加readmmap函数,PKE可以通过HTIF调用此函数读取ARM端被映射的内存。将ARM端用mmap映射的所有内存用数组存储映射地址,返回给PKE数组索引;PKE向readmmap传入索引,riscv-fesvr根据索引找到地址,读取ARM端的内存数据返回给PKE。
|
|
|
|
|
|
|
|
|
|
<a name="subsec_polling"></a>
|
|
|
|
|
|
|
|
|
|
### 6.1.4 轮询I/O控制方式
|
|
|
|
|
### 6.1.5 轮询I/O控制方式
|
|
|
|
|
|
|
|
|
|
在实验四中,我们设备管理的主要任务是控制设备与内存的数据传递,具体为从蓝牙设备读取到用户输入的指令字符(或传递数据给蓝牙在手机端进行打印),解析为小车前、后、左、右、停止等动作来传输数据给电机实现对小车的控制。在前两个实验中,我们分别需要对轮询控制方式和中断控制方式进行实现。
|
|
|
|
|
|
|
|
|
@ -72,7 +100,7 @@
|
|
|
|
|
|
|
|
|
|
<a name="subsec_plic"></a>
|
|
|
|
|
|
|
|
|
|
### 6.1.5 中断驱动I/O控制方式
|
|
|
|
|
### 6.1.6 中断驱动I/O控制方式
|
|
|
|
|
|
|
|
|
|
在前一种轮询的控制方式中,由于CPU的高速性和I/O设备的低速性,导致CPU浪费绝大多数时间处于等待I/O设备完成数据传输的循环测试中,会造成大量资源浪费。中断驱动的方式是,允许请求I/O的进程在设备工作时进入休眠状态,使CPU能够运行别的进程。直到设备工作完成时,再由设备发出中断,中断处理程序唤醒之前休眠的进程,使其能够接受设备返回的数据继续执行。采用中断驱动的控制方式,在I/O操作过程中,CPU可以执行其他的进程,CPU与设备之间达到了部分并行的工作状态,从而提升了资源利用率。
|
|
|
|
|
|
|
|
|
@ -84,7 +112,7 @@ Riscv包含三类中断:软中断、时钟中断和外部中断。软中断和
|
|
|
|
|
|
|
|
|
|
<a name="#subsec_file"></a>
|
|
|
|
|
|
|
|
|
|
### 6.1.6 设备文件
|
|
|
|
|
### 6.1.7 设备文件
|
|
|
|
|
|
|
|
|
|
用户程序访问外部设备通常有两种方式:通过特定系统调用访问和通过设备文件访问。前者即操作系统提供专门的函数控制设备,后者是操作系统把设备指定成一个文件,通过通用的文件的读写函数控制设备。设备文件常用的函数除了open、read、write、close,还有以下几种:
|
|
|
|
|
|
|
|
|
@ -140,9 +168,11 @@ Riscv包含三类中断:软中断、时钟中断和外部中断。软中断和
|
|
|
|
|
|
|
|
|
|
#### **实验内容**
|
|
|
|
|
|
|
|
|
|
如输出提示所表示的那样,需要找到并完成对uart_getchar的调用,完成后进行验证。
|
|
|
|
|
如输出提示所表示的那样,需要找到并完成对uart_getchar的调用,由于本实验给出的基础代码修改了硬件相关的部分代码,所以无法在Spike上运行,需在PYNQ开发板上进行验证,运行步骤如下:
|
|
|
|
|
|
|
|
|
|
手机端验证:首先将蓝牙模块接入pynq板,接口对应关系为:
|
|
|
|
|
1. 依照仓库https://gitee.com/hustos/fpga-pynq下**usb-device-pynq**分支的说明,在板上安装ARM端操作系统和下载必要的文件
|
|
|
|
|
2. 依照仓库https://gitee.com/hustos/myriscv-fesvr的说明,自行编译或直接下载修改后的riscv-fesvr
|
|
|
|
|
3. 连接外设:首先将蓝牙模块接入pynq板的PMODA接口组,接口对应关系为:
|
|
|
|
|
|
|
|
|
|
| pynq接口 | 蓝牙接口 |
|
|
|
|
|
| -------- | -------- |
|
|
|
|
@ -151,27 +181,19 @@ Riscv包含三类中断:软中断、时钟中断和外部中断。软中断和
|
|
|
|
|
| JA4 | RXD |
|
|
|
|
|
| JA3 | TXD |
|
|
|
|
|
|
|
|
|
|
接入时注意对应接口错位正确插入,然后在手机端下载任意一种蓝牙串口通信APP,匹配并连接蓝牙模块。蓝牙的名称通常是“HC-两位数字”。使用网线连接pynq板和电脑,打开开发板电源。
|
|
|
|
|
|
|
|
|
|
成功连接蓝牙模块后,启动连接:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
$ ssh xilinx@192.168.2.99
|
|
|
|
|
```
|
|
|
|
|
接入时注意对应接口错位正确插入,且插入的所有接口均在上面的一排。然后将小车的电机接口接入PMODB接口组,为了防止小车行走过程中接口松开,可自行使用胶布粘贴。
|
|
|
|
|
|
|
|
|
|
随后使用scp指令将编译后的pke内核和用户app文件导入:
|
|
|
|
|
![](pictures/fig6_6.jpg)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
$ scp 文件名 xilinx@192.168.2.99:~
|
|
|
|
|
```
|
|
|
|
|
4. 在手机端下载任意一种蓝牙串口通信APP,匹配并连接蓝牙模块。蓝牙的名称通常是“HC-两位数字”。使用网线连接开发板和电脑,同时使用USB线连接开发板和电脑或者充电宝,打开开发板电源。
|
|
|
|
|
|
|
|
|
|
此时便成功进入pynq板环境。运行:
|
|
|
|
|
5. 执行开机之后必要的操作后(烧录电路等,见步骤1里的仓库),运行:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
sudo ./riscv-fesvr riscv-pke app_poll
|
|
|
|
|
```
|
|
|
|
|
```
|
|
|
|
|
sudo ./riscv-fesvr riscv-pke app_poll
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
之后即可在手机上输入控制指令,小车应能根据指令反应。
|
|
|
|
|
之后即可在手机上输入控制指令,小车应能根据指令反应。
|
|
|
|
|
|
|
|
|
|
<a name="lab4_1_guide"></a>
|
|
|
|
|
|
|
|
|
@ -485,7 +507,7 @@ $ git commit -a -m "my work on lab4_2 is done."
|
|
|
|
|
47 }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
实验预期结果:小车在前进过程中能够正常识别障碍物后并自动停车。
|
|
|
|
|
实验预期结果:小车在前进过程中能够正常识别障碍物后并自动停车。测试时别忘记把摄像头接到USB接口,否则系统会找不到设备文件。
|
|
|
|
|
|
|
|
|
|
<a name="lab4_3_guide"></a>
|
|
|
|
|
|
|
|
|
|