[紀錄] Raspberry Pi社群聚會 #28 會後資料(樹莓派上的台灣創新專案)

第二十八次 Raspberry Pi 社群聚會會後資料,希望透過社群活動的分享和交流,找到更多 Raspberry Pi 的可能。本次主題是「樹莓派上的台灣創新專案」。過往資訊可看共筆,報名可到 KKTIX

樹莓派自 2012 年問世後,歷經多次改版,最新的型號是 Pi 4。一開始是在教育用途上,但現在許多商用領域也可以看見樹莓派的身影。台灣也有許多公司使用樹莓派做專案或是做產品,這次的聚會有兩家台灣新創團隊分享了他們在樹莓派上的應用。

天瓏書局 2F Coding Space
這次主題吸引很多同好來瞭解技術細節,天瓏書局 2F Coding Space 又被我們擠爆了。

Swind
第一位是 CloudMosa 的 Swind,負責軟體測試開發。

CloudMosa
CloudMosa 沈修平博士在 2009 年創立,目前公司的主要開發人員在台北。

CloudMosa Products
Puffin Web Browser 是 CloudMosa 的主要產品,是一個專注在手機上的網頁瀏覽器應用程式,目前全球累積一億的下載量,DAU(Daily Active User, 日活躍使用者)有兩百萬人。而 Puffin Internet Terminal 將是今天要介紹的主題。

Puffin OS
除了 Puffin Web Browser 和主打教育市場的 Puffin Internet Terminal 以外,CloudMosa 正在做可以跑在手機上的 Puffin OS ,希望能讓低階手機更為普及,彌平世界數位落差。

Puffin Internet Terminal
Puffin Internet Terminal 是一個瀏覽器的解決方案。能讓 Raspberry Pi 3 Model B+($35)的瀏覽網頁體驗可以媲美要價上千元 ChromeBook,並降低使用網路取得資訊的門檻。
由於學校單位大量使用 Adobe Flash 技術,Puffin Internet Terminal 可以跨平台和跨瀏覽器的特性讓許多教育單位採用。

Benchmark
由於越來越多的應用程式是以網頁(Web)的方式呈現,因此 Puffin Internet Terminal 的高效能也是主打特色之一。Swind 也展示了和 Chromium 的效能比較,是使用 JetStream 做評比,分數越高越好。

Why Puffin is fast?
為什麼 Puffin Internet Terminal 可以這麼快? 這其實是 CloudMosa 累積了多年的軟體工程能量達成的。簡單說可分為這三個部份。
1. 大幅降低 Client(和樹莓派) 端運算需求。
2. 節省大約 70% 資料傳輸量。
3. 強大且快速的伺服器與網路。

Puffin architecture
要介紹 Puffin Internet Terminal 就直接介紹 Puffin Browser,兩者在架構上是一樣的。Puffin Browser 的架構是,用戶端(Browser)不會直接連到 Web Server,而是透過 Puffin Cloud Server 向 Web Server 做請求,再回傳到用戶端。這樣的技術似乎和 Proxy 很像,但 Proxy 雖然會做快取(cache)或是壓縮,但並不會幫忙做運算,因此傳回到用戶端的資料還是需要用戶端即時運算顯示。這樣的問題是現行的網頁特效很多,如果將運算都移到用戶端,那用戶端的裝置需要在一定的規格以上才能有良好體驗。

Remote browser
所以 Puffin Browser 就像是一個 Remote Browser,幫用戶端在 Puffin Cloud Server 運算完畢後再將運算結果回傳。也因為雲端已經做完運算,等於節省用戶手機上的運算流量,幫沒有網路吃到飽方案的用戶省下費用。

Puffin Cloud Server
Puffin Browser 能跑得這麼快的第二個原因是歸功於 Puffin Cloud Server 的佈建。CloudMosa 目前有三個資料中心(Data Center),近萬台獨立的中高階實體伺服器與擁有近萬個 Public IP,這樣就可以快速的和全球各地的網頁伺服器進行高速傳輸。
除了架設伺服器做 remote browser 以外,Puffin Browser 可以用資料中心超快的網路去 Web Server 取得資料,還能因此大量減少 Client 與 Server 之間 資料傳輸的次數以及傳輸量,達到快速的回應時間。

Optimal for Raspberry Pi
而 Puffin Internet Terminal 針對 Raspberry Pi 的優化包括有。
1. 因為效能考量而不使用 Windows 版本正在用的 React Native,改使用 GTK 重新開發。
2. 支援 Raspberry Pi 的 GPU。

Brian
大家對於 Puffin Internet Terminal 後端的運作原理非常感興趣,對資源分配與安全性等都提出相關問題。因此 CloudMosa 的 Brian 在 QA 時間也回答了許多技術細節。

Puffin Internet Terminal 採取訂閱製,現在正在大特價,每個月只要 USD$1 就可以讓你的 Pi 快速和安全,非常適合學校單位、國安單位、軍方單位使用。

當 Puffin 瀏覽器跑在 Raspberry Pi 上 Puffin Internet Terminal 的投影片

 

Bofu
第二位來分享的講者是 DT42 的技術長 Bofu。

DT42
DT42 成立於 2015 年,是由一群對數據分析、深度學習與運算系統充滿熱忱的資訊工程師與數據工程師組成的合作團隊,團隊成員均曾於軟體開發、影像辨識專業單位,擁有豐富的技術能量,專長包括數據分析、智慧機器學習、嵌入式系統開發、智能圖像辨識等專業領域,我們利用嵌入式系統開發、資料科學以及人工智慧演算法方面的專長,降低了人工智慧應用開發門檻,不僅支援多種資料型態,且能簡易地被佈署到多樣化的硬體平台。

BerryNet
BerryNet 是 DT42 在 2017/04 年的開源專案,使用者(或開發者)可以透過 BerryNet 快速的在 Raspberry Pi(或者其他裝置) 上打造 AI Gateway,利用 Raspberry Pi 做運算深度學習,對影像或語音做即時分析。
在 2017 年時,DT42 展示了使用 BerryNet 在 Pi 3B 上進行物件偵測(Object Detection)可以達到 1FPS,在當時是很先進的。

AIoT - 01
AI Gateway 的經典範例就是一個 AI + IoT 的實際情境。例如有一隻貓來到你家後院,可是你想把他趕走,而不用花費人力,該怎麼做?
答案有很多,其中一個可能是架設一個 BerryNet 把貓嚇走。

AIoT - 02
當你架設好 BerryNet 以後,就可以透過自訂的攝影機將影像串流到 Raspberry Pi,再透過 BerryNet 內建的深度模型進行物件偵測。當有偵測到貓時就透過 WiFi 或是其他協定控制灑水系統進行灑水驅趕貓咪。
在這個情境中,物件辨識就是屬於 A.I.,而控制灑水系統則是 IoT 的概念。BerryNet 可以在樹莓派上完美的整合這兩者,成為 AI Gateway。雖然貓咪不一定會如你預期的被嚇走,搞不好還會玩的更開心 QQ。

Server AI
Bofu 再利用 YouBike 的演進說明了 Server AI 和 Edge AI 的分別。在過去,所有借還 YouBike 必須要先使用悠遊卡在 YouBike 的基站感應,而該站台會連回雲端主機,有著運算資源充沛、中央控管和容易追蹤各裝置狀況等優點。但也有受到基礎建設的限制或是佈署花費較高等缺點。這樣透過基站來計算處理資訊的方式稱為是 Server AI,也就是 YouBike 1.0。

Edge AI
而如果現在使用 YouBike,會發現使用體驗更順暢。包括了將基站主機的功能隱藏到每台車上成為各別的閘道器,所有感測資料就透過閘道器和雲端連線,有便於攜帶、容易部署和整體成本較低等優點。但有著受到本地運算機之運算資源限制和分散式系統個別更新不易等缺點。這樣透過各別低價的閘道器和和雲端主機直接連線做資訊交換,甚至多數的計算功能可以在閘道器上直接處理掉,這樣的方式稱為是 Edge AI,也就是 YouBike 2.0。

BerryNet Design Concept
BerryNet 希望成為 AI 和 IoT 的橋樑。目前各家廠商都有提出自己的 Framework,例如 FacebookPyTorch、或是 GoogleTensorFlow。許多硬體廠商,例如 Intel 也有推 OpenVINO 或是 NVIDIATensorRT
如果你只想要做個簡單的 AI 應用,光是選哪一套框架就會開始苦惱了,何況要控制後端的硬體控制又要再學習一堆硬體相關知識。那 BerryNet 提供了一個彈性的架構,讓使用者可以快速的整 AI 和 IoT 這兩端,專注在應用方面。

BerryNet Architecture
BerryNet 的架構可以從這張圖來說明。使用者會有多種 I/O 裝置,例如攝影機、麥克風或是要控制的硬體。而這些 I/O 裝置會透過 MQTT 的協定和 Raspberry Pi 溝通。而 BerryNet 整合多種深度學習模型,讓使用者可以透過指令列就能指定輸入/輸出設備,並設定適合的網路模型與參數,快速的部署一個 AIOT 的應用。

BerryNet step-by-step
整個操作情境,可以這樣舉例。如果你有一個手機當作影像的輸入來源,接著在 Raspberry Pi 跑 BerryNet,你就可以很輕鬆的透過可能是 RTSP 的協定將影像接到 Pi 上,並初始化 BerryNet 上的 TensorFlow Lite,決定好儀表板的顯示方式輸出到外接螢幕,如此一來我們就完成一個 BerryNet 的基本設定。

BerryNet result
接著我們就可以在螢幕上顯示推論結果(Dashboard),例如物件辨識,將辨認出的物體標記出來。

AIKEA
根據上一個範例,你可以發現使用者很輕鬆的就可以搭建出 AIOT 的應用,當然你會需要先準備一些硬體,包括 Raspberry Pi 和 Pi Camera 等。
如果你不想準備這些硬體與額外的設定,DT42 也在 Kickstarter 發起了 AIKEA 的群幕專案,標的物是是家庭的私有攝影機。但如果你仔細看專案說明,就會知道支持者最後會拿到 Pi 4BPi Camera 還有一個外盒。這是 DT42 團隊想要表達,使用者不需要花大錢買昂貴的硬體,只要使用手邊的裝置就可以建構出 AIOT 的應用。

BerryNet demo in 1 day
甚至 DT42 非技術性的專案經理,可以在一天之內從無到有使用 BerryNet 做出一個 AIOT 的應用。該應用是可以偵測過馬路的行人是否為長者或是行動不便的人士,而根據行人來決定是否要延長紅綠燈的秒數,能減少更多交通意外發生。
當然如果要做這樣的應用,使用者會需要蒐集足夠的影像來訓練模型才行。但這樣的範例告訴我們,很多使用者有很實際的應用,但因為缺乏技術性所以無法實做並驗證這些應用,而 BerryNet 可以快速打造 AIOT 應用,降低了人工智慧應用開發門檻。

BerryNet Demo
最後,Bofu 的 Live Demo 是使用手機收影像後,透過 RTSP 傳到 Pi 4 上的 BerryNet 即時做人物偵測。在沒有額外的硬體加速器的情形,大概有 5FPS 左右。

BerryNet – The first deep learning gateway for edge devices 的投影片

我們很高興能邀請到台灣的一些新創團隊來社群聚會分享,讓更多人看到台灣的創新能量。如果大家有想分享的主題,可以來信告訴我們(service_AT_raspberrypi.com.tw)。

[教學] Raspberry Pi學習路徑 | Learning Path

learning-path-v1_1800x1358

《基礎知識》
* [Link] Pi 選購指南
* [Link] Pi 設定安裝
* [Link] Linux 系統管理
* [Link]  Python 程式設計

《Raspberry Pi 基礎套件》
* [Link] 【Pi 4套餐I】Raspberry Pi 4 Model B/4G + SanDisk 32G microSD卡 + 官方原廠紅白外殼 + 官方原廠5.1V/3A電源 + 官方原廠HDMI線
* [Link] PL2303HXD USB轉TTL序列傳輸線

