星期二, 12月 18, 2012

星期四, 11月 22, 2012

PCIe

PCI Express (PCIe, PCI-E)
  • 以序列點對點匯流排取代之前 PCI、PCI-X、AGP 的並列共享匯流排,但軟體跟 PCI 相容。PCI 取代 ISA、VESA,是 multi-master。
  • 一組序列點對點匯流排稱為 lane (通道),包含傳跟收的差動訊號共四條線。一個 PCIe 插槽可有 2n lanes,0 ≤ n ≤ 5。
  • PCIe Gen 3 每個通道大約會轉換為 1 GB/s。PCIe Gen 4 每個通道大約會轉換 2 GB/s,可向下相容。
  • M.2。https://www.kingston.com/tw/community/articledetail/articleid/48543
  • M.2 介面的 SSD 有 PCIe NVMe 和 SATA3 兩種規格,PCIe 又有 3.0 和 4.0 的差異。
PCI Express Mini Card (Mini PCIe)
  • 插槽除了電源外,可包含 PCIe lane、USB 2.0、SMBus、SIM Card、LED 等介面。
  • 接頭也用在 mSATA
Express Card
  • 跟 MiniPCIe 類似,一樣包含 PCIe lane、USB 2.0 介面。其前身 CardBus 是 32-bit @33MHz PCI 介面 (3.3V 電源),再前身 PCMCIA Card (PC Card) 是 16-bit ISA 介面。

miniPCI: PCI, 2W max. (Mini PCIe 取代)
cPCI (CompactPCI): PCI 背板含 PCI bus 及其他自訂的訊號,如電話、網路等。

M.2 是電腦內部擴充卡連接的規格。

  • M.2 取代 mSATA。
  • 搭配更先進的界面 features,比 mSATA 更適合 SSD
  • 界面可以有 PCI Express 達 4 通道、SATA 3.0、和 USB 3.0 (a single logical port for each of the latter two),取決於主機和模組要支援什麼界面,不同 keying notches 來避免模組插到不相容的主機連接器。
  • SSD 邏輯界面支援傳統 SATA 的 Advanced Host Controller Interface (AHCI) 和 PCIe 的 NVM Express (NVMe)。NVMe 能進行平行 IO 來完整利用高速 PCIe 儲存裝置的能力。
YearSpec.Frequency/SpeedBandwidth
1992PCI33 MHz133 MB/s (32-bit simplex)
1993PCI 2.066 MHz533 MB/s (64-bit simplex)
1999PCI-X133 MHz1.06 GB/s (64-bit simplex)
2002PCI-X 2.0266 MHz2.13 GB/s (64-bit simplex)
2002PCIe 1.x2.5 GHz2 Gb/s (x16 duplex 8GB/s)
2006PCIe 2.x5 GHz 4 Gb/s (x16 duplex 16GB/s)
2010PCIe 3.x8.0 GHz 8 Gb/s (x16 duplex 32GB/s)
2017PCIe 4.x16.0 GT/s 128/130 編碼16 Gb/s (x16 duplex 64GB/s)
2019PCIe 5.x32.0 GT/s 128/130 編碼32 Gb/s (x16 duplex 128GB/s)

PCI device 的定址包括 8-bit bus、5-bit device (32 個)、及 3-bit function (8 個)。每個 PCI 系統可以有 256 PCI buses,bus 間透過 PCI bridge 連接。
  • ID: domain (16-bit) + bus (8-bit) + device (5-bit) + function (3-bit)
  • per device configuration space
  • per bus memory-mapped space
    • cached or uncached
  • per bus IO-mapped space
    • 會有附帶動作, uncached
  • interrupt: 4 interrupt pins per PCI slot
    • interrupt lines are shareable and the routing to CPU is platform dependent.
