修改dts后重编译_「正点原子FPGA连载」第二十章另一种方式编译ZYNQ镜像

1)摘自【正点原子】领航者 ZYNQ 之linux驱动开发指南

2)实验平台:正点原子领航者ZYNQ开发板
3)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
4)全套实验源码+手册+视频下载:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900
6)关注正点原子公众号,获取最新资料

cbf8353ba1330551780d128fb509dea3.png

第二十章另一种方式编译ZYNQ镜像


本篇是ARM Linux驱动开发篇中的第一章,本章跟驱动开发并没有什么关系,由于前面我们一直都是使用xilinx的petalinux工具编译镜像文件,例如包括u-boot、linux内核、设备树、ZYNQ PL端的bitstream文件以及fsbl等,虽然petalinux功能上比较全面,但是在编译速度上太慢了!完全是在浪费时间,相信大家在使用petalinux的时候已经感受到了它给你带来的无奈之处;为此笔者专门去研究了一下,那本章笔者就带大家通过另外一种比较快的方式编译各种镜像文件。
本章采用分步式的方式编译启动开发板所需要的各种镜像文件,虽然步骤比较繁琐,但灵活性比较高;虽然本章使用的是另一种方式编译镜像,但还是得需要用到petalinux提供的一些工具,所以大家一定要安装petalinux。
20.1由hdf文件得到bit文件
.bit文件是zynq pl端所需要用到的bitstream文件,例如我们使用petalinux-build命令完成工程编译之后会在images/linux目录会产生一个system.bit文件,这个就是我们这里说到bitstream文件,.bit可以通过.hdf硬件描述符文件得到,怎么得到呢?下面给大家说来。
将ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70103_Embedded_Linuxvivado_proNavigator_7010Navigator_7010.sdk文件夹拷贝到Ubuntu系统目录下,例如/home/zynq/hdf/目录,大家根据自己的情况选择目录,本实验以领航者7010为例,如果大家用的是领航者7020,则选择ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70203_Embedded_Linuxvivado_proNavigator_7020Navigator_7020.sdk文件夹。
在Navigator_7010.sdk目录下有一个.hdf文件,如下所示:

a0e73dfbb3320c826ab799ef6fec797c.png

图 31.1.1 hdf文件


接下来使用source命令执行petalinux的环境配置脚本settings.sh,如下所示:

  1. source /home/zynq/petalinux/v2018.3/settings.sh
b201dab08680e280d23bb79a68ba5e3b.png

图 31.1.2 运行settings.sh脚本文件


/home/zynq/petalinux/v2018.3是笔者的petalinux安装目录,完成环境配置之后执行hsi命令进入到hsi命令模式,如下所示:

  1. hsi
e2571255a07f56efddbc0a2146099339.png

图 31.1.3 hsi命令行


执行命令之后就可以进入到hsi命令行模式下了,hsi命令行模式就跟我们的linux命令行模式差不多,都可以执行命令,只不过执行的命令不同;hsi命令是petalinux工具提供的,所以一定安装petalinux才行;在这个模式下可以执行一些命令,例如执行下面这条命令可以打开硬件设计文件hdf得到bit文件:

  1. open_hw_design /home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.hdf
6576be545d82362a4a0b4eb0780c68e4.png

图 31.1.4 打开hdf文件


Open_hw_design命令紧跟着的是hdf文件路径,命令执行成功之后会在hdf文件所在目录下产生bit文件以及ps7_init命名的.c文件和.h文件,如下所示(在hsi命令行模式下执行exit命令退出该模式):
exit

d0eab762542dc86a08623b65522db5bc.png

图 31.1.5 退出hsi命令行模式

78181ed71049ee740fde802dbe8f7436.png

图 31.1.6 产生bit文件及其它文件


从上图中可以看到在hdf文件所在目录下产生了design_navigator_7010_wrapper.bit文件以及.c和.h文件。
20.2自动生成设备树文件
Petalinux可以根据hdf文件描述的硬件信息自动配置U-Boot和内核所需的设备树文件,那么我们也可以通过hsi命令来生成;首先需要导入xilinx的device-tree仓库,在我们提供的资料包中已经给大家准备好了,路径为:ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70103_Embedded_Linuxmiscdevice-tree-xlnx-xilinx-v2018.3.tar.gz,大家也可以通过https://github.com/Xilinx/device-tree-xlnx/releases网址进行下载,选择2018.3版本.tar.gz压缩格式文件,如下所示:

99531edd018175fa931409b09a8ef20e.png

图 31.2.1 设备树仓库下载


Xilinx device-tree描述了设备与设备树之间的匹配关系,将下载好或是资料包中的device-tree-xlnx-xilinx-v2018.3.tar.gz压缩文件拷贝到Ubuntu系统目录下,例如/home/zynq/device-tree,大家根据自己的情况选择,然后将其解压当前目录,解压之后会产生一个device-tree-xlnx-xilinx-v2018.3文件夹,如下所示:

5e2f32fac16e59d8c46a821017a5435b.png

图 31.2.2 device-tree目录


那么device-tree-xlnx-xilinx-v2018.3目录就是我们所需要的device-tree仓库。接下来我们执行hsi命令进入到hsi命令行模式,执行下面这些命令:

  1. open_hw_design /home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.hdf
  2. set_repo_path /home/zynq/device-tree/device-tree-xlnx-xilinx-v2018.3
  3. create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0
  4. generate_target -dir /home/zynq/linux/dts
d3bc164d81340707b1fe176f13fd2bdf.png

图 31.2.3 生成设备树文件


首先也是通过open_hw_design命令打开hdf文件,然后使用set_repo_path命令设置device-tree仓库所在路径,例如/home/zynq/device-tree/device-tree-xlnx-xilinx-v2018.3;使用create_sw_design创建软件设计,” -os device_tree”指定了软件设计的类型,我们这里使用device-tree表示它是一个设备树类型,” -proc ps7_cortexa9_0”指定处理器的名称,在hsi命令模式下使用”xxxx -help”可以查看xxxx命令的用法说明,这里就不给大家列举了;最后使用generate_target命令去产生目标,也就是我们的设备树文件,” -dir /home/zynq/linux/dts”指定路径。
此时我们可以退出hsi命令行模式,进入到/home/zynq/linux/dts目录下,可以看到自动配置产生的.dts和.dtsi文件,如下所示:

77982a2ad633c1b6ba9a8b87fe000956.png

图 31.2.4 生成设备树文件


