日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

嵌入式linux学习笔记(2)

發(fā)布時間:2023/12/10 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌入式linux学习笔记(2) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

筆記目錄

  • 學(xué)習(xí)目標(biāo)
  • 學(xué)習(xí)內(nèi)容
    • 一、VI 編輯器的設(shè)置
      • 1、設(shè)置 TAB 鍵為 4 字節(jié)
      • 2、VIM 編輯器顯示行號
      • 3.VI/VIM 編輯器使用空格代替了 TAB 鍵
    • 二、存儲
      • 1、ROM
      • 2、RAM
      • 3、FLASH
    • 三、Makefile語法
      • 重要提醒
      • 1、Makefile作用
      • 2、Makefile 規(guī)則格式
      • 3、gcc命令
      • 4、Makefile 變量
    • 四、U-Boot
      • 1、U-Boot 簡介
      • 2、U-Boot編譯
      • 3、U-Boot 一些命令
      • 4、uboot啟動linux測試
        • 從emmc啟動
        • 從網(wǎng)絡(luò)啟動
          • 在ubuntu上搭建tftp服務(wù)器
          • 配置網(wǎng)絡(luò)
      • 5、U-Boot 頂層makefile部分
      • 6、U-Boot 圖形化配置
      • 7、uboot移植
    • 五、linux內(nèi)核
      • 1、linux內(nèi)核編譯
      • 2、重要的文件夾
    • 六、根文件系統(tǒng)
      • 1、根文件系統(tǒng)介紹
      • 2、根文件系統(tǒng)的目錄
      • 3、BusyBox
        • 編譯 busybox
          • busybox編譯
          • 向根文件系統(tǒng)添加 lib 庫
    • 七、Linux 驅(qū)動開發(fā)
      • 1.字符設(shè)備驅(qū)動
    • 八、設(shè)備樹
  • 學(xué)習(xí)時間
  • 學(xué)習(xí)產(chǎn)出

學(xué)習(xí)目標(biāo)

學(xué)習(xí)linux開發(fā)


學(xué)習(xí)內(nèi)容

一、VI 編輯器的設(shè)置

vi 打開文件/etc/vim/vimrc

1、設(shè)置 TAB 鍵為 4 字節(jié)

VI 編輯器默認(rèn) TAB 鍵為 8 空格,為了使代碼更好看我們改成 4 空格。
在此文件最后面輸入如下代碼:set ts=4

2、VIM 編輯器顯示行號

在此文件最后面輸入如下代碼:set nu

3.VI/VIM 編輯器使用空格代替了 TAB 鍵

在此文件最后面輸入如下代碼:set noexpandtab



二、存儲

1、ROM

ROM是只讀內(nèi)存,其特性是一旦儲存資料就無法再將之改變或刪除,存儲的資料不會因為電源關(guān)閉而消失。

2、RAM

RAM是隨機存儲,掉電不會保存數(shù)據(jù)。
??SRAM(靜態(tài)隨機訪問存儲器)不需要刷新電路即能保存它內(nèi)部存儲的數(shù)據(jù)
??DRAM (動態(tài)隨機訪問存儲器)只能將數(shù)據(jù)保持很短的時間。為了保持?jǐn)?shù)據(jù),DRAM使用電容存儲,所以 必須隔一段時間刷新(refresh)一次,如果存儲單元沒有被刷新,存儲的信息就會丟失。
??SDRAM(同步動態(tài)隨機訪問存儲器)同步是指 Memory工作需要同步時鐘,內(nèi)部的命令的發(fā)送與數(shù)據(jù)的傳輸都以它為基準(zhǔn)。傳統(tǒng)的DRAM在兩個讀周期之間需要等待一段時間,用于充電操作。而SDRAM一個模組有兩個bank,在對一個bank充電時,可以操作另一個bank,實現(xiàn)流水線。SDRAM的發(fā)展已經(jīng)經(jīng)歷了五代:分別是SDR SDRAM、 DDR SDRAM、 DDR2 SDRAM、 DDR3 SDRAM、 DDR4 SDRAM。

3、FLASH

FLASH 存儲器又稱閃存,它結(jié)合了ROM和RAM的長處,不僅具備電子可擦除可編程(EEPROM)的性能,還不會斷電丟失數(shù)據(jù)同時可以快速讀取數(shù)據(jù)(NVRAM 的優(yōu)勢)。

??NOR Flash和NAND Flash區(qū)別
????NOR的讀速度比NAND稍快一些。
????NAND的寫入速度比NOR快很多。
????NAND的4ms擦除速度遠(yuǎn)比NOR的5s快。
????大多數(shù)寫入操作需要先進(jìn)行擦除操作。
????NAND的擦除單元更小,相應(yīng)的擦除電路更少。


EMMC=NAND閃存+閃存控制芯片+標(biāo)準(zhǔn)接口封裝(對廠家而言簡化了電路設(shè)計,降低了成本。)
DDR屬于SDRAM
NANO FLASH屬于flash

使用emmc的好處是,除了得到大容量的空間(這一點,只用NAND FLASH多堆疊也可以做到),還有就是emmc可以管理NAND (壞塊處理,ECC,FFS)等。



三、Makefile語法

重要提醒

Makefile 里面是由一系列的規(guī)則組成的。
Makefile在編寫時不能使用空格只能用TAB鍵,否則會報錯。
Makefile:12: *** 遺漏分隔符 (null)。 停止。

1、Makefile作用