每個 PCI function 的 configuration space 包含 256 bytes (PCI Express 有 4 KB), 須透過特別的 kernel 函數存取
  • standardized layout
  • First 64-byte is standardized
  • Little-endian
  • 4B unique function ID
  • Access: read and write registers of PCI controller (vendor dependent)
  • /proc/bus/pci/devices
  • /proc/bus/pci/*/* : binary
  • /sys/bus/pci/devices

參考

  1. https://en.wikipedia.org/wiki/M.2
  • Linux Device Drivers 3rd Edition, Chapter 12 PCI Driver

星期二, 11月 20, 2012

Raspberry Pi vs. MK802

一些 Raspberry Pi 跟 MK802 比較的文章
基本上,MK802 速度較快,記憶體較多,內建 Flash,有 802.11 b/g Wi-Fi (但無 Ethernet),有 USB OTG 當週邊。MK802 最大的問題是開放程度較低,相對支援跟社群也較少,要使用 GPIO 擴充較不容易。Ethernet 較容易解決,用 USB 轉就可以了,Raspberry Pi 也是用 SMSC LAN9512 將一個 USB 轉成 Ethernet 跟兩個 USB。

2012/11/27 補充: MK802 沒有 RCA Composite 端子,對沒有 HDMI 線及螢幕的我較不方便。另外,cubieboard  好像更好

星期六, 11月 17, 2012

shift register

Image from http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf
74HC595
74 系列的移位暫存器 IC 基本上都有序列輸入 (serial-input, SI) 及序列輸出 (serial-output, SO) 功能,有些有加上並列輸入 (parallel-input, PI) 或並列輸出 (parallel-output, PO),或者雙向移位功能,此外還有加上儲存暫存器或三態輸出。

例如 74164 是一個八位元的 SIPO 移位暫存器,而 74594 則再 PO 加上儲存暫存器,可讓移位過程中輸出不受影響。74595 則是 74594 再加上三態輸出,如圖。

74595 或 74594 可以作為 SPI 的 GPIO 擴充,把 SPI 的 SCK、MOSI、SS\ 分別接到 74595 的 SHCP、DS、STCP (MR\ 跟 OE\ 接地),SS\ 結束的 rising edge 剛好將資料載入儲存暫存器。

一些其它移位暫存器:
74165 8-bit PISO
74166 8-bit bidirectional PISO
74597 8-bit input register + PISO
74194 4-bit bidirectional + PI + PO
74299 8-bit bidirectional + 共用的 PI 及三態 PO
4014 PISO + 3-bit PO
4015 Dual 4-bit SIPO
4094 類似 74595,但沒有清除功能
7731 Quad 64-bit SISO

參考:
  1. http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf
  2. http://conductiveresistance.com/interactive-595-shift-register-simulator/

星期日, 11月 11, 2012

[Lua] Global Variable


全域變數不用宣告,存取尚未有的全域變數會得到 nil (存取未初始化的變數皆會得到 nil)。
一般不需要特地刪除全域變數,但指定為 nil 就是刪除。如果想要變數的生命有個範圍, 應該使用區域變數

[Lua] local variable

在 Lua 全域變數不需要宣告,但可以宣告區域變數 (local variable),例如:
local i=1
效用到區塊結束自動消失,區塊可能是一個 control structure、一個函數、或一個 chunk。

變數使用 local 宣告是較好的,避免充斥不必要的全域變數,存取也較快。未指定初始值時是 nil

local foo=foo 可以在區塊內加速 foo 存取,修改但最後保留原值。

在互動模式下使用時要注意,除非不是完整的指令,不然每輸入一行,就是一個 chunk,下一行 local 宣告就失效了。可用 do-end 區塊延續 local 宣告。

參考:
  1. Programming in Lua (second edition) by Roberto Ierusalimschy, Lua.org, March 2006

[Lua] multiple assignment


assignment (指定) 就是「變數=值」。而 multiple assignment 就是一次可以多個值指定給多個變數,多個變數跟多個值用「,」隔開。如果變數數目較多,多出來的部份指定為 nil:如果值的數目較多,多出來的部份忽略。
  • evaluate 所有值,然後才指定給變數 => 可用來做交換 (swap)
    • 例如 x 跟 y 交換:x, y = y, x
  • function 可以回傳多個值,需要 multiple assignment 才能接收多個值。

[Lua] nil

nil
  • 無或空的意思
  • 未初始化的變數會得到 nil
  • 變數指定為 nil 就是刪除
  • 在邏輯判斷上,nil 是 false

星期六, 11月 10, 2012

[OpenWrt] AR71xx Flash Partitions

之前提到 OpenWrt 至少要有 4 MiB Flash,例如 TL-WR703N 就用 4 MiB Flash,而 TL-WR1043ND 用 8 MiB,它們的 Flash 利用是怎樣規劃的呢?這裡是以 TP-Link 的路由器做說明:(有兩個數字的欄位,分別為 4 MiB Flash 跟 8 MiB Flash 的情形)

partitionoffsetsizesize (KiB)
u-boot
(mtd0)
0x00x20000128
firmware
(mtd5)
kernel
(mtd1)
0x200000x3D0000
0x7D0000
3904
8000
rootfs

(mtd2)

[squashfs]
/rom

rootfs_data
(mtd3)
/overlay
art
(mtd4)
0x3F0000
0x7F0000
0x1000064
  • u-boot 固定 128 KiB,其中位址 0x1FC00 為 MAC Address、0x1FE00 為 PIN
  • art 固定佔用最後的 64 KiB
  • u-boot 跟 art 之間的區域就是 firmware,其 image 由 OpenWrt 的工具程式 mktplinkfw 產生,共由 header、kernel、rootfs 三個部份組成。
    • header 固定為 512 (0x200) bytes,紀錄許多關於韌體資訊的欄位,mtd 分割併入 kernel。
    • kernel 使用剩下的就是 rootfs 空間。kernel 可使用 gzip 或 lzma 壓縮,後者使用的空間較小,讓 rootfs 有更多空間,尤其是使用 4MiB Flash 的時候。
      • 可能是 u-boot 不支援 lzma 壓縮的關係,lzma 壓縮的 kernel 其實會多一層 lzma-loader 載入,然後才能載入真正的 kernel,但整體來說使用的空間較小。例如我剛編譯的 kernel (vmlinux) 是 2,817,980 bytes,gzip 壓縮後是 1,282,951 bytes,lzma 壓縮後是 928,491 bytes。lzma-loader 4,630 bytes,但實際佔用 7,680 bytes 空間,加上 lzma kernel 為 93671,比 gzip 少了 338 KiB。
    • rootfs 使用 squashfs 唯讀檔案系統,使用剩下的空間又自動分出為 rootfs_data 分割作為可讀寫 overlay。
參考:
  1. http://wiki.openwrt.org/doc/techref/flash.layout

星期五, 11月 09, 2012

[Lua] boolean

boolean 是 Lua 八種基本資料型態之一,包括 false 跟 true。判斷時,false 跟 nil 為 false:其它皆為 true,數字 0 跟空字串 "" 也是 true

[Lua] string

Lua 字串 (Lua 八種基本資料型態之一)
  • 可包含任何字元,包括 \000,結尾沒有 \000。
  • 內容是不能改變的,改變需要另建新字串
  • single or double quoted
  • escape sequence
    • \a:bell
    • \b:backspace
    • \f:form feed
    • \n:換行
    • \r:carriage return
    • \t:水平跳位
    • \v:垂直跳位
    • \\:「\」
    • \":「"」
    • \':「'」
    • \數字:最多三位十進位數字,如果後面不是數字,數字開頭的 0 可省略
  • double square bracket,類似註解,可用成對的「[[」跟「]]」或「[=[」跟「]=]」(依此類推,兩邊等號數目要相等),不解釋裡面的 escape sequence,例如
    page=[[
    <html>
    <head>
    <title>An HTML Page</title>
    <head>
    <body>
    Hello World
    </body>
    </html>
    ]]

    write(page)
  • 數字運算時自動轉換成數字,明確轉換用函數 tonumber
  • 「..」字串 concatenation operator,如果前面接數字,要有空格,不然會視為小數點。明確轉為字串用函數 tostring
  • length operator:字串前面加「#」
參考:
  1. Programming in Lua (second edition) by Roberto Ierusalimschy, Lua.org, March 2006

[Lua] identifier

識別字
  • 由字母、數字 (不能當開頭)、或「_」組成的字串
  • 可以自己把「_」預留為 dummy 變數
  • 避免使用「_大寫字母」,例如 _VERSION,Lua 保留作為特殊用途
    • _PROMPT:互動模式時的提示字
  • 保留字:and break do else elseif end false for function if in local nil not or repeat return then true until while
參考:
  1. Programming in Lua (second edition) by Roberto Ierusalimschy, Lua.org, March 2006

[Lua] comment

註解
  • 任何地方「--」開始,直到行末
區塊註解
  • 以「--[[」開始,直到下個「]]」
  • 以「--[=[」開始,直到下個「]=]」,依此類推,兩邊等號數目要相等
小技巧:使用成對的「--[[」跟「--]]」,要取消註解,只要前面多加「-」變成「---[[」
--[[
--註解
--]]
取消
---[[
--取消區塊註解
--]]
參考:
  1. Programming in Lua (second edition) by Roberto Ierusalimschy, Lua.org, March 2006

星期四, 11月 08, 2012

[Lua] Hello World

安裝:sudo apt-get lua5.2
(註:目前 Ubuntu 1304 是用 liblua5.1)

檔案:hello.lua
print("Hello World")
執行:lua hello.lua
Hello World
參考:
  1. Programming in Lua (second edition) by Roberto Ierusalimschy, Lua.org, March 2006 
相關文章
  • lua教學 - 不錯的 lua Hello World 文章,應該是《Programming in Lua》某個章節的翻譯,使用 lua 互動模式使用 print 印出字串、數字,數字運算,字串運算,數字變數,io.write(),io.read()。

星期三, 11月 07, 2012

[OpenWrt] sysupgrade

/sbin/sysupgrade 是一個 shell 指令檔,在 OpenWrt 自動化韌體更新作業,包括保留設定檔、覆寫 firmware 分割[註]、重開機等等。

基本上,sysupgrade 需要 RAM 暫時儲存韌體及保留的設定檔。會保留的檔案或目錄紀錄在 /etc/sysupgrade.conf 跟 /lib/upgrade/keep.d/*。sysupgrade 加 -n 參數則不保留。

sysupgrade 會載入 /lib/upgrade 下的命令檔,不同 platform 需要提供自己的 platform_check_image() 來檢查更新檔是否正常,一般是 /lib/upgrade/platform.sh。此外亦可提供自己的 platform_do_upgrade() 及 platform_copy_config()。

註:raw flash 使用 mtd write,x86 跟 x86_64 用 dd,x86 的 olpc 用 > /dev/hda

參考:
  1. https://openwrt.org/docs/guide-user/installation/generic.sysupgrade
  2. /sbin/sysupgrade

星期一, 10月 22, 2012

[OpenWrt] preinit

一般 Linux 執行的第一個指令會是 /sbin/init、/etc/init、/bin/init、/bin/sh 其中之一 ,而 OpenWrt 將第一個執行的指令改為 /etc/preinit。

/etc/preinit 會呼叫 /lib/preinit/ 下的 script 來準備下列五組程式組,記在環境變數裡,並執行前面兩組:
  1. preinit_essential:會先執行,大致上是在掛載 /proc, /sys, /tmp, /dev 等,跟相關 daemon,以及初始化 console。
  2. preinit_main:大致包括載入 reset 按鍵驅動,設定網路界面,檢查是否執行 failsafe 程式組,初始化 hotplug,檢查是否執行 initramfs 程式組,執行 preinit_mount_root 程式組,回復系統設定,最後執行 /sbin/init。
  3. failsafe:提供 telnet 登入
  4. initramfs:似乎是空的
  5. preinit_mount_root:掛載根目錄

星期三, 10月 10, 2012

[設備] TP-LINK TL-WR703N

號稱市面上最小的含有 USB Host 的 Wi-Fi AP,也相當省電,低於 1W[參考來源]

主要處理器是 Atheros AR9331,內含:
  • AR7240 CPU @400MHz
  • Wi-Fi 802.11b/g/n
  • Fast Ethernet (有 5 port,但 WR703N 只用一個)
  • USB 2.0
外加 4MB Flash 及 32MB RAM

AR9331 也用在 TL-MR3020 (多開關及一些燈號)、TL-WR741ND (使用 5 port Ethernet)

由於 OpenWrt 有支援,常拿來改成其它應用。

拆解:[參考]。應該拿小一字起子,往有卡榫的地方插下去。我插在卡榫旁邊不太好拆,需要一些暴力,造成一些損傷。

接 UART 出來
  • 拆開後,正面下方的 TP_IN 及 TP_OUT 分別是 UART 的 Rx 及 Tx,如果接 FT232R 或其它轉 USB 的晶片或連接線,只需要再找一個 GND 接點。有人把 Ethernet 或 USB 的鐵殼當 GND,其實不是。除了背面的 TPGND 外,可以找的很多地方去接 GND。
  • baud rate 是 115200。
備份 u-boot 及 art:
  • u-boot 是 bootloader,損壞的話,將無法開機,也無法做任何更新動作,只能解焊 SPI Flash 透過燒錄器寫入好的 u-boot,才能讓 TL-WR703N 重新運作。有了 u-boot 之後,就可以更新其它任何部份。
  • art 是放無線校準後的資料,損壞的話,可以開機,但會影響到無線功能無法使用。這裡提到,如果沒經過校準,Wi-Fi 訊號可能會較差;也就是複製別台同樣型號及處理器的 art,未必適用。
  • 參考這裡,在 UART console 下用 Linux 的 cp 指令讀出 u-boot 及 art 分割,透過網頁存到 PC。應該也可以使用指令「dd if=/dev/mtd0 of=/tmp/boot.backup」跟「dd if=/dev/$(grep '"art"' /proc/mtd |cut -c 1-4) of=/tmp/art.backup」讀出。
加大 SPI Flash (例如改用 8MB SPI Flash)
  • firmware 修改:
    1. OpenWrt 的 tools/firmware-utils/src/mktplinkfw.c
      •  TL-WR703Nv1 的 fw_max_len 改成 0x7c0000
    2.  target/linux/ar71xx/files/arch/mips/ar71xx/mach-tl-wr703n.c
      • rootfs 的 .size 改成 0x6d0000
      • art 的 .offset 改成 0x7f0000
      • firmware 的 .size 改成 0x7d0000
    3. 編譯,結果在 bin/ar71xx/openwrt-ar71xx-tl-wr703n-v1-squashfs-*.bin
  • 最終 8MB SPI Flash 的內容應該是:
    • u-boot 複製自原本的 flash,放到 8MB flash
    • art 複製自原本的 flash,放到到最後分割,也就是位址 0x7f0000 開始的地方
    • firmware 需要改成支援 8MB Flash 後重新編譯產生,放到位址 0x20000 開始的地方
  • 解焊舊 SPI Flash,焊上新 8MB SPI Flash。
  • 參考
參考資料:

星期一, 10月 08, 2012

[OpenWrt] min. flash and RAM

OpenWrt 至少要有 4MB flash 及 16MB RAM。有些 2MB Flash 或 8MB RAM 的無線路由器 -- TL-WR702N 等,就無法執行 OpenWrt,但基於 Broadcom 處理器的在 DD-WRT 還勉強可以

星期六, 10月 06, 2012

OpenWrt LED

無線路由器有許多 LED 顯示狀態。在 OpenWrt 下,如何控制 LED 呢?

除了電源狀態 (PWR) 是有電就亮,及一些 Ethernet 狀態 (WAN 和 LAN 1 2 3 4) 是 Ethernet Controller 直接控制外,其它 LED 是接到 SoC 的 GPIO,Linux Kernel 有個 platform 子系統,並有一些針對 GPIO 的現成驅動程式,例如驅動程式 leds-gpio 用來控制 LED。只要把 GPIO 的位置,所使用的驅動程式及功能在編譯前設定好,編譯後的 Linux Kernel 就能支援這些 GPIO。
  • 準備資料結構 struct gpio_led,內含每個 LED 名稱、GPIO 接腳、是否 low 動作等。例如:
    static struct gpio_led tl_wr1043nd_leds_gpio[] __initdata = {
        {
            .name        = "tl-wr1043nd:green:wlan",
            .gpio        = TL_WR1043ND_GPIO_LED_WLAN,
            .active_low    = 1,
        }
    };
    不清楚 LED 名稱為何要取 tl-wr1043nd:green:wlan 這麼一長串
  • 透過 platform_device_alloc() 取得使用 "leds-gpio" 的資料結構 struct platform_device。(相反是 platform_device_put())
  • 建構資料結構 struct gpio_led_platform_data,包括 LED 數目,及 leds 欄位指到 struct gpio_led
  • 透過 platform_device_add_data() 加進 struct gpio_led_platform_data
  • 透過 platform_device_add() 登記到 Linux Kernel
上述例子是在 Linux 的 arch/mips/ar71xx/mach-tl-wr1043nd.c 執行 arch/mips/ar71xx/dev-leds-gpio.c 裡的 ar71xx_add_device_leds_gpio() 完成的。

編譯後的 Linux 就會有 /sys/class/leds/tl_wr1043nd:green:wlan/  目錄。使用方式,例如
點亮 LED:
echo 1 > /sys/class/leds/tl_wr1043nd:green:wlan/brightness
熄滅 LED
echo 0 > /sys/class/leds/tl_wr1043nd:green:wlan/brightness
應該還有其它用法,待了解。

星期六, 9月 22, 2012

FXS 轉 UART

連接話機的界面是 FXS (Foreign eXchange Station),連接局端的界面是 (FXO, Foreign eXchange Office),FXS 或 FXO 轉換成其它界面叫 ATA (Analog Telephone Adaptor)。網路上可以找到兩個將 FXS 轉成 UART 的專題,都是 David Rowe 的傑作:一開始的「 $10 ATA」跟構想延伸的「Mesh Potato 的 FXS 界面」,想在無線路由器加 FXS 界面,而 UART 是無線路由器都有的界面,只藏在裡面的電路板上,baud rate 115 kbit/s 就夠 64 kbit/s 的語音使用。

「$10 ATA」後來也受到 Mesh Potato 影響,但最後資訊是去年三月,之後可能沒有進展,或者作者未公佈,主要缺如何一起在 UART 傳振鈴及 hook 資訊,跟整合測試。其架構如下:
     +---------------+   +--------------------+
     |     Hybrid    |<->|ADC/PWM             |
話機-| DC-DC/ringing |<->|PWM/ADC  ATmega328P |--UART
     | hook detector |-->|PWM                 |
     +---------------+   +--------------------+
ATmega328P 是 AVR 八位元微處理器,也用於 Arduino,可以處理類比訊號,用其 ADC 及 PWM 來轉換類比訊號。作者一系列文章:
Mesh Potato 已經是一個產品了,是一個含有 FXS 界面的戶外型 802.11bg mesh router,相當特別。架構如下:
     +--------+   +--------------------+  +------------+
     |        |<--|SPI                 |<-|GPIOs       |
話機-| Si3210 |   |       CPLD         |  |     AR2317 |
     |        |<->|TDM                 |->|UART Rx     |
     +--------+   +--------------------+  |            |
                  | ATmega8L(16B FIFO) |<-|UART Tx     |
                  +--------------------+  +------------+
AR2317 是 Atheros 的無線 MIPS 4KEc SoC,用於 AIR-300 等無線路由器。Si3210 是 FXS 界面晶片,包括 hybrid、DC-DC converter、振鈴、hook 偵測等,語音走 TDM,控制走 SPI。CPLD 主要是要轉換 UART 跟 TDM,但可能是內部 buffer 不夠,所以加 ATmega8L。

參考

  • Silvertel Ag2130 PSTN 界面模組。(RT03106)
  • USB FXS

星期五, 9月 21, 2012

FT232R

FT232R 是一個 USB 轉 UART 的晶片,整合 clock 及 EEPROM 等,讓線路非常簡單。有些 Arduino 含有 FT232R 來提供 USB 界面,例如 DuemilanoveDiecimila,但新的 Leonardo 使用 ATmega32u4 處理器已經內建 USB 了。FT232R 除了 UART 功能外,亦可作為 Clock 產生器,透過 bit bang 模式提供 GPIO 或 SPI 功能,或者作為 FTDIChip-ID™ security dongle 功能。
  • 相關文件:DatasheetBit Bang Application NoteFTDIChip-ID™ Application Note
  • 內建 128 bytes EEPROM 作為設定用,其中 Manufacturer, ManufacturerId, Description, SerialNumber 字串最長 96 bytes,沒用完的可作為 user area 或 FTDIChip-ID 使用。
  • 可產生 6/12/24/48 MHz clock
  • Big Band I/O
    • Asynchronous:UART 8 IO 作為 8-bit data,CBUS 提供 RD# 跟 WR# 訊號
    • Synchronous:同上
    • CBUS Mode:CBUS0~CBUS3 4-bit GPIO
  • 內建 3.3V 電源轉換,最大提供 50mA。
  • 驅動程式
    • Virtaul Com Port (VCP):變成一般序列埠使用
      • Linux: ftdi_sio → usbserial
    • Direct (D2XX):設定 EEPROM 及 bit bang 需要
    • libFTDI for Linux
      • 裡面的 ftdi_eeprom_build() 或 ftdi_eeprom_decode() 可看出 EEPROM 內容每個位址的定義。

FT232RL IO 訊號
PinName預設功能Bit Bang
CBUS modeAsynchronous / Synchronous
1TXD 輸出D0
5RXD 輸入D1
3RTS# 輸出 (Arduino Reset)D2
11CTS# 輸入D3
2DTR# 輸出 (Arduino Reset)D4
9DSR# 輸入D5
10DCD# 輸入D6
6RI# 輸入D7
23CBUS0TXLED# 輸出4-bit GPIO其中兩個作為 RD# 及 WR#
22CBUS1RXLED# 輸出
13CBUS2TXDEN 輸出,RS-485 用。
14CBUS3PWREN# 輸出,需外加 10kΩ pull high,USB 設定完 low,USB suspend 時 high。
12CBUS4SLEEP# 輸出,USB suspend 時 low。
CBUSx 都可以設定成任何 CBUS 功能,除了表列五種外,尚有 TX&RXLED#、6/12/24/48 MHz clock 輸出。

內部 EEPROM,整理自 datasheet 及 libFTDI。
parameteraddressvalue說明
High Current I/Os0.20
10x40IN endpoint size
Vendor ID3~20403hFTDI default VID
Product ID5~46001hFTDI default PID
Device Type7~60x06000x0600=FT232R
Battery Powered8.40
Remote Wake Up8.51RI# low → wake up USB Host Controller in 20 ms
Bus Powered 8.61
Load VCP Driver8.71Make the host to load VCP driver。此位置是猜測的。
Max Bus Power Current990mA以 2 mA 為單位
IN endpoint is isochronous0x0a.00
OUT endpoint is isochronous0x0a.10
Enable suspend I/O power down0x0a.20
Use serial number string0x0a.30
Change USB Version0x0a.40
Invert TXD0x0b0
Invert RXD0
Invert RTS#0
Invert CTS#0
Invert DTR#0
Invert DSR#0
Invert DCD#0
Invert RI#0
USB Version0x0d~0x0c0x0200USB 2.0 Full Speed
Manufacturer Offset0x0e.6~00x18指向 10, 0x03, "FTDI"
Manufacturer Enabled0xe.71
Manufacturer Size0x0f10byte 數含結尾 0,因每個字佔 2 bytes,所以需乘二
Product Description Offset0x10.6~00x24指向 32, 0x03, "FT232R USB UART"
Product Description Enabled0x10.71
Product Description Size0x1132
Serial Number Offset0x12.6~00x46指向 18, 0x03, "A6001dHI",A unique serial number
Serial Number Enabled0x12.71
Serial Number Size0x1318
CBUS00x14.3~030=TXDEN, 1=PWREN#, 2=RXLED#, 3=TXLED#, 4=TXRXLED#, 5=SLEEP#, 6=CLK48, 7=CLK24, 8=CLK12, 9=CLK6, 10=Bitbang IO mode, 11=Bitbang WR#, 12=Bitbang RD#
CBUS10x14.7~42
CBUS20x15.3~00
CBUS30x15.7~41
CBUS40x16.3~05
Dynamic Content0x18~0x7f見說明預設應該是放 Manufacturer, Production Description, 及 Serial 字串。字串含 0,每字佔兩個 byte。格式依序是長度,0x03,字串本身。
10, 0x03, "FTDI"
32, 0x03, "FT232R USB UART"
18, 0x03, "A6001dHI"
ChipID0x86~0x89見說明

USB 的請求控制指令:
  • reset (0x00)
  • set baud rate (0x01)
  • set data (0x02):設定 RS-232 參數
  • set flow control (0x03)
  • modem control (0x04):設定 DTR, RTS 等。
  • poll modem status (0x05)
  • set event char (0x06)
  • set error char (0x07)
  • set latency timer (0x09)
  • get latency timer (0x0a)
  • set bit mode (0x0b)
  • read pins (0x0c)
  • read eeprom (0x90)
  • write eeprom (0x91)

實際應用

星期六, 9月 15, 2012

三輪車

小蘿蔔們合作完成的三輪車,少了腳踏板。

星期五, 8月 31, 2012

NXT-G 教育版 2.1 軟體修正

小蘿蔔把 Humanoid 做好,我把示範程式下載來試看看,結果 NXT-G 教育版 2.1 要上載到 NXT 時出現錯誤:
A required file is broken
Error code : 1003
但讀取 NXT 狀態是正常的。此後要上載任何程式到 NXT 都會同樣的錯誤,必須把整個 NXT-G 關掉再重新執行,使用其它本來可以的程式才會正常。這個問題需要 NXT EDU: 2.1f3 Patch for Windows 解決,說明檔提到有一項修正剛好就是:
Opening certain programs results in not being able to download any programs, error code 1003
(打開特定程式後無法下載,錯誤代碼 1003)
NXT EDU: 2.1f3 Patch for Windows 下載回來、解開、執行裡面的 setup.exe 便可修正。

Linux 用 USB 跟 NXT 通訊

之前在「Linux 用藍牙跟 NXT 通訊的程式」透過藍牙跟 NXT 通,其實最直接是接 USB,一樣使用 NXT Communication Protocol。

網路上就有現成可執行的程式 -- t2n (Talk To NXT),下載,放好 udev 規則讓一般使用者有權限,便可使用:C++,使用 USB
wget  http://www-verimag.imag.fr/~raymond/edu/lego/t2n/t2n-0.4.tgz
tar xvf t2n-0.4.tgz
sudo cp t2n-0.4/udev/71-lego.rules /etc/udev/rules.d/
開啟 NXT,接上 USB,執行
./t2n-0.4/t2n -b -i -ls
就可以取到電池電壓、NXT 資訊、檔案列表,如下:
battery level = 7948mV
#### NXT INFOS ###############
protocol version=1.124 firmware version=1.28
NXT Name: NXT
Blutooth address: 16:53:17:7f:ffffffcf:00
Blutooth signal: 0
Free user flash: 77180
FILE:"Untitled-1.rxe" SIZE:4768
FILE:"Program.tmp" SIZE:13
FILE:"a.rpg" SIZE:13
FILE:"NVConfig.sys" SIZE:6
FILE:"DemoV2.rxe" SIZE:3996
FILE:"RPGReader.sys" SIZE:5908
FILE:"faceclosed.ric" SIZE:316
FILE:"faceopen.ric" SIZE:316
FILE:"Woops.rso" SIZE:2232
FILE:"! Startup.rso" SIZE:4084
FILE:"! Attention.rso" SIZE:881
FILE:"! Click.rso" SIZE:229
FILE:"Try-Color.rtm" SIZE:4346
FILE:"Try-Touch.rtm" SIZE:1238
FILE:"Try-Light.rtm" SIZE:684
FILE:"Try-Ultrasonic.rtm" SIZE:1208
FILE:"Try-Motor.rtm" SIZE:676
FILE:"Try-Sound.rtm" SIZE:638
FILE:"" SIZE:0
另外還可以上載、下載檔案,執行參數是:
  • -put <檔名> : 上載檔案
  • -get <檔名> : 下載檔案
t2n 是 GPL 版權,有原始碼讓你研究,是用 C/C++ 寫的。


另外列出一些網路上找到的其它程式,不過我沒試就是。

順便列一些 NXT USB 資訊


lsusb 輸出:
Bus 003 Device 006: ID 0694:0002 Lego Group Mindstorms NXT

sudo cat /sys/kernel/debug/usb/devices 輸出:
T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  6 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=0694 ProdID=0002 Rev= 0.00
S:  SerialNumber=001653177FCF
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms

星期日, 8月 26, 2012

Linux 用藍牙跟 NXT 通訊的程式

遙控 NXT 車最簡單應該是用 NXT 內建的藍牙,上林老師教的 NXT 藍牙遙控車,是用一個 NXT 透過藍牙控制另一個 NXT 車,我想來搞一個不一樣的遙控車。但我只有一個 NXT,手機也沒有藍牙,就先由電腦來控制,剛好有一個幾年前申辦網路送的藍牙耳機附的 Dongle DBT-122T 可用。

Windows 下有現成的藍牙程式可以控制 NXT,例如 NXT Remote--使用電腦鍵盤遙控NXT。我平常用 Linux 電腦較多,NXT 在 Linux 的資源沒有 Windows 那麼豐富,不過找到了這份簡報,裡面有一個透過藍牙讀取 NXT 電池電壓的 C 程式,測試紀錄如後。
  1. 電腦安裝藍牙及編譯程式:我的電腦跑 Ubuntu 12.04,但不是標準的,很多套件被我移除了。bluez 包括 Linux 的藍牙程式及工具,libbluetooth-dev 含編譯藍牙用的標頭檔,gcc 是 C compiler。
    sudo apt-get install bluez libbluetooth-dev gcc
  2. 開啟 NXT 藍牙功能
  3. 搜尋藍牙設備:使用 hcitool scan,會顯示 NXT 的 MAC 位址及名稱。MAC 位址在下一步寫程式時會用到。
    $ hcitool scan
    Scanning ...
     00:16:53:17:7F:CF NXT
    
  4. 電腦藍牙程式:藍牙通訊也是用 socket,通訊協定依照 NXT Communication Protocol,可到 Bluetooth Developer Kit 下載,Mindstorms NXT 與 Arduino之間的藍牙通訊 有一些說明。複製簡報中的程式,填上 NXT 的 MAC 位址,並修正一些錯誤,如下。
    /* nxt_getbattery.c */
    #include <stdio.h>
    // Socket, used for Bluetooth socket
    #include <sys/socket.h>
    #include <sys/types.h>
    
    // Bluetooth headers
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/rfcomm.h>
    
    // Global Variables
    int nxtSocket;
    int init_bluetooth(char *btAddress)
    {
     struct sockaddr_rc addr={0};
     int status;
    
     /*-----------------------------------------------------------
      * SOCK_STREAM
      * Provides sequenced, reliable, two-way, connection-based
      * byte streams. An out-of-band data transmission
      * mechanism may be supported.
      *----------------------------------------------------------*/
    
     // Allocate a socket
     nxtSocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    
     // Set what type and who to connect to
     addr.rc_family = AF_BLUETOOTH;
     addr.rc_channel = (uint8_t) 1;
     str2ba(btAddress, &addr.rc_bdaddr);
    
     // Connect to the NXT
     status = connect(nxtSocket, (struct sockaddr *)&addr, sizeof(addr) );
     if (status < 0) {
      perror("Error connecting Bluetooth");
      return status;
     }
     return 0;
    }
    
    /****************************************************************
     * * nxt get battery level
     * * this will get the battery level on the nxt
     * * returns: the battery level as an integer
     * ***************************************************************/
    #define MAX_MESSAGE_SIZE 64
    int nxt_getbattery(void)
    {
     /*------------------------------------------------------
      * * direct command format:
      * * {length/lsb, length/msb, byte 0, byte 1... byte n}
      * *
      * * for getbatterylevel (see direct commands):
      * * byte 0: 0x00
      * * byte 1: 0x0b
      * * length/lsb: 0x02, the command length is 2 bytes
      * *----------------------------------------------------*/
     char cmd[4]={0x02, 0x00, 0x00, 0x0b};
     char reply[MAX_MESSAGE_SIZE];
     int result;
     int blevel;
     int replylength;
     int error = 0;
     //- send request -----------------------------------------
     if ( (result = write(nxtSocket, cmd, 4)) < 0 ) {
      perror("error sending getbatterylevel command ");
      return result;
     }
    
     //- read reply -----------------------------------------
     // get bluetooth message length
     if ( (result = read(nxtSocket, reply, 2)) < 0) {
      perror("error receiving getbatterylevel reply ");
      return result;
     }
     replylength = reply[0] + (reply[1] * 256);
    
     // get return package
     if ( (result = read(nxtSocket, reply, replylength)) < 0) {
      perror("error receiving getbatterylevel reply ");
      return result;
     }
    
     // quick check to make sure we got everything
     if (replylength != result) {
      fprintf(stderr,
       "getbatterylevel : lengths do not match : %d != %d\n",
       replylength, result);
     }
    
     /*------------------------------------------------------
      * * return package format:
      * * {length/lsb, length/msb, byte0, byte1..., byten}
      * * for getbatterylevel:
      * * byte0: 0x02
      * * byte1: 0x0b
      * * byte2: status byte
      * * byte3-4: voltage in millivolts (uword)
      * * length/lsb: 0x05
      * *----------------------------------------------------*/
     // byte 0
     if (reply[0] != 0x02) {
      fprintf(stderr, "getbatterylevel : byte 0 : %hhx != 0x02\n", reply[0]);
      error = 1;
     }
     // byte 1
     //if (reply[1] != 0x13) {
     if (reply[1] != 0x0b) {
      fprintf(stderr, "getbatterylevel : byte 1 : %hhx != 0x0b\n", reply[1]);
      error = 1;
     }
     // byte 2
     if (reply[2] != 0x00) {
      fprintf(stderr, "getbatterylevel : byte 2, status : %hhx \n", reply[2]);
      error = 1;
     }
     if (error) {
      return -1;
     }
     // byte 3-4
     blevel = reply[3] + (reply[4] * 256);
     return blevel;
    }
    
    int main (void) {
     // nxt brick alpha bluetooth address
     //char btaddress[18] = "00:16:53:01:2c:84";
     char btaddress[18] = "00:16:53:17:7F:CF";
     int blevel;
    
     // initiate bluetooth connection
     if (init_bluetooth(btaddress) < 0) {
      close(nxtSocket);
      return 1;
     }
     printf("bluetooth connected to %s \n", btaddress);
     // get battery level (direct command)
     blevel = nxt_getbattery();
     if (blevel < 0) {
      close(nxtSocket);
      return 1;
     }
     printf("battery level: %.3f\n", blevel/1000.0);
     close(nxtSocket);
     return 0;
    }
    
  5. 編譯
    gcc nxt_getbattery.c -o nxt_getbattery -lm -lbluetooth
  6. 執行程式,NXT 會「ㄅㄧ」一聲顯示 Passkey: 1234,按橘色鈕確認會發生 Permission denied 錯誤,原來藍牙需要先配對一次。
    $ ./nxt_getbattery
    Error connecting Bluetooth: Permission denied
    
  7. 藍牙配對 (只有第一次需要,配對過後就不需要了):正常安裝的 Linux 可能會出現小視窗讓你輸入就解決了,可是我的電腦較慢,用較陽春的 LXDE 桌面,並移除了許多套件,並不會自動出現輸入 Passkey 的小視窗。找到這篇,裡面提到許多方式,但我偏好指令行,開另一個終端機,執行:
    bluetooth-agent 1234
  8. 最後執行成功,電壓只有 6.9 V,有點低。
    $ ./nxt_getbattery 
    bluetooth connected to 00:16:53:xx:xx:xx 
    battery level: 6.903
    