《I/O》
* [Link]  GPIO 學習套件
* [Link] 基礎感測器學習套件
* [Link] 進階感測器學習套件
* [Link] 空氣盒子(PiM25)套件
* [Link] Win10 開發套件
* [Link]  智慧開關套件
* [Link] Linux Driver 學習套件

《無線/IoT》
* [Link] RFID/NFC 門禁系統
* [Link] LoRa IoT 閘道器套件
* [Link] 生理資訊監控 IoT(藍牙)
* [Link] 毫米波人流/熱點監控(mmWave)
* [Link] 5G 行動寬頻人才培育計畫(物聯網平台 Raspberry Pi)

《相機/影像處理》
* [Link] 特色相機改裝套件
* [Link]  寵物小車套件
* [Link] 自控機器手臂套件
* [Link] 小鴨車套件(Duckietown)

《人工智慧》
* [Link] 驢車套件(Donkey Car)
* [Link] Google AIY Vision Kit
* [Link] Intel 神經運算棒
* [Link] Google Coral USB 加速器

《語音/訊號處理》
* [Link]  智慧音箱套件
* [Link] Google AIY Voice Kit

[常見問與答] 如何更新Raspbian?

2017-09-07-raspbian-stretch-rpi-update本圖是從安裝 2017-09-07-raspbian-stretch 經過更新後的版本資訊。

很多人拿到 Pi 3B+ 之後會迫不及待的把原本在 Pi 3B 上所使用的 SD 卡拿到 Pi 3B+ 使用,但是會發現無法開機。這是因為 Pi 3B+ 使用新的晶片(BCM2837B0),因此如果沒有安裝 2018-03-13 以後所發布的核心(kernel)或是韌體(firmware)是無法直接使用的。

但如果要重新燒錄的話,原本的資料不是就會不見了嗎? 那該如何正確更新 Raspbian

Raspbian 是源自於 Debian 但根據 Raspberry Pi 硬體所衍生初的分支,使用 APT 作為套件管理系統。而根據 apt-get 的手冊,常用的更新指令分別說明如下:

1. 更新 /etc/apt/sources.list 底下的套件清單。

$ sudo apt-get update

2. 比對套件清單決定是否需要更新,但如果要更新的套件有相依性問題,則放棄更新。

$ sudo apt-get upgrade

3. 會處理新版本套件與相依性套件的衝突,並試著安裝/移除有問題的套件來完成更新。

$ sudo apt-get dist-upgrade

4. 刪除之前因為有相依性而安裝,但現在已經不再使用的套件(非必要)。

$ sudo apt-get autoremove

5. 清除下載到 /var/cache/apt/archives 的 .deb 套件檔(非必要)

$ sudo apt-get autoclean

6. 更新核心和韌體到最新版本(可能不穩定),因此更新前一定要先備份重要資料!

$ sudo rpi-update

Pi 3B 依序執行 1 到 6 的步驟(4 和 5 非必要)以後關機,將 microSD 拔下換到 Pi 3B+,就可以順利在 Pi 3B+ 上使用了。

購買產品:[產品] Raspberry Pi 3 Model B+(現貨)

Reference:
* UPDATING AND UPGRADING RASPBIAN
* UPDATING THE KERNEL

[教學] 啟用 Pi 3B+的WiFi

當拿到 Pi 3B+ 以後,如果安裝目前最新版(2018-03-13)的映像檔開機後,會發現看不到這次改版最大的 WiFi 裝置。

default_pi3_bplus_no_wifi

如果從指令列 ifconfig 也會發現找不到內建的網卡。
default_pi3_bplus_ifconfig

查詢一下原來這次的 release noteswpa_supplicant.conf 的國碼設定拿掉了。

2018-03-13:
* Raspberry Pi 3 B+ support
  * WiFi is disabled until wireless regulatory domain is set (Pi 3 B+ only)
    - The domain can be done through 'Raspberry Pi Configuration' (rc_gui),
      'raspi-config' or by setting 'country=' to an appropriate ISO 3166
      alpha2 country code in /etc/wpa_supplicant/wpa_supplicant.conf.

可以從 sudo raspi-config 選單中設定 WiFi 的國碼即可,步驟如下。
4 Localisation Options > I4 Change Wi-fi Country > TW Taiwan
stretch_raspi_config_localisation
stretch_raspi_config_localisation_change_wifi_country
stretch_raspi_config_localisation_change_wifi_country_tw

完成後再執行 ifconfig 就可以看到 wlan0 出來了。
set_country_pi3_bplus_ifconfig

可以用 iw dev 查看支援的頻段,有到 5GHz 了。

$ iw dev
phy#0
	Unnamed/non-netdev interface
		wdev 0x2
		addr ba:27:eb:18:80:cb
		type P2P-device
		txpower 31.00 dBm
	Interface wlan0
		ifindex 3
		wdev 0x1
		addr b8:27:eb:18:80:cb
		type managed
		channel 165 (5825 MHz), width: 20 MHz, center1: 5825 MHz
		txpower 31.00 dBm

還有 iw list 查看支援的模式。

$ iw list
	Supported interface modes:
		 * IBSS
		 * managed
		 * AP
		 * P2P-client
		 * P2P-GO
		 * P2P-device

如果設定完國碼還看不到 wlan0 這張網卡的話,可以用 rfkill list 確認無線的啟用狀況,看是被軟體或硬體的設定擋住。

$ sudo rfkill list
0: phy0: Wireless LAN
	Soft blocked: yes
	Hard blocked: no
1: hci0: Bluetooth
	Soft blocked: no
	Hard blocked: no

如果是 phy0Soft blocked: yes,可以用 rfkill unblock wifi 啟用 WiFi 即可。

$ sudo rfkill unblock wifi
$ sudo rfkill list
0: phy0: Wireless LAN
	Soft blocked: no
	Hard blocked: no
1: hci0: Bluetooth
	Soft blocked: no
	Hard blocked: no

另外,原本在 Jessie 使用的 ifconfig wlan0 up,在 Scretch 也不能用了,會出現這樣的訊息。

$ sudo ifconfig wlan0 up
SIOCSIFFLAGS: Operation not possible due to RF-kill

要改為下面的方式啟用/停用網路裝置。

$ ip link set wlan0 up
$ ip link set wlan0 down

或是啟用/停用內建的 WiFi 裝置。

$ sudo rfkill block 0
$ sudo rfkill unblock 0

更多有關 /etc/wpa_supplicant/wpa_supplicant.conf 的參數可以參考這篇

參考資料:
* New Pi3B+ Wireless issues
* Wifi on Raspberry Pi 3
* wpa_supplicant.conf

[教學] Raspberry Pi Camera + Python + OpenCV投影片和範例程式 @虎科大

20170727_NFU_Camera_Python_OpenCV_2_Days_Workshop
七月底我們應虎科大電機工程系蔡老師的邀請,帶 Raspberry Pi + Python + Camera 兩天的工作坊。最後會實作”鄉民查水表”功能,是使用 Pi Camera 拍照後,用 OpenCV 做影像處理取得水表指針角度,就可以知道水表目前度數。學生很認真程度也很好,兩天的練習與實做都可以在時間內完成。我們未來也會和虎科大有更多的合作。

 

這次的工作坊共分為兩天,第一天是介紹 Raspberry Pi Camera + Python。內容與時間如下:
1. 相機原理與應用(1 小時)
2. 控制 Raspberry Pi Camera(2 小時)
- 使用指令列
- 使用 Python
3. 串接 imagga 網路服務(1 小時)
4. Camera和 Webcam(1 小時)
5. 影像串流(3 小時)
- 使用 RTSP + H.264
- 使用 HTTP + MJPG

投影片我們已經放在 slideshare 上了。範例程式在 github 上了。
Raspberry Pi Camera + Python + OpenCV (Day1) from raspberrypi-tw

 

第二天是介紹 Raspberry Pi Camera + OpenCV。內容與時間如下:
1. 色彩空間與基本影像處理(2 小時)
- 色彩空間介紹
- 用 Python + OpenCV 做影像處理
2. 常用影像處理方法(3 小時)
- 平滑,侵蝕與膨脹
- 找邊緣與找直線
- 找重心與找輪廓
3. 機器學習應用與綜合練習(3 小時)
- 人臉偵測
- 圖形分類(手寫辨識)

其中,在第二天工作坊中的圖形分類(手寫辨識),我們參考了 Ashing’s Blog內容,裡面有許多不錯的自學心得。

投影片在 slideshare 上。範例程式在 github 上了。
Raspberry Pi Camera + Python + OpenCV (Day2) from raspberrypi-tw

[常見問與答] 解決從序列埠登入到 Pi 3 的亂碼問題

購買產品:PL2303HX USB轉TTL傳輸線PL2303HXD USB轉TTL傳輸線

raspberry-pi-3-login-via-uart-baud-rates-broken

剛拿到 Pi 3 如果安裝 2016-02-26-raspbian-jessie 的映像檔後想使用序列埠連線,會發現出現亂碼,該怎麼辦?

這是因為原本 Pi 3 內建的硬體 UART 被 BCM2837 SoC 拿去給 Bluetooth 晶片組使用,而原本的 UART 輸出腳位(GPIOs 14 & 15)改成用 mini-uart port。意思是原本硬體 UART 有獨立的 clock divisor,因此 baud rate 可以維持在 115200,可是 mini-uart 使用系統核心時脈,實際只能跑到 72000 左右的 baud rate,因此當使用 115200 的 baud rate 連線就會出現亂碼。

解決的方法為:
步驟一,增加一個 pi3-disable-bt-overlaydevice tree overlay。這個 overlay 會停用藍牙,並且將 UART0/ttyAMA0 再設定給 GPIOs 14 & 15。
建議將 image 寫入 SD 卡後就直接修改 /boot/config.txt,在檔案最後增加兩行。

force_turbo=1
dtoverlay=pi3-disable-bt

add-pi3-disable-bt-overlay-at-config-file

其中,force_turbo=1 是強制 CPU 的時脈維持 1.2GHz 的時脈。預設值為 0 時表示時脈為 ondemand,會隨著負載而調整。
dtoverlay=pi3-disable-bt 表示載入 pi3-disable-bt 這個 device tree overlay,將會停用藍牙並將 UART0/ttyAMA0 設定到 GPIOs 14 & 15 腳位。

其實做完步驟一以後就可以用 115200 的 baud rate 透過序列埠連線進 Pi 了。可是雖然載入 pi3-disable-bt-overlay,但藍牙的服務依然是開啟的,因此還是要進入系統將藍牙服務停掉。

$ sudo systemctl disable hciuart

最後,因為使用 force_turbo=1 這個設定,整個 SoC 溫度會很高,因此再更新系統(包括 firmware 和 dtb)後就可以把這個設定註解掉,重開機生效。

$ sudo apt-get update
$ sudo apt-get upgrade

connect-to-raspberry-pi-3-via-serial

更多資訊:

1. 要如何看 CPU 時脈?
可以用 cat 指令查看以下三個檔案如下,分別為最高時脈、目前時脈、最低時脈。

$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
$ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq

2. 如何看目前的 Device Tree?
首先要安裝 device tree compiler

$ sudo apt-get install device-tree-compiler

再用 dtc 指令查看。

$ dtc -I fs /proc/device-tree

結果會像

/dts-v1/;