make 的執(zhí)行過程,make 工具就是在 Makefile 中一層一層的查找依賴關(guān)系,并執(zhí)行
相應(yīng)的命令。編譯出最終的可執(zhí)行文件。
Makefile 的好處就是“自動化編譯”,一旦寫好了 Makefile文件,以后只需要一個 make 命令即可完成整個工程的編譯,極大的提高了開發(fā)效率。

2、Makefile 規(guī)則格式

?目標(biāo)… : 依賴文件集合…
??命令 1
??命令 2
??…

3、gcc命令

gcc [選項] [文件名字]
?主要選項如下:
??-c:只編譯不鏈接為可執(zhí)行文件,編譯器將輸入的.c 文件編譯為.o 的目標(biāo)文件。
??-o:<輸出文件名> 用來指定編譯結(jié)束以后的輸出文件名,如果使用這個選項的話 GCC 默
認(rèn)編譯出來的可執(zhí)行文件名字為 a.out。
??-g:添加調(diào)試信息,如果要使用調(diào)試工具(如 GDB)的話就必須加入此選項,此選項指示編
譯的時候生成調(diào)試所需的符號信息。
??-O:對程序進(jìn)行優(yōu)化編譯,如果使用此選項的話整個源代碼在編譯、鏈接的的時候都會進(jìn)
行優(yōu)化,這樣產(chǎn)生的可執(zhí)行文件執(zhí)行效率就高。
??-O2:比-O 更幅度更大的優(yōu)化,生成的可執(zhí)行效率更高,但是整個編譯過程會很慢。

簡單的例程:

main: main.o input.o calcu.o #需要main.o input.o等文件生成maingcc -o main #編譯的最終目標(biāo)是生成一個可執(zhí)行文件main main.o: main.c #需要的main.o文件由main.c文件生成gcc -c main.c #編譯main.c生成main.o input.o: input.cgcc -c input.c calcu.o: calcu.cgcc -c calcu.cclean: #執(zhí)行make clean清理文件rm *.orm main

??在第一次編譯的時候由于 main 還不存在,因此第一條規(guī)則會執(zhí)行,第一條規(guī)則依賴于文件 main.o、 input.o 和 calcu.o這個三個.o 文件,這三個.o 文件目前還都沒有,因此必須先更新這三個文件。make 會查找以這三個.o 文件為目標(biāo)的規(guī)則并執(zhí)行。以 main.o 為例,發(fā)現(xiàn)更新 main.o 的是第二條規(guī)則,因此會執(zhí)行第二條規(guī)則,第二條規(guī)則里面的命令為“gcc –c main.c”,這行命令很熟悉了吧,就是不鏈接編譯 main.c,生成 main.o,其它兩個.o 文件同理。最后一個規(guī)則目標(biāo)是 clean,它沒有依賴文件,因此會默認(rèn)為依賴文件都是最新的,所以其對應(yīng)的命令不會執(zhí)行,當(dāng)我們想要執(zhí)行 clean 的話可以直接使用命令“make clean”,執(zhí)行以后就會刪除當(dāng)前目錄下所有的.o 文件以及 main。

4、Makefile 變量

Makefile 中變量的引用方法是"$(變量名)"
注釋"#"

#Makefile 變量的使用 objects = main.o input.o calcu.omain: $(objects) gcc -o main $(objects) 賦值符“?=”
變量追加“+=”


四、U-Boot

1、U-Boot 簡介


Linux 系統(tǒng)要啟動就必須需要一個 bootloader 程序,也就說芯片上電以后先運行一段bootloader 程序。這段 bootloader 程序會先初始化 DDR 等外設(shè),然后將 Linux 內(nèi)核從 flash(NAND,NOR FLASH,SD,MMC 等)拷貝到 DDR 中,最后啟動 Linux 內(nèi)核。

2、U-Boot編譯

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- (加空格) mx6ull_14x14_ddr512_emmc_defconfig make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12

ARCH=arm 設(shè)置目標(biāo)為 arm 架構(gòu),CROSS_COMPILE 指定所使用的交叉編譯器。
第一條命令相當(dāng)于“make distclean”,目的是清除工程,一般在第一次編譯的時候最好清理一下工程。
第二條指令相當(dāng)于“make mx6ull_14x14_ddr512_emmc_defconfig”,用于配置 uboot,配置文件為mx6ull_14x14_ddr512_emmc_defconfig。(14x14代表芯片的封裝大小)
最后一條指令相當(dāng)于 “make -j12”也就是使用 12 核來編譯 uboot。

在頂層的makefile輸入

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
可以make后面不用加
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

3、U-Boot 一些命令

uboot 命令中的數(shù)字都是十六進(jìn)制的!不是十進(jìn)制的!
進(jìn)入 uboot 的命令行模式