雖然是個簡單的程式,但是其它應用重要的基礎。簡報裡後面還有一個 NXT Mailbox 範例,以後再研究。

星期六, 4月 07, 2012

VirtualBox 共用資料夾

建立客端跟主端間共用使用的資料夾。

首先,客端必須安裝好客端額外功能
再來,主端要建立共用資料夾
  • 透過視窗選單「裝置」→「共用資料夾」,加入共用資料夾,設定
    • 資料夾路徑:選擇在主端的一個目錄。
    • 資料夾名稱:給一個名稱識別,後面識別時會用此名稱,但都小寫。
    • 是否
      • 唯讀:在客端不能寫入
      • 自動掛載:自動掛載到 media/sf_資料夾名稱,vboxsf 群組才能使用。(所有檔在在客端變成可執行,這樣不太好)
      • 永久性:屬於「機器資料夾」,會記下來;否則屬於「暫時資料夾」,關機後就消失了
最後,客端連結共用資料夾 (不同客端作業系統方式不同,這裡是 Ubuntu 10.04 Server 的情形)
sudo mount -t vboxsf -o rw,uid=<your-uid>,gid=<your-gid> <資料夾名稱小寫> <掛載點>
或在 /etc/fstab 加一行
<資料夾名稱小寫> <掛載點> vboxsf rw,uid=<your-uid>,gid=<your-gid> 0 0
使得在開機時自動掛載。