/ {
    model = "Raspberry Pi 3 Model B Rev 1.2";
    compatible = "brcm,bcm2710", "brcm,bcm2709";
    memreserve = <0x3b000000 0x4000000>;
    #address-cells = <0x1>;
    #size-cells = <0x1>;
    interrupt-parent = <0x1>;
...
    soc {
        compatible = "simple-bus";
        ranges = <0x7e000000 0x3f000000 0x1000000>;
        #address-cells = <0x1>;
        phandle = <0x27>;
        #size-cells = <0x1>;
        linux,phandle = <0x27>;
...
            uart0_pins {
                phandle = <0x34>;
                brcm,function = <0x4>;
                brcm,pins = <0xe 0xf>;
                brcm,pull = <0x0 0x2>;
                linux,phandle = <0x34>;
            };
            uart1_pins {
                phandle = <0xf>;
                brcm,function = <0x2>;
                brcm,pins = <0xe 0xf>;
                brcm,pull = <0x0 0x2>;
                linux,phandle = <0xf>;
            };
...

參考資料:
* CONFIG.TXT
* DEVICE TREES, OVERLAYS AND PARAMETERS
* Raspberry Pi Device Tree Overlays
* Raspberry Pi 3 UART Overlay Workaround
* Raspberry Pi 3 compatibility (BT disable & serial port remap fix)
* RPi Serial Connection
* Raspberry Pi Serial Communication: What, Why, and a Touch of How
* More on Raspberry Pi serial ports

[常見問與答] 如何看 Raspbian 的版本資訊?

自從 Raspbian 從 Wheezy 升級到 Jessie 以後,許多系統性的設計都有所不同。那要如何看 Raspbian 的版本資訊呢?

1. uname -a 查詢 kernel 版本。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ uname -a
Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.1.17-v7+ #834 SMP Mon Feb 1 15:17:54 GMT 2016 armv7l GNU/Linux

 

2. /opt/vc/bin/vcgencmd version 查詢 firmware 版本。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ /opt/vc/bin/vcgencmd version
Apr 21 2015 14:42:19 
Copyright (c) 2012 Broadcom
version 2d5ad04b63af4233440c3f7c8587108223201102 (clean) (release)
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ /opt/vc/bin/vcgencmd version
Feb  1 2016 17:51:17 
Copyright (c) 2012 Broadcom
version b3dc56931507f355d503ea69397778643f7a3dc3 (clean) (release)

 

3. strings /boot/start.elf | grep VC_BUILD_ID 查詢 firmware 版本。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ strings /boot/start.elf | grep VC_BUILD_ID
VC_BUILD_ID_USER: dc4
VC_BUILD_ID_TIME: 14:42:19
VC_BUILD_ID_BRANCH: master
VC_BUILD_ID_TIME: Apr 21 2015
VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333
VC_BUILD_ID_PLATFORM: raspberrypi_linux
VC_BUILD_ID_VERSION: 2d5ad04b63af4233440c3f7c8587108223201102 (clean)
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ strings /boot/start.elf | grep VC_BUILD_ID
VC_BUILD_ID_USER: dc4
VC_BUILD_ID_TIME: 17:51:17
VC_BUILD_ID_BRANCH: master
VC_BUILD_ID_TIME: Feb  1 2016
VC_BUILD_ID_HOSTNAME: dc4-XPS13-9333
VC_BUILD_ID_PLATFORM: raspberrypi_linux
VC_BUILD_ID_VERSION: b3dc56931507f355d503ea69397778643f7a3dc3 (clean)

 

4. cat /proc/version 查詢更完整的 kernel 資料。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ cat /proc/version
Linux version 3.18.11-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ cat /proc/version
Linux version 4.1.17-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #834 SMP Mon Feb 1 15:17:54 GMT 2016

 

5. cat /etc/os-release 查詢 OS 版本資訊。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 7 (wheezy)"
NAME="Raspbian GNU/Linux"
VERSION_ID="7"
VERSION="7 (wheezy)"
ID=raspbian
ID_LIKE=debian
ANSI_COLOR="1;31"
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ cat /etc/os-release 
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

 

6. cat /etc/issue 查詢 Linux distro 版本。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ cat /etc/issue
Raspbian GNU/Linux 7 \n \l

# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ cat /etc/issue
Raspbian GNU/Linux 8 \n \l

 

7. cat /etc/debian_version 查詢 Debian 版本編號。

# 2015-05-05-raspbian-wheezy 
pi@raspberrypi ~ $ cat /etc/debian_version
7.8
# 2016-02-03-raspbian-jessie
pi@raspberrypi:~ $ cat /etc/debian_version
8.0

[常見問與答] Raspbian Jessie版本差異?

Raspbian 是最多人在 Raspberry Pi 上安裝的作業系統,也是 Raspberry Pi 基金會持續維護的版本。在 Raspberry Pi 官方網站的下載JessieJessie Lite 兩種選擇,這兩者有什麼差別呢?
Download-Raspbian-Jessie-and-Raspbian-Jessie-Lite

其實這兩者主要分別在於 Jessie Lite 沒有預設安裝 X-server 與相關的套件,因此無法用 startx 啟動視窗管理員。因為也沒有安裝 QtGTK+ 的函式庫,因此也無法執行相關的視窗程式。

比較 Jessie 和 Jessie Lite 這兩個映像檔的大小(2016-02-03),分別是 3.9G(Jessie) 和 1.4G(Jessie Lite)。
jessie-vs-jessie-lite-file-size

我們可以用 ncdu / 從根目錄開始比較目錄與檔案在磁碟的使用量。下圖左邊是 Jessie 右邊是 Jessie Lite。 /usr 目錄下主要放的是 shared library,例如 Jessie 有 libreoffice 和 libQtWebKit 等視窗應用程式函式庫。
jessie-vs-jessie-ncdu-root

也可以用 dpkg -l 列出已經安裝的套件列表,並用 dpkg -l|wc 統計安裝套件數目。左邊是 Jessie 約 1150 個,右邊是 Jessie Lite 約 411 個。
jessie-vs-jessie-lite-dpkg-list

再比較這兩個映像檔預設安裝套件,可以看到 Jessie Lite 少了 x11 和 xserver 相關套件。
meld-jessie-dpkg-list-vs-jessie-lite-dpkg-list

因為少了 X 與相關套件,因此 Jessie Lite 可以有更小的磁碟空間使用與更低的記憶體使用量。一般來說 Jessie 是適合個人桌面環境使用,而 Jessie Lite 適合安裝在伺服器上。

那要如何在 Jessie Lite 上安裝視窗環境呢? 只要用 sudo apt-get updatesudo apt-get install lxde 就可以將 LXDE 和相依的套件裝起來,大約會新裝 602 個套件共計 842MB。之後就可以用 startx 開始使用 GUI。
jessie-lite-install-lxde

如果執行 startx 無法順利啟動,或是想要安裝別的桌面環境,例如 PIXELXFCEMATE、i3 GUI 等,可以參考這篇文章。

另外,除了 Jessie Lite,還有一套針對單板電腦(Single-Board Computer)所優化過的系統 DietPi。DietPi 也做了一個比較表,列出與 Jessie Lite 不同的地方,是打造輕量級產品的另一個選擇。
DietPi-Jessie-vs-Raspbian-Jessie-Lite
圖片來源:Raspbian Jessie Lite now available

參考資料:
* Raspbian Jessie Lite now available
* 鳥哥的私房菜第二十三章、X Window 設定介紹
* Lightweight Debian: LXDE Desktop From Scratch
* [GUIDE] Raspbian Lite with PIXEL/LXDE/XFCE/MATE/i3 GUI

[常見問與答] Raspberry Pi Zero 網路解決方案

由於 Raspberry Pi Zero 沒有內建乙太網路插槽,因此如何讓 Zero 可以上網需要額外安裝其他週邊,以下我們介紹幾種可能的方式。

1. (Ethernet)OTG + USB to RJ45 Converter

圖片來源:How to give an internet access to Raspberry Pi Zero

需要搭配的硬體如下:
- OTG Cable(支援 Micro USB)
- RJ45 to USB Converter(H1102NL 晶片)
- 網路線與數據機(或是路由器)

2. (Ethernet)OTG + USB to RJ45 Converter

圖片來源:How to give an internet access to Raspberry Pi Zero

需要搭配的硬體如下:
- OTG Cable(支援 Micro USB)
- RJ45 to USB Converter(SR9800 晶片)
- 網路線與數據機(或是路由器)

3. (Ethernet)Ethernet Module
zero-enc28j60
需要搭配的硬體如下:
- Ethernet Module(ENC28J60)
- 杜邦線母對母 x6
- 網路線與數據機(或是路由器)

4. (Tethering)OTG + Sharing Internet connections via USB

圖片來源:How to give an internet access to Raspberry Pi Zero

需要搭配的硬體如下:
- OTG Cable(支援 Micro USB)
- 智慧型手機資料傳輸線
- 可上網的智慧型手機

5. (WiFi)OTG + WiFi Dongle

圖片來源:How to give an internet access to Raspberry Pi Zero

- OTG Cable(支援 Micro USB)
- EDIMAX EW-7811Un 無線網卡(RTL8188CUS 晶片)

6. (WiFi)Hack WiFi Dongle
zero-hack-wifi-dongle
- EDIMAX EW-7811Un 無線網卡(RTL8188CUS 晶片)
- 單芯線 x4
* 注意:從 Micro USB 腳位直接接線到無線網卡將導致原本的 Micro USB 插槽無法同時讀取其他裝置

《速度測試》
我們使用 speedtest-cli,測速單位為 Mbit/s

Type Download Upload
OTG + USB to RJ45 Converter(H1102NL) Ethernet 19.37 2.16
OTG + USB to RJ45 Converter(SR9800) Ethernet 7.65 4.1
Ethernet Module(ENC28J60) Ethernet 3.67 3.1
OTG + WiFi Dongle(RTL8188CUS) WiFi 18.3 4.96
Hack WiFi Dongle(RTL8188CUS) WiFi 16.5 3.92

結論:
1. 想使用 Ethernet 上網,選擇 OTG + USB to RJ45 Converter(H1102NL) 方案。
2. 想使用 WiFi 上網,選擇 OTG + WiFi Dongle 方案。
3. 最好外接 USB Hub,一方面可提供穩定的電力,另一方面也能有更多的 USB 插槽可以使用。

參考資料:
* How to give an internet access to Raspberry Pi Zero
* Ethernet On Pi Zero – How To Put An Ethernet Port On Your Pi
* FIRST RASPBERRY PI ZERO HACK – PIGGY-BACK WIFI.

[常見問與答] Raspberry Pi 的工作溫度範圍?

以下內容翻自於 geektopiaRPi FAQ

使用 BCM2835Raspberry Pi Model B,熱的來源主要從以下三個元件而來:
1. 電源輸入的穩壓器(voltage regulator)。
2. SoC BCM2835,包含了 ARM11 CPU、GPU 和 RAM。
3. LAN9512,是 USB 和 Ethernet 的控制器。

我們可以比較幾個情境。
* 閒置狀態(僅通電開機,沒有連接 Ethernet)
thermal raspberrypi idle
圖片來源:geektopia
BCM2835 平均溫度在 48.7°C。Voltage regulator 平均溫度在 49.9°C。LAN9512 溫度是三者最高的,平均溫度在 53.0°C。

* 網路傳輸狀態(Ethernet 以平均 40MBits/s 速度傳輸 20 分鐘後)
thermal raspberrypi samba
圖片來源:geektopia
LAN9512 溫度仍然是三者最高的,平均溫度在 59.2°C。

* 忙碌狀態(以 stress 程式對 CPU 進行壓力測試,使用率達 100%)
thermal raspberrypi stress.png
圖片來源:geektopia
LAN9512 溫度仍然是三者最高的,平均溫度在 60.6°C。

* 影片播放狀態(從隨身碟播放以 x264 視訊格式和 AC3 音訊格的 1080p 影片為例)
thermal raspberrypi video playback
圖片來源:geektopia
LAN9512 溫度仍然是三者最高的,平均溫度在 58.5°C。

結論:
1. LAN9512 溫度會比 voltage regulator 和 SoC 來的高。

2. 從以上幾張圖片的條件,我們可以知道 CPU 滿載或是檔案傳輸最容易讓溫度升高。並且在正常使用情況下(未超頻),各元件的最高溫度會是在 65°C 以下。

3. 而根據 RPi FAQ,LAN9512 的工作溫度範圍在 0°C 到 70°C,BCM2835 的工作溫度範圍在 -40°C 到 85°C。

The Raspberry Pi is built from commercial chips which are qualified to different temperature ranges; the LAN9512 is specified by the manufacturers being qualified from 0°C to 70°C, while the AP is qualified from -40°C to 85°C. You may well find that the board will work outside those temperatures, but we’re not qualifying the board itself to these extremes.

4. 根據實測,在 -78°C 的低溫下,Raspberry Pi 會停止反應。

圖片來源:geek

5. 除了使用紅外線測溫外,我們還可以使用 /opt/vc/bin/vcgencmd measure_temp 指令來查看 CPU 的溫度。
raspberry_pi_measure_cpu_temp

參考資料:
* Does the computer Raspberry Pi is heated? Study their operating temperatures
* RPi FAQ
* Raspberry Pi proven to be stable when submerged in liquid nitrogen
* Raspberry Pi model B Thermal Tests

[常見問與答] Raspbian (2015-01-31) 在 Pi 2 的 RPi.GPIO 問題

問題:
2015-01-31 釋出的 RaspbianPi 2 呼叫 RPi.GPIO 模組會出現 RuntimeError: This module can only be run on a Raspberry Pi! 錯誤訊息。

情境:
假設我們寫一個可以控制 LED 一明一滅的 python 程式。範例來自 用 Raspberry Pi 學 GPIO – 自己做遊戲機

線路圖如下:
led_blink_schematic

程式碼範如 led_blink.py

import RPi.GPIO as GPIO 
import time

LED_PIN = 12    
GPIO.setmode(GPIO.BOARD)
GPIO.setup(LED_PIN, GPIO.OUT)

try:
    while True:
        print("LED is on")
        GPIO.output(LED_PIN, GPIO.HIGH)
        time.sleep(1)
        print("LED is off")
        GPIO.output(LED_PIN, GPIO.LOW)
        time.sleep(1)

except KeyboardInterrupt:
    print "Exception: KeyboardInterrupt"

finally:
    GPIO.cleanup()    

如果在 Raspberry Pi 2 (2015-01-31 版本)執行這段程式碼會出現以下訊息:

pi@raspberrypi ~ $ sudo python led_blink.py
Traceback (most recent call last):
  File "led_blink.py", line 1, in 
    import RPi.GPIO as GPIO    
RuntimeError: This module can only be run on a Raspberry Pi!

看起來是沒有 RPi.GPIO 的模組。所以我們用 sudo pip install RPi.GPIO 指令安裝 RPi.GPIO 模組看看。

pi@raspberrypi ~ $  sudo pip install RPi.GPIO
Requirement already satisfied (use --upgrade to upgrade): RPi.GPIO in /usr/lib/python2.7/dist-packages
Cleaning up...

解答:
原來是要升級模組才行。我們要使用 sudo pip install --upgrade RPi.GPIO 指令。

pi@raspberrypi ~ $ sudo pip install --upgrade RPi.GPIO
Downloading/unpacking RPi.GPIO from https://pypi.python.org/packages/source/R/RPi.GPIO/RPi.GPIO-0.5.11.tar.gz#md5=9dc3dab6ce2b7ccb833a866efb392821
  Downloading RPi.GPIO-0.5.11.tar.gz
  Running setup.py egg_info for package RPi.GPIO
    
Installing collected packages: RPi.GPIO
  Found existing installation: RPi.GPIO 0.5.9
    Uninstalling RPi.GPIO:
      Successfully uninstalled RPi.GPIO
  Running setup.py install for RPi.GPIO
    building 'RPi.GPIO' extension
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/py_gpio.c -o build/temp.linux-armv7l-2.7/source/py_gpio.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/c_gpio.c -o build/temp.linux-armv7l-2.7/source/c_gpio.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/cpuinfo.c -o build/temp.linux-armv7l-2.7/source/cpuinfo.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/event_gpio.c -o build/temp.linux-armv7l-2.7/source/event_gpio.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/soft_pwm.c -o build/temp.linux-armv7l-2.7/source/soft_pwm.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/py_pwm.c -o build/temp.linux-armv7l-2.7/source/py_pwm.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/common.c -o build/temp.linux-armv7l-2.7/source/common.o
    gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I/usr/include/python2.7 -c source/constants.c -o build/temp.linux-armv7l-2.7/source/constants.o
    gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro build/temp.linux-armv7l-2.7/source/py_gpio.o build/temp.linux-armv7l-2.7/source/c_gpio.o build/temp.linux-armv7l-2.7/source/cpuinfo.o build/temp.linux-armv7l-2.7/source/event_gpio.o build/temp.linux-armv7l-2.7/source/soft_pwm.o build/temp.linux-armv7l-2.7/source/py_pwm.o build/temp.linux-armv7l-2.7/source/common.o build/temp.linux-armv7l-2.7/source/constants.o -o build/lib.linux-armv7l-2.7/RPi/GPIO.so
    
Successfully installed RPi.GPIO
Cleaning up...

再次執行,沒問題了。

[基礎] Raspberry Pi 用 3G 網卡(3G USB dongle)上網

e1820_with_raspberry_pi_model_b_plus

本文章使用 Raspberry Pi Model B+,映像檔為 2014-12-24-wheezy-raspbian.img。使用的 3G 網卡為 Huawei E1820 3G 網卡。

現在的 3G/4G 網卡(或稱為 USB 數據機)大多同時有儲存設備和 USB 數據機的功能,其中儲存設備功能存放 MS Windows 的驅動程式,USB 數據機就是可撥號連線接取上網際網路。

如果是第一次將 3G 網卡插在安裝了 Windows 系統的電腦上,網卡將會以虛擬光碟機的模式掛載成儲存設備,並且自動安裝驅動程式。當完成安裝後就可用虛擬光碟機轉換工具(Virtual CD-ROM switching utility)或稱為模式轉換工具,正確轉換網卡為 USB 數據機。

如果要在 Raspberry Pi 上使用 3G/4G 網卡上網,要做的事就是安裝設定模式轉換工具與安裝設定撥號連線程式。步驟如下:
 
1. 確認硬體資訊。
當插上 E1820 時,可以看到系統可辨認成 HSPA modem。

pi@raspberrypi ~ $ lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
... skip ...
Bus 001 Device 008: ID 12d1:1446 Huawei Technologies Co., Ltd. E1552/E1800/E173 (HSPA modem)
... skip ...

dmesg 查看時,可看到系統將網卡的儲存功能辨認成 scsi 介面的 CD-ROM(sr0)。

pi@raspberrypi ~ $ dmesg
... skip ...
[    7.062455] usb 1-1.4: new high-speed USB device number 6 using dwc_otg
[    7.195063] usb 1-1.4: New USB device found, idVendor=12d1, idProduct=1446
[    7.219562] usb 1-1.4: New USB device strings: Mfr=3, Product=2, SerialNumber=0
[    7.242348] usb 1-1.4: Product: HUAWEI Mobile
[    7.251156] usb 1-1.4: Manufacturer: Huawei Technologies
[    7.282719] usb-storage 1-1.4:1.0: USB Mass Storage device detected
[    7.309727] scsi0 : usb-storage 1-1.4:1.0
[    7.323198] usb-storage 1-1.4:1.1: USB Mass Storage device detected
[    7.351048] scsi1 : usb-storage 1-1.4:1.1
[    8.322907] scsi 0:0:0:0: CD-ROM            HUAWEI   Mass Storage     2.31 PQ: 0 ANSI: 2
[    8.363958] scsi 1:0:0:0: Direct-Access     HUAWEI   TF CARD Storage       PQ: 0 ANSI: 2
[    8.417357] sd 1:0:0:0: [sda] Attached SCSI removable disk
[    8.583801] sr0: scsi-1 drive
[    8.591172] cdrom: Uniform CD-ROM driver Revision: 3.20
[    8.681129] sr 0:0:0:0: Attached scsi generic sg0 type 5
[    8.698176] sr 0:0:0:0: Attached scsi CD-ROM sr0

e1820_dmesg_before_mode_switch
如果我們將 sr0 掛載起來,就可清楚的看到裡面所存放的檔案是 Windows 驅動程式。

pi@raspberrypi ~ $ ls -al /dev/disk/by-id/
total 0
drwxr-xr-x 2 root root 140 Dec 24 12:31 .
drwxr-xr-x 6 root root 120 Jan  1  1970 ..
lrwxrwxrwx 1 root root  13 Jan  1  1970 memstick-SU16G_0x27885644 -> ../../mmcblk0
lrwxrwxrwx 1 root root  15 Dec 24 12:28 memstick-SU16G_0x27885644-part1 -> ../../mmcblk0p1
lrwxrwxrwx 1 root root  15 Dec 24 12:28 memstick-SU16G_0x27885644-part2 -> ../../mmcblk0p2
lrwxrwxrwx 1 root root   9 Dec 24 12:38 usb-HUAWEI_Mass_Storage-0:0 -> ../../sr0
lrwxrwxrwx 1 root root   9 Dec 24 12:31 usb-HUAWEI_TF_CARD_Storage-0:0 -> ../../sda
pi@raspberrypi ~ $ sudo mount /dev/sr0 /mnt
mount: block device /dev/sr0 is write-protected, mounting read-only
pi@raspberrypi ~ $ ls -al /mnt/
total 586
dr-xr-xr-x  1 root root   2048 Nov 27  2012 .
drwxr-xr-x 22 root root   4096 Dec 21 11:09 ..
-r-xr-xr-x  1 root root 148320 Mar 14  2011 AutoRun.exe
-r-xr-xr-x  1 root root     45 Oct  1  2008 AUTORUN.INF
dr-xr-xr-x  1 root root   2048 Nov 27  2012 Mobile Partner
-r-xr-xr-x  1 root root 439926 Nov 15  2009 Startup.ico
-r-xr-xr-x  1 root root   1742 Nov 23  2012 SysConfig.dat

e1820_mount_device

 
2. 安裝與設定模式轉換工具。
安裝 usb-modeswitch 會將有相依性的 usb-modeswitch-data 一併安裝起來。

pi@raspberrypi ~ $ sudo apt-get install -y usb-modeswitch

e1820_install_usb_modeswitch

我們可以比較模式轉換前後的分別,這可幫助我們確認是否有成功轉換 3G 網卡成 USB 數據機。檢查方式是執行 ls /dev/tty*,在模式還沒有轉換前,可以看到最後兩項是 /dev/ttyAMA0/dev/ttyprintk
e1820_ls_tty_before_mode_switch

安裝完成後就要進行模式的設定,usb-modeswitch 需要和 udev 搭配。

udev 包含 user space daemon(udevd)和工具程式 udevinfo(或 udevadm),並可以讓使用者自訂規則存放於 /etc/udev/rules.d/ 下。有關 udev 可以看 wiki 的介紹。

udev 是 Linux kernel 2.6 系列的設備管理器。它主要的功能是管理 /dev 目錄底下的設備節點。它同時也是用來接替 devfs 及 hotplug 的功能,這意味著它要在添加/刪除硬件時處理 /dev 目錄以及所有用戶空間的行為,包括加載 firmware 時。

實際上 usb-modeswitchudev 的運作順序如下:

* /lib/udev/rules.d/40-usb_modeswitch.rules:udev 的規則文件,如果設備被識別(包括 Vendor ID 和 Product ID)就會啟動 usb_modeswitch。
* /lib/udev/usb_modeswitch: 執行 usb_modeswitch_dispatcher 的 script。
* /usr/sbin/usb_modeswitch_dispatcher:usb_modeswitch 的 wrapper,用 tcl 寫的,會根據所選擇的設備與設定實際執行 /usr/sbin/usb_modeswitch。
* /etc/usb_modeswitch.conf:全域的設定檔案,也可用於單一的設備設定資訊。
* /etc/usb_modeswitch.d:該文件夾包含了各別設備的獨立設定資訊,各別裝置的設定檔案是用設備的 ID 來命名。
* /usr/sbin/usb_modeswitch:實際轉換裝置模式的二進位程式。

因此我們要新增網卡設備的規則到 /lib/udev/rules.d/40-usb_modeswitch.rules

pi@raspberrypi ~ $ sudo vi /lib/udev/rules.d/40-usb_modeswitch.rules

在檔案最後加上兩行。

# E1820
ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1446", RUN+="usb_modeswitch '%b/%k'"

e1820_udev_config

其中 idVendor="12d1" 和 idProduct="1446" 這些資訊是由 lsusb 得到的。
e1820_lsusb_before_mode_switch

接著再將網卡要轉換的資訊加到 /etc/usb_modeswitch.conf 下。

pi@raspberrypi ~ $ sudo vi /etc/usb_modeswitch.conf

在檔案最後加上幾行。

DefaultVendor=0x12d1
DefaultProduct=0x1446

TargetVendor=0x12d1
TargetProduct=0x14ac

MessageContent="5553424312345678000000000000061e000000000000000000000000000000"

e1820_usb_modeswitch_config

DefaultVendor 和 DefaultProduct 也是剛剛 lsusb 的結果。但 TargetVendor 和 TargetProduct 就需要上網爬文,例如這裡有提供。

而將 EnableLogging=0 改為 EnableLogging=1 可在 /var/log 下查看 usb_modeswitch_** 的 log 方便除錯。

如果設定沒問題,重開機用 dmesg 就可以看到已經成功的將 USB 數據機(usb 1-1.4) 掛載到 ttyUSB0、ttyUSB1 和 ttyUSB2。

... skip ...
[    7.062368] usb 1-1.4: new high-speed USB device number 6 using dwc_otg
[    7.185037] usb 1-1.4: New USB device found, idVendor=12d1, idProduct=1446
[    7.208299] usb 1-1.4: New USB device strings: Mfr=3, Product=2, SerialNumber=0
[    7.230322] usb 1-1.4: Product: HUAWEI Mobile
[    7.250718] usb 1-1.4: Manufacturer: Huawei Technologies
[    7.273445] usb-storage 1-1.4:1.0: USB Mass Storage device detected
[    7.297764] scsi0 : usb-storage 1-1.4:1.0
[    7.313332] usb-storage 1-1.4:1.1: USB Mass Storage device detected
[    7.342617] scsi1 : usb-storage 1-1.4:1.1
[    8.315111] scsi 0:0:0:0: CD-ROM            HUAWEI   Mass Storage     2.31 PQ: 0 ANSI: 2
[    8.345229] scsi 1:0:0:0: Direct-Access     HUAWEI   TF CARD Storage       PQ: 0 ANSI: 2
[    8.373824] sd 1:0:0:0: [sda] Attached SCSI removable disk
[    9.630014] scsi 0:0:0:0: Attached scsi generic sg0 type 5
[    9.773321] sd 1:0:0:0: Attached scsi generic sg1 type 0
[    9.819475] sr0: scsi-1 drive
[    9.942382] cdrom: Uniform CD-ROM driver Revision: 3.20
[   10.122331] sr 0:0:0:0: Attached scsi CD-ROM sr0
[   11.142844] usb-storage 1-1.4:1.0: USB Mass Storage device detected
[   11.153861] usb 1-1.4: USB disconnect, device number 6
[   11.176368] scsi2 : usb-storage 1-1.4:1.0
[   11.208558] scsi 1:0:0:0: rejecting I/O to offline device
[   11.218302] scsi 1:0:0:0: killing request
[   15.762375] usb 1-1.4: new high-speed USB device number 7 using dwc_otg
[   15.885281] usb 1-1.4: New USB device found, idVendor=12d1, idProduct=14ac
[   15.906715] usb 1-1.4: New USB device strings: Mfr=4, Product=3, SerialNumber=0
[   15.929998] usb 1-1.4: Product: HUAWEI Mobile
[   15.959491] usb 1-1.4: Manufacturer: Huawei Technologies
[   15.999001] usb-storage 1-1.4:1.5: USB Mass Storage device detected
[   16.040642] scsi3 : usb-storage 1-1.4:1.5
[   16.057131] usb-storage 1-1.4:1.6: USB Mass Storage device detected
[   16.099706] scsi4 : usb-storage 1-1.4:1.6
[   16.366181] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
[   16.445601] usbcore: registered new interface driver cdc_ether
[   16.491873] usbcore: registered new interface driver usbserial
[   16.586318] usbcore: registered new interface driver usbserial_generic
[   16.617253] usbcore: registered new interface driver cdc_wdm
[   16.679164] usbserial: USB Serial support registered for generic
[   16.721907] qmi_wwan 1-1.4:1.1: cdc-wdm0: USB WDM device
[   16.751517] qmi_wwan 1-1.4:1.1 wwan0: register 'qmi_wwan' at usb-bcm2708_usb-1.4, WWAN/QMI device, a6:37:fd:d4:42:14
[   16.800868] usbcore: registered new interface driver qmi_wwan
[   16.830143] usbcore: registered new interface driver option
[   16.866417] usbserial: USB Serial support registered for GSM modem (1-port)
[   16.953166] option 1-1.4:1.0: GSM modem (1-port) converter detected
[   17.008423] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB0
[   17.054788] scsi 3:0:0:0: CD-ROM            HUAWEI   Mass Storage     2.31 PQ: 0 ANSI: 2
[   17.095286] sr0: scsi-1 drive
[   17.113002] sr 3:0:0:0: Attached scsi CD-ROM sr0
[   17.113502] sr 3:0:0:0: Attached scsi generic sg0 type 5
[   17.134929] option 1-1.4:1.3: GSM modem (1-port) converter detected
[   17.155709] scsi 4:0:0:0: Direct-Access     HUAWEI   TF CARD Storage       PQ: 0 ANSI: 2
[   17.193722] sd 4:0:0:0: [sda] Attached SCSI removable disk
[   17.204968] sd 4:0:0:0: Attached scsi generic sg1 type 0
[   17.326895] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB1
[   17.473045] option 1-1.4:1.4: GSM modem (1-port) converter detected
[   17.612898] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB2
... skip ...

e1820_dmesg_after_mode_switch
 
ls /dev/tty* 也可看到最後長出了 /dev/ttyUSB0、/dev/ttyUSB1 和 /dev/ttyUSB2。

pi@raspberrypi ~ $ ls /dev/tty*

e1820_ls_tty_after_mode_switch

這時候我們用 lsusb 也可以發現讀到的硬體資訊改變了,包括 idProduct 和名稱都有變化。

pi@raspberrypi ~ $ lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
... skip ...
Bus 001 Device 007: ID 12d1:14ac Huawei Technologies Co., Ltd. 
... skip ...

e1820_lsusb_after_mode_switch

 
3. 安裝與設定撥號程式。
安裝撥號程式 wvdial 會一同安裝 ppp

pi@raspberrypi ~ $ sudo apt-get install -y wvdial

e1820_install_wvdial
 
再來設定 wvdial.conf

pi@raspberrypi ~ $ sudo vi /etc/wvdial.conf

加上一個撥號的 profile。

[Dialer E1820]
Phone = *99#
APN = internet
Username = username
Password = password
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1, "IP","Internet"
Modem = /dev/ttyUSB0
Baud = 460800
Stupid Mode = 1

e1820_wvdial_config
其中
* [Dialer xxx]:profile 名稱,之後撥號就會以 xxx 為名,可設定多組 profile。
* Modem:wvdial 所用的數據機設備位置,預設為 /dev/modem。
* Baud:wvdial 和數據機所溝通的 baud rate。
* Stupid Mode:如果啟用 stupid mode,數據機在和終端伺服器(terminal server)溝通時將不會出現提示,並且當數據機連上後會立即啟動 pppd。

使用 wvdial 進行撥號連線,選擇 E1820 的 profile。

pi@raspberrypi ~ $ sudo wvdial E1820

在進行 pppd 連線過程中,會看到像是亂碼的符號,但如果連線成功會得到 IP 和 DNS 的位址。
e1820_wvdial
 
再用 ifconfig 查看網路介面資訊,可以發現多了一個 ppp0 的連線。
e1820_wvdial_ifconfig
 
開啟瀏覽器,確認可以連上網際網路。
browser_show_raspberry_pi_taiwan
 

常見問與答:

1. 如何測連線速度?
有關測網路的連線速度方法有很多,我們使用 speedtest-cli 這個用 python 寫的命令列測速套件,原始碼在 github。實際執行時,這個工具會連線到 speedtest.net 並測試上傳和下載的速度。

使用前需要先安裝相關的套件如下。

pi@raspberrypi ~ $ sudo apt-get install python-dev python-pip
pi@raspberrypi ~ $ sudo pip install speedtest-cli

執行 speedtest-cli

pi@raspberrypi ~ $ speedtest-cli
Retrieving speedtest.net configuration...
Retrieving speedtest.net server list...
Testing from Chunghwa Telecom Co., Ltd. (223.136.198.66)...
Hosted by Taiwan Fixed Network (New Taipei) [7.30 km]: 91.097 ms
Testing download speed........................................
Download: 2.48 Mbits/s
Testing upload speed..................................................
Upload: 1.41 Mbits/s

speedtest-cli 會根據使用者所在的位置,連線到最近的伺服器做測速。我們可以加上 --list 列出在台灣的伺服器列表。

pi@raspberrypi ~ $ speedtest-cli --list | grep Taiwan
2133) Taiwan Fixed Network (Taipei, Taiwan) [0.47 km]
2327) Far Eastone Telecommunications Co., Ltd. (Taipei, Taiwan) [0.47 km]
5008) Asia Pacific Telecom (Taipei, Taiwan) [0.47 km]
5661) NCIC Telcom (Taipei, Taiwan) [0.47 km]
2188) TFN Media Co., Ltd. (Taipei, Taiwan) [0.47 km]
3967) Chief Telecom (Taipei, Taiwan) [0.47 km]
5056) Taipei Fiber (Taipei, Taiwan) [0.47 km]
5660) NCIC Telcom (New Taipei, Taiwan) [9.09 km]
4505) Chief Telecom (New Taipei, Taiwan) [9.09 km]
5219) Taiwan Fixed Network (New Taipei, Taiwan) [9.09 km]
5067) Far Eastone Telecommunications Co., Ltd. (New Taipei, Taiwan) [9.09 km]
3921) Taiwan Fixed Network (Taoyuan, Taiwan) [31.66 km]
2589) Far EasTone Telecommunications Co., Ltd (Taoyuan, Taiwan) [31.66 km]
... skip ...