命令含義備注
help/?幫助help/?命令名
bdinfo查看板子信息DRAM 的起始地址和大小、啟動參數(shù)保存起始地址、波特率、sp(堆棧指針)起始地址等信息
printenv輸出環(huán)境變量信息
version查看 uboot 的版本號
setenv設(shè)置環(huán)境變量字符串中有空格需要使用單引號‘’將其括起來
saveenv保存修改的環(huán)境變量刪除一個環(huán)境變量只要給這個環(huán)境變量賦空值
md顯示內(nèi)存值md[.b, .w, .l] address [# of objects]命令中的[.b .w .l]對應(yīng) byte、word 和 long,也就是分別以 1 個字節(jié)、2 個字節(jié)、4 個字節(jié)來顯示內(nèi)存值。address 就是要查看的內(nèi)存起始地址,[# of objects]表示要查看的數(shù)據(jù)長度,這個數(shù)據(jù)長度單位不是字節(jié),而是跟你所選擇的顯示格式有關(guān)。(md.b 80000000 14)
nm修改指定地址的內(nèi)存值nm [.b, .w, .l] address(nm.l 80000000)
mm修改指定地址內(nèi)存值的使用 mm 修改內(nèi)存值的時候地址會自增,而使用命令 nm 的話地址不會自增
mw用于使用一個指定的數(shù)據(jù)填充一段內(nèi)存mw [.b, .w, .l] address value [count]mw 命令同樣可以以.b、.w 和.l 來指定操作格式, address 表示要填充的內(nèi)存起始地址, value為要填充的數(shù)據(jù), count 是填充的長度。
cp數(shù)據(jù)拷貝命令cp [.b, .w, .l] source target count cp 命令同樣可以以.b、.w 和.l 來指定操作格式,source 為源地址,target 為目的地址,count為拷貝的長度。
cmp比較兩段內(nèi)存的數(shù)據(jù)是否相等cmp [.b, .w, .l] addr1 addr2 count 其中cmp 命令同樣可以以.b、.w 和.l 來指定操作格式,addr1 為第一段內(nèi)存首地址,addr2 為第二段內(nèi)存首地址, count 為要比較的長度。
ipaddr開發(fā)板 ip 地址使用 dhcp 命令來從路由器獲取 IP 地址
ethaddr開發(fā)板的 MAC 地址一定要設(shè)置
gatewayip網(wǎng)關(guān)地址
netmask子網(wǎng)掩碼
serverip服務(wù)器 IP 地址,也就是 Ubuntu 主機 IP 地址用于調(diào)試代碼
ping測試開發(fā)板的網(wǎng)絡(luò)能否使用
dhcp用于從路由器獲取 IP 地址
nfs計算機之間通過網(wǎng)絡(luò)來分享資源nfs [loadAddress] [[hostIPaddr:]bootfilename]其中l(wèi)oadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename]是要下載的文件地址。分析

4、uboot啟動linux測試

從emmc啟動

emmc三個分區(qū),第一個分區(qū)存放uboot,第二個分區(qū)格式化成FAT文件系統(tǒng)在里面存放.dtb和zimage文件,第三個分區(qū)放根文件系統(tǒng)。

首先查看emmc里面是否有系統(tǒng),linux鏡像zimage和.dtb文件。先將當(dāng)前設(shè)備切換到emmc

mmc dev 1 //切換到EMMC fatls mmc 1:1 //查看EMMC分區(qū)1里面的文件 fatload mmc 1:1 80800000 zImage //將zimage下載到DDR的0x80800000 fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb //將dtb下載到DDR的0x83000000 bootz 80800000 - 83000000 //啟動內(nèi)核

如果內(nèi)核啟動成功,說明uboot支持emmc啟動,驗證成功。

從網(wǎng)絡(luò)啟動

tftp服務(wù)器
需要確定ubuntu的~/linux/tftpboot文件夾下有.dtb和zimage文件

在ubuntu上搭建tftp服務(wù)器

tftp 命令的作用和 nfs 命令一樣,都是用于通過網(wǎng)絡(luò)下載東西到 DRAM 中,只是 tftp 命令使用的 TFTP 協(xié)議,Ubuntu 主機作為 TFTP 服務(wù)器。因此需要在 Ubuntu 上搭建 TFTP 服務(wù)器,需要安裝 tftp-hpa 和 tftpd-hpa,命令如下:

sudo apt-get install tftp-hpa tftpd-hpa sudo apt-get install xinetd

和 NFS 一樣,TFTP 也需要一個文件夾來存放文件,在用戶目錄下新建一個目錄,命令如下:

mkdir /home/wyd/linux/tftpboot chmod 777 /home/wyd/linux/tftpboot

最后配置 tftp,安裝完成以后新建文件/etc/xinetd.d/tftp,如果沒有/etc/xinetd.d 目錄的話自行創(chuàng)建sudo vi /etc/xinetd.d/tftp,然后在里面輸入如下內(nèi)容:

service tftp {socket_type=dgramprotocol=udpwait=yesuser=rootserver=/usr/sbin/in.tftpdserver_args=-s /home/wyd/linux/tftpboot/disable=noper_source=11cps=100 2flags=IPv4}

sudo vi /etc/default/tftpd-hpa,然后在里面輸入如下內(nèi)容:

# /etc/default/tftpd-hpa TFTP_USERNAME="tftp" TFTP_DIRECTORY="/home/wyd/linux/tftpboot" TFTP_ADDRESS=":69" TFTP_OPTIONS="-1 -c -s"

最后輸入如下命令, 重啟 tftp 服務(wù)器:
sudo service tftpd-hpa restart
將 zImage 鏡像等文件拷貝到 tftpboot 文件夾中,并且給予 zImage 相應(yīng)的權(quán)限

cp zImage /home/wyd/linux/tftpboot/ cd /home/wyd/linux/tftpboot/ chmod 777 zImage chmod 777 tftpboot chmod 777 。。。。。

進(jìn)入 uboot 的命令行模式

tftp 80800000 zImage //將 tftpboot 文件夾里面的 zImage 文件下載到開發(fā)板 DRAM 的 0X80800000 地址處 tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb //將 tftpboot 文件夾里面的 dtb 文件下載到開發(fā)板 DRAM 的 83000000 地址處 bootz 80800000 - 83000000 //啟動內(nèi)核

設(shè)置 bootargs 和 bootcmd 這兩個環(huán)境變量,設(shè)置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw' setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000' saveenv

一開始是通過 tftp 下載 zImage 和 imx6ull-alientek-emmc.dtb 這兩個文件