VirtualBox 安裝客端額外功能

在客端 (guest) 作業系統安裝完成後,可以再安裝客端額外功能,包括一些驅動程式及系統應用程式,讓主客間有更好的整合及效能。功能包括 (依據 VirtualBox 官網文件):
  • 滑鼠整合
  • 共用資料夾:跟主端共用,這是我會去安裝客端額外功能就是為了這個功能。
  • 更佳顯示支援:包括較高解析度非標準顯示模式,可以調整視窗大小及解析度,並提供 2D/3D 加速。
  • 支援無痕視窗
  • 通用主客通信通道
  • 時間同步:同步主端時間。
  • 跟主端共享剪貼簿
  • 自動登入
每個 VirtualBox 版本都有其對應的客端額外功能,最好兩者能維持一致,所以要用每個 VirtualBox 版本附的 VBoxGuestAdditions.iso 來安裝。
  1. 安裝編譯外部 kernel 模組環境
    • sudo apt-get update
    • sudo apt-get upgrade
    • sudo apt-get dist-upgrade (有可能更新 kernel 版本)
    • sudo apt-get install dkms (安裝 Dynamic Kernel Module Support,我的客端是 Ubuntu 10.04 Server,安裝的套件計有 binutils dkms fakeroot gcc gcc-4.4 libc-dev-bin libc6-dev libgomp1 linux-headers-2.6.32-40 linux-headers-2.6.32-40-generic linux-headers-generic linux-libc-dev manpages-dev,最後可移除)
  2. 掛載 VBoxGuestAdditions.iso 並執行
    • [VirtualBox VM 視窗] 裝置 → 插入 Guest Additions CD 映像 (相當於放入 VBoxGuestAdditions.iso 光碟給客端用)
    • sudo mount /dev/cdrom /mnt
    • sh /mnt/VBoxLinuxAdditions.run (由於沒視窗環境,所以安裝視窗系統驅動程式會失敗)
    • 重啟生效