我們也可以指定伺服器做測試。只要在 speedtest-cli 後面加上伺服器的編號例如 --server 2133 就可以了。但我們實際測試時是沒有加上這個選項,而讓它自己選擇最近的伺服器。

2. 有其他網卡的設定可參考嗎?
以下是我們測過的幾張網卡的設定檔。

Huawei E220/Huawei E230
修改 /lib/udev/rules.d/40-usb_modeswitch.rules

ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1003", RUN+="usb_modeswitch '%b/%k'"

修改 /etc/usb_modeswitch.conf

DefaultVendor=0x12d1
DefaultProduct=0x1003
TargetVendor=0x12d1
TargetProductList="1001,1003,1406,140c,14ac"
MessageContent="55534243123456780000000000000011060000000000000000000000000000"

使用 speedtest-cli 的參考結果。
E230_speedtest_cli
 

Huawei E372
修改 /lib/udev/rules.d/40-usb_modeswitch.rules

ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1505", RUN+="usb_modeswitch '%b/%k'"

修改 /etc/usb_modeswitch.conf

DefaultVendor=  0x12d1
DefaultProduct= 0x1505
TargetVendor=   0x12d1
TargetProduct=  0x140c
TargetProductList="1001,1406,140b,140c,1412,141b,1433,14ac,1506,150f"
MessageContent="5553424312345678000000000000061e000000000000000000000000000000"

