机器已经部署到淮安

8月底出差告一段落,运行一切正常
1. 添加了喷阀数据队列走空计数和自动补偿功能
2. 喷阀数据队列发生不可恢复的异常时向上位机报告错误
3. 取消双FIFO
This commit is contained in:
Miaow 2022-09-01 21:40:16 +08:00
parent 1dd8210404
commit 71f8e672d5
26 changed files with 760 additions and 414 deletions

View File

@ -2,7 +2,7 @@
## 开发
本次开发基于zynq芯片因此FPGA设计软件为Vitis中包含的[Vivado 2021.2](https://china.xilinx.com/support/download/index.html/content/xilinx/zh/downloadNav/vitis.html)Linux编译工具为[petalinux 2022.1](https://china.xilinx.com/support/download/index.html/content/xilinx/zh/downloadNav/embedded-design-tools.html)Linux应用程序编译工具为linaro的[arm-linux-gnueabihf-gcc 12.0.1](https://snapshots.linaro.org/gnu-toolchain/12.0-2022.02-1/arm-linux-gnueabihf/)。
本次开发基于zynq xc7z010-1clg400芯片因此FPGA设计软件为Vitis中包含的[Vivado 2021.2](https://china.xilinx.com/support/download/index.html/content/xilinx/zh/downloadNav/vitis.html)Linux编译工具为[petalinux 2022.1](https://china.xilinx.com/support/download/index.html/content/xilinx/zh/downloadNav/embedded-design-tools.html)Linux应用程序编译工具为linaro的[arm-linux-gnueabihf-gcc 12.0.1](https://snapshots.linaro.org/gnu-toolchain/12.0-2022.02-1/arm-linux-gnueabihf/)。
### 生成硬件描述文件
@ -19,19 +19,17 @@
$ petalinux-create -t modules --name encoder --enable
```
2. 上传驱动代码[source/linux_driver/fifo.c](../source/linux_driver/fifo.c)和[source/linux_driver/encoder.c](../source/linux_driver/encoder.c)
2. 分别上传驱动代码[source/linux_driver/fifo.c](../source/linux_driver/fifo.c)和[source/linux_driver/encoder.c](../source/linux_driver/encoder.c)到下面的目录中
```shell
$ cd ~/ps-linux/project-spec/meta-user/recipes-modules/fifo
$ rz # 上传source/linux_driver/fifo.c
$ cd ~/ps-linux/project-spec/meta-user/recipes-modules/encoder
$ rz # 上传source/linux_driver/encoder.c
~/ps-linux/project-spec/meta-user/recipes-modules/fifo/files
~/ps-linux/project-spec/meta-user/recipes-modules/encoder/files
```
3. 上传xsa文件并config
3. 上传硬件描述文件[source/petalinux_hwdescription/system_wrapper.xsa](source/petalinux_hwdescription/system_wrapper.xsa)到`ps-linux`目录中并config
```shell
$ cd ~/ps-linux; rz # 上传source/petalinux_hwdescription/system_wrapper.xsa
system_wrapper.xsa上传到~/ps-linux
$ petalinux-config --get-hw-description system_wrapper.xsa
```
@ -71,7 +69,7 @@
```shell
$ cd ~/ps-linux/project-spec/meta-user/recipes-bsp/device-tree/files
$ rm system-user.dtsi
$ rz # 上传source/petalinux_devicetree/system-user.dtsi
上传source/petalinux_devicetree/system-user.dtsi
```
5. 配置kernel使用命令`petalinux-config -c kernel`,按下面提示或[source/petalinux_config/kernel.cfg](../source/petalinux_config/kernel.cfg)配置
@ -188,39 +186,53 @@
# ├─imagefeature-hwcodecs (勾选为星号)
# ├─imagefeature-package-management (勾选为星号)
# modules
# ├─encoder (勾选为星号)
# └─fifo (勾选为星号)
# ├─encoder (不选)
# ├─fifo (不选)
# PetaLinux RootFS Settings
# ├─ADD_EXTRA_USERS (root:3703;petalinux:3703;)
# ├─ADD_USERS_TO_GROUPS (petalinux:audio,video;)
# └─ADD_USERS_TO_SUDOERS (petalinux)
```
### 编译PETALINUX工程
### 编译系统
1. 编译工程,使用命令`petalinux-build`。编译完成在当前工程目录下生成images文件夹该命令将生成设备树文件、FSBL文件、U-Boot文件Linux Kernel文件和rootfs文件镜像
2. 制作BOOT.BIN启动文件具体命令如下
```shell
$ cd ~/petalinux-projects/ps-linux/images/linux/ # 生成的BOOT.BIN在该路径下
$ cd ~/ps-linux/images/linux/ # 生成的BOOT.BIN在该路径下
$ petalinux-package --boot --fsbl ./zynq_fsbl.elf --fpga ./system.bit --u-boot ./u-boot.elf --force
```
## 部署
> 注意这部分所需的文件按上一章节编译得到或者从github的release中下载
### 编译驱动
### SSH连接
1. 电脑网卡设置到开发板同一网段
2. SSH连接信息如下
依次运行如下命令单独编译3个驱动程序
```shell
$ sshpass -p "3703" ssh root@192.168.10.10 -p 22
$ petalinux-build -c fifo
$ petalinux-build -c encoder
```
编译后的模块文件为` ps-linux/build/tmp/sysroots-components/zynq_generic/fifo/lib/modules/5.15.19-xilinx-v2022.1/extra/fifo.ko`和`ps-linux/build/tmp/sysroots-components/zynq_generic/encoder/lib/modules/5.15.19-xilinx-v2022.1/extra/encoder.ko`
### 编译应用程序
在运行make时要设置好交叉编译工具链前缀命令如下
```shell
$ make CROSS_COMPILE=交叉编译工具链前缀
例如 make CROSS_COMPILE=/home/miaow/software/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-
```
编译后的可执行文件为工程目录的`build/target`交叉编译工具链前缀也可以在Makefile中修改设定
## 部署
有两种方式部署,一种是修改文件系统,这也是我第一次构建这个系统时的操作;另一种是直接写入镜像,推荐使用这种方式,省时省力不易出错
> 注意修改文件系统方法所需的文件按上一章节编译得到或者从github的release中下载直接写入镜像所需的文件在release中
### 修改文件系统
@ -267,31 +279,36 @@
$ reboot
```
7. 安装编译得到的驱动文件fifo.ko和encode.ko并设置自动加载对应脚本见[script/loadfifo.sh](../script/loadfifo.sh)和[script/loadencoder.sh](../script/loadencoder.sh)
ssh方式root登录:
7. 电脑网卡设置到开发板同一网段 SSH连接信息如下
```shell
$ cd ~; rz #上传fifo.ko
$ rz # 上传encoder.ko
$ mv fifo.ko encoder.ko /lib/modules/[内核版本]/kernel/drivers/
在电脑上执行下面命令
$ sshpass -p "3703" ssh root@192.168.10.10 -p 22
```
8. 安装编译得到的驱动文件fifo.ko和encode.ko并设置自动加载对应自启脚本可以如下方式写入也可以直接上传[script/loadfifo.sh](../script/loadfifo.sh)和[script/loadencoder.sh](../script/loadencoder.sh)ssh方式root登录:
```shell
上传fifo.ko、encoder.ko到/lib/modules/[内核版本]/kernel/drivers/
$ cd /lib/modules/[内核版本]; depmod
$ set +H
$ echo -e "#!/bin/sh\nmodprobe fifo" > /etc/init.d/loadfifo.sh
$ echo -e "#!/bin/sh\nmodprobe encoder" > /etc/init.d/loadencoder.sh
$ chmod 755 /etc/init.d/loadfifo.sh
$ chmod 755 /etc/init.d/loadencoder.sh
$ chmod 755 /etc/init.d/loadfifo.sh /etc/init.d/loadencoder.sh
$ cd /etc/rc5.d
$ ln -s ../init.d/loadfifo.sh S20loadfifo.sh
$ ln -s ../init.d/loadencoder.sh S20loadencoder.sh
```
8. 安装编译得到的应用程序target并设置自启动对应脚本见[script/target.sh](../script/target.sh)
9. 安装编译得到的应用程序target并设置自启动对应脚本见[script/target.sh](../script/target.sh)
ssh方式root登录:
```shell
$ cd ~; rz # 上传target
上传target到/home/root
$ cd ~
$ chmod 755 target
$ set +H
$ echo -e "#!/bin/sh\nif [ -x /home/root/target ]; then\n /home/root/target\nfi" > /etc/init.d/target.sh
@ -300,34 +317,35 @@
$ ln -s ../init.d/target.sh S99target.sh
```
9. \[可选\] 设置.bashrc美化PS1对应脚本见[script/.profile](../script/.profile)和[script/.bashrc](../script/.bashrc)
10. \[可选\] 设置.bashrc修改PS1对应脚本见[script/.profile](../script/.profile)和[script/.bashrc](../script/.bashrc)
```shell
$ cd ~; rz # 上传.bashrc
$ rz # 上传.profile
$ cd ~; rm .bashrc .profile
上传.bashrc和.profile到/home/root
$ if [ ! -a /home/petalinux/.profile ]; then cp /home/root/.profile /home/petalinux/ fi
$ if [ ! -a /home/petalinux/.bashrc ]; then cp /home/root/.bashrc /home/petalinux/ & chown petalinux:petalinux -R /home/petalinux fi
$ source ~/.profile
```
10. \[可选\] 安装ncurses-6.3和htop.
11. \[可选\] 安装ncurses-6.3和htop
```shell
$ cd ~; rz # 上传ncurses-6.3.tar.gz
$ tar xmzf /home/root/ncurses-6.3.tar.gz -C /usr/
$ rz # 上传htop.tar.gz
$ tar xmzf /home/root/htop.tar.gz -C /usr/
$ echo "export TERMINFO=/usr/share/terminfo" >> /etc/profile
$ reboot
```
### SD卡启动
### 直接写入镜像
1. 给SD卡创建DOS分区表然后分2个区并创建文件系统细节如下表
强烈推荐的傻瓜式的方法在windows上准备好正版[DiskGenius标准版或专业版](https://www.diskgenius.cn/)盗版有BUG从release中下载sdimage.pmfx文件
| 扇区 | 大小 | 分区类型 | 文件系统 | 卷标 |
| -------------- | -------------- | ----------------- | -------- | ------ |
| 2048~x扇区 | 100M | C W95 FAT32 (LBA) | FAT32 | boot |
| x扇区~最后扇区 | ≈SD卡大小-100M | 83 Linux | ext4 | rootfs |
1. 在windows上插入16G的TF卡
2. 打开DiskGenius
3. 左侧栏选中TF卡右键从镜像文件还原磁盘
4. 选sdimage.pmfx文件
5. 点击开始
2. 将Github Release中的BOOT.BIN、boot.scr和image.ub复制到boot分区将rootfs.tar.gz解压到rootfs分区。
3. 拨码开关拨到SD卡启动插入SD卡到XME0724底板上上电启动。
把TF卡插回板子启动方式拨到SD卡启动上电。要进入系统参考修改文件系统章节的第7步。

View File

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

View File

@ -1,54 +1,77 @@
# 硬件平台
PL端主要由4个外设组成分别时**风扇控制器**(FAN)**编码和分频控制器**(ENCODER)**先入先出队列**(FIFO)和**阀板控制器**(VALVE)。其中阀板控制器没有提供AXI接口因此并没有映射寄存器软件也无法进行控制。各个控制器的连接关系如下图所示。
PL端主要由4个外设组成分别时**风扇控制器**(FAN)**编码和分频控制器**(ENCODER)**先入先出队列*(FIFO)阀板控制器**(VALVE)。其中阀板控制器没有提供AXI接口因此并没有映射寄存器软件也无法进行控制。各个控制器的连接关系如下图所示。
![2](hardware_description.assets/2.png)
![2](hardware_description.assets/system_arch.png)
由于开发板的PL端没有自带晶振所以4个外设由统一的同步时钟驱动时钟源来自PS端为200MHz软件不可修改。外部编码器信号输入**编码和分频控制器**,控制器根据软件设置的阀触发分频值和相机触发分频值对编码器信号进行分频,分频后的信号用于驱动喷阀动作和触发相机拍照。为同步触发相机和移出队列以及保持队列中数据的动态平衡,**先入先出队列**在相机触发同时输出一个数据,即**先入先出队列**读信号和相机触发共用同一个信号。而由于电磁阀的物理特性导致电磁阀无法以触发相机的频率进行开关,因此**阀板控制器**对先入先出队列输出总线上的数据进行重采样,即按照**编码和分频控制器**输出的阀触发信号更新并转换为阀板协议输出电磁阀的状态。设计的风扇控制器用于驱动风扇的启停给ZYNQ芯片进行降温防止芯片过热导致工作中出现问题
由于开发板的PL端没有自带晶振所以4个外设由统一的同步时钟驱动时钟源来自PS端为200MHz软件不可修改。外部编码器信号输入**编码和分频控制器**,控制器根据软件设置的阀触发分频值和相机触发分频值对编码器信号进行分频,分频后的信号用于驱动喷阀动作和触发相机拍照。光谱相机的触发频率较慢,为编码器频率/CDIV彩色相机触发频率快为⌊编码器频率/CDIV⌋\* 4。上位机发来的喷阀动作数据有两个对应的分别是光谱和彩色相机的识别结果都是为256宽度*1024高度。识别结果存储到**先入先出队列**中
## 生成硬件描述文件
为同步触发相机和队列移出信号以及保持队列中数据的动态平衡,两个先入先出队列在彩色相机触发同时输出一个数据,即**先入先出队列**的读信号和彩色相机触发共用同一个信号。而由于电磁阀的物理特性导致电磁阀可能无法以触发相机的频率进行开关,因此**阀板控制器**对先入先出队列输出总线上的数据重采样,即按照**编码和分频控制器**输出的阀触发信号读入。两个先入先出队列移出的数据在**阀板控制器**中进行按位或运算,得到的数据转换为阀板协议,输出给阀板。**风扇控制器**用于驱动风扇的启停给ZYNQ芯片进行降温防止芯片过热导致工作中出现问题。由于风扇寿命短因此目前采用散热片方案风扇不开。
1. 创建名为test_lower_machine的工程打开**Block Design**添加ZYNQ7 Processing System、ip_fifo、ip_encoder、ip_fan、valve_interfaces模块。
2. 在ZYNQ7 Processing System中勾选Quad SPI Flash [1-6]、Ethernet 0 [16-27]、USB 0 [28-39]、SD 0 [40-45]、SD 1 [46-51]、UART 0 [14-15]、TTC 0 [EMIO]、GPIO MIO {Ethernet PHY Reset [7]、USB PHY Reset[8]}
3. 按顺序点击**Generate Outputs Product** -> **Create HDL Wrapper** -> **Generate Bitstream****File** -> **Export Export Hardware** 得到xsa文件。
## PS模块
下面列出需要开启的外设和采用的IO口BANK0为LVCMOS3.3VBANK1为LVCOMS1.8V
| 外设 | IO | 备注 |
| --------------------------------------------------- | ---------------------- | -------------------------------------- |
| Quad SPI Flash | 1~6 | Single SS 4bit IOFast , ss_b pullup |
| Ethernet 0<br />MDIO | 16~27<br /> 52~53 | Fast, all pullup |
| USB0 | 28~39 | Fast, all pullup |
| SD0 | 40~45 | Fast, all pullup |
| SD1 | 46~51 | Fast, all pullup |
| UART0 | 14~15 | all pullup, baud 115200, 8bits, 1 stop |
| TTC0 | EMIO | |
| GPIO MIO<br />Ethernet PHY Reset<br />USB PHY Reset | 所有剩下的<br/>7<br/>8 | Fast, all pullup |
时钟配置上ARM为666.66MHzDDR为533.33MHz用IOPLL给PL端提供200MHz的FCLK_CLK0。
如果用的是7010的板子内存选忽略下面这一段内存配置上选择DDR3数据位宽32bit=16bit/chip \* 2chip, 4096Mbits/chip频率533.33速度等级为1066F行/列/Bank地址宽度为15/10/3CL=7CWL=6RCD=7RP=7RC=51nsFAW=40ns
ARM核上还开启AXI GP0接口与PL通信
## ENCODER模块
1. encoder模块自定义接口in_signal、out_signal_camera_posedge、out_signal_valve_posedge、out_signal_camera、out_signal_valve
encoder模块主要接口为in_signal、out_signal_camera_posedge、out_signal_camera_posedge_x4、out_signal_valve_posedge、out_signal_camera、out_signal_camera_x4、out_signal_valve
2. in_signal接口与外部编码器相连接收外部编码器信号
接口比较乱,这个模块内部逻辑也实现的不优雅,这得怪老倪动不动就改需求
3. out_signal_camera为分频后的信号用于驱动相机拍照
1. in_signal接口与外部编码器相连接收外部编码器信号
4. out_signal_camera_posedge为out_signal_camera的上升沿该信号输出给fifo模块的rd_en接口用来驱动fifo模块将数据加载到AXI总线上
2. out_signal_camera用于触发光谱相机拍照可以认为光谱相机一次触发产生4行喷阀数据
5. out_signal_valve_posedge为out_signal_valve的上升沿该信号输出给valve_interfaces模块的valve_en信号用于输出AXI总线上的数据驱动喷阀动作
3. out_signal_camera_x4则为out_signal_camera的4倍频率触发彩色相机彩色相机一次产生1行喷阀数据
6. ENCODER模块寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的ENCODER控制器部分
4. out_signal_camera_posedge_x4为out_signal_camera_x4的上升沿控制FIFO的读出
5. out_signal_valve_posedge为out_signal_valve的上升沿驱动**阀板控制器**动作
ENCODER模块输入输出频率的详细计算方式和寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的ENCODER控制器部分
## FIFO模块
1. fifo模块自定义接口rd_en、dout[383:0]、empty、full、almost_full、almost_empty、data_count[11:0]、fifo_valid
2. rd_en接收out_signal_camera_posedge传来的信号用来驱动fifo模块将数据加载到AXI总线上
3. dout[383:0]为驱动喷阀动作的总数据数据位宽为384bit
4. 当empty信号拉高时表示fifo中数据已经为空无法输出有效数据
5. fifo模块寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的FIFO控制器部分
FIFO模块的主要接口为rd_en、dout[383:0]、empty、full、almost_full、almost_empty、data_count[11:0]、fifo_valid
1. rd_en接收ENCODER模块传来的信号控制模块内部FIFO按ENCODER模块所需频率进行读取和输出
2. dout[383:0]为FIFO中读出数据数据位宽为384bit
3. empty信号为1表示fifo中数据已经为空无法输出有效数据但输出寄存器仍然保持上次输出的值
FIFO模块寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的FIFO控制器部分
## FAN模块
1. fan模块自定义接口fan用于控制风扇的启停
2. fan模块寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的FAN控制器部分
fan模块接口fan输出为PWM波形连接到外部的风扇驱动电路。
> Notefan模块代码中设计了PWM调速功能但由于硬件兼容问题导致无法观察到调速现象。但正常的启停可以做到
fan模块寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的FAN控制器部分
> Notefan模块代码中设计了PWM调速功能对于带程序的交流风扇无法观察到调速现象。但正常的启停可以做到
## VALVE_INTERFACES模块
1. valve_interfaces模块自定义接口total_valve_data[383:0]、empty、valve_en、sclk[7:0]、sen[7:0]、sdata[7:0]
2. total_valve_data[383:0]接收fifo模块dout接口传输的数据对其重采样后由sdata接口输出给各个阀板
3. empty信号与fifo模块的empty信号相连。valve_interfaces模块检测到empty信号为高后表示fifo中的数据被读空此时将total_valve_data的384bit的数据全部置为0然后输出给阀板
4. valve_en信号拉高后将384bit的数据输出给阀板更新喷阀状态。该信号不拉高时则不更新喷阀状态
5. sclk[7:0]、sen[7:0]、sdata[7:0]为对应8块阀板的时钟信号线、使能信号线以及数据信号线
VALVE_INTERFACES模块的主要接口为total_valve_data[383:0]、empty、valve_en、sclk[7:0]、sen[7:0]、sdata[7:0]。VALVE_INTERFACES会将total_valve_data_a和total_valve_data_b两路数据进行或运算得到同为384位的单路数据。
1. total_valve_data接收FIFO模块中读出的数据。
2. empty信号与两个FIFO模块的empty信号相连。检测到任意一个empty信号为高时无论输入数据如何只按协议输出全关给阀板。
3. valve_en信号上升沿将total_valve_data按协议发送给阀板
4. sclk[7:0]、sen[7:0]、sdata[7:0]连接到外部差分芯片为最多8块阀板的时钟信号线、使能信号线以及数据信号线

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -105,9 +105,9 @@ ENCODER模块的寄存器主要有控制寄存器 (ENCODER_CR)、阀触发分频
| **Field** | **Description** |
| :---------- | :----------------------------------------------------------- |
| 位31:3 保留 | 必须保持复位值 |
| 位2 **VTS** | 内部触发信号 (Virtual Triggle Signal)<br /> **MOD**位置1时上位机软件写入,将该位信号作为触发信号 |
| 位1 **MOD** | 模式选择 (Mode)<br /> 0: 外部触发模式,外部触发编码器转动<br /> 1: 内部触发模式,上位机软件模拟触发信号 |
| 位0 **CLR** | 清除缓存 (Clear)<br /> 0: 正常工作 1: 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV<br /> 注意: 程序置位该位后后需再写入0使计数器退出清零状态正常工作 |
| 位2 **VTS** | 内部触发信号 (Virtual Triggle Signal)<br /> **MOD**位置1时软件写入,将该位信号直接充当触发信号<br /> 0: 低电平<br /> 1: 高电平 |
| 位1 **MOD** | 模式选择 (Mode)<br /> 0: 外部触发模式,外部触发编码器转动<br /> 1: 内部触发模式,软件模拟触发信号 |
| 位0 **CLR** | 清除缓存 (Clear)<br /> 0: 正常工作 <br /> 1: 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV<br /> 注意: 程序置位该位后后需再写入0使计数器退出清零状态正常工作 |
#### ENCODER阀触发分频寄存器 (ENCODER_VDIVR)
@ -117,7 +117,7 @@ ENCODER模块的寄存器主要有控制寄存器 (ENCODER_CR)、阀触发分频
| **Field** | **Description** |
| :-------------- | :----------------------------------------------------------- |
| 位31:0 **VDIV** | 阀触发分频值<br /> 写入数据后编码和分频控制器自动清除缓存并应用新的数值 <br /> 注意0表示不间断触发即PL端每个时钟周期均触发阀模块 |
| 位31:0 **VDIV** | 阀触发分频值<br /> 阀控制器重采样频率和编码器脉冲的分频值, 写入数据后编码和分频控制器自动清除缓存并应用新的数值 <br /> 注意0表示不间断触发即PL端每个时钟周期均触发阀模块 |
#### ENCODER相机触发分频寄存器 (ENCODER_CDIVR)
@ -194,6 +194,18 @@ FIFO的写宽度为384bit因此需12个32位寄存器**FIFO_DAT0**-**FIFO_DAT
| 位12 **FU** | 队列满标志 (Almost Full)<br /> 0: 队列中的有效数据小于FIFO数据深度<br /> 1: 队列中的有效数据达到FIFO数据深度 |
| 位11:0 **CNT** | 队列数据数量 (Data Count)<br />该值指示队列中的数据数量<br />注意一个数据为384位宽 |
#### FIFO空计数寄存器 (FIFO_ECR)
队列为空后被读的次数
偏移地址: 0x34<br/>复位值: 0x0000 0000
![image-20220613212701816](pl_reference_mannual.assets/fifo_ecr.png)
| **Field** | **Description** |
| :------------- | :----------------------------------------------------------- |
| 位31:0 **CNT** | 队列为空读次数 (Empty Count)<br />该值指示队列为空后被读的次数<br />注意改寄存器只读仅在FIFO复位时自动清零 |
#### FIFO控制寄存器 (FIFO_CR)
偏移地址: 0x38<br/>复位值: 0x0000 00xx
@ -210,4 +222,4 @@ FIFO的写宽度为384bit因此需12个32位寄存器**FIFO_DAT0**-**FIFO_DAT
FIFO寄存器可映射为32位可寻址寄存器如下表所述
<img src="pl_reference_mannual.assets/fifo_regs.png" alt="image-20220613220214064" />
<img src="pl_reference_mannual.assets/fifo_regs.png"/>

View File

@ -1 +1 @@
1.0
1.2

View File

@ -1 +1 @@
1.0
1.1

View File

@ -1 +1 @@
1.2
1.3

View File

@ -1,4 +1,4 @@
# 下位机和上位机通信协议 V1.2
# 下位机和上位机通信协议 V1.3
| 起始 | 长度高 | 长度低 | 类型高 | 类型低 | 数据字节1 | ... | 数据字节n | 校验低 | 校验高 | 结束 |
| ---- | ------ | ------ | ------ | ------ | --------- | ---- | --------- | ------ | ------ | ---- |
@ -18,13 +18,11 @@
- 设置相机触发周期对应的脉冲数sc**长度**10数据为十进制字符串'0''0''0''0''0''0''5''0'表示值50'5'在前,'0'在后
- 设置阀板动作对应的脉冲数sv**长度**10数据为十进制字符串'0''0''0''0''0''0''5''0'表示值50'5'在前,'0'在后
- 设置相机触发到阀板动作的延迟脉冲数sa**长度**10数据为十进制字符串'0''0''0''0''0''0''5''0'表示值50'5'在前,'0'在后
- 设置相机触发到阀板动作的延迟脉冲数sb**长度**10数据为十进制字符串'0''0''0''0''0''0''5''0'表示值50'5'在前,'0'在后
- 数据命令da **长度**为视需求而定,数据要有(**长度**-2个字节
- 数据命令db **长度**为视需求而定,数据要有(**长度**-2个字节
- 数据
数据就是阀数据,其实这是一个命令,也就是数据命令'da''db'分到数据这一节写是因为它的参数格式和其他命令不同下表为字节排序接收时从右往左也就是数据字节1先接收到然后是数据字节2最后是数据字节(m-1)。
数据就是阀数据,其实这是一个命令,也就是数据命令'da'分到数据这一节写是因为它的参数格式和其他命令不同下表为字节排序接收时从右往左也就是数据字节1先接收到然后是数据字节2最后是数据字节(m-1)。
阀1代表面向各块阀板最靠近右边的阀所以最左边的为阀n

View File

@ -1,4 +1,3 @@
#makefile for file_ioctl
CROSS_COMPILE ?= /home/miaow/software/gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf/bin/arm-none-linux-gnueabihf-
TARGET := target
BUILD_DIR := build

View File

@ -0,0 +1,52 @@
/**
* @file data_filter.c
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/08/06
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/08/06 <td>1.0 <td>Miaow <td>Write this module
* </table>
*/
#include <stdlib.h>
#include <string.h>
#include <data_filter.h>
void datafilter_init(datafilter_typedef *filter, int w_size)
{
filter->cache = (int *)malloc(sizeof(int) * (w_size + 1));
memset(filter->cache, 0, sizeof(int) * (w_size + 1));
filter->w_size = w_size;
filter->sum = 0;
filter->head = 0;
}
int datafilter_calculate(datafilter_typedef *filter, int z)
{
filter->cache[filter->head] = z;
filter->head = (filter->head + 1) % (filter->w_size + 1);
filter->sum = filter->sum + z - filter->cache[filter->head];
if (filter->w_size != 0)
return filter->sum / filter->w_size;
else
return -1;
}
void datafilter_deinit(datafilter_typedef *filter)
{
if (filter->cache != NULL)
{
free(filter->cache);
filter->cache = NULL;
}
filter->sum = 0;
filter->w_size = 0;
filter->head = 0;
}

View File

@ -0,0 +1,34 @@
/**
* @file data_filter.h
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/08/06
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/08/06 <td>1.0 <td>Miaow <td>Write this module
* </table>
*/
#ifndef __DATA_FILTER_H
#define __DATA_FILTER_H
typedef struct
{
int w_size;
int head;
int sum;
int *cache;
} datafilter_typedef;
void datafilter_init(datafilter_typedef *filter, int w_size);
int datafilter_calculate(datafilter_typedef *filter, int z);
void datafilter_deinit(datafilter_typedef *filter);
#endif

View File

@ -1,12 +1,21 @@
/**
* @file fifo_dev.c
* @brief Operate the hardware fifo with Linux application
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write_xxx() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @mainpage github.com/NanjingForestryUniversity
* @author miaow
* @email 3703781@qq.com
* @version 1.0
* @date 2022/06/09
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/09 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/07 <td>1.1 <td>miaow <td>Add ignore_row_num to fifo_dev_write_frame
* </table>
*/
#include <fifo_dev.h>
@ -14,13 +23,15 @@
#include <unistd.h>
#include <common.h>
#include <fcntl.h>
#include <host_computer.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <data_filter.h>
#define FIFO_CMD_FUNCTION_CLEAR 1
#define FIFO_CMD_FUNCTION_PADDING 2
#define FIFO_CMD_GET_EMPTYCOUNT 3
static int fifo_dev_fd = -1;
static char perror_buffer[128];
@ -37,15 +48,34 @@ int fifo_dev_init()
return 0;
}
/**
* @brief Get the count of read operation when the fifo is empty.
* @note The empty read count will be set to zero at fifo_dev_clear() only.
* @return >=0 - success, other - error
*/
int fifo_dev_get_emptycount()
{
int count;
int res = ioctl(fifo_dev_fd, _IOR('D', FIFO_CMD_GET_EMPTYCOUNT, 0), &count);
ON_ERROR_RET(res, "", "", -1);
return count;
}
/**
* @brief Set value to put of a frame.
* @param valve_data An array 32bytes * 600rows.
* @param valve_data An array HOST_COMPUTER_PICTURE_COLUMN_BYTES bytes * HOST_COMPUTER_PICTURE_ROW_NUM rows.
* @param ignore_row_num Remove the ignore_row_num rows at the beginning of the frame. range: [0, HOST_COMPUTER_PICTURE_BYTES)
* @return 0 - success, other - error
*/
int fifo_dev_write_frame(void *valve_data)
int fifo_dev_write_frame(void *valve_data, int ignore_row_num)
{
ssize_t size = write(fifo_dev_fd, valve_data, 32 * 600);
int res = -(size < 32 * 600);
ssize_t size;
char *valve_to_write = (char *)valve_data + ignore_row_num * HOST_COMPUTER_PICTURE_COLUMN_BYTES;
int size_to_write = HOST_COMPUTER_PICTURE_COLUMN_BYTES * (HOST_COMPUTER_PICTURE_ROW_NUM - ignore_row_num);
size = write(fifo_dev_fd, valve_to_write, size_to_write);
int res = -(size < size_to_write);
ON_ERROR_RET(res, "size=", "", -1);
return 0;
@ -71,7 +101,6 @@ int fifo_dev_write_row(void *valve_data)
int fifo_dev_clear()
{
int res = ioctl(fifo_dev_fd, _IOW('D', FIFO_CMD_FUNCTION_CLEAR, 0));
ON_ERROR_RET(res, "", "", -1);
return 0;
}
@ -84,7 +113,7 @@ int fifo_dev_clear()
*/
int fifo_dev_write_delay(uint32_t count)
{
int res = ioctl(fifo_dev_fd, _IOW('D', FIFO_CMD_FUNCTION_CLEAR, 0), count);
int res = ioctl(fifo_dev_fd, _IOW('D', FIFO_CMD_FUNCTION_PADDING, 0), count);
ON_ERROR_RET(res, "", "", -1);
return 0;
@ -93,7 +122,7 @@ int fifo_dev_write_delay(uint32_t count)
/**
* @brief Get the count of items in the hardware fifo.
* @note An item from hardware fifo is of 256 bits in size, aka. 32 bytes, 8 integers
* @return 0 - success, other - error
* @return >=0 - success, other - error
*/
int fifo_dev_get_count()
{

View File

@ -1,12 +1,21 @@
/**
* @file fifo_dev.h
* @brief Operate the hardware fifo with Linux application
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write_xxx() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @mainpage github.com/NanjingForestryUniversity
* @author miaow
* @email 3703781@qq.com
* @version 1.0
* @date 2022/06/09
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/09 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/07 <td>1.1 <td>miaow <td>Add ignore_row_num to fifo_dev_write_frame
* </table>
*/
#ifndef __FIFO_DEV_H
#define __FIFO_DEV_H
@ -16,7 +25,8 @@
#define FIFO_DEV_PATH "/dev/fifo"
int fifo_dev_init(void);
int fifo_dev_write_frame(void *valve_data);
int fifo_dev_get_emptycount(void);
int fifo_dev_write_frame(void *valve_data, int ignore_row_num);
int fifo_dev_clear(void);
int fifo_dev_write_delay(uint32_t count);
int fifo_dev_write_row(void *valve_data);

View File

@ -2,8 +2,8 @@
* @file host_computer.c
* @brief Commnunicate with host computer. Protocal is described in hostcomputer通信协议.md
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/01/16
* @version 1.1
* @date 2022/08/06
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
@ -12,6 +12,7 @@
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/01/16 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/06 <td>1.1 <td>miaow <td>Add fifob
* </table>
*/
#include <host_computer.h>
@ -27,9 +28,7 @@
#include <fcntl.h>
#include <fifo_dev.h>
#include <encoder_dev.h>
#define HOST_COMPUTER_PICTURE_COLUMN_BYTES (HOST_COMPUTER_PICTURE_COLUMN_NUM / 8)
#define HOST_COMPUTER_RAW_DATA_BYTES (HOST_COMPUTER_PICTURE_COLUMN_BYTES * HOST_COMPUTER_PICTURE_ROW_NUM)
#include <data_filter.h>
static char perror_buffer[128];
/**
@ -63,6 +62,12 @@ int hostcomputer_init(queue_uint64_msg_t *cmd_q)
return 0;
}
static void send_error(int fd)
{
write(fd, "error", 5);
printf("\r\nerror sent\r\n");
}
/**
* @brief Receive `size` bytes from a socket. If no more bytes are available at the socket, this function return -1 when timeout reaches.
* @param fd The socket fd
@ -111,13 +116,18 @@ static int is_connected(int sock_fd)
*/
void *loop_thread_func(void *param)
{
printf("loop thread in %s start\r\n", __FILE__);
int need_exit = 0;
// printf("loop thread in %s start\r\n", __FILE__);
int need_exit = 0, frame_count = 0, error_sent = 0;
int std_count, empty_packets_num = 0;
int empty_count_initial = 0;
int empty_count_processed = 0;
char pre;
uint16_t n_bytes;
char type[2];
char data[HOST_COMPUTER_RAW_DATA_BYTES + 1];
char data[HOST_COMPUTER_PICTURE_BYTES + 1];
char check[2];
datafilter_typedef datafilter;
while (!need_exit)
{
pthread_mutex_lock(&_global_structure.loop_thread_mutex);
@ -169,10 +179,10 @@ void *loop_thread_func(void *param)
continue;
}
n_bytes = ntohs(n_bytes);
if (n_bytes != HOST_COMPUTER_RAW_DATA_BYTES + 2 && n_bytes > 10)
if (n_bytes != HOST_COMPUTER_PICTURE_BYTES + 2 && n_bytes > 10)
{
// close(_global_structure.socket_fd);
printf("n_bytes> 10 and n_bytes!=HOST_COMPUTER_RAW_DATA_BYTES + 2\r\n");
printf("n_bytes> 10 and n_bytes!=HOST_COMPUTER_PICTURE_BYTES + 2\r\n");
continue;
}
if (recvn(_global_structure.socket_fd, (char *)type, 2) != 2)
@ -212,17 +222,94 @@ void *loop_thread_func(void *param)
// commands are reformed as an uint64_t, 0x--------xxxxxxxx, where `-` refers its paramter and `x` is HOSTCOMPUTER_CMD
if (type[0] == 'd' && type[1] == 'a')
{
// printf("%dbytes of data put to data queue\r\n", (int)n_bytes - 2);
if (n_bytes - 2 != HOST_COMPUTER_RAW_DATA_BYTES)
/*
int current_count = fifo_dev_get_count();
int current_count_filtered = datafilter_calculate(&datafilter_a, current_count);
if (++frame_count_a > HOST_COMPUTER_BEGINNING_PICTURES_IGNORE_NUM)
{
printf("n_bytes-2!=%d\r\n", HOST_COMPUTER_RAW_DATA_BYTES);
fifo_dev_write_frame(data, 0);
}
int added_count = fifo_dev_get_count();
printf("before %d->after %d, diff %d, filter %d\r\n", current_count, added_count, added_count - current_count, current_count_filtered);
*/
//=================================================
int current_count, current_count_filtered, diff_count, empty_count_to_process;
if (n_bytes - 2 != HOST_COMPUTER_PICTURE_BYTES)
{
printf("n_bytes-2!=%d\r\n", HOST_COMPUTER_PICTURE_BYTES);
continue;
}
fifo_dev_write_frame(data);
// get the item counts and its slide average value
current_count = fifo_dev_get_count();
current_count_filtered = datafilter_calculate(&datafilter, current_count);
frame_count++;
if (frame_count == HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM + 1)
{
empty_count_initial = fifo_dev_get_emptycount();
}
else if (frame_count == 100) // record the normal item counts in fifo
{
std_count = current_count_filtered;
}
if (frame_count > HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM)
{
// do nothing at first two frames, because that the first frame is set to zero and was concatenated to the delay frame before
// in case of late arrival of the first two frames.
empty_count_to_process = fifo_dev_get_emptycount() - empty_count_initial - empty_count_processed;
if (empty_count_to_process >= HOST_COMPUTER_PICTURE_ROW_NUM)
{
empty_count_processed += HOST_COMPUTER_PICTURE_ROW_NUM;
}
else
{
fifo_dev_write_frame(data, empty_count_to_process);
empty_count_processed += empty_count_to_process;
}
}
if (current_count == 0)
empty_packets_num++;
else
empty_packets_num = 0;
// print fifo status
printf("a ||| %d | cnt %d | avgcnt %d | stdcnt %d",
frame_count, current_count, current_count_filtered, std_count);
fflush(stdout);
// if (empty_count_to_process)
printf(" ||| initemp %d | toprc %d | prcd %d\r\n", empty_count_initial,
empty_count_to_process, empty_count_processed);
// else
// printf("\r\n");
// if the item counts changes a lot compared with normal counts,
// meaning something goes wrong, a message will send to the hostcomputer
diff_count = current_count_filtered - std_count;
int diff_cond = diff_count > 250 || diff_count < -250;
int frame_count_cond = frame_count > 100;
int empty_packets_cond = empty_packets_num >= 5;
if (((frame_count_cond && diff_cond) || empty_packets_cond) && !error_sent)
{
error_sent = 1;
printf("\r\na ||| avgcnt %d | %d larger", current_count_filtered, diff_count);
fflush(stdout);
send_error(_global_structure.socket_fd);
}
}
else if (type[0] == 's' && type[1] == 't')
{
// printf("Start put to cmd queue, param:%d\r\n", (int)atoll(data));
frame_count = 0;
error_sent = 0;
empty_packets_num = 0;
std_count = 0;
datafilter_deinit(&datafilter);
datafilter_init(&datafilter, 20);
empty_count_processed = 0;
empty_count_initial = 0;
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_START);
}
else if (type[0] == 's' && type[1] == 'p')
@ -255,15 +342,11 @@ void *loop_thread_func(void *param)
// printf("Set valve pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETVALVETRIGPULSECOUNT);
}
else if (type[0] == 's' && type[1] == 'd')
else if ((type[0] == 's' && type[1] == 'd'))
{
// printf("Set camera to valve pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATOVALVEPULSECOUNT);
}
else
{
printf("Unknown command received");
}
}
printf("loop thread in %s exit\r\n", __FILE__);
return NULL;

View File

@ -2,8 +2,8 @@
* @file host_computer.h
* @brief Commnunicate with host computer. Protocal is described in hostcomputer通信协议.md
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/01/16
* @version 1.1
* @date 2022/08/6
*
* @copyright Copyright (c) 2022 miaow
*
@ -11,6 +11,7 @@
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/01/16 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/06 <td>1.1 <td>miaow <td>Add fifob
* </table>
*/
#ifndef __HOST_COMPUTER_H
@ -22,11 +23,14 @@
#define HOST_COMPUTER_IP "192.168.10.8"
#define HOST_COMPUTER_PORT 13452
#define HOST_COMPUTER_PICTURE_ROW_NUM 600
#define HOST_COMPUTER_PICTURE_ROW_NUM 1024
#define HOST_COMPUTER_PICTURE_COLUMN_NUM 256
#define HOST_COMPUTER_PICTURE_COLUMN_BYTES (HOST_COMPUTER_PICTURE_COLUMN_NUM / 8)
#define HOST_COMPUTER_PICTURE_BYTES (HOST_COMPUTER_PICTURE_COLUMN_BYTES * HOST_COMPUTER_PICTURE_ROW_NUM)
#define HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM 1
/**
* @brief The commonds, ref hostcomputer通信协议 v1.1.md
* @brief The commonds, ref
*/
enum HOSTCOMPUTER_CMD
{
@ -38,7 +42,6 @@ enum HOSTCOMPUTER_CMD
HOSTCOMPUTER_CMD_SETVALVETRIGPULSECOUNT = 7,
HOSTCOMPUTER_CMD_SETCAMERATOVALVEPULSECOUNT = 8,
HOSTCOMPUTER_CMD_STOP_TEST = 9
};
int hostcomputer_init(queue_uint64_msg_t *cmd_q);

View File

@ -25,9 +25,12 @@
#include <stdio.h>
#include <unistd.h>
#define SET_VALVE_ONLY_N_ON(u32_buf, n) bzero(u32_buf, sizeof(u32_buf));SET_VALVE_N_ON(u32_buf, n)
#define SET_VALVE_ONLY_N_ON(u32_buf, n) \
bzero(u32_buf, sizeof(u32_buf)); \
SET_VALVE_N_ON(u32_buf, n)
#define SET_VALVE_N_ON(u32_buf, n) u32_buf[n / 32] = 1 << (n % 32)
/**
* @brief Value of state machine
*/
@ -42,7 +45,7 @@ queue_uint64_msg_t cmd_queue = {0};
static status_enum_t status = SLEEPING;
static int camera_trigger_pulse_count = 1200;
static int valve_trigger_pulse_count = 120;
static int camera_to_valve_pulse_count = 5000;
static int camera_to_valve_pulse_count = 500;
void process_cmd(uint64_t *cmd);
@ -59,8 +62,40 @@ int main(int argc, char *argv[])
// Initialize drivers and clear all caches
encoder_dev_init();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(2, 2);
encoder_dev_set_divide(2, 8);
fifo_dev_init();
//==test encoder================================================================
// fifo_dev_init();
// encoder_dev_set_trigmod(ENCODER_TRIG_MODE_EXTERNEL);
// encoder_dev_set_divide(4, 8);
// int a = 1;
// while (a)
// {
// printf("input a\r\n");
// scanf("%d", &a);
// printf("a=%d\r\n\r\n\r\n", a);
// }
// encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
// encoder_dev_deinit();
// queue_uint64_deinit(&cmd_queue);
// return 0;
//==test fifo================================================================
// char data[HOST_COMPUTER_PICTURE_COLUMN_BYTES * HOST_COMPUTER_PICTURE_ROW_NUM + 1];
// fifo_dev_init();
// fifo_dev_write_frame(data);
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_write_frame(data);
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_clear();
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_deinit();
// encoder_dev_deinit();
// return 0;
//==================================================================
fifo_dev_clear();
hostcomputer_init(&cmd_queue);
printf("\r\n>>>>>\r\nstatus==SLEEPING\r\n<<<<<\r\n\r\n");
uint64_t cmd;
@ -70,14 +105,14 @@ int main(int argc, char *argv[])
{
if (queue_uint64_get(&cmd_queue, &cmd) == 0)
process_cmd(&cmd);
usleep(100000);
usleep(1000);
}
// Never run here
hostcomputer_deinit();
fifo_dev_clear();
encoder_dev_set_divide(2, 2);
encoder_dev_virtual_trig(10);
encoder_dev_set_divide(2, 8);
encoder_dev_virtual_trig(20);
fifo_dev_deinit();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
@ -104,11 +139,14 @@ void process_cmd(uint64_t *cmd)
// Before running, clear the hardware fifo and hardware encoder. Then, the two dividers and delay value should be set.
// Also, the hareware encoder is expected to receiving pluse of encoder: the EXTERNAL mode
fifo_dev_clear();
fifo_dev_write_delay(camera_to_valve_pulse_count);
encoder_dev_flush();
encoder_dev_set_divide(valve_trigger_pulse_count, camera_trigger_pulse_count);
fifo_dev_write_delay(camera_to_valve_pulse_count + HOST_COMPUTER_PICTURE_ROW_NUM * HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM);
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_EXTERNEL);
printf("\r\n>>>>>\r\nstatus==RUNNING\r\ncamera_trigger_pulse_count=%d\r\nvalve_trigger_pulse_count=%d\r\ncamera_to_valve_pulse_count=%d\r\n<<<<<\r\n\r\n", camera_trigger_pulse_count, valve_trigger_pulse_count, camera_to_valve_pulse_count);
printf("\r\n>>>>>\r\nstatus==RUNNING\r\ncamera_trigger_pulse_count=%d\r\nvalve_trigger_pulse_count=%d\r\n"
"camera_to_valve_pulse_count=%d\r\n<<<<<\r\n\r\n", camera_trigger_pulse_count,
valve_trigger_pulse_count, camera_to_valve_pulse_count + HOST_COMPUTER_PICTURE_ROW_NUM * HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM);
status = RUNNING;
}
else if (tmp_cmd == HOSTCOMPUTER_CMD_TEST)
@ -120,16 +158,16 @@ void process_cmd(uint64_t *cmd)
fifo_dev_clear();
encoder_dev_flush();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(2, 2);
encoder_dev_set_divide(2, 8); // fifo out every 8/4=2 cycle, valveboard operate every 2 cycle
// A parameter below 256 represents a single shot, the value of parameter indicates the valve to triggle.
if (tmp_data < 256)
{
SET_VALVE_ONLY_N_ON(row_data, tmp_data);
fifo_dev_write_row(row_data);
// delay for 100 ms and turn off the valve
// delay for 15000 us and turn off the valve
encoder_dev_virtual_trig(2);
usleep(100000);
usleep(15000);
encoder_dev_virtual_trig(2);
}
// 257 represents triggle valve from NO.1 to 256 sequenctially. This loop blocks for 25.7s.
@ -139,11 +177,17 @@ void process_cmd(uint64_t *cmd)
{
SET_VALVE_ONLY_N_ON(row_data, i);
fifo_dev_write_row(row_data);
bzero(&row_data, sizeof(row_data));
fifo_dev_write_row(row_data);
// printf("%d,%d\r\n", fifo_dev_get_count(), fifob_dev_get_count());
}
for (int i = 0; i < 257; i++)
{
encoder_dev_virtual_trig(2);
usleep(100000);
usleep(15000);
encoder_dev_virtual_trig(2);
usleep(100000 - 15000);
// printf("%d,%d\r\n", fifo_dev_get_count(), fifob_dev_get_count());
}
}
}
@ -170,8 +214,8 @@ void process_cmd(uint64_t *cmd)
// Hardware encoder is flushed for a fresh start.
fifo_dev_clear();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(2, 2);
encoder_dev_virtual_trig(10);
encoder_dev_set_divide(4, 4);
encoder_dev_virtual_trig(20);
encoder_dev_flush();
status = SLEEPING;
printf("\r\n>>>>>\r\nstatus==SLEEPING\r\n<<<<<\r\n\r\n");

0
source/linux_app/main.h Normal file
View File

View File

@ -113,9 +113,12 @@ int queue_uint64_init(queue_uint64_msg_t *q, int max_count)
* @return 0 - success
*/
int queue_uint64_deinit(queue_uint64_msg_t *q)
{
if (q->buffer != NULL)
{
free(q->buffer);
q->buffer = NULL;
}
pthread_mutex_destroy(&q->_mux);
// pthread_cond_destroy(&q->_cond_get);
// pthread_cond_destroy(&q->_cond_put);

View File

@ -1 +1 @@
1.0
1.2

View File

@ -18,7 +18,6 @@
#define ENCODER_CMD_INPUT_MODE_EXTERNEL 100
#define ENCODER_CMD_INPUT_MODE_INTERNEL 101
/*
*
*/
@ -28,11 +27,15 @@
#define ENCODER_REG_2_OFFSET 0x00000008
#define ENCODER_REG_3_OFFSET 0x0000000C
#define ENCODER_CR_VTS_MASK ((u32)(1 << 2)) // 内部触发信号 (Virtual Triggle Signal) MOD位置1时由上位机软件写入将该位信号作为触发信号
#define ENCODER_CR_MOD_MASK ((u32)(1 << 1)) // 模式选择 (Mode) 0: 外部触发模式,外部触发编码器转动, 1: 内部触发模式,上位机软件模拟触发信号
#define ENCODER_CR_CLR_MASK ((u32)(1 << 0)) // 清除缓存 (Clear) 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *encoder_reg_0_addr;
static void __iomem *encoder_reg_1_addr;
static void __iomem *encoder_reg_2_addr;
static void __iomem *encoder_reg_3_addr;
static void __iomem *encoder_cr_addr;
static void __iomem *encoder_vdivr_addr;
static void __iomem *encoder_cdivr_addr;
static void __iomem *encoder_reg3_addr;
struct encoder_dev
{
@ -92,18 +95,23 @@ static ssize_t encoder_write(struct file *filp, const char __user *buf, size_t c
printk(KERN_ERR "kernel write failed!\r\n");
return -EFAULT;
}
if (!(kern_buf.valve_divide_value || kern_buf.camera_divide_value))
return 0;
// 最小分频值为4
if (kern_buf.valve_divide_value < 2 || kern_buf.camera_divide_value < 4)
{
return -EFAULT;
}
data = readl(encoder_reg_0_addr);
writel(data & ~(u32)(1 << 0), encoder_reg_0_addr);
// 写入0后清除ENCODER内部计数器缓存清除
data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr);
if (kern_buf.valve_divide_value != 0)
writel(kern_buf.valve_divide_value, encoder_reg_1_addr);
writel(kern_buf.valve_divide_value, encoder_vdivr_addr);
if (kern_buf.camera_divide_value != 0)
writel(kern_buf.camera_divide_value, encoder_reg_2_addr);
writel(kern_buf.camera_divide_value, encoder_cdivr_addr);
writel(data | (u32)(1 << 0), encoder_reg_0_addr);
// 写入1退出清除状态使得ENCODER内部计数器能正常工作内部计数器在正常工作前已经被清零
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr);
return cnt;
}
@ -127,33 +135,38 @@ static long encoder_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
return -EINVAL;
}
cmd_parsed = _IOC_NR(cmd);
data = readl(encoder_reg_0_addr);
data = readl(encoder_cr_addr);
if (cmd_parsed == ENCODER_CMD_FUNCTION_CLEAR)
{
writel(data & ~(u32)(1 << 0), encoder_reg_0_addr);
writel(data | (u32)(1 << 0), encoder_reg_0_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr); // 写入0后清除ENCODER内部计数器缓存清除
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr); // 写入1退出清除状态使得ENCODER内部计数器能正常工作内部计数器在正常工作前已经被清零
}
else if (cmd_parsed == ENCODER_CMD_INPUT_MODE_EXTERNEL)
{
writel(data & ~(u32)(1 << 1), encoder_reg_0_addr);
// 设为外部触发模式
writel(data & ~ENCODER_CR_MOD_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_INPUT_MODE_INTERNEL)
{
writel(data | (u32)(1 << 1), encoder_reg_0_addr);
// 设为内部触发模式
writel(data | (u32)(1 << 1), encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_FUNCTION_VIRT_INPUT)
{
int i;
// 1. ENCODER_CMD_INPUT_MODE_INTERNEL
writel(data | (u32)(1 << 1), encoder_reg_0_addr);
// 2. Generate pluses
// 虚拟触发tmp为周期数
// 1. 设为内部触发模式
writel(data | (u32)(1 << 1), encoder_cr_addr);
// 2. 产生虚拟的高低电平
for (i = 0; i < tmp; i++)
{
writel(data & ~(u32)(1 << 2), encoder_reg_0_addr);
writel(data | (u32)(1 << 2), encoder_reg_0_addr);
writel(data & ~ENCODER_CR_VTS_MASK, encoder_cr_addr);
writel(data | ENCODER_CR_VTS_MASK, encoder_cr_addr);
}
// 3. Recover the original configuration
writel(data, encoder_reg_0_addr);
// 3. 恢复为原来的状态和模式
writel(data, encoder_cr_addr);
}
return 0;
@ -173,10 +186,10 @@ static int __init encoder_init(void)
int ret;
u32 data;
/* 寄存器地址映射 */
encoder_reg_0_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_0_OFFSET, 4);
encoder_reg_1_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_1_OFFSET, 4);
encoder_reg_2_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_2_OFFSET, 4);
encoder_reg_3_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_3_OFFSET, 4);
encoder_cr_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_0_OFFSET, 4);
encoder_vdivr_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_1_OFFSET, 4);
encoder_cdivr_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_2_OFFSET, 4);
encoder_reg3_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_3_OFFSET, 4);
/* 注册字符设备驱动 */
//(1)创建设备号
@ -222,11 +235,11 @@ static int __init encoder_init(void)
}
//默认分频系数1000
data = readl(encoder_reg_0_addr);
writel(data & ~(u32)(1 << 0), encoder_reg_0_addr);
writel(1000, encoder_reg_1_addr);
writel(1000, encoder_reg_2_addr);
writel(data | (u32)(1 << 0), encoder_reg_0_addr);
data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除硬件计数器缓存
writel(1000, encoder_vdivr_addr); // 设置阀触发分频
writel(1000, encoder_cdivr_addr); // 设置相机触发分频
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除完毕
return 0;
@ -240,10 +253,10 @@ FAIL_ADD_CDEV:
unregister_chrdev_region(encoder.devid, ENCODER_CNT);
FAIL_REGISTER_CHR_DEV:
iounmap(encoder_reg_0_addr);
iounmap(encoder_reg_1_addr);
iounmap(encoder_reg_2_addr);
iounmap(encoder_reg_3_addr);
iounmap(encoder_cr_addr);
iounmap(encoder_vdivr_addr);
iounmap(encoder_cdivr_addr);
iounmap(encoder_reg3_addr);
return ret;
}
@ -263,10 +276,10 @@ static void __exit encoder_exit(void)
unregister_chrdev_region(encoder.devid, ENCODER_CNT);
//(5)取消内存映射
iounmap(encoder_reg_0_addr);
iounmap(encoder_reg_1_addr);
iounmap(encoder_reg_2_addr);
iounmap(encoder_reg_3_addr);
iounmap(encoder_cr_addr);
iounmap(encoder_vdivr_addr);
iounmap(encoder_cdivr_addr);
iounmap(encoder_reg3_addr);
}
/* 驱动模块入口和出口函数注册 */

View File

@ -14,6 +14,7 @@
#define FIFO_NAME "fifo" /* 名字 */
#define FIFO_CMD_FUNCTION_CLEAR 1
#define FIFO_CMD_FUNCTION_PADDING 2
#define FIFO_CMD_GET_EMPTYCOUNT 3
/*
*
@ -35,22 +36,34 @@
#define FIFO_REG_13_OFFSET 0x00000034
#define FIFO_REG_14_OFFSET 0x00000038
#define FIFO_CR_CLR_MASK ((u32)(1 << 1)) // 清空队列 (Clear) 对该位写入1队列将清空同时队列输出为全0。注意不要写入除1以外的任何值。
#define FIFO_CR_WS_MASK ((u32)(1 << 0)) // 写入同步 (Write Synchronization) 对该位写入1FIFO_DATx的数据按字节小端序进入队列。 注意不要写入除1以外的任何值。
#define FIFO_SR_VLD_MASK ((u32)(1 << 16)) // 数据输出有效标志 (Valid) 0: 当前无有效输出,输出保持上一状态 1: 当前队列正在输出有效数据
#define FIFO_SR_AMEM_MASK ((u32)(1 << 15)) // 队列将空标志 (Almost Empty) 0: 队列没有被读空 1: 队列在一个读时钟周期后会被读空
#define FIFO_SR_EM_MASK ((u32)(1 << 14)) // 队列空标志 (Empty) 0: 队列中存在有效数据,没有被读空 1: 队列中已经没有有效数据
#define FIFO_SR_AMFU_MASK ((u32)(1 << 13)) // 队列将满标志 (Almost Full) 0: 队列没有被写满 1: 队列在一个写时钟周期后会被写满
#define FIFO_SR_FU_MASK ((u32)(1 << 12)) // 队列满标志 (Almost Full) 0: 队列中的有效数据小于FIFO数据深度 1: 队列中的有效数据达到FIFO数据深度
#define FIFO_SR_CNT_MASK ((u32)(0xFFF << 0)) // 队列数据数量 (Data Count) 该值指示队列中的数据数量 注意一个数据为384位宽
#define FIFO_ECR_CNT_MASK ((u32)0xFFFFFFFF) // 队列空读取累计次数
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *fifo_reg_0_addr;
static void __iomem *fifo_reg_1_addr;
static void __iomem *fifo_reg_2_addr;
static void __iomem *fifo_reg_3_addr;
static void __iomem *fifo_reg_4_addr;
static void __iomem *fifo_reg_5_addr;
static void __iomem *fifo_reg_6_addr;
static void __iomem *fifo_reg_7_addr;
static void __iomem *fifo_reg_8_addr;
static void __iomem *fifo_reg_9_addr;
static void __iomem *fifo_reg_10_addr;
static void __iomem *fifo_reg_11_addr;
static void __iomem *fifo_reg_12_addr;
static void __iomem *fifo_reg_13_addr;
static void __iomem *fifo_reg_14_addr;
static void __iomem *fifo_dat0_addr;
static void __iomem *fifo_dat1_addr;
static void __iomem *fifo_dat2_addr;
static void __iomem *fifo_dat3_addr;
static void __iomem *fifo_dat4_addr;
static void __iomem *fifo_dat5_addr;
static void __iomem *fifo_dat6_addr;
static void __iomem *fifo_dat7_addr;
static void __iomem *fifo_dat8_addr;
static void __iomem *fifo_dat9_addr;
static void __iomem *fifo_dat10_addr;
static void __iomem *fifo_dat11_addr;
static void __iomem *fifo_sr_addr;
static void __iomem *fifo_ecr_addr;
static void __iomem *fifo_cr_addr;
/* fifo设备结构体 */
struct fifo_dev
@ -87,7 +100,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
*/
static ssize_t fifo_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
u32 data = readl(fifo_reg_12_addr) & 0xFFF;
u32 data = readl(fifo_sr_addr) & FIFO_SR_CNT_MASK;
copy_to_user(buf, &data, 4);
return cnt;
}
@ -109,7 +122,7 @@ static ssize_t fifo_write(struct file *filp, const char __user *buf, size_t cnt,
if (cnt % 32 != 0 || cnt > sizeof(kern_buf_u32))
{
printk(KERN_ERR "cnt error, cnt=%d\r\n", cnt);
printk(KERN_ERR "cnt error, cnt=%d, sizeof=%d\r\n", cnt, (u32)sizeof(kern_buf_u32));
return -1;
}
@ -122,19 +135,19 @@ static ssize_t fifo_write(struct file *filp, const char __user *buf, size_t cnt,
for (i = 0; i < (cnt / sizeof(u32)); i += 8)
{
writel(kern_buf_u32[i], fifo_reg_0_addr);
writel(kern_buf_u32[i + 1], fifo_reg_1_addr);
writel(kern_buf_u32[i + 2], fifo_reg_2_addr);
writel(kern_buf_u32[i + 3], fifo_reg_3_addr);
writel(kern_buf_u32[i + 4], fifo_reg_4_addr);
writel(kern_buf_u32[i + 5], fifo_reg_5_addr);
writel(kern_buf_u32[i + 6], fifo_reg_6_addr);
writel(kern_buf_u32[i + 7], fifo_reg_7_addr);
writel(0, fifo_reg_8_addr);
writel(0, fifo_reg_9_addr);
writel(0, fifo_reg_10_addr);
writel(0, fifo_reg_11_addr);
writel(1, fifo_reg_14_addr);
writel(kern_buf_u32[i], fifo_dat0_addr);
writel(kern_buf_u32[i + 1], fifo_dat1_addr);
writel(kern_buf_u32[i + 2], fifo_dat2_addr);
writel(kern_buf_u32[i + 3], fifo_dat3_addr);
writel(kern_buf_u32[i + 4], fifo_dat4_addr);
writel(kern_buf_u32[i + 5], fifo_dat5_addr);
writel(kern_buf_u32[i + 6], fifo_dat6_addr);
writel(kern_buf_u32[i + 7], fifo_dat7_addr);
writel(0, fifo_dat8_addr);
writel(0, fifo_dat9_addr);
writel(0, fifo_dat10_addr);
writel(0, fifo_dat11_addr);
writel(FIFO_CR_WS_MASK, fifo_cr_addr);
}
return cnt;
@ -152,33 +165,45 @@ static int fifo_release(struct inode *inode, struct file *filp)
static long fifo_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
{
if (_IOC_TYPE(cmd) != 'D' || _IOC_DIR(cmd) != _IOC_WRITE)
if (_IOC_TYPE(cmd) != 'D')
{
printk(KERN_ERR "IOC_TYPE or IOC_WRITE error: IOC_TYPE=%c, IOC_WRITE=%d\r\n", _IOC_TYPE(cmd), _IOC_DIR(cmd));
return -EINVAL;
}
if (_IOC_NR(cmd) == FIFO_CMD_FUNCTION_CLEAR)
if (_IOC_NR(cmd) == FIFO_CMD_GET_EMPTYCOUNT)
{
writel(((u32)1 << 1), fifo_reg_14_addr);
u32 empty_count = readl(fifo_ecr_addr) & FIFO_ECR_CNT_MASK;
printk("%d\r\n", empty_count);
if (copy_to_user((u32 *)tmp, &empty_count, 4) < 0)
{
printk(KERN_ERR "get empty count error\r\n");
return -EINVAL;
}
}
else if (_IOC_NR(cmd) == FIFO_CMD_FUNCTION_CLEAR)
{
// 清空队列
writel(FIFO_CR_CLR_MASK, fifo_cr_addr);
}
else if (_IOC_NR(cmd) == FIFO_CMD_FUNCTION_PADDING)
{
// 对队列中添加tmp个数的0元素
int i;
for (i = 0; i < tmp; i ++)
{
writel((u32)0, fifo_reg_0_addr);
writel((u32)0, fifo_reg_1_addr);
writel((u32)0, fifo_reg_2_addr);
writel((u32)0, fifo_reg_3_addr);
writel((u32)0, fifo_reg_4_addr);
writel((u32)0, fifo_reg_5_addr);
writel((u32)0, fifo_reg_6_addr);
writel((u32)0, fifo_reg_7_addr);
writel((u32)0, fifo_reg_8_addr);
writel((u32)0, fifo_reg_9_addr);
writel((u32)0, fifo_reg_10_addr);
writel((u32)0, fifo_reg_11_addr);
writel((u32)1, fifo_reg_14_addr);
writel((u32)0, fifo_dat0_addr);
writel((u32)0, fifo_dat1_addr);
writel((u32)0, fifo_dat2_addr);
writel((u32)0, fifo_dat3_addr);
writel((u32)0, fifo_dat4_addr);
writel((u32)0, fifo_dat5_addr);
writel((u32)0, fifo_dat6_addr);
writel((u32)0, fifo_dat7_addr);
writel((u32)0, fifo_dat8_addr);
writel((u32)0, fifo_dat9_addr);
writel((u32)0, fifo_dat10_addr);
writel((u32)0, fifo_dat11_addr);
writel(FIFO_CR_WS_MASK, fifo_cr_addr);
}
}
return 0;
@ -198,21 +223,21 @@ static int __init fifo_init(void)
{
int ret;
/* 寄存器地址映射 */
fifo_reg_0_addr = ioremap(FIFO_REG_BASE + FIFO_REG_0_OFFSET, 4);
fifo_reg_1_addr = ioremap(FIFO_REG_BASE + FIFO_REG_1_OFFSET, 4);
fifo_reg_2_addr = ioremap(FIFO_REG_BASE + FIFO_REG_2_OFFSET, 4);
fifo_reg_3_addr = ioremap(FIFO_REG_BASE + FIFO_REG_3_OFFSET, 4);
fifo_reg_4_addr = ioremap(FIFO_REG_BASE + FIFO_REG_4_OFFSET, 4);
fifo_reg_5_addr = ioremap(FIFO_REG_BASE + FIFO_REG_5_OFFSET, 4);
fifo_reg_6_addr = ioremap(FIFO_REG_BASE + FIFO_REG_6_OFFSET, 4);
fifo_reg_7_addr = ioremap(FIFO_REG_BASE + FIFO_REG_7_OFFSET, 4);
fifo_reg_8_addr = ioremap(FIFO_REG_BASE + FIFO_REG_8_OFFSET, 4);
fifo_reg_9_addr = ioremap(FIFO_REG_BASE + FIFO_REG_9_OFFSET, 4);
fifo_reg_10_addr = ioremap(FIFO_REG_BASE + FIFO_REG_10_OFFSET, 4);
fifo_reg_11_addr = ioremap(FIFO_REG_BASE + FIFO_REG_11_OFFSET, 4);
fifo_reg_12_addr = ioremap(FIFO_REG_BASE + FIFO_REG_12_OFFSET, 4);
fifo_reg_13_addr = ioremap(FIFO_REG_BASE + FIFO_REG_13_OFFSET, 4);
fifo_reg_14_addr = ioremap(FIFO_REG_BASE + FIFO_REG_14_OFFSET, 4);
fifo_dat0_addr = ioremap(FIFO_REG_BASE + FIFO_REG_0_OFFSET, 4);
fifo_dat1_addr = ioremap(FIFO_REG_BASE + FIFO_REG_1_OFFSET, 4);
fifo_dat2_addr = ioremap(FIFO_REG_BASE + FIFO_REG_2_OFFSET, 4);
fifo_dat3_addr = ioremap(FIFO_REG_BASE + FIFO_REG_3_OFFSET, 4);
fifo_dat4_addr = ioremap(FIFO_REG_BASE + FIFO_REG_4_OFFSET, 4);
fifo_dat5_addr = ioremap(FIFO_REG_BASE + FIFO_REG_5_OFFSET, 4);
fifo_dat6_addr = ioremap(FIFO_REG_BASE + FIFO_REG_6_OFFSET, 4);
fifo_dat7_addr = ioremap(FIFO_REG_BASE + FIFO_REG_7_OFFSET, 4);
fifo_dat8_addr = ioremap(FIFO_REG_BASE + FIFO_REG_8_OFFSET, 4);
fifo_dat9_addr = ioremap(FIFO_REG_BASE + FIFO_REG_9_OFFSET, 4);
fifo_dat10_addr = ioremap(FIFO_REG_BASE + FIFO_REG_10_OFFSET, 4);
fifo_dat11_addr = ioremap(FIFO_REG_BASE + FIFO_REG_11_OFFSET, 4);
fifo_sr_addr = ioremap(FIFO_REG_BASE + FIFO_REG_12_OFFSET, 4);
fifo_ecr_addr = ioremap(FIFO_REG_BASE + FIFO_REG_13_OFFSET, 4);
fifo_cr_addr = ioremap(FIFO_REG_BASE + FIFO_REG_14_OFFSET, 4);
/* 注册字符设备驱动 */
//(1)创建设备号
@ -269,21 +294,21 @@ FAIL_ADD_CDEV:
unregister_chrdev_region(fifo.devid, FIFO_CNT);
FAIL_REGISTER_CHR_DEV:
iounmap(fifo_reg_0_addr);
iounmap(fifo_reg_1_addr);
iounmap(fifo_reg_2_addr);
iounmap(fifo_reg_3_addr);
iounmap(fifo_reg_4_addr);
iounmap(fifo_reg_5_addr);
iounmap(fifo_reg_6_addr);
iounmap(fifo_reg_7_addr);
iounmap(fifo_reg_8_addr);
iounmap(fifo_reg_9_addr);
iounmap(fifo_reg_10_addr);
iounmap(fifo_reg_11_addr);
iounmap(fifo_reg_12_addr);
iounmap(fifo_reg_13_addr);
iounmap(fifo_reg_14_addr);
iounmap(fifo_dat0_addr);
iounmap(fifo_dat1_addr);
iounmap(fifo_dat2_addr);
iounmap(fifo_dat3_addr);
iounmap(fifo_dat4_addr);
iounmap(fifo_dat5_addr);
iounmap(fifo_dat6_addr);
iounmap(fifo_dat7_addr);
iounmap(fifo_dat8_addr);
iounmap(fifo_dat9_addr);
iounmap(fifo_dat10_addr);
iounmap(fifo_dat11_addr);
iounmap(fifo_sr_addr);
iounmap(fifo_ecr_addr);
iounmap(fifo_cr_addr);
return ret;
}
@ -304,21 +329,21 @@ static void __exit fifo_exit(void)
unregister_chrdev_region(fifo.devid, FIFO_CNT);
//(5)取消内存映射
iounmap(fifo_reg_0_addr);
iounmap(fifo_reg_1_addr);
iounmap(fifo_reg_2_addr);
iounmap(fifo_reg_3_addr);
iounmap(fifo_reg_4_addr);
iounmap(fifo_reg_5_addr);
iounmap(fifo_reg_6_addr);
iounmap(fifo_reg_7_addr);
iounmap(fifo_reg_8_addr);
iounmap(fifo_reg_9_addr);
iounmap(fifo_reg_10_addr);
iounmap(fifo_reg_11_addr);
iounmap(fifo_reg_12_addr);
iounmap(fifo_reg_13_addr);
iounmap(fifo_reg_14_addr);
iounmap(fifo_dat0_addr);
iounmap(fifo_dat1_addr);
iounmap(fifo_dat2_addr);
iounmap(fifo_dat3_addr);
iounmap(fifo_dat4_addr);
iounmap(fifo_dat5_addr);
iounmap(fifo_dat6_addr);
iounmap(fifo_dat7_addr);
iounmap(fifo_dat8_addr);
iounmap(fifo_dat9_addr);
iounmap(fifo_dat10_addr);
iounmap(fifo_dat11_addr);
iounmap(fifo_sr_addr);
iounmap(fifo_ecr_addr);
iounmap(fifo_cr_addr);
}
/* 驱动模块入口和出口函数注册 */

View File

@ -1 +1 @@
1.0
1.2

View File

@ -1 +1 @@
1.0
1.1