去查 kernel 模組多了 vboxguest 及 vboxsf。

註:fedora 10 安裝客端額外功能 [參考來源]
先安裝
yum -y update kernel
yum -y install kernel-devel kernel-headers dkms gcc gcc-c++

星期三, 3月 07, 2012

初識 iSCSI

Synology DS212j 有支援 iSCSI,來了解一下這是什麼。

iSCSI (Internet SCSI) 是將 SCSI 硬碟的指令在 IP 網路上跑,類似網路芳鄰的一種網路儲存空間的通訊協定,不同的是網路芳鄰看到的儲存空間是一個可放檔案的目錄,而 iSCSI 看到的是更底層的硬碟,無論是實體的或虛擬的硬碟,可以對它格式化,決定使用的檔案系統,就像本機硬碟一樣。我想如果 BIOS 有支援的話,應該可以用當開機碟。一個 iSCSI 硬碟群稱為 iSCSI Target,會有一個 IQN 名稱給使用端 iSCSI Initiator 識別連接用。

這篇的比較結果,iSCSI 速度比網路芳鄰慢,且我的分享以檔案為主,而不是硬碟分享,所以暫且就不考慮使用 iSCSI。

整理一下 Synology 的儲存架構,由下而上分別為:
  • 實體硬碟是最基本儲存硬體。
  • 硬碟群組 (Disk Group) 由數個硬碟組成。(我的沒有這一層)
  • 儲存空間 (Volume) 可能是一個實體硬碟,或一個硬碟群組的全部或部份。
  • iSCSI LUN 代表一顆 iSCSI 硬碟,可放在某個儲存空間裡 (Synology 支援機動空間配置),或是一個硬碟群組的全部或部份。
  • iSCSI Target 代表一個硬碟群,可有一個或數個 iSCSI LUN,並有一個 IQN 名稱給 iSCSI Initiator 連接其下所有硬碟用。