使用 speedtest-cli 的參考結果。
E372_speedtest_cli
 

Huawei E398u-1
修改 /lib/udev/rules.d/40-usb_modeswitch.rules

ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1505", RUN+="usb_modeswitch '%b/%k'"

修改 /etc/usb_modeswitch.conf

DefaultVendor=0x12d1
DefaultProduct=0x1505
TargetVendor=0x12d1
TargetProduct=0x1506
MessageContent="5553424312345678000000000000061e000000000000000000000000000000"

使用 speedtest-cli 的參考結果。
E398_speedtest_cli
E372 和 E398 的 idProduct 相同,只是因為 Huawei 沒有給每一個裝置都使用唯一的 idProduct。
 

3. 這錯誤訊息是什麼意思?

--> WvDial: Internet dialer version 1.61
--> Initializing modem.
--> Sending: ATZ
ATZ
OK
--> Sending: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
OK
--> Sending: AT+CGDCONT=1, "IP","Internet"
AT+CGDCONT=1, "IP","Internet"
ERROR
--> Bad init string.
--> Initializing modem.
--> Sending: ATZ
ATZ
OK
--> Sending: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
OK
--> Sending: AT+CGDCONT=1, "IP","Internet"
AT+CGDCONT=1, "IP","Internet"
ERROR
--> Bad init string.
--> Initializing modem.
--> Sending: ATZ
ATZ
OK
--> Sending: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
OK
--> Sending: AT+CGDCONT=1, "IP","Internet"
AT+CGDCONT=1, "IP","Internet"
ERROR                                             
--> Bad init string.