Linux设备树是是一个很重要的知识点,将会在后面给大家详细说明,本章先不讲,这些文件后面我们会用到。
20.3创建、编译fsbl工程
fsbl(First Stage Boot Loader)是ZYNQ第一启动引导加载代码,它的主要任务就是初始化DDR,并将用户代码(例如U-Boot、bit文件或者是SDK裸机代码)从存储设备中拷贝到DDR中运行。在使用petalinux-build命令编译完成之后,在images/linux目录下有一个zynq_fsbl.elf文件,这个就是fsbl编译之后产生了elf格式文件,同样也可以使用hsi命令来创建fsbl工程并进行编译。
首先我们需要导入Xilinx embeddedsw存储库,该embeddedsw仓库用于裸机应用,例如fsbl、pmu固件、plm等,在我们提供的资料包中已经给大家准备好了,路径:ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70103_Embedded_Linuxmiscembeddedsw-xilinx-v2018.3.tar.gz,大家也可以从https://github.com/Xilinx/embeddedsw/releases网址进行下载,选择2018.3版本.tar.gz压缩格式,如下所示:

50ba4eae21e8c5c681b933224b90cf7e.png

图 31.3.1 下载embeddedsw仓库


将下载好或是资料包中的embeddedsw-xilinx-v2018.3.tar.gz压缩文件拷贝到Ubuntu系统目录下,例如/home/zynq/embeddedsw,大家根据自己的情况选择;然后将其解压当前目录,解压之后会产生一个embeddedsw-xilinx-v2018.3文件夹,如下所示:

de3afbb43b3b004bc4dd8f780ced8994.png

图 31.3.2 embeddedsw目录


在Ubuntu中执行下面这条命令,建立一个软链接文件gmake,链接到make:

  1. sudo ln -s /usr/bin/make /usr/bin/gmake
05daf53d674f694b6fbb7459c5caeacb.png

图 31.3.3 建立gmake软链接文件


因为在编译的过程中会用到gmake,其实gmake就是GNU make的缩写,Linux系统环境下的make就是GNU make;之所有有gmake,是因为在别的平台上,make一般被占用,GNU make只好叫gmake了;比如在进行编译时要使用make命令,但如果在非GNU系统中运行,必须使用GNU make,而不是使用系统自带的make版本,这时要用gmake代替make进行编译。
完成上面的工作之后,我们就可以进行fsbl的创建与编译了,执行hsi命令进入hsi命令行模式,执行下面这些命令:

  1. open_hw_design /home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.hdf
  2. set hwdsgn design_navigator_7010_wrapper // 定义hwdsgn变量
  3. set_repo_path /home/zynq/embeddedsw/embeddedsw-xilinx-v2018.3 // 设置embeddedsw仓库路径
  4. set fsbl_dir /home/zynq/linux/fsbl // 定义fsbl_dir变量
  5. generate_app -hw $hwdsgn -os standalone -proc ps7_cortexa9_0 -app zynq_fsbl -compile -sw fsbl -dir $fsbl_dir
df7ba5e63a990410aa2e26073043edbb.png

图 31.3.4 编译fsbl-1

60a9743129385624365dededd5d9f098.png

图 31.3.5 编译fsbl-2


首先还是使用open_hw_design命令打开hdf硬件描述符文件;使用set_repo_path命令设置embeddedsw仓库所在路径,例如/home/zynq/embeddedsw/embeddedsw-xilinx-v2018.3;set命令用于定义变量,我们使用set命令定义了一个hwdsgn变量等于design_navigator_7010_wrapper,当执行generate_app命令的时候使用该变量,定义了一个fsbl_dir变量定义了用于存放fsbl工程的路径;最后使用generate_app命令产生和编译fsbl,”-hw $hwdsgn”指定硬件设计的名字,就是hdf文件去掉后缀即可,”-os standalone”指定我们的app是一个无操作系统的裸机程序,”-proc ps7_cortexa9_0”指定处理器,”-app zynq_fsbl”指定app的名字(这个不能改),”-compile”表示要编译生成的源文件(如果不加的话则表示仅产生fsbl工程源码并不进行编译),”-sw fsbl”指定本软件设计的名字(这个名字可以自己定),”-dir $fsbl_dir”我们的fsbl工程存放的路径,笔者这里以/home/zynq/linux/fsbl为例,大家根据自己的情况设定。
整个过程完成之后,我们可以执行exit命令退出hsi命令行模式了,此时/home/zynq/linux/fsbl目录下的内容如下所示:

53cba8a6b02ef6fe7ba30e768963f408.png

图 31.3.6 fsbl工程源码目录


/home/zynq/linux/fsbl就是我们通过hsi命令生成的fsbl对应的源码目录,这个就像是在Windows下使用SDK软件创建了一个FSBL工程一样,上图中的executable.elf文件fsbl工程编译之后得到elf格式文件;得到fsbl源码工程之后,我们就可以直接在fsbl工程目录进行编译了,例如,在/home/zynq/linux/fsbl目录下执行make clean命令对fsbl工程目录进行清理,如下:
make clean

d3bda4c05b061d1b57436749ad0e3797.png

图 31.3.7 清理工程


我们可以修改Makefile文件,将编译产生的fsbl镜像文件名字改为zynq_fsbl.elf,在fsbl工程目录下,打开Makefile文件,修改EXEC变量,如下所示:
vi Makefile

1f5350987ffe4c46b88f62255114e46c.png

图 31.3.8 修改EXEC变量


将该变量由executable.elf修改为zynq_fsbl.elf,除此之外,我们还可以看到变量CC := arm-none-eabi-gcc,这指定了编译fsbl时使用的交叉编译工具,这个不用改,修改完成之后保存退出即可!我们直接在该目录下执行make命令即可编译,如下:
make

3000a1ee655c02f919df7d998a3916b8.png

图 31.3.9 make编译fsbl工程


编译成功之后产生的镜像文件就成了fsbl_zynq.elf,如下所示:

33ff281df6379ab2eb36b4edb1fa70c5.png

图 31.3.10 fsbl镜像文件


20.4编译U-Boot
在中,已经让大家把xilinx官方的U-Boot拷贝到Ubuntu系统中了,并对他们进行了修改,添加了一些自己定义的文件,本篇教程不使用前面移植后的U-Boot,我们用一份新的xilinx官方2018.3版本(这个版本是xilinx设定的版本,其U-Boot版本为2018.01)的U-Boot源码,源码已经提供给大家了,路径为:ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70103_Embedded_Linux资源文件甥潢瑯u-boot-xlnx-xilinx-v2018.3.tar.gz,大家也可以通过https://github.com/Xilinx/u-boot-xlnx/releases网址进行下载。
首先将U-Boot源码压缩包文件拷贝到Ubuntu系统目录中,例如/home/zynq/linux/u-boot目录,并将其解压到当前目录,解压之后会产生一个u-boot-xlnx-xilinx-v2018.3文件夹,进入到该目录下,就可以看到U-boot源码目录下的文件和文件夹了,如下所示:

0a7fabe45c691ed1221608a3918e3efb.png

图 31.4.1 U-Boot源码目录


