1. 程式人生 > >如何為BBB製作cape(或:如何在系統啟動時自動載入dtbo)

如何為BBB製作cape(或:如何在系統啟動時自動載入dtbo)

原文地址:bbs.eeworld.com.cn/thread-432698-1-1.html,感覺有用先存著,感謝作者分享!

如果你買來BBB是為了搞跟硬體相關的專案,那你八成需要製作一個cape。cape是BBB官方的叫法,其實就是指BBB的軟體和硬體外設。通過學習device tree我們瞭解到BBB是使用capemgr和device tree來控制cape的,通過向$SLOTS傳入dtbo檔案來載入某個cape,像這樣:

  1. echo BB-ADC > $SLOTS
複製程式碼 但有時候我們不想每次都手動輸入這樣一條命令來啟用某個cape,而是想讓它開機自動啟動。這時就需要用到本文講的內容了。

要做到開機自動啟動,你只需要增加一個eeprom(官方推薦的型號是CAT24C256),並把它接到特定的引腳上,裡面寫上符合規定格式的內容就行了。系統在啟動時會檢查特定引腳上有沒有符合規定格式的eeprom,如果有的話,就按照eeprom裡面的內容自動載入相應的dtbo檔案。

還記得我們 cat $SLOTS 看到了什麼嗎?
  1. cat /sys/devices/bone_capemgr.*/slots  
  2. 0: 54:PF---   
  3. 1: 55:PF---   
  4. 2: 56:PF---   
  5. 3: 57:PF---   
  6. 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G  
  7. 5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
複製程式碼 這裡前4項為什麼是空的呢?因為它們就是給那些有EEPROM的實體cape預留的位置。不難看出,這樣的實體cape最多隻能插4個。

二、eeprom的連線