會發生這樣錯誤訊息的可能性有很多種,比如說網卡和 /etc/usb_modeswitch.conf 不匹配,或是 wvdial.conf 連線設定有誤,有可能是 SIM 卡沒安裝或沒插好,也有可能是網卡壞掉,甚至有時候從 Model B 換到 Model B+ 就解決了。
 

4. 如果發現連線到一半容易斷線該怎麼辦?
這通常是供電不足造成的結果。如果使用好的電源還是會容易斷線的話,解決方法第一個可以先修改 /boot/config.txt 如下,讓 USB 的電流可以從 600mA 提升到 1200 mA。

max_usb_current=1

解決方法第二是接一個有獨立供電的 USB Hub,問題就會解決了。
 

參考資料:
* Huawei E220
* How to setup a USB 3G Modem on Raspberry PI using usb_modeswitch and wvdial
* Use 3g/UMTS USB Dongle for WAN connection
* USB_ModeSwitch – Handling Mode-Switching USB Devices on Linux
* usb_modeswitch_dispatcher
* usb_modeswitch(1) – Linux man page
* udev
* Device Reference
* Linux / Unix Command: wvdial.conf
* Huawei E372 mobile broadband
* TROUBLESHOOT HUAWEI E398 ON MANJARO LINUX
* How to check Internet Speed via Terminal?
* How to Test Internet Connection Speed using Speedtest-Cli on Ubuntu Server

[基礎] 命令列設置無線網路

本文章使用的映像檔為 2014-09-09-wheezy-raspbian.img
setting-up-wifi-with-the-command-line

一般設置 Raspberry Pi 的無線網路大多是透過 WiFi Config 這個應用程式做設定。
wifi-config-gui

但在某些情況,例如 從序列埠登入到 Raspberry Pi,就只能靠命列列設置無線網路。但是記得,做任何修改前要先備份原始設定,以免出錯了無法回復原始狀態。

用命令列設置無線網路的步驟如下:

1. 確認硬體資訊,我們使用 EDIMAX 7811Un 這張無線網卡做設定。建議使用的網卡有在清單中,才可隨插即用。

pi@raspberrypi ~ $ lsusb
Bus 001 Device 005: ID 7392:7811 Edimax Technology Co., Ltd EW-7811Un 802.11n Wireless Adapter [Realtek RTL8188CUS]

2. 查看目前無線網路設定,一開始還沒連接上無線網路,所以狀態會是 “unassociated”。

pi@raspberrypi ~ $  iwconfig wlan0
wlan0     unassociated  Nickname:""
          Mode:Managed  Frequency=2.412 GHz  Access Point: Not-Associated   
          Sensitivity:0/0  
          Retry:off   RTS thr:off   Fragment thr:off
          Power Management:off
          Link Quality:0  Signal level:0  Noise level:0
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

3. 掃描無線網路,我們會根據掃描結果來設定無線網路。假設本例的 SSID 為 foo,加密方式為 WPA2,使用的 pre-shared key 為 1234567890123。

pi@raspberrypi ~ $ sudo iwlist wlan0 scan
wlan0     Scan completed :
          Cell 03 - Address: 40:4A:03:92:BA:4B
                    ESSID:"foo"
                    Protocol:IEEE 802.11bgn
                    Mode:Master
                    Frequency:2.462 GHz (Channel 11)
                    Encryption key:on
                    Bit Rates:144 Mb/s
                    Extra:rsn_ie=30140100000fac040100000fac040100000fac020c00
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP
                        Authentication Suites (1) : PSK
                    Quality=88/100  Signal level=42/100  

4. 修改 /etc/wpa_supplicant/wpa_supplicant.conf

pi@raspberrypi:~$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

所對應的設定檔如下。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
        ssid="foo"
        psk="1234567890123"
        proto=RSN
        key_mgmt=WPA-PSK
        pairwise=CCMP
        auth_alg=OPEN
}

掃描結果與設定檔對應的欄位說明如下。

IE: IEEE 802.11i/WPA2 Version 1

表示加密方式為 WPA2,所對應的欄位 proto。
RSN:WPA(2)
WPA:WPA(1)

Group Cipher : CCMP 
Pairwise Ciphers (1) : CCMP

表示 WPA2 使用 AES 加密方式,所對應的欄位 pairwise。
CCMP:AES cipher,WPA(2)
TKIP:TKIP cipher,WPA(1)

Authentication Suites (1) : PSK

表示使用 pre-shared key 做鑑別,所對應的欄位為 key_mgmt。
WPA-PSK:Authentication via pre-shared key
WPA-EAP:Authentication via enterprise authentication server。

再例如使用 SSID 為 bar,加密的方式為 WEP,使用的 WEP key 為 1234567890123。

pi@raspberrypi ~ $  iwlist wlan0 scan
wlan0     Scan completed :
          Cell 03 - Address: 40:4A:03:92:BA:4B
                    ESSID:"bar"
                    Protocol:IEEE 802.11bg
                    Mode:Master
                    Frequency:2.437 GHz (Channel 6)
                    Encryption key:on
                    Bit Rates:54 Mb/s
                    Quality=72/100  Signal level=43/100  

所對應的設定檔如下。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
        ssid="bar"
        key_mgmt=NONE
        auth_alg=OPEN
        wep_key0="1234567890123"
}

更多 wpa_supplicant.conf 的範例可參考這裡

5. 停用 wlan0 網卡。

pi@raspberrypi ~ $ sudo ifdown wlan0

6. 啟用 wlan0 網卡。

pi@raspberrypi ~ $ sudo ifup wlan0

可能會回傳以下訊息,我們忽略掉。

ioctl[SIOCSIWAP]: Operation not permitted
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument

7. 將原來讀取 wpa_supplicant.conf 的程序 wpa_supplicant 殺掉。

pi@raspberrypi ~ $ sudo kill -9 $(ps -ef | grep wpa | awk '{print $2}')

8. 重新執行 wpa_supplicant,並讀取 wpa_supplicant.conf 設定。

pi@raspberrypi ~ $ sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf

-B 表示以 daemon 方式在背景執行。
-i 表示指定介面(interface)名稱。
-c 表示設定檔路徑。

若回傳以下訊息,我們忽略掉。

rfkill: Cannot open RFKILL control device
ioctl[SIOCSIWAP]: Operation not permitted
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument

9. 執行 DHCP 用戶端,取得 IP。

pi@raspberrypi ~ $ sudo dhclient

若回傳以下訊息,我們忽略掉。

RTNETLINK answers: File exists

10. 查尋 IP 位址,成功取得 192.168.1.117

pi@raspberrypi ~ $ ifconfig wlan0
wlan0     Link encap:Ethernet  HWaddr 74:da:38:05:68:4c  
          inet addr:192.168.1.117  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1158 errors:0 dropped:79 overruns:0 frame:0
          TX packets:53 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:109024 (106.4 KiB)  TX bytes:6214 (6.0 KiB)

 

常見問與答:

1. WiFi連不上怎麼辦?
接螢幕用 GUI 設定吧,可避免錯誤的設定。
wifi-config-gui-setting

2. WiFi Config的Adapter不見了怎麼辦?
wifi-config-gui-no-adapter
/etc/network/interfaces/etc/wpa_supplicant/wpa_supplicant.conf 回復成預設值吧。

##### Default configuration of /etc/network/interfaces #####
auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
##### Default configuration of /etc/wpa_supplicant/wpa_supplicant.conf #####
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

[基礎] 從序列埠登入到 Raspberry Pi

購買產品:PL2303HX USB轉TTL傳輸線PL2303HXD USB轉TTL傳輸線

Raspberry Pi 有提供原生的序列(Serial)傳輸介面,因此只要透過 USB 轉 TTL 序列傳輸線,就可以在不需要螢幕和鍵盤滑鼠的情況下登入 Raspberry Pi (預設帳號密碼是 pi/raspberry),連上的虛擬終端機為 ttyAMA0。
序列傳輸介面至少需要有三條線,包括接地(GND)、接收(RX)和傳送(TX),參考接線圖如下。
connect-serial-to-raspberry-pi-model-b
connect-serial-to-raspberry-pi-model-b-plus本 Raspberry Pi B+ GPIO 腳位圖獲得授權使用

比較好的產品會有較多的連接線,例如做流量控制的 RTS/CTS 等。在不同作業系統使用的方式大同小異,詳細步驟如下。

注意:
1. 目前 PL2303HX 僅支援 Windows XP/Vista/7 和 Linux 使用,如果是 Windows 8 和 Mac 作業系統,需使用 PL2303HXD 才能正常使用。
2. 安裝 USB 轉 TTL 傳輸線設定時,Raspberry Pi 不需要開機。但是完成安裝後,記得要將 Raspberry Pi 開機,才能透過該序列傳輸線連接。

Windows XP
1. 沒有接上 USB 轉 TTL 序列傳輸線時的裝置管理員。
not-connect-to-serial

2. 接上 USB 轉 TTL 序列傳輸線時的裝置管理員,一開始會跳出”歡迎使用尋找新增硬體精靈”。我們先暫時忽略這訊息並下載驅動程式吧。
ask-for-insert-new-hardware

3. PL2303HXPL2303HXD 都是使用旺玖科技的晶片,官方網站驅動程式下載連結為:
http://www.prolific.com.tw/TW/ShowProduct.aspx?p_id=226&pcid=79
prolific-driver-download-url-windows

4. 下載後解壓縮執行 PL2303_Prolific_DriverInstaller_v1.8.0.exe,按照指示完成後重開機。再次開啟裝置管理員,可以發現多了一個連接埠 COM3。
connect-to-serial

5. 下載並開啟 putty。
putty-windows

6. 在 Connection type 先選擇 Serial,再根據剛剛的連接埠依序填入 Serial line、Speed的值。由於剛剛裝置管理員是看到 COM3,因此在 Serial line 也填入 COM3,Speed 填入 115200。
putty-serial-setting-windows

7. 相關的參數填完後,按 “Open” 就能連上 Raspberry Pi 如下圖。如果等了幾秒還是沒有畫面,可將 Raspberry Pi 重開(電源重插拔),應該就可以順利看到登入訊息。
successful-to-connect-to-raspberry-pi-via-serial-on-windows

Ubuntu Linux
1. 接上 USB 轉 TTL 序列傳輸線,打 ls /dev/ttyUSB*,在我們的環境是長在 ttyUSB0。
tty-usb0

2. 開啟 putty,如果還沒安裝請執行sudo apt-get install putty安裝。
putty-linux

3. 在 Connection type 先選擇 Serial,再根據剛剛的連接埠依序填入 Serial line、Speed的值。由於該節點是長在 ttyUSB0,因此在 Serial line 也填入 ttyUSB0,Speed 填入 115200。
putty-serial-setting-linux

4. 如果出現 Unable to open serial port 如下圖,改用 sudo 權限執行 putty。
putt_unable_to_open_serial_port

5. 相關的參數填完後,按 “Open” 將能連上 Raspberry Pi 如下圖。如果等了幾秒還是沒有畫面,可將 Raspberry Pi 重開(電源重插拔),應該就可以順利看到登入訊息。
successful-to-connect-to-raspberry-pi-via-serial-on-linux

Mac
1. 下載並安裝 PL2303HXD Driver,安裝後會重新開機。官方網站驅動程式下載連結為:
http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=229&pcid=41
prolific-driver-download-url-mac

2. 重開機生效。

3. 檢查是否出現裝置節點,打 ls /dev/cu*,如果出現 /dev/cu.usbserial,可以直接使用指令 screen /dev/cu.usbserial 115200 連線進去。

4. 如果沒出現 /dev/cu.usbserial,試著重插拔 USB 轉 TTL 傳輸線和重新插拔電源。