在前面给大家讲过,使用"petalinux-config -c u-boot"命令可以对U-Boot进行配置、使用"petalinux-build -c u-boot"命令可以编译u-boot,那么这些方法都是使用petalinux工具时的做法,这里教大家如何在U-Boot源码目录下配置、编译而不通过petalinux-xxx命令;
关于U-Boot我们已经在前面给大家进行了详细的讲解,包括Makefile文件、各个文件目录的作用以及源码的分析、U-Boot配置、U-Boot常用命令等等,这里就不再讲解。
1、添加设备树文件
关于设备树的概念现在不给大家讲,后面会说。除了Linux内核支持设备树之外,我们使用的U-Boot也是支持设备树的;在31.2小节中我们使用hsi命令生成了一些dts和dtsi的设备树源文件,现在我们要用到它们了,这些设备树文件都是根据我们的hdf硬件设计而自动生成的,如果我们使用U-Boot中自带的设备树文件则不能满足我们的情况。
将前面生成的设备树文件(笔者这里生成的设备树文件在/home/zynq/linux/dts目录下)pcw.dtsi、pl.dtsi、system-top.dts以及zynq-7000.dtsi四个文件拷贝到U-Boot源码目录下的arch/arm/dts目录下,拷贝过去之后进入到arch/arm/dts目录下查看,如下所示:

086323c08b7ce649d84e9f0f3a3a561d.png

图 31.4.2 拷贝设备树文件到U-Boot


接下来我们需要对system-top.dts文件进行一个简单地修改,打开system-top.dts文件,修改之前内容如下:
示例代码20.4.1 system-top.dts修改之前

  1. 1 /*
  2. 2 * CAUTION: This file is automatically generated by Xilinx.
  3. 3 * Version: HSI
  4. 4 * Today is: Mon Mar 16 02:51:23 2020
  5. 5 */
  6. 6
  7. 7
  8. 8 /dts-v1/;
  9. 9 #include "zynq-7000.dtsi"
  10. 10 #include "pl.dtsi"
  11. 11 #include "pcw.dtsi"
  12. 12 / {
  13. 13 chosen {
  14. 14 bootargs = "earlycon";
  15. 15 stdout-path = "serial0:115200n8";
  16. 16 };
  17. 17 aliases {
  18. 18 ethernet0 = &gem0;
  19. 19 i2c0 = &i2c_2;
  20. 20 i2c1 = &i2c0;
  21. 21 i2c2 = &i2c1;
  22. 22 serial0 = &uart0;
  23. 23 serial1 = &uart1;
  24. 24 spi0 = &qspi;
  25. 25 };
  26. 26 memory {
  27. 27 device_type = "memory";
  28. 28 reg = <0x0 0x20000000>;
  29. 29 };
  30. 30 };


这里我们对该文件进行一个简单地修改,修改之后如下所示:
示例代码20.4.2 system-top.dts修改之后

  1. 1 /*
  2. 2 * CAUTION: This file is automatically generated by Xilinx.
  3. 3 * Version: HSI
  4. 4 * Today is: Mon Mar 16 02:51:23 2020
  5. 5 */
  6. 6
  7. 7
  8. 8 /dts-v1/;
  9. 9 #include "zynq-7000.dtsi"
  10. 10 #include "pl.dtsi"
  11. 11 #include "pcw.dtsi"
  12. 12 / {
  13. 13 model = "Alientek ZYNQ Development Board";
  14. 14
  15. 15 chosen {
  16. 16 bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait";
  17. 17 stdout-path = "serial0:115200n8";
  18. 18 };
  19. 19 aliases {
  20. 20 ethernet0 = &gem0;
  21. 21 i2c0 = &i2c_2;
  22. 22 i2c1 = &i2c0;
  23. 23 i2c2 = &i2c1;
  24. 24 serial0 = &uart0;
  25. 25 serial1 = &uart1;
  26. 26 spi0 = &qspi;
  27. 27 };
  28. 28 memory {
  29. 29 device_type = "memory";
  30. 30 reg = <0x0 0x20000000>;
  31. 31 };
  32. 32 };
  33. 33
  34. 34 &gem0 {
  35. 35 local-mac-address = [00 0a 35 00 1e 53];
  36. 36 };
  37. 37
  38. 38 &qspi {
  39. 39 #address-cells = <1>;
  40. 40 #size-cells = <0>;
  41. 41 flash0: flash@0 {
  42. 42 compatible = "n25q512a","micron,m25p80";
  43. 43 reg = <0x0>;
  44. 44 #address-cells = <1>;
  45. 45 #size-cells = <1>;
  46. 46 spi-max-frequency = <50000000>;
  47. 47 partition@0x00000000 {
  48. 48 label = "boot";
  49. 49 reg = <0x00000000 0x00500000>;
  50. 50 };
  51. 51 partition@0x00500000 {
  52. 52 label = "bootenv";
  53. 53 reg = <0x00500000 0x00020000>;
  54. 54 };
  55. 55 partition@0x00520000 {
  56. 56 label = "kernel";
  57. 57 reg = <0x00520000 0x00a80000>;
  58. 58 };
  59. 59 partition@0x00fa0000 {
  60. 60 label = "spare";
  61. 61 reg = <0x00fa0000 0x00000000>;
  62. 62 };
  63. 63 };
  64. 64 };


修改完成之后保存退出即可!
以上主要修改了bootargs属性、添加了model属性、网口0的MAC地址以及给qspi进行了分区操作。修改完成之后,我们还需要将system-top.dts文件添加到arch/arm/dts/Makefile文件中,找到dtb-$(CONFIG_ARCH_ZYNQ)这里,将system-top.dtb(.dts编译之后得到的就是.dtb文件)添加上去,这样当CONFIG_ARCH_ZYNQ宏被选中的时候,system-top.dts才会被编译进去,如下所示:

2f2e240ff307dc1e02163b3cada5d213.png

图 31.4.3 添加system-top.dtb文件


注意在zynq-zybo.dtb后面加上一个反斜杠””,跟上面的保持一致。
添加好之后保存退出文件。
2、修改zynq-common.h和zynq_zc70x.h配置文件
include/configs/目录下有很多的配置文件,该目录下的配置文件中有很多宏定义,这些宏定义将会在编译U-Boot源码时会被用到;前面我们使用petalinux工具的时候并没有去配置U-Boot、内核等,原因在于petalinux确实比较智能,它能够根据hdf文件记录的信息自动配置,例如一些时钟频率、外设时钟、环境变量偏移量等。
zynq-common.h和zynq_zc70x.h都在include/configs目录下,zynq-common.h是xilinx提供的用于配置zynq系列处理器的通用配置文件,zynq-common.h头文件被zynq_zc70x.h包含,下面我们要对这两个头文件进行一些简单地修改!
首先对zynq_zc70x.h文件进行修改,修改之前如下所示:
示例代码20.4.3 zynq_zc70x.h修改之前

  1. 1 /*
  2. 2 * (C) Copyright 2013 Xilinx, Inc.
  3. 3 *
  4. 4 * Configuration settings for the Xilinx Zynq ZC702 and ZC706 boards
  5. 5 * See zynq-common.h for Zynq common configs
  6. 6 *
  7. 7 * SPDX-License-Identifier: GPL-2.0+
  8. 8 */
  9. 9
  10. 10 #ifndef __CONFIG_ZYNQ_ZC70X_H
  11. 11 #define __CONFIG_ZYNQ_ZC70X_H
  12. 12
  13. 13 #define CONFIG_ZYNQ_I2C0
  14. 14 #define CONFIG_ZYNQ_EEPROM
  15. 15
  16. 16 #include
  17. 17
  18. 18 #endif /* __CONFIG_ZYNQ_ZC70X_H */