配置網(wǎng)絡(luò)
setenv ipaddr 192.168.1.10 //開發(fā)板 IP 地址 setenv ethaddr 00:04:9f:04:d2:35 //開發(fā)板網(wǎng)卡 MAC 地址 setenv gatewayip 192.168.1.1 //開發(fā)板默認(rèn)網(wǎng)關(guān) setenv netmask 255.255.255.0//開發(fā)板子網(wǎng)掩碼 setenv serverip 192.168.1.6 //服務(wù)器地址,也就是 Ubuntu 地址(如果不是靜態(tài)地址可能需要長期更改) saveenv //保存環(huán)境變量

ping測試

=> ping 192.168.1.6Using FEC1 devicehost 192.168.1.6 is alive

5、U-Boot 頂層makefile部分

#版本號 VERSION = 2016 #主版本號 PATCHLEVEL = 03 #修補版本號 SUBLEVEL = #次版本號 EXTRAVERSION = #附加信息 NAME = #名字#隱含規(guī)則 #隱含規(guī)則則是內(nèi)建在make 中,為make 提供了重建某一類目標(biāo)文件(.o 等)的通用方法,同時這些隱含規(guī)則所用到的變量也就是所謂的隱含變量。 #隱含規(guī)則的好處是在Makefile 中不需要明確給出重建某一個目標(biāo)的命令,甚至可以不需要規(guī)則。make會為你自動搜尋匹配的隱含規(guī)則鏈。 #隱含規(guī)則的代價之一就是低效,系統(tǒng)必須搜索可能的隱含規(guī)則鏈。同時隱含規(guī)則也有可能應(yīng)用了不是你想要的規(guī)則而引入很難debug的錯誤。 #變量SHELLMAKEFLAGS一樣,默認(rèn)情況(沒有用“unexport”聲明)下在整個make的執(zhí)行過程中被自動的傳遞給所有的子make。 #“+=”來給變量 MAKEFLAGS 追加了一些值,-rR”表示禁止使用內(nèi)置的隱含規(guī)則和變量定義,--include-dir”指明搜索路徑,”$(CURDIR)”表示當(dāng)前目錄 MAKEFLAGS += -rR --include-dir=$(CURDIR) #CURDIR是make的內(nèi)嵌變量,自動設(shè)置為當(dāng)前目錄#export將變量傳遞到子make過程,unexport禁止將變量傳遞到子make過程。 #在locale環(huán)境中,有一組變量,代表國際化環(huán)境中的不同設(shè)置,"C"是系統(tǒng)默認(rèn)的locale: #LC_ALL是一個宏,如果該值設(shè)置了,則該值會覆蓋所有LC_*的設(shè)置值。注意,LANG的值不受該宏影響。 #LC_COLLATE定義該環(huán)境的排序和比較規(guī)則 #LC_NUMERIC非貨幣的數(shù)字顯示格式 unexport LC_ALL LC_COLLATE=C LC_NUMERIC=C export LC_COLLATE LC_NUMERIC# Avoid interference with shell env settings #根據(jù)注釋可以看到為了避免當(dāng)前shell環(huán)境變量對編譯的影響,去除grep的配置選項GREP_OPTIONS; unexport GREP_OPTIONS#輸入make -j12 V=1 打印詳細(xì)信息 #判斷V的代碼是不是來自于命令行 #origin 用于告訴你變量是哪來的 ifeq ("$(origin V)", "command line")KBUILD_VERBOSE = $(V) #如果是,KBUILD_VERBOSE=1 endif ifndef KBUILD_VERBOSEKBUILD_VERBOSE = 0 endififeq ($(KBUILD_VERBOSE),1) #如果 KBUILD_VERBOSE1quiet = #quiet和 Q 都為空Q = elsequiet=quiet_Q = @ #加 @ 命令不顯示在終端 endif# If the user is running make -s (silent mode), suppress echoing of # commands#make -s 靜默輸出#判斷當(dāng)前正在使用的編譯器版本號是否為 4.x#filter 是個過濾函數(shù),函數(shù)格式如下: #$(filter <pattern...>,<text>) #filter 函數(shù)表示以 pattern 模式過濾 text 字符串中的單詞,僅保留符合模式 pattern 的單詞, #可以有多個模式。函數(shù)返回值就是符合 pattern 的字符串。因此$(filter 4.%,$(MAKE_VERSION)) #的 含 義 就 是 在 字 符 串 “ MAKE_VERSION ” 中 找 出 符 合 “ 4.% ” 的 字 (% 為 通 配 符 ) , #MAKE_VERSION 是 make 工具的版本號, #ubuntu16.04 里面默認(rèn)自帶的 make 工具版本號為 4.1, ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4 #firstword 是獲取首單詞,函數(shù)格式如下: #$(firstword <text>) #firstword 函數(shù)用于取出 text 字符串中的第一個單詞,函數(shù)的返回值就是獲取到的單詞。 ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)quiet=silent_ endif else # make-3.8x ifneq ($(filter s% -s%,$(MAKEFLAGS)),)quiet=silent_ endif endif #導(dǎo)出 quiet Q KBUILD_VERBOSE export quiet Q KBUILD_VERBOSEifeq ($(KBUILD_SRC),)# OK, Make called in directory where kernel src resides # Do we want to locate output files in a separate directory? #make -O 指定輸出結(jié)果到某一個文件夾 ifeq ("$(origin O)", "command line")KBUILD_OUTPUT := $(O) endif# That's our default target when none is given on the command line PHONY := _all _all:# Cancel implicit rules on top Makefile $(CURDIR)/Makefile Makefile: ;ifneq ($(KBUILD_OUTPUT),) # Invoke a second make in the output directory, passing relevant variables # check that the output directory actually exists saved-output := $(KBUILD_OUTPUT) KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \&& /bin/pwd) $(if $(KBUILD_OUTPUT),, \$(error failed to create output directory "$(saved-output)"))PHONY += $(MAKECMDGOALS) sub-make$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make@:sub-make: FORCE$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))# Leave processing to above invocation of make skip-makefile := 1 endif # ifneq ($(KBUILD_OUTPUT),) endif # ifeq ($(KBUILD_SRC),)# We process the rest of the Makefile if this is the final invocation of make ifeq ($(skip-makefile),)# Do not print "Entering directory ...", # but we want to display it when entering to the output directory # so that IDEs/editors are able to understand relative filenames. MAKEFLAGS += --no-print-directory# Call a source code checker (by default, "sparse") as part of the # C compilation. # # Use 'make C=1' to enable checking of only re-compiled files. # Use 'make C=2' to enable checking of *all* source files, regardless # of whether they are re-compiled or not. # # See the file "Documentation/sparse.txt" for more details, including # where to get the "sparse" utility. #“make C=1”使能代碼檢查,檢查那些需要重新編譯的文件。 #“make C=2”用于檢查所有的源碼文件 ifeq ("$(origin C)", "command line")KBUILD_CHECKSRC = $(C) endif ifndef KBUILD_CHECKSRCKBUILD_CHECKSRC = 0 endif# Use make M=dir to specify directory of external module to build # Old syntax make ... SUBDIRS=$PWD is still supported # Setting the environment variable KBUILD_EXTMOD take precedence #編譯模塊 ifdef SUBDIRSKBUILD_EXTMOD ?= $(SUBDIRS) endififeq ("$(origin M)", "command line")KBUILD_EXTMOD := $(M) endif# If building an external module we do not care about the all: rule # but instead _all depend on modules PHONY += all ifeq ($(KBUILD_EXTMOD),) _all: all else _all: modules endififeq ($(KBUILD_SRC),)# building in the source treesrctree := . elseifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))# building in a subdirectory of the source treesrctree := ..elsesrctree := $(KBUILD_SRC)endif endif objtree := . src := $(srctree) obj := $(objtree)VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))#srctree 源碼路徑 export srctree objtree VPATH#打印變量便于調(diào)試 mytest:echo srctree=$(srctree)echo objtree=$(objtree) # Make sure CDPATH settings don't interfere unexport CDPATH######################################################################### #獲取主機架構(gòu)和系統(tǒng) HOSTARCH := $(shell uname -m | \sed -e s/i.86/x86/ \-e s/sun4u/sparc64/ \-e s/arm.*/arm/ \-e s/sa110/arm/ \-e s/ppc64/powerpc/ \-e s/ppc/powerpc/ \-e s/macppc/powerpc/\-e s/sh.*/sh/)HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \sed -e 's/\(cygwin\).*/cygwin/')export HOSTARCH HOSTOS########################################################################## set default to nothing for native builds #設(shè)置目標(biāo)架構(gòu)、交叉編譯器 ifeq ($(HOSTARCH),$(ARCH)) CROSS_COMPILE ?= endif################ ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf- #################設(shè)置配置文件 KCONFIG_CONFIG ?= .config export KCONFIG_CONFIG# SHELL used by kbuild CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \else if [ -x /bin/bash ]; then echo /bin/bash; \else echo sh; fi ; fi)HOSTCC = cc HOSTCXX = c++ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2ifeq ($(HOSTOS),cygwin) HOSTCFLAGS += -ansi endififeq ($(HOSTOS),darwin) # get major and minor product version (e.g. '10' and '6' for Snow Leopard) DARWIN_MAJOR_VERSION = $(shell sw_vers -productVersion | cut -f 1 -d '.') DARWIN_MINOR_VERSION = $(shell sw_vers -productVersion | cut -f 2 -d '.')os_x_before = $(shell if [ $(DARWIN_MAJOR_VERSION) -le $(1) -a \$(DARWIN_MINOR_VERSION) -le $(2) ] ; then echo "$(3)"; else echo "$(4)"; fi ;)# Snow Leopards build environment has no longer restrictions as described above HOSTCC = $(call os_x_before, 10, 5, "cc", "gcc") HOSTCFLAGS += $(call os_x_before, 10, 4, "-traditional-cpp") HOSTLDFLAGS += $(call os_x_before, 10, 5, "-multiply_defined suppress")# since Lion (10.7) ASLR is on by default, but we use linker generated lists # in some host tools which is a problem then ... so disable ASLR for these # tools HOSTLDFLAGS += $(call os_x_before, 10, 7, "", "-Xlinker -no_pie") endif# Decide whether to build built-in, modular, or both. # Normally, just do built-in.KBUILD_MODULES := KBUILD_BUILTIN := 1# If we have only "make modules", don't compile built-in objects. # When we're building modules with modversions, we need to consider # the built-in objects during the descend as well, in order to # make sure the checksums are up to date before we record them.ifeq ($(MAKECMDGOALS),modules)KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) endif# If we have "make <whatever> modules", compile modules # in addition to whatever we do anyway. # Just "make" or "make all" shall build modules as well# U-Boot does not need modules #ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) # KBUILD_MODULES := 1 #endif#ifeq ($(MAKECMDGOALS),) # KBUILD_MODULES := 1 #endifexport KBUILD_MODULES KBUILD_BUILTIN export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD# We need some generic definitions (do not try to remake the file). scripts/Kbuild.include: ; #用文件 scripts/Kbuild.include 這個文件 include scripts/Kbuild.include# Make variables (CC, etc...) #交叉編譯工具變量設(shè)置 AS = $(CROSS_COMPILE)as # Always use GNU ld ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),) LD = $(CROSS_COMPILE)ld.bfd else LD = $(CROSS_COMPILE)ld endif CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm LDR = $(CROSS_COMPILE)ldr STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump AWK = awk PERL = perl PYTHON = python DTC = dtc CHECK = sparseCHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \-Wbitwise -Wno-return-void -D__CHECK_ENDIAN__ $(CF)KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__KBUILD_CFLAGS := -Wall -Wstrict-prototypes \-Wno-format-security \-fno-builtin -ffreestanding KBUILD_AFLAGS := -D__ASSEMBLY__# Read UBOOTRELEASE from include/config/uboot.release (if it exists) UBOOTRELEASE = $(shell cat include/config/uboot.release 2> /dev/null) UBOOTVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION #架構(gòu)(arm)cpu(arm7)板卡(mx6ullevk)供應(yīng)商(freescale)soc(mx6) cpu文件所處的目錄 板子配置信息所處目錄 #config.mk定義變量 export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC export CPP AR NM LDR STRIP OBJCOPY OBJDUMP export MAKE AWK PERL PYTHON export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGSexport KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS export KBUILD_CFLAGS KBUILD_AFLAGS# When compiling out-of-tree modules, put MODVERDIR in the module # tree rather than in the kernel tree. The kernel tree might # even be read-only. export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions# Files to ignore in find ... statementsexport RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \-name CVS -o -name .pc -o -name .hg -o -name .git \) \-prune -o export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \--exclude CVS --exclude .pc --exclude .hg --exclude .git