一個 iSCSI 硬碟可讓多個 iSCSI Initiator 連結使用,但一般檔案系統會有檔案完整性問題,要特定檔案系統,如「VMware 虛擬主機檔案系統 (VMFS)」或「Oracle Cluster 檔案系統 (OCFS)」才適合。

在 Linux 的 iSCSI Initiator 是 open-iscsi,可參考「在Ubuntu中使用iSCSI Initiator連接至iSCSI Target」或「在Ubuntu 使用 iSCSI Initiator」。

星期六, 3月 03, 2012

Synology DS212j 初次使用

此時最重要的參考是快速安裝指南
  1. 內部至少裝上一顆硬碟。
  2. 接上網路、電源,開機。
  3. 在電腦安裝 Synology Assistant 並執行,會自動搜尋 Synology 設備。要 DS212j 開機完成,此時藍色電源燈恆亮,才能搜尋到。
  4. 透過 Synology Assistant 安裝 DSM (版本 3.2_1955) 到 DS212j,等候完成。
  5. 完成後 DS212j 會重開機,此時  SynologyAssistant 還在等候,最後會寫入設定。然後可開啟網頁 GUI 登入,可看到它正在新增「儲存空間 1」,包括檢查硬碟中及建立檔案系統,這會相當久,去做其它事吧。
  6.  「儲存空間 1」正常後,到「控制台」→「共用資料夾」新增共用資料夾後,就可以透過網路芳鄰存取。