这里我们要把CONFIG_ZYNQ_I2C0和CONFIG_ZYNQ_EEPROM宏定义给去掉,原因就是我不想在U-Boot中使用I2C设备,直接给去掉!修改之后如下:
示例代码20.4.4 zynq_zc70x.h修改之后

  1. 1 /*
  2. 2 * (C) Copyright 2013 Xilinx, Inc.
  3. 3 *
  4. 4 * Configuration settings for the Xilinx Zynq ZC702 and ZC706 boards
  5. 5 * See zynq-common.h for Zynq common configs
  6. 6 *
  7. 7 * SPDX-License-Identifier: GPL-2.0+
  8. 8 */
  9. 9
  10. 10 #ifndef __CONFIG_ZYNQ_ZC70X_H
  11. 11 #define __CONFIG_ZYNQ_ZC70X_H
  12. 12
  13. 13 #include
  14. 14
  15. 15 #endif /* __CONFIG_ZYNQ_ZC70X_H */


接下来修改zynq-common.h文件,打开该文件,修改CONFIG_CPU_FREQ_HZ(ARM主频),将频率由800000000修改为666666687(如果是7020核心板则修改为766666687):
示例代码20.4.5 zynq-common.h修改内容-1

  1. 12
  2. 13 /* CPU clock */
  3. 14 #ifndef CONFIG_CPU_FREQ_HZ
  4. 15 # define CONFIG_CPU_FREQ_HZ 666666687
  5. 16 #endif
  6. 17


接下来修改CONFIG_SF_DEFAULT_SPEED(默认的QSPI速率),由30000000改为50000000,如下所示:
示例代码20.4.6 zynq-common.h修改内容-2

  1. 50
  2. 51 /* QSPI */
  3. 52 #ifdef CONFIG_ZYNQ_QSPI
  4. 53 # define CONFIG_SF_DEFAULT_SPEED 50000000
  5. 54 #endif
  6. 55


修改CONFIG_ENV_SIZE(环境变量大小),由(128 << 10)修改为0x20000:
示例代码20.4.7 zynq-common.h修改内容-3

  1. 148
  2. 149 /* Total Size of Environment Sector */
  3. 150 #ifdef CONFIG_ENV_IS_IN_EEPROM
  4. 151 # define CONFIG_ENV_SIZE CONFIG_SYS_EEPROM_SIZE
  5. 152 # define CONFIG_EXTRA_ENV_SETTINGS
  6. 153 #else
  7. 154 # define CONFIG_ENV_SIZE 0x20000
  8. 155 #endif
  9. 156


修改CONFIG_ENV_OFFSET(环境变量存储位置偏移量),由0xE0000修改为0x500000:
[size=13.3333px]示例代码20.4.8 zynq-common.h修改内容-4

  1. 163
  2. 164 /* cc108 requires to be 0xF00000 to have boot.bin with bitstream included */
  3. 165 # ifndef CONFIG_ENV_OFFSET
  4. 166 # define CONFIG_ENV_OFFSET 0x500000
  5. 167 # endif
  6. 168 #endif
  7. 169


需要注意CONFIG_ENV_SIZE和CONFIG_ENV_OFFSET这两个是U-Boot环境变量存储有关的,在下面menuconfig配置U-Boot的时候我们会将环境变量存储在QSPI中,CONFIG_ENV_SIZE指定了环境变量分区的大小,CONFIG_ENV_OFFSET指定环境变量分区的偏移量,这些都与QSPI的分区表有关!
修改完成之后保存退出即可,接下来就可以正式使用make命令进行配置和编译了。
3、defconfig配置
在U-Boot的源码目录下,执行下面这条命令对xilinx官方的U-Boot进行defconfig配置,如下所示:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zynq_zc702_defconfig

c9a717ad3cdd73a178ee89c57dbd4f22.png

图 31.4.4 defconfig配置


“ARCH=arm”指定了u-boot运行的机器架构,“CROSS_COMPILE=arm-linux-gnueabihf-”指定了交叉编译工具的前缀,交叉编译工具我们使用的是xilinx官方提供的,在我们安装petalinux的时候也安装了,在petalinux安装目录下的tools/linux-i386目录,如下所示:

642b1fc2321eb6873e4f271a03019227.png

图 31.4.5 交叉编译工具链安装目录


gcc-arm-linux-gnueabi和gcc-arm-none-eabi两个目录下安装的是两种不同的交叉编译工具链(其它那几个目录安装的也是交叉编译工具链,对于ZYNQ 7010/7020来说用不上),两者之间的区别大家可以简单地理解为gcc-arm-linux-gnueabi一般用于编译linux系统的源码,例如ARM Linux内核源码、ARM Linux应用程序等,而gcc-arm-none-eabi一般用于编译ARM裸机程序,例如我们前面编译fsbl代码的时候用的就是它;这么一说的话,那我们编译U-Boot应该用gcc-arm-none-eabi咯,但这里我们用的是gcc-arm-linux-gnueabi,主要笔者看到xilinx wiki文档中用的也是这个,那就这个吧。
交叉编译命令就在安装目录下的bin文件夹中,例如:

635b6b2382c84eccee9a39c6ccb3ee6a.png

图 31.4.6 交叉编译命令


CROSS_COMPILE指定的就是这些命令的前缀,我们在前面source petalinux目录下的settings.sh脚本时已经将它们的路径导出到环境变量了,所以不用加全路径。
zynq_zc702_defconfig是xilinx为7010/7020添加的配置文件,所以我们也是使用这个!
4、menuconfig图形化配置
U-Boot图形化配置前面已经给大家讲过了,在U-Boot源码目录下,执行下面这条命令进入到menuconfig图形化配置界面:

  1. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
601297e0e6d6b5adbceb54c126f4f623.png

图 31.4.7 menuconfig配置


各个配置项就不给大家一一讲解了,相信大家通过前面的学习已经对U-Boot的menuconfig图形化配置有一定的认识和理解了,接下来我直接把配置列出来:

  1. Boot media --->
  2. Support for booting from SD/EMMC // 选择
  3. SPL / TPL --->
  4. [ ] Enable SPL // 取消
  5. Command line interface --->
  6. Memory commands --->
  7. [ ] eeprom - EEPROM subsystem // 取消
  8. Device access commands --->
  9. [ ] i2c // 取消
  10. Device Tree Control --->
  11. (system-top) Default Device Tree for DT control // 将设备树设置为system-top(也就是system-top.dts)
  12. Device Drivers --->
  13. Serial drivers --->
  14. [ ] Enable an early debug UART for debugging // 取消