6、U-Boot 圖形化配置

menuconfig是一套圖形化的配置工具,需要 ncurses 庫支持。ncurses 庫提供了一系列的 API 函數(shù)供調(diào)用者
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev

在uboot源碼的根目錄下輸入命令打開圖形化窗口
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
如果要將某個功能編譯為模塊,那就按下“M”,此時“[ ]”就會變?yōu)椤?lt; M >。

設(shè)置完成后需要重新編譯
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

7、uboot移植

uboot的燒寫有兩種方法,一種是燒寫到SD卡,一種是燒寫到EMMC中(也需要用到SD卡)。

下載NXP的uboot(NXP有一個例程板卡,仿照那個板卡改自己的板子)
編譯NXP的uboot

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16

需要將SD卡格式化成FAT32的格式。
(正點原子專門編寫了一個軟件來將編譯出來的.bin 文件燒寫到 SD 卡中,這個軟件叫做“imxdownload”,軟件放到了開發(fā)板光盤中,路徑為:開發(fā)板光盤->5、開發(fā)工具->2、Ubuntu 下裸機燒寫軟件->imxdownload,imxdownlaod 只能在 Ubuntu 下使用。)
將imxdownlaod拷貝到工程根目錄下。
確定要燒寫的 SD 卡(ls /dev/sd*(我的是/dev/sdb))
使用 imxdownload 軟件將 u-boot.bin燒寫到 SD 卡中。