這裡的知識比較零散,我將分點闡述:
  • eeprom的地址必須在0x54到0x57之間,否則系統不會載入。
    科普一下:不管什麼牌子的eeprom晶片,它們的地址都是一樣的,高4位是1010,低3位對應著晶片的A2,A1,A0這3個引腳的電平(有的晶片只有A1和A0),所以通過外接電路就能改變eeprom的地址。也就是說eeprom的地址只可能是0x50到0x57這8種,如果A2保持高電平,那麼就只有0x54到0x57這4個地址可用了(這就是SRM(BBB官方參考手冊)裡eeprom電路中把A2接高電平的原因。
  • eeprom必須連線到BBB的I2C2_SCL和I2C2_SDA引腳上(在系統中看到的是i2c-1)。因為I2C2這兩個引腳的預設功能就是i2c功能。這也告訴我們,程式中儘量不要永久改變這兩個引腳的功能複用,否則就沒法載入cape了。
  • BBB最多隻支援同時插4個eeprom,它們的地址必須互不相同
  • 如果一次插入多個eeprom,會依次讀取之。準確來說,讀取順序就是從0x54到0x57的順序。為什麼如此強調overlay的載入順序呢?因為一旦前面載入的overlay佔用了某些片上資源,其他overlay就不能再用了。比如我要做的LCD使用的引腳跟預設載入的HDMI用的引腳是有重疊的,當系統啟動時首先載入了LCD的overlay,那麼HDMI就不能再載入了。
  • eeprom上WP引腳是防寫用的,一旦上拉,就不能進行寫入了。所以自己做電路的時候可以把它懸空或者拉低。

三、eeprom的讀寫

下面先介紹如何進行讀寫,再介紹該寫入什麼東西。

首先確定eeprom的地址。由A0,A1,A2三個引腳的電平確,按照上面剛剛說的,比如我把A0,A1接地,A2拉高,地址就是0x54。

然後在命令列操作:
  1. cd /sys/bus/i2c/devices/1-0054/  #到eeprom目錄中  
  2. cat eeprom | hexdump -C  #讀取eeprom內容並以字元形式顯示  
  3. echo -e "\xaa\x55\x33\xeeA1Beaglebone LCD4 Cape\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0000A1BeagleboardToys\x00BB-BONE-LCD4-01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" > eeprom  #寫入內容  
  4. cat eeprom | hexdump -C  #確認是否寫入成功  
複製程式碼 其中\x開頭的字元代表按ASCII碼值寫入。上面就寫入了官方LCD4 cape的eeprom內容。如果你想自制LCD cape,使用的LCD面板引數跟官方的一樣的話,那麼系統使用的驅動程式就是一樣的,所以就可以直接用上面的eeprom內容載入BBB自帶的dtbo檔案了,就不必自己重寫dtbo檔案了。

寫入內容時,要按照SRM裡的標準(如下圖),最重要的是要把頭6個位元組\xaa\x55\x33\xeeA1以及後面的版本號00A1和要呼叫的dtbo檔名BB-BONE-LCD4-01寫對,其他的比Number of Pins什麼的都無所謂。空餘的地方必須用\x00補全,用其他字元會產生錯誤。



經過上面的方法配置好eeprom後,系統就能在啟動時自動載入對應的dtbo檔案了。但是這裡還是再強調一下dts檔案編寫的注意事項。

四、編寫dts檔案的注意事項

  • 檔名必須是 boardname-version.dts 的形式,比如 BB-BONE-LCD4-01-00A0.dts。這裡面BB-BONE-LCD4-01就是boardname,00A0就是version號。(其實dts的名字無所謂了。。關鍵是編譯出來的dtbo名字必須是它,為了統一,就都這麼規定吧)。
  • version必須是00AX的形式,X從0開始按版本依次增加,而且,想命名00A1,必須有00A0的存在才行!不能跨越版本
  • dts檔案裡面會有part-number和version這兩項,其內容必須跟檔名相符!part-number就是boardname。
  • 編譯完的dtbo檔案必須放到 /lib/firmware/ 目錄中才可以載入。

OK,上面介紹了所有cape通用的內容。具體某個cape需要載入特定的驅動,那就是如何寫dts檔案和配置驅動的問題了,在此就不做討論啦。

五、其實不用eeprom也能做——uEnv.txt

其實不用eeprom的話,也可以通過修改uEnv.txt檔案來實現自動載入dtbo檔案。USB連線好BBB以後在電腦裡會出現一個碟符,裡面有一個叫做uEnv.txt的檔案。通過它可以設定系統啟動時載入或禁止載入的dtbo。比如我想在系統啟載入BB-ADC。我們就可以開啟它,在下面新增一行:
  1. optargs=quiet capemgr.enable_partno=BB-ADC
複製程式碼 然後安全彈出這個碟符,重啟BBB就行啦。

我們知道BBB啟動會自動載入HDMI,而HDMI與LCD公用了部分引腳。如果我們想啟動後再插上LCD,然後 echo BB-BONE-LCD4-01 > $SLOTS 來載入LCD cape的話,會提示你File exists,就是因為HDMI已經首先載入了,那些引腳就不能再動了。但我們可以配置uEnv.txt使得啟動時不自動載入HDMI,方法是在uEnv.txt中新增一行:
  1. optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
複製程式碼 就OK啦。

注意,如果想同時實現上面兩個,即禁用HDMI並載入ADC的話,不能簡簡單單把上面兩句話寫進去,應該合併成一句話:
  1. optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN capemgr.enable_partno=BB-ADC
複製程式碼 否則會失敗。

所以,使用eeprom的意義就在於方便啦。什麼也不用配置,買回來插上就能用。如果你愛折騰的話,那麼實現方法就多了去啦。
六、其實不用eeprom也能做——systemd

上面說的修改uEnv.txt的方法其實跟用eeprom的效果是差不多的——一個不能用的話另一個也不能用= =!

6月的Angstrom系統(終端輸入 uname -a 檢視你的BBB裡裝的是哪個版本的系統)有bug,如果你自己編譯了一個dtbo檔案,即便放進 /lib/firmware 目錄下也不能自動載入(/lib/firmware裡原本就有的可以載入是因為它們已經被編譯進核心了)。所以除非你自己編譯一遍系統,否則不能用這個辦法在啟動時自動載入自己的cape。剛說了用uEnv.txt跟用eeprom差不多……所以也不行。

9月的Angstrom系統稍微修改了這個bug,但還是不好用——系統啟動時會在載入cape那步停留60秒才繼續……本來Angstrom是以啟動速度快見長的,只需10秒。這一下拖了太多後腿了。(而且9月的Angstrom系統增添了新的bug——LCD電阻觸控式螢幕指標會漂移!想自己解決這個問題當然依舊只能重新編譯系統——不是每個人都有耐心編譯系統玩的!所以即便它是新系統,我還是果斷使用6月的吧,至少觸控式螢幕正常。)

總之,無論哪個版本的Angstrom系統,eeprom和uEnv.txt法都不太好使,下面就介紹一個完全不同的招數:使用systemd。

Step by step教學:

Step 1.
在/etc/systemd/system目錄下新建一個檔案,命名mystartup.service(名字可以自定),內容如下:
  1. [Unit]
  2. Description=My script
  3. [Service]
  4. ExecStart=/home/root/mystartup.sh
  5. [Install]
  6. WantedBy=multi-user.target
複製程式碼 Description是寫給自己看的註釋,可以隨便寫。mystartup.sh是要啟動時自動執行的指令碼。
注意:不能寫成ExecStart=/bin/sh /path/to/script.sh這樣的,直接按上面給出的例子寫就好了。

Step 2.
然後在 /home/root 目錄新建一個mystartup.sh,內容如下:
  1. #!/bin/sh
  2. echo BB-YOUR-CAPE > /sys/devices/bone_capemgr.8/slots
複製程式碼 注意:
1、這裡必須用sh指令碼,不能用bash指令碼。
2、sh指令碼中不能使用bone_capemgr.*這樣的萬用字元,必須是bone_capemgr.8或者.9(根據你的系統來寫)
3、當然,dtbo檔案還是必須得放在 /lib/firmware 下才行。

Step 3.
最後執行命令:
  1. systemctl enable myscript.service
複製程式碼 就可以了。重啟BBB會發現成功載入了dtbo。

如果你執行dmesg | grep capemgr,會發現載入dtbo的時間點跟用eeprom或uEnv.txt不同,所以跟啟動以後手動輸入 echo 命令的效果類似。

七、結束

我當然推薦第六種方法。預計在找到更好的辦法之前,這就是我將來在Development Kit裡採用的辦法了。想要使用我的Kit的話建議掌握這個小技巧。

最後這句寫給能看懂的人,看不懂就不必深究了:crontab @reboot 在BBB的Angstrom裡不好使,不用嘗試了。似乎會被系統kill掉。