配置完成之后保存退出,执行下面这条命进行编译:

  1. make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j10
4eb57213102d158ddab8169255cf3e00.png

图 31.4.8 编译U-Boot


编译完成之后将会在当前目录下生成一个u-boot文件、u-boot.bin文件以及其它一些文件,如下所示:

57346cad66fa07e723c5ebd0bfb9d63d.png

图 31.4.9 编译完成


u-boot文件是elf格式的镜像文件,而u-boot.bin则是纯二进制格式的镜像文件。
20.5编译kernel
同样本篇教程不使用前面移植后的Linux内核源码,我们用一份新的xilinx官方2018.3版本(这个版本是xilinx设定的版本,其linux版本为4.14.0)的内核源码,源码已经提供给大家了,路径为:ZYNQ开发板资料盘(A盘)4_SourceCodeZYNQ_70103_Embedded_Linux资源文件kernellinux-xlnx-xilinx-v2018.3.tar.gz,大家也可以通过https://github.com/Xilinx/linux-xlnx/releases网址进行下载。
将内核源码压缩包文件拷贝到Ubuntu系统目录中,例如/home/zynq/linux/kernel目录,并将其解压到当前目录,解压之后会产生一个linux-xlnx-xilinx-v2018.3文件夹,进入到该目录下,就可以看到内核源码目录下的文件和文件夹了,如下所示:

d68d750a1734b804998ee9dbba6cbf3a.png

图 31.5.1 内核源码目录


本小节我们也是直接在内核源码目录下进行编译,而不使用petalinux工具,其实这些知识前面都已经给大家介绍过了。
1、添加设备树文件
这里我们直接将前面U-Boot源码arch/arm/dts目录下的那四个设备树文件(pl.dtsi、pcw.dtsi、system-top.dts和zynq-7000.dtsi)直接拷贝到内核源码目录下的arch/arm/boot/dts目录中,不用进行修改。同样我们也需要修改arch/arm/boot/dts目录下的Makefile文件,将设备树添加上去,如下:

9c479849395fa313ed42a577523bf380.png

图 31.5.2 Makefile中添加设备树


修改完成之后保存退出即可!
2、defconfig配置
在内核源码目录下执行下面这条命令对内核进行defconfig配置:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xilinx_zynq_defconfig

7e0101ad4d4027274ee3df3395cf7e17.png

图 31.5.3 defconfig配置


命令这里就不给大家解释了,前面我们已经解释过,内核的配置、编译方式基本跟U-Boot是一样的,需要注意的是命令中间的空格不要漏掉了,因为以前发现很多初学者老是会漏掉这些空格,这样就导致命令执行失败。
3、menuconfig配置
这里我们暂时就不进行配置,以后有需要的时候再配,先保持默认!
4、编译内核
执行下面这条命令编译内核源码:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j10

b80b561f9685c4705668941b8c0977a7.png

图 31.5.4 编译内核

2078b3762ee6d375c9aa781a6e5f765f.png

图 31.5.5 编译完成


编译完成之后会在arch/arm/boot/目录下生成一个名为zImage的内核镜像文件,后面我们在用。
5、编译设备树
内核与u-boot不同的是,U-Boot的设备树默认是与内核一起编译的,并且产生的dtb文件已经与U-Boot镜像文件集成在一起了;在内核里边我们需要单独编译出设备树的dtb文件,前面已经将我们所需要的设备树文件拷贝到内核的arch/arm/boot/dts目录下了,接下来执行这条命令编译system-top.dtb文件:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- system-top.dtb -j10

a8376925363a89af2bb152965994b9b1.png

图 31.5.6 编译设备树


编译成功之后会在arch/arm/boot/dts目录下生成system-top.dtb文件。
20.6编译rootfs
根文件系统我们直接使用petalinux进行编译即可,首先进入petalinux的安装目录,使用petalinux-create命令新建一个petalinux工程,如下:
petalinux-create --type project --template zynq --name ALIENTEK-ZYNQ

ab9dacb7f6a89f98fe4b58061600b446.png

图 31.6.1 新建petalinux工程


进入到ALIENTEK-ZYNQ工程目录下,执行petalinux-config --get-hw命令导入hdf硬件描述符文件:
cd ALIENTEK-ZYNQ

  1. petalinux-config --get-hw-description /home/zynq/hdf/Navigator_7010.sdk
f04962cf083e6e42a604c1eb3bc221d1.png

图 31.6.2 导入hdf文件


这里用的hdf文件就是31.1小节中使用的,在弹出来的配置界面中,我们不用进行任何配置,直接保存退出即可!等待它配置完成。
接下来直接编译根文件系统:

  1. petalinux-build -c rootfs
9d82f7eefebc66d76d57a23c3ab5bf4f.png

图 31.6.3 编译根文件系统


等待其编译完成,完成之后产生的根文件系统压缩包在images/linux目录下,如下所示:

58797bd6e4b1e7fe1da1d7f0144536fb.png

图 31.6.4 产生的根文件系统压缩包


因为我们要使用SD卡启动,并且SD卡会有一个EXT4格式的分区专门存放根文件系统,所以我们要使用压缩格式的根文件系统,例如rootfs.tar.gz或rootfs.tar.bz2。
20.7启动开发板
经过上面一系列的过程之后,我们就已经得到了启动开发板的所有所需的镜像文件了。例如我们使用petalinux工具会生成image.ub和BOOT.BIN文件,使用这两个文件我们就可以启动开发板了,但是这里我们不这样做。
前面给大家介绍过image.ub这个文件的本质,那么它其实是多个文件组合在一起的,包括内核镜像、dtb以及根文件系统,这样的做法有一个弊端,不够灵活,一个变了整个image.ub文件就得重新制作一遍,很麻烦。同样BOOT.BIN文件是fsbl镜像、u-boot镜像以及pl端bit文件集合在一起的,那么既然是集合在一起的,那么我们单独使用也是可以的嘛。
所以我们这里的思路就是将内核镜像文件zImage、内核设备树文件以及根文件系统从image.ub文件中分离出来;而将bit文件从BOOT.BIN文件中分离出来,这样做之后我们的SD卡中将会存在5部分内容:zImage、dtb、rootfs、bit以及BOOT.BIN(fsbl镜像与u-boot镜像的集合体),明确之后我们将他们拷贝到我们的SD卡中。
1、制作SD启动卡
SD启动卡的制作方式在17.2.10小节当中已经给大家介绍过了,这里不再细说,笔者直接将一张16G的TF卡格式化了2个分区,FAT32和EXT4,如下所示:

197ced9e573aad290bada1ad09d8698d.png