5. 如果使用 screen 後沒畫面出現,重新插拔電源試試看(USB 轉 TTL 傳輸線不要拔掉)。

常見問與答:

1. 我需要接紅色的線嗎?
如果將 USB 轉 TTL 傳輸線的紅色線接到 Pin 2,將會從傳輸線供電給 Pi 而讓 Pi 開機。由於我們已經有供給穩定的電源給 Pi,因此這邊我們不會將紅色線接到 Pin 2。

2. 我可以將序列埠的功能關掉嗎?
我們可以透過修改/boot/cmdline.txt,將

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

改為

dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

還要再修改/etc/inittab,將

#Spawn a getty on Raspberry Pi serial line
T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

改為

#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

再重開機即可。

[常見問與答] 如何在Raspberry Pi上擷取畫面?

如果是在 X Window 下,最簡單的方式是安裝 shutter,但這有兩個缺點,就是 shutter 相依的套件太多,所以光是截圖這個小功能就需要安裝將近 90MB 的套件,並且執行起來很慢,但使用最容易。

步驟如下:
1. 先安裝必要套件

pi@raspberrypi:~$ sudo apt-get install shutter

2. 從主要功能選單(main-menu)叫起來
shutter_shortcut
3. 執行區域性的截圖、或是全螢幕的截圖等功能
shutter_capture_window

如果覺的 shutter 不適合,還可以用 scrot + openbox,之後就可以按 PrtSc 直接做 snapshot。有關 scrot 的使用方式可以參考這篇

步驟如下:
1. 先安裝必要套件

pi@raspberrypi:~$ sudo apt-get install scrot

2. 增加按鍵的繫結(key binding),將 keybind 的定義放在 <keyboard> 和 </keyboard> 之間

pi@raspberrypi:~$ vi ~/.config/openbox/lxde-rc.xml
  <keybind key="Print">
      <action name="Execute">
          <command>scrot</command>
      </action>
  </keybind>

3. 進到桌面環境下,按 PrtSc 做 snapshot,擷取畫面的預設路徑是放在家目錄 (/home/pi) 下。
xwindow

 

如果是在 console 底下 可以透過 cat /dev/fb0 > snapshot.rawframebuffer 的資料轉存為 RGB565 的 raw 檔。但如果要用 Eye 等看圖軟體讀取,就需要將 raw 檔透過 FFmpeg 等軟體先轉為 PNG 或是 BMP 等格式。

幸運的是,我們也可以透過 vc_dispmanx_snapshot 這個函式取得目前螢幕的狀態。
Andrew Duncan 已經寫成成執行檔,下載後編譯就可以在 console 底下隨時擷取螢幕畫面。

步驟如下:
1. 先安裝必要套件

pi@raspberrypi:~$ sudo apt-get install libpng12-dev

2. 下載原始碼

pi@raspberrypi:~$ git clone https://github.com/AndrewFromMelbourne/raspi2png.git

3. 編譯

pi@raspberrypi:~$ cd raspi2png
pi@raspberrypi:~$ make

4. 使用,不加任何參數時預設是存成 png 格式的檔案

pi@raspberrypi:~$ ./raspi2png

console

可用的參數有以下幾種,當然這指令也可以在X Window下執行。

--pngname - 抓圖後的存檔名稱(預設是 snapshot.png )
--verbose - 顯示完整資訊
--height - 圖片高度(預設是螢幕的高度)
--width - 圖片寬度(預設是螢幕的寬度)
--type - 圖片的色彩格式,可用的格式為 RGB565 RGB888 RGBA16 RGBA32
--delay - 多久後擷取(預設是0,立刻執行)

最後,我們最喜歡用的其實是同一個作者的 fb2png。這程式可以讀取 framebuffer 並直接儲存成 png 格式的檔案。

步驟如下:
1. 先安裝必要套件

pi@raspberrypi:~$ sudo apt-get install libpng12-dev

2. 下載原始碼

pi@raspberrypi:~$ git clone https://github.com/AndrewFromMelbourne/fb2png.git

3. 編譯

pi@raspberrypi:~$ cd fb2png
pi@raspberrypi:~$ make

4. 使用

pi@raspberrypi:~$ ./fb2png

最後比較一下 raspi2png 和 fb2png,底下是相同時間的擷取結果,可以發現 raspi2png 是根據 VideoCore API 的 vc_dispmanx_display_get_info 傳回螢幕解析度,因此雖我們已經將 framebuffer 的解析度調整成 800×600,但是因為我們用的螢幕解析度是 1280×800,因此最後還是抓下 1280×800 的截圖。
snapshot

而 fb2png 則是開啟 /dev/fb0 的裝置檔,並根據 fb_var_screeninfo 回傳 framebuffer 的 xres 和 yres,因此最後截圖結果會是 800×600 的解析度,比較符合我們想要的結果。
fb

[基礎] 以 VNC 和 Raspberry Pi 連線

VNC 是一種使用 RFB 協定的螢幕畫面分享及遠端操作軟體。由於 VNC 與作業系統無關,因此可跨平台使用。如果我們需要和 Pi 做有圖形介面的連線,VNC 是首選。

這裡簡介如何在 Pi 上安裝設定 VNC 伺服器,並透過個人電腦以 VNC 用戶端連線到 Pi。

1. 在 Pi 上安裝 VNC 伺服器。

pi@raspberrypi:~$ sudo apt-get install tightvncserver

2. 在個人電腦安裝 VNC 用戶端。

sosorry@ubuntu:~$ sudo apt-get install vncviewer gtkvncviewer

3. 在 Pi 上啟動 vncserver。

pi@raspberrypi:~$ vncserver

如果是第一次執行 vncserver 時會問幾個問題,包括登入的密碼和可供其他人流覽的 read-only 密碼,而 read-only 密碼可以不設定。登入的密碼會加密後存在 ~/.vnc/passwd 檔案裡。

You will require a password to access your desktops.

Password: 
Verify:   
Would you like to enter a view-only password (y/n)? n

之後我們就可以透過 vncviewer 或是 gtkvncviewer 之類的軟體和 Pi 連線了。假設 Pi 的 IP 為 192.168.1.2。

sosorry@ubuntu:~$ vncviewer 192.168.1.2:5901

tightvnc

如果要對 VNC 伺服器做更多設定,常用的參數有:
- 連線埠 (:$NUM):例如設定 :1 開啟的 port 為5901,:2 開啟的 port 為5902,依此類推,預設為 :1。
- 解析度(geometry):例如 640×480, 800×600, 1024×768 等,預設為 1024×768。
- 像素深度(depth):例如 8, 16, 24 等,這是指每個像素可顯示的位元數,預設為 16。

例如我們想設定 VNC 伺服器監聽 5902 這個埠號,當有用戶連線到 5902 後可開啟一個 640×480 BGR233的畫面。

pi@raspberrypi:~$ vncserver :2 -geometry 640x480 -depth 8

如果使用 gtkvncviewer 連線,需要輸入 IP、port 和密碼,使用者名稱可任意輸入。

sosorry@ubuntu:~$ gtkvncviewer

gtkvncviewer_setup

連線成功的畫面。
gtkvncviewer

 

常見問與答:

1. 如何修改 VNC 伺服器的連線密碼?
我們可以用 vncpasswd 這個指令改 VNC 的連線密碼。

Using password file /home/pi/.vnc/passwd
Password: 
Verify:   
Would you like to enter a view-only password (y/n)? n

 

2. 我忘了設定 VNC 伺服器聽哪一個 port 了?
我們可以用 netstat 這個指令來查看目前系統開啟的 port。

pi@raspberrypi:~$ netstat -nutlp

-n :列出數字形式的連線地址
-u :列出 UDP 的連線
-t :列出 TCP 的連線
-l :正在進行 Listen (監聽)的服務之網路狀態
-p :列出 PID 與 Program 的檔名

pi@raspberrypi:~$ netstat -nutlp
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:6002            0.0.0.0:*               LISTEN      2124/Xtightvnc  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:5902            0.0.0.0:*               LISTEN      2124/Xtightvnc  
udp        0      0 0.0.0.0:22316           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -               
udp        0      0 192.168.1.2:123         0.0.0.0:*                           -               
udp        0      0 127.0.0.1:123           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:123             0.0.0.0:*                           -

我們也可以用 ps 這個指令查看目前系統執行的程序中。

pi@raspberrypi:~$ ps aux | grep vnc

- a :不和終端機 (terminal) 有關的所有程序
- u :所有有效使用者 (effective user) 的程序
- x :與 a 這個參數一起使用可列出完整資訊
- | grep vnc 表示只列出有包含 vnc 關鍵字的程序

pi@raspberrypi:~$ ps aux | grep vnc
pi        2124  0.0  0.9   6532  3460 ?        S    14:36   0:03 Xtightvnc :2 -desktop X -auth /home/pi/.Xauthority -geometry 640x480 -depth 8 -rfbwait 120000 -rfbauth /home/pi/.vnc/passwd -rfbport 5902 -fp /usr/share/fonts/X11/misc/,/usr/share/fonts/X11/Type1/,/usr/share/fonts/X11/75dpi/,/usr/share/fonts/X11/100dpi/ -co /etc/X11/rgb
pi        2128  0.0  0.1   1760   508 ?        S    14:36   0:00 /bin/sh /home/pi/.vnc/xstartup
pi        2426  0.0  0.2   3548   800 pts/0    S+   15:44   0:00 grep --color=auto vnc

 

3. 如何在開機時就啟動 VNC 伺服器?
在 /etc/init.d/ 下建立一個控制的腳本 (script),例如取名為 tightvncserver

pi@raspberrypi:~$ sudo vim /etc/init.d/tightvncserver

內容如下,重要的是在 start) 部份設定啟動的參數。

#!/bin/bash
### BEGIN INIT INFO
# Provides:          tightvncserver
# Required-Start:    $syslog
# Required-Stop:     $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: vnc server
# Description:
### END INIT INFO

export USER='pi'

eval cd ~$USER

# Check the state of the command - this'll either be start or stop 
case "$1" in
  start)
    # if it's start, then start vncserver using the details below
    su $USER -c '/usr/bin/vncserver :1 -geometry 800x600 -depth 16 -pixelformat rgb565'
    echo "Starting vncserver for $USER "
    ;;
  stop)
    # if it's stop, then just kill the process
    pkill Xtightvnc
    echo "vncserver stopped"
    ;;
  *)
    echo "Usage: /etc/init.d/tightvncserver {start|stop}"
    exit 1
    ;;
esac
exit 0

修改腳本權限。

pi@raspberrypi ~ $ sudo chmod 755 /etc/init.d/tightvncserver

將該腳本加入預設的啟動程序。

pi@raspberrypi ~ $ sudo update-rc.d tightvncserver defaults

執行結果如下。

update-rc.d: using dependency based boot sequencing
insserv: warning: script 'mathkernel' missing LSB tags and overrides

如果不喜歡這 warning,就順便修改一下 mathkernel 的腳本吧。

pi@raspberrypi ~ $ sudo vim /etc/init.d/mathkernel

根據 LSB 的規則將啟動資訊加到最前面。

### BEGIN INIT INFO
# Provides:          mathkernel
# Required-Start:    $local_fs 
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5 
# Default-Stop:      0 1 6 
# Short-Description: mathkernel
### END INIT INFO

重新啟動 Pi,再執行 netstat -nutlp 或是 ps aux | grep vnc,可以看到 VNC 伺服器已經跑起來了。

[常見問與答] sudo: effective uid is not 0, is sudo installed setuid root?

在某些情況下,sudo 會突然失靈,回傳錯誤訊息如: sudo: effective uid is not 0, is sudo installed setuid root?

解決方法如下:

1. 將 SD 卡接到其他電腦,在 /boot/cmdline.txt 最後面加上 single

2. 將 SD 卡插回 Raspberry Pi,重新啟動後將會進入 single user mode。

3. 將 /usr 的擁有者和群組改成 root,並修改全部權限為 rX 。

chown -R root:root /usr
chmod -R a+rX /usr

4. 更改 sudo 相關檔案的使用者和權限。