chmod 777 imxdownload //給予 imxdownload 可執(zhí)行權(quán)限 ./imxdownload u-boot.bin /dev/sdb //燒寫 u-boot.bin 到 SD 卡中

五、linux內(nèi)核

1、linux內(nèi)核編譯

需要下載lzop庫,用于打包和加載zimage
sudo apt-get install lzop

編譯內(nèi)核

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distcleanmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfigmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfigmake ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

編譯完成以后就會在 arch/arm/boot 這個目錄下生成一個叫做 zImage 的文件,zImage 就是我們要用的 Linux 鏡像文件。另外也會在 arch/arm/boot/dts 下生成很多.dtb 文件(imx6ull-alientek-emmc.dtb),這些.dtb 就是設(shè)備樹文件。

2、重要的文件夾

名字描述
arch架構(gòu)相關(guān)目錄名
block塊設(shè)備相關(guān)目錄
crypto加密相關(guān)目錄
Documentation文檔相關(guān)目錄
drivers驅(qū)動相關(guān)目錄
firmeare固件相關(guān)目錄
fs文件系統(tǒng)相關(guān)目錄
include頭文件相關(guān)目錄
init初始化相關(guān)目錄
ipc進(jìn)程間通信相關(guān)目錄
kernel內(nèi)核相關(guān)目錄
lib庫相關(guān)目錄
mm內(nèi)存管理相關(guān)目錄
net網(wǎng)絡(luò)相關(guān)目錄
samples例程相關(guān)目錄
scripts腳本相關(guān)目錄
security安全相關(guān)目錄
sound音頻處理相關(guān)目錄
tools工具相關(guān)目錄
usr與 initramfs 相關(guān)的目錄,用于生成initramfs
virt提供虛擬機技術(shù)(KVM)

linux頂層的makefile和uboot非常相似



六、根文件系統(tǒng)

1、根文件系統(tǒng)介紹

根文件系統(tǒng)首先是內(nèi)核啟動時所 mount(掛載)的第一個文件系統(tǒng),內(nèi)核代碼映像文件保存在根文件系統(tǒng)中,而系統(tǒng)引導(dǎo)啟動程序會在根文件系統(tǒng)掛載之后從中把一些基本的初始化腳本和服務(wù)等加載到內(nèi)存中去運行。

2、根文件系統(tǒng)的目錄