图 31.7.1 SD启动卡分区信息


2、拷贝镜像到FAT分区
将前面过程当中生成的各种镜像文件拷贝到SD启动卡的FAT分区,包括zImage(内核镜像,内核源码目录arch/arm/boot/zImage)、system-top.dtb(内核设备树dtb文件,内核源码目录arch/arm/boot/dts/system-top.dtb)、design_navigator_7010_wrapper.bit(pl端bitstream文件,/home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.bit)。大家根据自己前面步骤当中文件存放的目录去找到相应的这些镜像文件。
接下来我们需要将BOOT.BIN文件拷贝到FAT分区,但是前面的过程中我们并没有生成BOOT.BIN文件,这里就需要使用前面生成的u-boot(U-Boot elf格式镜像,U-Boot源码目录u-boot)和zynq_fsbl.elf(fsbl elf格式镜像,/home/zynq/linux/fsbl/zynq_fsbl.elf)来制作BOOT.BIN文件。
首先我们进入到U-Boot源码目录下,将生成的u-boot文件重命名为u-boot.elf,如下所示:

  1. mv u-boot u-boot.elf
2455c9f780dae178528a715970c6204d.png

图 31.7.2 u-boot重命名


为啥要重命名呢?因为笔者发现使用petalinux-package命令制作BOOT.BIN文件的时候,如果elf格式文件没有带.elf后缀名会识别不了。接下来我们就可以用petalinux-package命令去生成BOOT.BIN文件了,在U-Boot源码目录下执行下面这条命令:
petalinux-package --boot -p /home/zynq/petalinux/v2018.3/ALIENTEK-ZYNQ --fsbl /home/zynq/linux/fsbl/zynq_fsbl.elf --u-boot ./u-boot.elf -o ./BOOT.BIN --force

5c3904a70cfd1e6cc3ab4f3444b6fc47.png

图 31.7.3 生成BOOT.BIN文件


petalinux-package命令前面已经给大家介绍过了,”-p”选项指定一个petalinux工程,如果直接在petalinux工程目录下运行该命令则不需要用”-p”指定;”--fsbl”指定fsbl的elf格式镜像;” --u-boot”指定U-Boot的elf格式镜像文件,大家根据自己的路径情况进行修改;”-o”选项指定输出文件的名字以及存放的路径,例如这里是将BOOT.BIN文件存放在当前目录下,命令执行完成之后就会在当前目录下生成一个BOOT.BIN文件,如上图所示。我们使用ls查看下它的大小:

70b471e0677e3db5da7edf0e81950bfe.png

图 31.7.4 BOOT.BIN文件大小


我们发现它只有600多K,但是u-boot.elf文件可是有4M多的,而zynq_fsbl.elf文件也有600多K,为啥合成为BOOT.BIN文件之后只有600多K了呢?原因在于格式问题,elf格式文件中除了机器码之外,还包含了很多额外的信息,例如符号表、调试信息、重定位表、运行地址和加载地址等,信息量很大,所以导致elf文件很大,例如linux下的应用程序就是elf格式的,程序加载运行的时候会去解析,但是裸机下不能用elf格式,包括内核镜像和U-Boot镜像等都不能用elf格式;而bin文件则是最纯粹的二进制机器代码,没有任何多余的信息,所以文件小。
使用petalinux-package命令生成的BOOT.BIN文件的时候,它会解析我们给定的elf格式文件,获取它的运行地址、加载地址以及真正的二进制机器代码,然后再把它俩集合起来,所以BOOT.BIN文件就是一个.bin格式的文件,所以它小,相信说到这里大家应该明白了!需要注意我们生成的BOOT.BIN文件中并不包含bit文件,前面已经跟大家说过了。
之后将BOOT.BIN文件也拷贝到SD启动卡的FAT分区,那么此时来看看我们的FAT分区有哪些文件:

31dad6e27e5bb3c4306ec5d5ca24f045.png

图 31.7.5 FAT分区文件列表


为了方便、好看,笔者将design_navigator_7010_wrapper.bit文件和system-top.dtb文件进行了重命名,分别为system.bit和system.dtb,如下:

5763ba40558aea948d5cf6f6a5db5013.png

图 31.7.6 文件重命名


3、将根文件系统解压到EXT4分区
接下来我们需要将31.6小节编译的根文件系统压缩包文件解压到SD启动卡的EXT4分区,这里笔者使用rootfs.tar.gz压缩包文件,进入到rootfs.tar.gz压缩包文件所在目录,执行解压命令:

116d07cb1b53541328b201d13e8f0881.png

图 31.7.7 解压rootfs.tar.gz


/media/zynq/ext4是笔者的SD启动卡对应的EXT4分区的挂载点,注意解压的时候需要使用前面要加sudo,也就是要以root用户的身份进行解压。解压完成之后执行sync命令将数据同步到SD卡中,之后卸载SD启动卡,卸载成功之后拔掉它!

fb107fa5e74f5394b7f4c6e442412f2a.png

图 31.7.8 卸载SD启动卡


4、启动开发板
将我们做好的启动卡插入开发板,连接电源、串口启动,打印信息如下所示:

920249c32f27451ad4f5b4a39ca97cde.png

图 31.7.9 开发板启动


在U-Boot启动2秒倒计时之前,按回车或者是空格键停止启动,进入到U-Boot的命令行模式,因为现在不能直接启动,我们需要对U-Boot环境变量进行修改,在U-Boot命令行下执行下面这些命令设置环境变量,如下所示:

5e80801561336a42a96bd576edb3a31f.png

图 31.7.10 设置环境变量


示例代码20.7.1 U-Boot环境变量设置

  1. Zynq> setenv bitstream_load_address 0x100000
  2. Zynq> setenv bitstream_image system.bit
  3. Zynq> setenv bitstream_size 0x300000
  4. Zynq> setenv kernel_image zImage
  5. Zynq> setenv devicetree_image system.dtb
  6. Zynq>
  7. Zynq> setenv sdboot 'if mmcinfo; then run uenvboot; echo Copying Linux from SD to RAM... && load mmc 0 ${bitstream_load_address} ${bitstream_image} && fpga loadb 0 ${bitstream_load_address} ${bitstream_size} && load mmc 0 ${kernel_load_address} ${kernel_image} && load mmc 0 ${devicetree_load_address} ${devicetree_image} && bootz ${kernel_load_address} - ${devicetree_load_address}; fi'