chown root:root /usr/lib/sudo/sudoers.so
chown -R root:root /etc/sudoers*
chmod 4755 /usr/bin/sudo

5. 測試。

su - pi
sudo
usage: sudo [-D level] -h | -K | -k | -V
usage: sudo -v [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-u user name|#uid]
usage: sudo -l[l] [-AknS] [-D level] [-g groupname|#gid] [-p prompt] [-U user name] [-u user name|#uid] [-g groupname|#gid] [command]
usage: sudo [-AbEHknPS] [-r role] [-t type] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []
usage: sudo -e [-AknS] [-r role] [-t type] [-C fd] [-D level] [-g groupname|#gid] [-p prompt] [-u user name|#uid] file ...

6. 將 single user mode 取消後重開機就大功告成了。

[進階] 編譯 Raspberry Pi 的核心

本文前言來自鳥哥的私房菜中的第二十六章、Linux 核心編譯與管理

核心是什麼?

其實核心就是系統上面的一個檔案而已,這個檔案包含了驅動主機各項硬體的偵測程式與驅動模組。

為什麼要編譯核心?

新功能的需求、原本核心太過臃腫、與硬體搭配的穩定性、其他需求(如嵌入式系統)。

 

這裡簡介編譯安裝 Raspberry Pi 的流程,未來我們還會常常回來看這篇。

1. 在個人電腦建構交叉編譯的環境,步驟可參考這裡

2. 查詢目前 Pi 的核心版本(以安裝2014-01-07-wheezy-raspbian.img 的映像檔為例,使用的核心版本為 3.10.25)。

pi@raspberrypi:~$ uname -a
Linux raspberrypi 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l GNU/Linux

3. 取得 Pi 的核心設定。

pi@raspberrypi:~$ zcat /proc/config.gz > .config

4. 在個人電腦下載核心原始碼。

sosorry@ubuntu:~$ cd rpi
sosorry@ubuntu:~/rpi$ git clone https://github.com/raspberrypi/linux.git
Initialized empty Git repository in /home/sosorry/linux/.git/
remote: Counting objects: 3512060, done.
remote: Compressing objects: 100% (586452/586452), done.
Receiving objects: 100% (3512060/3512060), 957.40 MiB | 3.18 MiB/s, done.
remote: Total 3512060 (delta 2897634), reused 3510306 (delta 2896207)
Resolving deltas: 100% (2897634/2897634), done.
Checking out files: 100% (43371/43371), done.

5. 切到目標分支。

sosorry@ubuntu:~/rpi$ cd linux
sosorry@ubuntu:~/rpi/linux$ git checkout rpi-3.10.y

6. 讀取目前 Pi 的核心設定,假設 Pi 的 IP 為 192.168.1.2。

sosorry@ubuntu:~/rpi/linux$ make mrproper
  CLEAN   scripts/basic
  CLEAN   scripts/kconfig
  CLEAN   include/config include/generated

sosorry@ubuntu:~/rpi/linux$ scp pi@192.168.1.2:/home/pi/.config .

sosorry@ubuntu:~/rpi/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- oldconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  SHIPPED scripts/kconfig/zconf.tab.c
  SHIPPED scripts/kconfig/zconf.lex.c
  SHIPPED scripts/kconfig/zconf.hash.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
scripts/kconfig/conf --oldconfig Kconfig
*
* Restart config...
*
*
* ALSA for SoC audio support
*
ALSA for SoC audio support (SND_SOC) [M/n/?] m
  SoC Audio for the Atmel System-on-Chip (SND_ATMEL_SOC) [N/m/?] n
  SoC Audio support for the Broadcom BCM2708 I2S module (SND_BCM2708_SOC_I2S) [M/n/?] m
    Support for HifiBerry DAC (SND_BCM2708_SOC_HIFIBERRY_DAC) [M/n/?] m
    Support for HifiBerry Digi (SND_BCM2708_SOC_HIFIBERRY_DIGI) [N/m/?] (NEW) 
    Support for RPi-DAC (SND_BCM2708_SOC_RPI_DAC) [M/n/?] m
    Support for IQaudIO-DAC (SND_BCM2708_SOC_IQAUDIO_DAC) [N/m/?] (NEW) 
  Synopsys I2S Device Driver (SND_DESIGNWARE_I2S) [N/m/?] n
  Build all ASoC CODEC drivers (SND_SOC_ALL_CODECS) [N/m/?] n
  ASoC Simple sound card support (SND_SIMPLE_CARD) [N/m/?] n
#
# configuration written to .config
#

7. 以選單方式選取所需要的功能。

sosorry@ubuntu:~/rpi/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig

raspberry_pi_kernel_configuration

8. 編譯核心(k, –keep-going)。

sosorry@ubuntu:~/rpi/linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -k V=1

9. 安裝核心模組。

sosorry@ubuntu:~/rpi/linux$ mkdir ../modules
sosorry@ubuntu:~/rpi/linux$ make modules_install ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=../modules/

10. 使用內建的工具產生出 Raspberry Pi 的核心(kernel.img)。

sosorry@ubuntu:~/rip/linux$ cd ~/tools/mkimage
sosorry@ubuntu:~/rpi/tools/mkimage$ ./imagetool-uncompressed.py ~/rpi/linux/arch/arm/boot/zImage"

11. 將 kernel、firmware、lib 安裝到 Pi 上(假設 SD 卡已經 mount 在 ~/sdb1 和 ~/sdb2)。

sosorry@ubuntu:~/rpi/tools/mkimage$ sudo cp -Rf ~/rpi/modules/lib/firmware/ ~/sdb2/lib/
sosorry@ubuntu:~/rpi/tools/mkimage$ sudo cp -Rf ~/rpi/modules/lib/modules/ ~/sdb2/lib/

12. 移除 SD 卡,重新啟動 Pi,查詢核心版本,可以看到我們從 3.10.25 升級到 3.10.37。

pi@raspberrypi:~$ uname -a
Linux raspberrypi 3.10.37+ #1 PREEMPT Wed Apr 16 03:12:08 CST 2014 armv6l GNU/Linux

常見問與答:

1. 如果沒有 /proc/config.gz 怎麼辦?
請先執行 pi@raspberrypi:~$ sudo modprobe configs 就可以了
(感謝 Jimmy Chen 的貢獻)

RASPBERRY.ORG參考資料:
* KERNEL BUILDING
* CONFIGURING THE KERNEL
* PATCHING THE KERNEL

[進階] 安裝 Raspberry Pi 的 Toolchain

Toolchain 是一套能讓你編譯、連結、除錯程式的軟體,例如 GCCLDGDBAS glibc 等。

假設我們寫了一個 hello.c 的程式要在個人電腦上執行,我們只要打 gcc hello.c 就可以將 hello.c 編譯成 x86 架構的可執行檔。

由於 Raspberry Pi 上的處理器是 ARM 架構的,因此要將同樣的 hello.c 在 Raspberry Pi 執行,必須將程式編譯成 ARM 架構的可執行檔。

我們有兩個選擇,第一是直接在 Raspberry Pi 上編譯。第二是先在我們的個人電腦用 Raspberry Pi 的 toolchain 編譯完成後,再上傳到 Pi。

這裡簡介如何在個人電腦安裝 Raspberry Pi 的 toolchain,以在 ubuntu 上安裝 gcc-linaro-arm-linux-gnueabihf-raspbian 為例。

1. 在個人電腦安裝必要的套件。

sosorry@ubuntu:~$ sudo apt-get install make git-core ncurses-dev

2. 下載最新版的 toolchain。

sosorry@ubuntu:~$ mkdir rpi
sosorry$ubuntu:~$ cd rpi
sosorry@ubuntu:~/rpi$ git clone https://github.com/raspberrypi/tools.git
remote: Reusing existing pack: 17273, done.
remote: Total 17273 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (17273/17273), 311.52 MiB | 343 KiB/s, done.
Resolving deltas: 100% (11698/11698), done.
Checking out files: 100% (15860/15860), done.

3. 安裝 toolchain。安裝方法是將 gcc-linaro-arm-linux-gnueabihf-raspbian 加到環境變數裡。

sosorry@ubuntu:~/rpi$ vi ~/.bashrc
export PATH=$PATH:/home/sosorry/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin   # add this line at the end of file

4. 測試。先開啟一個新的終端機,輸入 arm 後連續按兩次 tab 鍵,如果跑出來一堆像下面的提示表示安裝成功。

arm-linux-gnueabihf-addr2line        arm-linux-gnueabihf-gcc              arm-linux-gnueabihf-gfortran         arm-linux-gnueabihf-objdump
arm-linux-gnueabihf-ar               arm-linux-gnueabihf-gcc-4.7.2        arm-linux-gnueabihf-gprof            arm-linux-gnueabihf-pkg-config
arm-linux-gnueabihf-as               arm-linux-gnueabihf-gcc-ar           arm-linux-gnueabihf-ld               arm-linux-gnueabihf-pkg-config-real
arm-linux-gnueabihf-c++              arm-linux-gnueabihf-gcc-nm           arm-linux-gnueabihf-ld.bfd           arm-linux-gnueabihf-ranlib
arm-linux-gnueabihf-c++filt          arm-linux-gnueabihf-gcc-ranlib       arm-linux-gnueabihf-ldd              arm-linux-gnueabihf-readelf
arm-linux-gnueabihf-cpp              arm-linux-gnueabihf-gcov             arm-linux-gnueabihf-ld.gold          arm-linux-gnueabihf-size
arm-linux-gnueabihf-elfedit          arm-linux-gnueabihf-gdb              arm-linux-gnueabihf-nm               arm-linux-gnueabihf-strings
arm-linux-gnueabihf-g++              arm-linux-gnueabihf-gdbtui           arm-linux-gnueabihf-objcopy          arm-linux-gnueabihf-strip

讓我們實際寫一個 hello.c 並編譯它吧。

sosorry@ubuntu:~/rpi$ vi hello.c
#include <stdio.h>
int main()
{
	printf("hello, world\n");
        return 0;
}

用 Raspberry Pi 的 toolchain 編譯 hello.c。這一步驟稱為交叉編譯(cross-compiling)。

sosorry@ubuntu:~/rpi$ arm-linux-gnueabihf-gcc hello.c -o hello-arm

讓我們看看檔案的資訊,可以看到該檔案是 ARM 的格式。

sosorry@ubuntu:~/rpi$ file hello-arm
hello-arm: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, not stripped

如果我們在 x86 環境下試著執行會發現無法成功。

sosorry@ubuntu:~/rpi$ ./hello-arm 
bash: ./hello-arm: cannot execute binary file

我們把 hello-arm 上傳到我們的 Pi,假設 IP 為 192.168.1.2。

sosorry@ubuntu:~/rpi$ scp hello-arm pi@192.168.1.2:/home/pi
pi@192.168.1.2's password: 
hello-arm                                                                                                                             100% 5447     5.3KB/s   00:00

在我們的 Pi 上執行,看看結果吧。

pi@raspberrypi:~$ ./hello-arm
hello, world

 

常見問與答:

1. 為什麼要在個人電腦上安裝 toolchain?
因為個人電腦的處理速度通常高於 Raspberry Pi ,因此如果要開發比較大的專案(例如編譯核心),建議在個人電腦上處理,才不會等等等等。實務上在嵌入式系統的開發過程中,目標機器通常不會有 toolchain,因此常常會需要先在開發環境上將專案交叉編譯後再燒到目標機器。

2. 為什麼要安裝 gcc-linaro-arm-linux-gnueabihf-raspbian?
因為在 userland README.md 告訴我們的。

This repository contains the source code for the ARM side libraries used on Raspberry Pi. These typically are installed in /opt/vc/lib and includes source for the ARM side code to interface to: EGL, mmal, GLESv2, vcos, openmaxil, vchiq_arm, bcm_host, WFC, OpenVG.

Use buildme to build. It requires cmake to be installed and an arm cross compiler. It is set up to use this one: https://github.com/raspberrypi/tools/tree/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian

3. 如果個人電腦(主機端)是 64 位元的要裝那個版本的 toolchain?
要使用 tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin 目錄下的執行檔,也就是將該路徑加入環境變數即可。