名字描述
/bin系統(tǒng)需要的可執(zhí)行文件(ls rm…)
/dev設(shè)備文 件(串口…)
/etc存放配置文件目錄
/mnt臨時掛載目錄,可以將 SD 卡或者 U 盤掛載到/mnt/sd 或者/mnt/usb 目錄中
/proc臨時掛載目錄,存儲系統(tǒng)運行信息文件
/usr軟件資源目錄
/var此目錄存放一些可以改變的數(shù)據(jù)
/sbin用戶存放一些可執(zhí)行文件
/sys系統(tǒng)啟動以后此目錄作為 sysfs 文件系統(tǒng)的掛載點,sysfs 是一個類似于 proc 文件系統(tǒng)的特殊文件系統(tǒng),sysfs 也是基于 ram 的文件系統(tǒng),也就是說它也沒有實際的存儲設(shè)備。此目錄是系統(tǒng)設(shè)備管理的重要目錄,此目錄通過一定的組織結(jié)構(gòu)向用戶提供詳細(xì)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)信息。
/opt可選的文件、軟件存放區(qū)(由用戶決定)

3、BusyBox

BusyBox 是一個集成了大量的 Linux 命令和工具的軟件,像 ls、mv、ifconfig 等命令 BusyBox 都會提供。BusyBox 就是一個大的工具箱,這個工具箱里面集成了 Linux 的許多工具和命令。

編譯 busybox

busybox編譯

make //將編譯的結(jié)果放入/home/wyd/linux/mnt/rootfs文件夾下
make install CONFIG_PREFIX=/home/wyd/linux/mnt/rootfs

編譯完成以后會在 busybox 的所有工具和文件就會被安裝到 rootfs 目錄中, rootfs 目錄內(nèi)容有:bin linuxrc sbin usr。

Linux 內(nèi)核 init 進(jìn)程最后會查找用戶空間的 init 程序,找到以后就會運行這個用戶空間的 init 程序,從而切換到用戶態(tài)。如果 bootargs 設(shè)置 init=/linuxrc,那么 linuxrc 就是可以作為用戶空間的 init 程序,所以用戶態(tài)空間的 init 程序是 busybox 來生成的。busybox 的工作就完成了,但是此時的根文件系統(tǒng)還不能使用,還需要一些其他的文件。

向根文件系統(tǒng)添加 lib 庫

在 rootfs 中創(chuàng)建一個名為“l(fā)ib”的文件夾 mkdir lib
將交叉編譯器的庫文件放到根文件系統(tǒng)中。

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib //*so*(*是通配符)和.a 文件,這些就是庫文件 “-d”表示拷貝符號鏈接 cp *so* *.a /home/wyd/linux/mnt/rootfs/lib/ -d

cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib

mkdir dev proc mnt sys tmp root

setenv bootargs ‘console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.250(服務(wù)器ip地址ubuntu):
/home/wyd/linux/nfs/rootfs,proto=tcp rw ip=192.168.1.251(開發(fā)板):192.168.1.250(服務(wù)器ip地址ubuntu):192.168.1.1:
255.255.255.0::eth0:off’ //設(shè)置 bootargs


七、Linux 驅(qū)動開發(fā)

1.字符設(shè)備驅(qū)動

字符設(shè)備是 Linux 驅(qū)動中最基本的一類設(shè)備驅(qū)動,字符設(shè)備就是一個一個字節(jié),按照字節(jié)
流進(jìn)行讀寫操作的設(shè)備,讀寫數(shù)據(jù)是分先后順序的。比如我們最常見的點燈、按鍵、IIC、SPI,
LCD 等等都是字符設(shè)備,這些設(shè)備的驅(qū)動就叫做字符設(shè)備驅(qū)動。

Linux 驅(qū)動有兩種運行方式,第一種就是將驅(qū)動編譯進(jìn) Linux 內(nèi)核中,這樣當(dāng) Linux 內(nèi)核啟
動的時候就會自動運行驅(qū)動程序。第二種就是將驅(qū)動編譯成模塊(Linux 下模塊擴展名為.ko),在
Linux 內(nèi)核啟動以后使用“insmod”命令加載驅(qū)動模塊。

模塊有加載和卸載兩種操作,我們在編寫驅(qū)動的時候需要注冊這兩種操作函數(shù),模塊的加載和
卸載注冊函數(shù)如下:

module_init(xxx_init); //注冊模塊加載函數(shù) module_exit(xxx_exit); //注冊模塊卸載函數(shù)

printk在內(nèi)核源碼中用來記錄日志信息的函數(shù),只能在內(nèi)核源碼范圍內(nèi)使用。用法和printf非常相似

.ko文件是kernel object文件(內(nèi)核模塊),該文件的意義就是把內(nèi)核的一些功能移動到內(nèi)核外邊, 需要的時候插入內(nèi)核,不需要時卸載。
insmod xxx.ko 裝載驅(qū)動
modprobe xxx.ko 裝載驅(qū)動
cat /proc/device
lsmod 內(nèi)核中已經(jīng)加載的設(shè)備程序
rmmod 驅(qū)動設(shè)備名稱 卸載驅(qū)動

八、設(shè)備樹

設(shè)備樹(Device Tree),將這個詞分開就是“設(shè)備”和“樹”,描述設(shè)備樹的文件叫做 DTS(Device
Tree Source),這個 DTS 文件采用樹形結(jié)構(gòu)描述板級設(shè)備,也就是開發(fā)板上的設(shè)備信息,比如
CPU 數(shù)量、 內(nèi)存基地址、IIC 接口上接了哪些設(shè)備、SPI 接口上接了哪些設(shè)備等等。