关于U-Boot命令的使用在前面已经给大家讲解过,不过这里也给大家简单地说明一下我们设置的这些环境变量的作用:
首先第一条命令我们设置了bitstream_load_address变量存放bitstream文件从SD卡中拷贝到内存中的地址;第二条命设置了bitstream_image变量等于SD卡中bitstream文件的名字,也就是system.bit;第三条命设置了bitstream_size变量等于bitstream文件的大小;第四条命令设置了kernel_image变量等于SD卡中内核镜像的名字,也就是zImage;第五条命令设置了devicetree_image变量等于SD卡中内核设备树dtb文件的名字,也就是system.dtb;kernel_image和devicetree_image我们的这个U-Boot中默认是有的,只不过它们的内容并不是我们SD中的文件名,所以需要重新设定。
最后一条命令设置了sdboot变量,其实这个变量在我们使用的这个U-Boot中也是存在的,这里也是对他重新定义,这个变量的内容很长,我们可以把它的内容整理一下,如下:
示例代码20.7.2 sdboot变量内容整理

  1. if mmcinfo; then
  2. run uenvboot;
  3. echo Copying Linux from SD to RAM... && // 打印字符串
  4. load mmc 0 ${bitstream_load_address} ${bitstream_image} && // 从SD卡拷贝bitstream文件到内存
  5. fpga loadb 0 ${bitstream_load_address} ${bitstream_size} && // 从内存中加载bitstream数据到FPGA
  6. load mmc 0 ${kernel_load_address} ${kernel_image} && // 从SD卡拷贝内核镜像到内存
  7. load mmc 0 ${devicetree_load_address} ${devicetree_image} &&// 从SD卡拷贝设备树到内存
  8. bootz ${kernel_load_address} - ${devicetree_load_address}; // bootz启动内核
  9. fi


“&&”符号其实就是C语言中”与”,跟C语言里面的作用一毛一样,${xxx}就是变量的引用,if … fi这个就是if条件判断语句了,fi表示条件判断的结束,U-Boot里边的这种语法很简单地,就不给大家细说了,如果不明白可以在网上找找资料。
前面跟大家讲过,U-Boot中的bootcmd变量的作用,U-Boot启动内核或在命令行下执行boot命令时其实就是去执行bootcmd,那我们来看看bootcmd的内容是什么:

6915996ba712f71174f43840edd42cf7.png

图 31.7.11 bootcmd的内容

65e70ab21d55652aa2d25193c2ef0046.png

图 31.7.12 modeboot的内容


所以从上面可以知道,bootcmd的内容其实就是运行sdboot,也就是上面定义的那个。
变量设置完成之后,执行saveenv保存环境变量到QSPI Flash中,那么下次就不用再设置了

542c3dc71cf098bc8afbc845eac97217.png

图 31.7.13 保存环境变量


保存完成执行boot命令启动内核:

1c77161a2491eff6880a6d1c54a6fa60.png

图 31.7.14 启动内核


启动完成之后登陆系统(用户名和密码都是root):

ad8825813849c3f5a6e9519a411f8961.png

图 31.7.15 登陆系统


后面我们的驱动开发篇将以本章使用的U-Boot源码、内核源码等进行开发工作!
20.8tcl脚本
前面我们在hsi终端下通过执行相应的命令去获取bit文件、自动生成设备树以及构建一个fsbl源码等,觉得这样非常的不方便,每次都要先执行hsi命令进入到hsi终端模式,然后在一个一个命令敲,这样感觉非常不好,那可不可以像shell命令一样,创建一个shell脚本之类的呢?其实是可以的,我们可以创建一个后缀名为.tcl的脚本,然后把我们的命令添加上去,然后直接执行这个脚本就行了。
例如我在Ubuntu目录下新建一个hsi_test.tcl文件,内容如下所示:

  1. 1
  2. 2 hsi::open_hw_design /home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.hdf


文件中的hsi::open_hw_design xxx.hdf就表示执行his的open_hw_design命令,后面跟着的参数就是对应的hdf文件路径了,例如我们将31.2小节中执行的命令写入到hsi_test.tcl脚本中,如下所示:
示例代码20.8.1 tcl脚本示例 hsi_test.tcl内容

  1. 1 # tcl script test
  2. 2
  3. 3 hsi::open_hw_design /home/zynq/hdf/Navigator_7010.sdk/design_navigator_7010_wrapper.hdf
  4. 4 hsi::set_repo_path /home/zynq/device-tree/device-tree-xlnx-xilinx-v2018.3
  5. 5 hsi::create_sw_design device-tree -os device_tree -proc ps7_cortexa9_0
  6. 6 hsi::generate_target -dir /home/zynq/linux/dts
  7. 7


第一行#号表示注释。
那我们如何执行hsi_test.tcl脚本呢?执行方法如下所示:

  1. xsct hsi_test.tcl
abf1f085ac607c16a88f4da0c52fef24.png

图 31.8.1 运行hsi_test.tcl脚本


“xsct xxx.tcl”即可!xsct也是petalinux工具安装的时候自带的,它也是命令行终端,例如运行xsct命令就会进入到xsct终端模式,如下所示:

da0bb321a191075ce4f9e8bee4abf0ef.png

图 31.8.2 xsct终端


例如我们在xsct终端下也可以执行脚本中的命令,例如:

ae872bd4d1113ba24a7039fe0dabfe0a.png

图 31.8.3 xsct运行hsi命令


所以当我们执行”xsct hsi_test.tcl”命令时其实就是类似于将hsi_test.tcl交给xsct去解析并运行。
关于xsct、hsi以及tcl脚本等更多的内容这里就不讲了,笔者对这些没有什么深入的了解!如果大家感兴趣自己去网上找找相关的资料。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/472655.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流畅的Python 2. 数据结构 - 序列构成的数组

文章目录1. 内置序列2. 列表推导 []、生成器() 表达式3. 元组 tuple4. 切片5. , * 操作6. 增量赋值7. 排序8. bisect管理已排序序列8.1 用 bisect.bisect 二分搜索8.2 用 bisect.insort 二分插入新元素9. 列表的替代9.1 数组9.2 内存视图9.3 NumPy、SciPy9.4 队列1. 内置序列 …

hadoop 多机全分布式安装步骤(虚拟机1master+2slave)

文章目录1. 虚拟机安装Centos72. 配置静态IP3. 更改主机名4. 编辑域名映射5. 安装配置Java6. 配置SSH免密登录7 .安装Hadoop8. 关闭防火墙9. 格式化文件系统10. 启动验证11. 第一个MapReduce程序: WordCount12. 关闭Hadoop参考书&#xff1a;《Hadoop大数据原理与应用》1. 虚拟…

ie浏览器模拟器_航空飞机模拟器安卓版下载-航空飞机模拟器游戏下载

3D建模射击&#xff0c;真实的飞行世界&#xff0c;在航空飞机模拟器游戏中玩家将化身为飞行员&#xff0c;这里的飞机类型非常齐全&#xff0c;每一辆都要熟练操作&#xff0c;最大程度还原了飞行员最真实的驾驶场景&#xff0c;完成任务获得奖励还能提高它的性能哦&#xff0…

npm安装vue_vue搭建脚手架的方式

基于window系统整理的vue脚手架npm、yarn安装方法&#xff0c;记得网络一定要好先说npm的安装方法先在需要创建项目的文件夹下打开终端&#xff0c;如果没有node可以先去官网下载&#xff0c;然后一路next&#xff0c;就OK&#xff0c;记得看清楚电脑操作系统是64还是32&#x…