DS212j 算是 Synology NAS 產品裡最省電的,存取中 17.6W (我放一顆 640GB 硬碟 Seagate ST3640323AS,實測是 11W),硬碟休眠中 5.5W (實測 4W)。最省電當然是把它關掉,長按電源鍵就會啟動關機程序,最後關閉電源,是很友善的設計。

DS212j 沒有 WOL,應該是處理器 88F6281 不支援。但有定時開關機功能,以每週為排程週期,時間一到會自動關機,也會自動開機喔,神奇吧。如果可以設定一次性的關開機那就更好了,例如已經事先知道停電時間,設定好就可以在停電前關機,復電後自動開機,回復所有服務。

[2012/03/09 補充] 新增一顆 1TG 硬碟 WD10EARX
[2012/03/07 補充] 2012/03/06 Synology 釋出 DSM 4.0-2197
[2012/03/07 補充] DS212j 前身 DS211j 使用韌體 3.2beta 跟 QNap TS-212 詳盡的比較:QNap TS-212 NAS vs Synology DS-211j

星期五, 1月 20, 2012

Ubuntu 家目錄漢文目錄名稱改為英文

2013/12/3 補充:LANG=C xdg-user-dirs-gtk-update 勾選「Don't ask me this again」,然後按「Update Names」也可以

參考太武山人:改更 Ubuntu 中文目錄名稱,但作一些簡化,並借用 4$ 的圖來說明
1.進 Terminal 先把語系設成英文
export LANG=en_US
2. 執行更新名稱程式
xdg-user-dirs-gtk-update
出現如下圖,勾選 Don't ask me this again,然後按 Update Names (不是 Keep Old Names 喔)

星期四, 1月 12, 2012

架個人網頁伺服器 -- 使用 ligthttpd

架設 lighttpd 放個人網頁 ( 網址:http:///~<帳號>),步驟如下:

sudo apt-get install lighttpd
sudo lighty-enable-mod userdir
sudo /etc/init.d/lighttpd force-reload
mkdir ~/public_html
vi ~/public_html/index.html

延伸閱讀
  • 台北行: 台灣黑客鬆:「lighttpd 雖然對 server 來說是 light,但是在 embedded 系統上仍屬於大噸位的程式」