DTS 是設(shè)備樹源碼文件,DTB 是將DTS 編譯以后得到的二進(jìn)制文件。
將.dts 編譯為.dtb需要用到 DTC 工具

編譯 DTS 文件的話只需要進(jìn)入到 Linux 源碼根目錄下,然后執(zhí)行如下命令:
make all或者:make dtbs
“make all”命令是編譯 Linux 源碼中的所有東西,包括 zImage,.ko 驅(qū)動模塊以及設(shè)備樹,如果只是編譯設(shè)備樹的話建議使用“make dtbs”命令。

DTS 語法
.dtsi 頭文件:設(shè)備樹的頭文件擴展名為.dtsi,一般.dtsi 文件用于描述 SOC 的內(nèi)部外設(shè)信息,比如 CPU 架構(gòu)、主頻、外設(shè)寄存器地址范圍,比如 UART、IIC 等等。

設(shè)備節(jié)點:設(shè)備樹是采用樹形結(jié)構(gòu)來描述板子上的設(shè)備信息的文件,每個設(shè)備都是一個節(jié)點,叫做設(shè)備節(jié)點,每個節(jié)點都通過一些屬性信息來描述節(jié)點信息,屬性就是鍵—值對。

節(jié)點標(biāo)簽(label) :節(jié)點名字(節(jié)點名字@首地址)
節(jié)點標(biāo)簽可以用來給節(jié)點追加信息。
例如:

/ {aliases {can0 = &flexcan1;};cpus {#address-cells = <1>;#size-cells = <0>;cpu0: cpu@0 {compatible = "arm,cortex-a7";device_type = "cpu";reg = <0>;};};intc: interrupt-controller@00a01000 {compatible = "arm,cortex-a7-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0x00a01000 0x1000>,<0x00a02000 0x100>;}; }

每個節(jié)點都有不同屬性,不同的屬性又有不同的內(nèi)容,屬性都是鍵值對,值可為空或任意的字節(jié)流。設(shè)備樹源碼中常用的幾種數(shù)據(jù)形式如下所示:
1、字符串
compatible = “arm,cortex-a7”;
2、32 位無符號整數(shù)
reg = <0>;
也可以設(shè)置為一組值,比如:
reg = <0 0x123456 100>;
3、字符串列表
屬性值也可以為字符串列表,字符串和字符串之間采用“,”隔開,如下所示:
compatible = “fsl,imx6ull-gpmi-nand”, “fsl, imx6ul-gpmi-nand”;

compatible 屬性
compatible 屬性也叫做“兼容性”屬性,compatible 屬性的值是一個字符串列表,compatible 屬性用于將設(shè)備和驅(qū)動綁定起來。一般驅(qū)動程序文件都會有一個 OF 匹配表,此 OF 匹配表保存著一些 compatible 值,如果設(shè)備節(jié)點的compatible 屬性值和 OF 匹配表中的任何一個值相等,那么就表示設(shè)備可以用這個驅(qū)動。

model 屬性
model 屬性值也是一個字符串,一般 model 屬性描述設(shè)備模塊信息,比如名字之類的。

status 屬性
status 屬性看名字就知道是和設(shè)備狀態(tài)有關(guān)的,status 屬性值是字符串,字符串是設(shè)備的狀態(tài)信息。常用的是“okay”和“disabled”
“okay”表明設(shè)備是可操作的。
“disabled” 表明設(shè)備當(dāng)前是不可操作的,但是在未來可以變?yōu)榭刹僮鞯?比如熱插拔設(shè)備插入以后。至于 disabled 的具體含義還要看設(shè)備的綁定文檔。

#address-cells 和#size-cells 屬性
這兩個屬性的值都是無符號 32 位整形,#address-cells 和#size-cells 這兩個屬性可以用在任何擁有子節(jié)點的設(shè)備中,用于描述子節(jié)點的地址信息。 #address-cells 屬性值決定了子節(jié)點 reg 屬性中地址信息所占用的字長(32位)
#size-cells 屬性值決定了子節(jié)點 reg 屬性中長度信息所占的字長(32位)。
#address-cells 和#size-cells 表明了子節(jié)點應(yīng)該如何編寫 reg 屬性值,一般 reg 屬性都是和地址有關(guān)的內(nèi)容,和地址相關(guān)的信息有兩種:起始地址和地址長度。

reg 屬性
reg 屬性的值一般是(address,length),reg 屬性一般用于描述設(shè)備地址空間資源信息,一般都是某個外設(shè)的寄存器地址范圍信息。
reg 屬性的格式一為:reg = <address1 length1 address2 length2 address3 length3......>
每個“address length”組合表示一個地址范圍,其中 address 是起始地址,length 是地址長度,#address-cells 表明 address 這個數(shù)據(jù)所占用的字長,#size-cells 表明 length 這個數(shù)據(jù)所占用的字長。

開發(fā)板查看設(shè)備樹:/proc/device-tree
cd /lib/modules/4.1.15-gb78e551/

root@ATK-IMX6U:~# cp /mnt/gpioled.ko /lib/modules/4.1.15-gb78e551/
root@ATK-IMX6U:~# cp /mnt/ledApp /lib/modules/4.1.15-gb78e551/
cd /lib/modules/4.1.15-gb78e551/

depmod: ERROR: could not open directory /lib/modules/4.1.15-g871ccc8: No such file or directory
depmod: FATAL: could not search modules: No such file or directory

學(xué)習(xí)時間

2021.4-2021.10


學(xué)習(xí)產(chǎn)出

1、 csdn筆記 1篇

總結(jié)

以上是生活随笔為你收集整理的嵌入式linux学习笔记(2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。