《BI那点儿事》运用标准计分和离差——分析三国超一流统帅综合实力排名 绝对客观,数据说话...

数据分析基础概念&#xff1a;标准计分&#xff1a; 1、无论作为变量的满分为几分&#xff0c;其标准计分的平均数势必为0&#xff0c;而其标准差势必为1。2、无论作为变量的单位是什么&#xff0c;其标准计分的平均数势必为0&#xff0c;而其标准差势必为1。公式为&#xff1a…

天池 在线编程 最佳利用率(二分查找 + 哈希)

文章目录1. 题目2. 解题1. 题目 给两个排序的数组。 从两个数组中各取取一个数&#xff0c;这两个数之和需要小于或等于k&#xff0c; 需要找到两数之和最大的索引组合。 返回一对包含两个列表的索引。 如果有多个两数之和相等的索引答案&#xff0c;你应该选择第一个数组索引…

python re 匹配多行_Python正则表达式,看这一篇就够了

作者 | 猪哥来源 | 裸睡的猪(ID: IT--Pig)大多数编程语言的正则表达式设计都师从Perl&#xff0c;所以语法基本相似&#xff0c;不同的是每种语言都有自己的函数去支持正则&#xff0c;今天我们就来学习 Python中关于 正则表达式的函数。re模块主要定义了9个常量、12个函数、1个…

nsga2算法_用遗传算法进行容量管理 让虚拟机放置策略更优

随着互联网技术的高速发展&#xff0c;云计算已经成为各行各业的“水电煤”&#xff0c;成为“互联网”的基础设施&#xff0c;而数据中心则是云服务背后的刚性保障。无论是传统的数据中心&#xff0c;还是云形态的数据中心&#xff0c;虚拟化技术都是提升其资源利用率、降低管…

php预处理_如何用预处理让 PHP 更先进

原标题&#xff1a;如何用预处理让 PHP 更先进先来点趣事。不久以前&#xff0c; 来添加 Python 的 range 语法。然后&#xff0c; 大虾 &#xff0c;并且 建议为 PHP 添加 C# 风格的 getter 和 setter。我意识到对于一个局外人来说&#xff0c;建议和实现新的语言特性是件缓慢…

天池 在线编程 两句话中的不常见单词(哈希计数)

文章目录1. 题目2. 解题1. 题目 给定两个句子 A 和 B 。 &#xff08;句子是一串由空格分隔的单词。每个单词仅由小写字母组成。&#xff09; 如果一个单词在其中一个句子中只出现一次&#xff0c;在另一个句子中却没有出现&#xff0c;那么这个单词就是不常见的。 返回所有…

iphone屏幕上的圆圈怎么设置_iPhone手机屏幕突然变暗或者黑屏怎么办?看这里你就知道该怎么办...

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到各种有关娱乐的文章了。每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。 …

C语言库函数大全及应用实例六

C语言库函数大全及应用实例六 原文:C语言库函数大全及应用实例六[编程资料]C语言库函数大全及应用实例六函数名: getlinesettings 功 能: 取当前线型、模式和宽度 用 法: void far getlinesettings(struct linesettingstype far *lininfo): 程序例: <?xml:namespace prefix…

天池 在线编程 最小的行程(动态规划)

文章目录1. 题目2. 解题1. 题目 给定一个二维矩阵&#xff0c;找到从上到下的最小路径。只能向左下&#xff0c;下&#xff0c;右下移动 所有的元素都是正整数 矩阵大小 < 200x200 样例 1: 输入: 1 2 3 4 5 6 7 8 9 输出: 12 解释: 最短的路径为:1->4->7, 返回12.样…

fluent瞬态计算终止条件在哪里设置_Fluent案例7【圆柱绕流】

一个瞬态的圆柱绕流案例知识点&#xff1a;瞬态圆柱绕流的模拟一个后处理的方法&#xff1a;将瞬态模型中一个点的速度变化绘成图表并将数值导出excel文件模型如下图所示&#xff0c;左边界为速度边界进口速度0.5m/s&#xff0c;试模拟出计算域中的速度变化打开workbench&#…

qq登录界面句柄_别小看QQ邮箱测试,80%的测试新手都不能写出完整的测试用例~...

对于很多刚进入测试行业的新手来说&#xff0c;由于自身的工作经验不足&#xff0c;虽有测试基础知识傍身&#xff0c;但仍然很难将测试用例写的尽善尽美。因此&#xff0c;学习别人的测试经验&#xff0c;将是你成为测试达人的必经之路。今天&#xff0c;我们就以QQ邮箱为例&a…

LeetCode 878. 第 N 个神奇数字(二分查找)

文章目录1. 题目2. 解题1. 题目 如果正整数可以被 A 或 B 整除&#xff0c;那么它是神奇的。 返回第 N 个神奇数字。由于答案可能非常大&#xff0c;返回它模 10^9 7 的结果。 示例 1&#xff1a; 输入&#xff1a;N 1, A 2, B 3 输出&#xff1a;2示例 2&#xff1a; 输…

为什么百度统计里面的广告那么多_里面东西一模一样的桶装方便面为什么比袋装贵那么多?...

今天特地买了一桶桶装的和一袋袋装的&#xff0c;同品牌同系列同口味&#xff0c;里面面饼&#xff0c;配料包也一模一样&#xff0c;桶装的只是多了一个小勺子&#xff0c;为什么一袋二元五&#xff0c;一桶就要卖4元&#xff1f;并且大家好像都不觉得有什么不妥……(好吧我就…

LeetCode 1790. 仅执行一次字符串交换能否使两个字符串相等

文章目录1. 题目2. 解题1. 题目 给你长度相等的两个字符串 s1 和 s2 。 一次 字符串交换 操作的步骤如下&#xff1a;选出某个字符串中的两个下标&#xff08;不必不同&#xff09;&#xff0c;并交换这两个下标所对应的字符。 如果对 其中一个字符串 执行 最多一次字符串交换…

gradle 上传jar包_Gradle学习记录014 关于依赖的声明

详细学习Gradle构建的依赖声明。该学习记录基于Gradle官方网站资料。本篇参考链接如下&#xff1a;https://docs.gradle.org/current/userguide/declaring_dependencies.html声明一个模块作为依赖通常声明一个模块作为依赖&#xff0c;需要指定这个模块的版本。Gradle提供了一套…

win10版本查看_想知道电脑中安装的win10版本号,用这3招就对了,一键查看

自从微软在Windows 10中更改了发布模型后&#xff0c;很多用户就对找出他们在电脑上安装的Windows 10版本感兴趣。大家可能都已经知道&#xff0c;微软不会再发布Windows的主要版本&#xff0c;而是会不断发布更新&#xff0c;这让人想起许多Linux发行版的滚动发行模型。如果你…