2008年12月20日 星期六

關於 touch screen driver

其實 touch screen driver 的部分,這裡這裡的文章已經提過了,只要把 patch 抓下來 apply 至核心原始碼中,再加上些修正即可。不過沒人規定不能重新發明輪子吧?我還是想先自己寫寫看,來了解一下應該如何去設定相關的控制器,以及實際在板子上的運作情況如何。既然是自己找樂趣玩,又有何不可?

不過實際寫了之後,發現雖然使用手冊詳實敘述了各個暫存器的意義,但對於該如何設定以及設定順序為何,還是非常空洞;沒辦法,再回去參考了 patch 的原始碼,才豁然開朗。但話說回來,經過了親手下去實作的過程,有了更深一層的了解,再回來看原始程式,才能很快地抓住你所想知道的關鍵部分,並立即套用至你的程式中。這也算是一種學習驅動程式撰寫的方法之一吧…

接下來,再把程式修改修改,就可以上版子來測試了。

2008年11月17日 星期一

近況報告

自從 2.6.27 發布以來,我就沒有再 post 新的 patch 了。當然不是因為熱情消失了,主要是因為最近這幾個月工作上的事情比較繁忙,下班回到家就有些懶了;再加上上個禮拜個人家中開發用的 PC 主機板出了問題,開不了機,拿去送修又折騰了一段時日,是故這個月沒什麼產出。
不過好在主機板送修回來了,如果測試後確定沒問題,那麼等到工作告一段落,計畫應該就可以繼續進行下去。

2008年10月11日 星期六

加入 Frame buffer 支援

上個月底,我上傳了另一個 patch,主要為加入開發板的 LCD 支援。由於 S3C2440 的 LCD 控制器已有完整的驅動程式支援,是故在設定上也相當容易。你需要根據面板的 datasheet 來設定如解析度、pixel clock、bpp (bits per pixel)和其他相關的 timing 參數,剩下的 LCDCON5 的內容可直接參考其他開發板的設定。

和面板有關的參數設定在 struct s3c2410fb_display 這個結構中,其宣告為

struct s3c2410fb_display {
    /* LCD type */
    unsigned type;

    /* Screen size */
    unsigned short width;
    unsigned short height;

    /* Screen info */
    unsigned short xres;
    unsigned short yres;
    unsigned short bpp;

    unsigned pixclock;    /* pixclock in picoseconds */
    unsigned short left_margin;    /* value in pixels (TFT) or HCLKs (STN) */
    unsigned short right_margin;    /* value in pixels (TFT) or HCLKs (STN) */
    unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */
    unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */
    unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */
    unsigned short vsync_len;    /* value in lines (TFT) or 0 (STN) */

    /* lcd configuration registers */
    unsigned long lcdcon5;
};

以我的面板為例,這塊面板是 HITACHI 的七吋面板,型號為 TX18D16VM1CAA,根據手冊所記載,其可接受的 pixel clock 的最大週期為 33ns (相當於 30KHz);Hsync 訊號寬度為 128 個 pclk,螢幕左方邊界寬度為 88 個 pclk,右方為 40 pclk;Vsync 訊號寬度為 2 個 Hsync 週期,上方邊界寬度為 32 個 Hsync,下方為 11 個 Hsync。解析度為 800x480。

程式碼加入後,在 make config 中開啟 S3C24xx 之 frame buffer 支援,重新編譯後下載至開發板即可。

另外,你也可以在核心啟動參數中加上 fbcon=rotate:<n> 來設定螢幕的方向。0 為不旋轉,1 為旋轉 90 度,2 為旋轉 180 度,3 為旋轉 270 度,方向皆為逆時針方向。

2008年9月12日 星期五

[好文] 如何加入 Linux 開發社群

How to participate in the Linux Community
http://ldn.linuxfoundation.org/book/how-participate-linux-community

就在幾個月前,動心起念想要貢獻一些程式碼時,還真是不知該如何入門;深怕一個不小心,也許是程式的錯誤,或是英文不好引起誤會,或不了解某些規矩,而被 list 上的開發者給打槍,並回以鄙夷的指責。不過在 post 了幾個 patch 之後,事實證明了我是多慮了。當然還是有些規矩要遵守,只是犯了錯也沒那麼嚴重,通常開發者會好心提醒你該作什麼事,改回來就好,社群仍然會歡迎你的加入。

當然如果可以有一些文件教導我們這些新人,豈不更好?幸好有這本小書的出現,替我們指點迷津。24 頁的內容包含新進開發者該有的心態,以及該如何和社群互動、修改程式、準備及上傳 patch、撰寫信件的注意事項、開發者常犯的錯誤等等,足夠菜鳥們在正式踏入前有個心理準備,而我也從中受惠許多,發現了一些自己不曾注意到的小細節,或許可以再做得更好。

總之,強烈推薦新進開發者一定要讀讀這本書。

2008年9月1日 星期一

The fix for the SD controller driver

前一陣子在測試新加入的 SD 驅動程式時,發現了一個怪異的問題:某些卡可以正確偵測,某些卻不行。目前我所可以拿來測試的 SD 卡有兩塊;一塊是 512MB,SD 1.1 標準的卡,另一塊則是 256MB,SD 2.0 的卡。第一張卡沒有問題,但第二張卡卻出現以下的錯誤訊息:

s3c2440-sdi s3c2440-sdi: running at 0kHz (requested: 0kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: running at 265kHz (requested: 264kHz).
s3c2440-sdi s3c2440-sdi: mci_setup_data() transfer stillin progress.
s3c2440-sdi s3c2440-sdi: CMDSTAT: error CMDTIMEOUT
s3c2440-sdi s3c2440-sdi: powered down.
mmc0: error -110 whilst initialising SD card
s3c2440-sdi s3c2440-sdi: powered down.
倒數第四行出現了 command timeout 的訊息,再仔細查看,發生錯誤的命令是 CMD6 (switch card function),而之前的命令是 ACMD51 (read SCR),該命令需要設定資料傳輸來讀取 SCR 的值。怪就怪在,當資料已傳輸完成,下個指令 (CMD6) 要重新設定資料傳輸時,卻發現狀態暫存器中的旗標仍然指示資料在傳輸中,因而驅動程式強迫終止資料傳輸,並重設 (reset) 控制器。重設的結果,便是所有暫存器中的內容回復為初始化前的預設值,同時關閉了控制器送給 SD 卡的時脈輸出。當然緊接在後的命令也都跟著錯誤。

雖然我並不非常熟悉 SD 的 protocol,但我覺得應該不是上層 protocol stack 的問題,畢竟第一張卡是可以正確運作的;由於 S3C2440 的使用手冊上載明這個控制器只有符合 SD 1.0 的規範,是故猜想可能是控制器的問題,所以我送了一個 patch,主要是在重設控制器以後,重新打開 SD 的時脈輸出,以便使後續的命令可以繼續運作。

即使手上有晶片使用手冊,並仔細研讀,但在面對這種在文件上毫無著墨的怪異行為時,仍是不免讓人感到挫折。

PS.
MMC protocol stack 的維護者 Pierre Ossman 提醒我,不要在 SD 卡的電源關閉時開啟 SD 時脈訊號,此舉有可能會導致 SD 卡的損壞。不過我認為應該不會發生這種情況;會執行到這段程式碼時,表示 SD 卡的電源已被開啟,並且已經開始接受命令了。又控制器重設時並沒有動到對應於 SD 時脈的 GPIO 針腳的狀態,是故應該不會有損壞的問題。

2008年7月29日 星期二

加入 SD/MMC 支援

昨天送了一個 patch主要為加入 SD/MMC 的支援到這塊開發板上。由於在最近幾個月,git kernel 終於加入了 S3C24xx 系列 SD/MMC 驅動程式的支援,是故我的修正就只是將這塊板子的設定照著填入對應的資料結構內即可。

另外稍微需要做些修改的地方在於,s3cmci.c 中對於 S3C2410 及 S3C2440 的初始化有一點不同,而 Ben Dooks 在 /arch/arm/plat-s3c24xx/devs.c 所定義的 s3c_device_sdi 名稱為 "s3c2410-sdi",這部分要改為使用 "s3c2440-sdi"。此外,在 card detection 上,這塊開發板使用的是 GPIO G10,也要額外設定其 s3c24xx_mci_pdata 結構。

2008年7月11日 星期五

ARM Linux source tree freeze

7月9日,Russell King 在回覆信件時提到,上禮拜六釋出了 2.6.26-rc9,距離 2.6.26 正式版只剩一個禮拜;但這一個禮拜以來,他還是收到了大量的修正(他形容為 mad panic mode),光星期一就收到了 136 份修正,得花掉他整整二天的時間來消化,令他疲於奔命。

因此在 10 日他發了一封聲明,表示他將要凍結目前的源碼樹以進行合併,除了臭蟲修正以外,請大家不要再送新的 patch 給他了;如果要送 patch,下次請早。

2008年7月1日 星期二

發送第一個 patch

大約在上星期的時候,我發送了第一個針對開發板修改的 patch 後,Ben Dooks 隨後不久便回覆我,除了指出我一個未察覺到的錯誤外,還希望我針對一些他不明瞭的部分再多做說明。當我回答後,他似乎覺得沒什麼大問題,便要我針對之前的 review comment 再做修改,並且先將這些修正修補到一份乾淨的核心原始碼樹中做編譯測試,確定沒問題後,再把修改過的 patch 送上來。

經過了幾天,在上星期六,我再發送了第二個版本的 patch,這次就沒什麼問題了,Ben 也會將這份修正加入到他的合併清單之中。

當然對於嫻熟於開放原始碼社群運作模式的人,送 patch 是家常便飯,沒什麼值得大書特書的;不過對於像我這種新手來說卻是一種很奇妙的體驗,藉由送修正、審查修正、再送修正…這樣多次往返的流程,讓程式碼更臻完美,得以一種簡潔的樣貌合併進入主流核心之中。正如 Thomas Gleixner 所言,和核心團隊一同運作,除了增進程式碼的品質,開發者自身的能力也會在這樣互動的過程中逐步提升,這是一個多贏的局面。

我想,我未來應該還會再繼續送 patch 吧。

2008年6月30日 星期一

為何要和主流核心保持互動?

就在幾天前我送出第一個針對開發板移植的 patch 後,Eric Miao 看到了我的訊息,便利用 gTalk 丟水球來聊一聊。Eric 是 PXA 架構的維護者,本身也在 Marvell 工作。他以為我是開發版廠商裡頭的人,我跟他說我是以個人名義做開發,他才了解怎麼一回事,並開玩笑地說我可以去向他們要錢了。

不過他提到,大陸在做開發板的公司,由於成本考量,往往移植的核心都固定在某一個版本,而不願意跟著主流核心版本做維護,這引發了我另外一種的思考。不錯,當公司的產品還不夠普遍時,確實需要另外請人維護並確保新版核心可以在產品上運作;不過將修改過的原始碼合併至主流版本的同時,你也達到了廣告的效果,告訴人們你有在賣這類產品,並且最新版的核心直接就可以在上面運作。能夠增加曝光的機會,代表的是可能會有更多的訂單進來。當你的銷售量達到一定規模、夠普遍的時候,你不需要請人,自然就會有人來接手維護的工作,那麼額外的人事成本就能夠節省下來。

所以問題在於,公司願不願意多花些錢做點廣告,介紹你的產品,讓全世界的人都能認識你的產品,並為你的產品多增加些潛在的客群?

當然,對我而言,動機就單純得多。我只是想要在上面跑最新版的核心,但不希望每次新版釋出就要再改一次程式碼,於是將修正貢獻合併回主流核心就成了最佳的選擇。

一點意見,還請不吝指教。

2008年6月29日 星期日

網路支援完成

最近這二天適逢周末,我趁著有空閒時,開始來研究 git kernel 及原廠自行修改的 DM9000 網路晶片驅動程式原始碼。不過兩相對照之下,初始化過程其實差不多,雖然在 dm9000_rx() 函式中程式有些不同,不過經過測試後發現其實沒什麼影響。後來我根據初始化時所做的條件判斷及開發板的線路圖,在開發板初始化程式中再加入了以下的定義:

static struct dm9000_plat_data at2440evb_dm9k_pdata = {
    .flags = (DM9000_PLATF_8BITONLY | DM9000_PLATF_NO_EEPROM),
};

意思是指示驅動程式晶片的資料埠寬度為 8 bits,且晶片並未連接 eeprom。
不過測試時卻無法驅動。我照著線路圖和晶片手冊設定的應該沒錯,可就是不會動,真是百思不得其解。後來無意間設定成 DM9000_PLATF_16BITONLY,竟然就可以動了…可是這樣一來就和線路圖產生矛盾了…難不成廠商給我的是錯的???有必要再釐清一下。

花了一個下午的時間,網路算是可以正常工作了,稍後整理一下就可以送 patch 了。

2008年6月17日 星期二

開機成功

經過幾天的 code tracing,大致上已經了解 S3C24xx 架構的原始碼是如何安排的,接下來我在 ARM Linux 的 machine registry 去註冊了新的 machine type,接著開始移植的工作。我先以 arch/arm/s3c2440/ 目錄下的 mach-anubis.c 為樣板,刪去了不需要的程式碼,並加入了一些板子獨有的硬體設定,接著修改 Kconfig 以及 Makefile,最後重新編譯核心,第一階段完成。

接下來將核心的 rootfs 掛載為 initramfs,可以順利開機,其他基本的驅動程式,如 RTC,UART,NAND 等也順利啟動,唯一有問題的就是網路晶片。核心原始碼中已附有 DM9000 的驅動程式,但不知為何,無法正確驅動,我猜測可能是始初化過程的問題。最近這幾天要再拿隨貨附的原始程式來對照一下。

以上。

2008年6月12日 星期四

目前工作

目前正在進行的項目是將最新版本的 Linux kernel (2.6.26-rc5)移植到這塊開發板上。雖然購買這塊板子時已隨貨附上修改過的 Linux 2.6.18.2 原始碼,但原作者似乎並未將這些修正合併回主流核心版本中。是故我的計畫是將這些修改過的程式做個整理,以符合核心的 coding style,然後註冊新的 machine type,將整理完的程式碼送上 mailing list。

當然過程中,仍少不了要追蹤硬體初始化的部分,來和晶片使用手冊的說明相對照。所幸拜 Ben Dooks 的努力,S3C24xx 系列的程式碼發展地相當完整,要加入新開發板的支援比較方便,只要將現有的程式碼拿來直接套用即可,剩下的工作就是針對開發板上特殊的周邊做些修改了。

2008年6月7日 星期六

利用 busybox 實作熱插拔機制

目前在 PC 系統下的 Linux 2.6 熱插拔機制是採用 udev 來實作;核心在偵測到硬體插入/移除時,會發出事件通知 udev daemon,udev 則根據事先設定好的規則來建立裝置檔案、symlink 或做其他處理。

在嵌入式系統中,當然也可以使用 udev 來設定當硬體熱插拔時要做那些處理,不過若你的目的相對比較單純時,其實 busybox 也提供了名叫 mdev 的 applet 來達成相同的功能。mdev 可以說是精簡版本的 udev,其設定檔相較於 udev,規則簡單,但也犧牲了一些 udev 才有的彈性。

要使用 mdev,只需在 kernel 啟動後的初始化程式(如 linuxrc 或是 /etc/init.d/ 下的 scripts),先掛載 /dev 及 /sys,接著下指令:
mdev -s
以建立裝置檔案,然後再設定使用 mdev 程式做為核心熱插拔事件的處理程式:
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
如此,在核心熱插拔事件發生時,mdev 就可根據核心傳入的參數來建立對應的裝置檔案。

若你有在 busybox 中勾選 mdev 設定檔的支援,你還可以透過撰寫設定檔來客制化你的熱插拔機制。該檔案位於 /etc/mdev.conf,其語法如下:
<device name regex> <uid>:<gid> <umask> [<@|$|*> command]
例如要設定當 MMC 卡插入時要執行自定的 script 時,可以這樣寫:
mmcblk[0-9]p[0-9]* 0:0 660 *myscript

除 mdev 外,busybox 也提供許多有用的工具以方便嵌入式系統的開發,非常值得開發人員好好地玩玩。

相關連結:
busybox:http://busybox.net/
udev:http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html

2008年5月26日 星期一

S3C2440 開發板初體驗

自從上禮拜收到貨之後,由於本人那幾天比較忙,懶得動,是故清點完包裝內的物品後,便暫時擱在一旁。今天終於有空來玩一玩。

代理商出貨時就有先幫我燒好 Linux,是故接上 LCD 後開機就可以順利顯示圖形界面,可以確定 LCD driver 沒問題。再來開到以 COM port 連接的終端機檢視其中的 /proc 目錄,確認 CPU 的型別、記憶體大小、已驅動的裝置,再來做幾個測試,小結如下:
  • USB Host:可連接 mass storage device
  • MTD:可正確讀出/寫入
  • OSS:可正確播放音效。不過聲音有點破破的。
  • UART:沒問題
  • Framebuffer:沒問題
目前做到這裡,接下來再來寫幾個簡單的 kernel module 來測試其他硬體。

此外,這塊板子出廠附的 bootloader 並非是 U-Boot,而是廠商自己做的 bootloader,主要功能是將 NAND Flash 自動分區並燒錄核心及檔案系統,雖然支援以 USB 下載檔案是很方便沒錯,但除了燒錄外,其他功能付之闕如。因此我想玩玩過後,還是會重新再燒個 U-Boot 吧。

2008年5月23日 星期五

新開發板入手

今天終於收到昨天新買的 s3c2440 開發板。眾所周知,三星所推出以 ARM 為基礎的 SoC 一直以「俗擱大碗」著稱;不僅價格便宜,許多該有的周邊 IO 也都不缺,不僅在學校實習課上常用到,也是像我們這些阮囊羞澀的窮人不錯的選擇。

唯一我比較在意的是,這塊板子是大陸做的;一般人印象中總是對大陸產品有品質不佳的印象,尤其代理商又賣我這麼便宜,實在很難不讓人起疑。不過在網路上找來找去,s3c2440 的開發板似乎沒有很多選擇,加上並非都有台灣的代理商在賣,我又懶得直接跟原廠購買,就姑且信之吧。好在廠商附的文件倒是不少,該有的燒錄工具也都送給你,按步就班地做,希望不會出什麼大問題。

總之,這算是我生平第一塊自費的 ARM 開發板,就來好好研究研究唄。

後記:
後來在 http://www.arm.linux.org.uk/developer/machines/ 上看到不少 2440 為基礎的開發板,不過似乎在原始碼中沒看到這麼多啊?還是只是註冊假的?

2008年4月28日 星期一

Linux SPI subsystem (3)

在上二篇的文章中我們提到了 Linux SPI 子系統的架構以及如何撰寫 master driver,接下來則是要討論如何撰寫 protocol driver。

如同 master driver,要讓核心能夠使用 protocol driver,必須先註冊我們所要驅動的硬體以及對應的驅動程式。硬體裝置的註冊有兩種方法:

  1. 事先在核心平台相關初始化程式碼中,填入相關的周邊硬體資訊在 spi_board_info 結構中。該結構的宣告如下:

    struct spi_board_info {
        char modalias[KOBJ_NAME_LEN];
        const void *platform_data;
        void *controller_data;
        int irq;
        u32 max_speed_hz;
        u16 bus_num;
        u16 chip_select;
        u8 mode;
    }

    其中 modalias 必須與 protocol driver 的名稱相同以供核心比對;其他欄位的意義可參照 include/spi/spi.h 檔案中的說明。完成後呼叫 spi_register_board_info 來註冊這些裝置。
  2. 若是無法確定會接上什麼裝置,則可以在核心模組程式碼中,填入上述的結構,但改為呼叫 spi_new_device 來註冊該裝置。函式中的 master 參數可透過呼叫 spi_busnum_to_master 來取得。
在註冊時,核心會為每個裝置配置一個 spi_device 結構,將上述 spi_board_info 結構中的資訊填入對應的欄位中。

接下來我們要將我們所撰寫的 protocol driver 回呼函式填入 spi_driver 結構中,如下所示:

struct spi_driver mydriver {
    .probe = mydriver_probe,
    .remove = mydriver_remove,
    .driver = {
        .name = "mydriver",
        .owner = THIS_MODULE,
    }
}

接著呼叫 spi_register_driver 來註冊新的 protocol driver。

結語
從這一系列文章,我們可以了解到,即使是像 SPI 如此簡單的硬體介面,為了讓驅動程式更具可移植性及模組化,核心開發者設計了分層式的架構,讓每個驅動程式能夠各司其職,互不干擾。這樣的架構在其他核心子系統中也常會見到,也許名稱不同,但基本理念仍是相同的。

2008年3月24日 星期一

Linux SPI subsystem (2)

我們在上一篇文章中提到,master driver 負責初始化硬體控制器,寫入暫存器以及中斷處理。換句話說,它必須要能夠做到低階的硬體控制;在以 ARM 為基礎的 SoC 當中,也就是要實際上對 I/O memory 做讀寫的動作。因此撰寫 master driver 前,必須要先熟讀 SoC 的使用手冊,充分了解如何操作這些暫存器以支援相關的功能。

此外,master driver 還必須要將從上層傳送來的訊息封包加以解析,並將傳送該封包所需要的硬體參數設定事先寫入暫存器,最後才起始資料傳送。如果控制器支援中斷,那麼 master driver 也必須先註冊中斷常式以便處理例外狀況。接下來我們就來看看一些細節部分的資料結構與函式。

一般在 SoC 系統下,SPI 控制器會以 platform device 的形式存在,是故我們會將 master driver 註冊為一種 platform driver,接著在 probe 函式中呼叫 spi_alloc_master,該函式宣告如下:

struct spi_master *spi_alloc_master(struct device *host, unsigned size);

該函式會分配一塊記憶體並回傳指向 spi_master 結構的指標,參數 size 則可以指定額外的空間大小,該空間可以透過 spi_master_get_devdata 來取得,開發者可用以存放額外的資訊。接著我們需要設定一些關於該控制器的資訊,如:

master->bus_num = 0;
master->num_chipselect = 1;
master->setup = mysetup;
master->transfer = mytransfer;
master->cleanup = mycleanup;

其中 bus_num 是代表控制器的識別號碼,若指定 -1 則表示由系統動態分配。num_chipselect 是這個控制器所能連接的裝置編號的最大值,1 代表最多可連接 2 個裝置 (0, 1)。最後呼叫 spi_register_master 來向系統註冊即可。

當開始要進行傳輸時,在上面程式片段中的 setup 會在傳送前被呼叫,讓 master driver 根據周邊所能接受的傳輸模式參數來設定控制器;接著 transfer 會被呼叫,其參數包括要傳送的周邊以及指向 spi_message 結構的指標。其中 spi_message 結構還包含了一個或多個要傳輸的 buffer,定義在 spi_transfer 結構中。要注意的是,由於 transfer 函式中不可呼叫任何會進入睡眠的函式,是故實際的傳輸會由另外產生的 worker thread 來達成;並且在傳輸完成後,呼叫 spi_message 結構中的 complete 函式以通知 bus driver。最後則是 cleanup 函式被呼叫以釋放進行傳輸時所使用的資源。

另外當要卸載核心模組時,需要呼叫 spi_unregister_master 以解除註冊。

下一篇我們將會來討論 protocol driver 的部分。

2008年3月20日 星期四

Linux SPI subsystem (1)

目前進行中的項目是在 DaVinci 平台上開發 SPI 控制器驅動程式,不過由於手邊缺乏硬體平台可供測試的關係,現在仍然進度緩慢。不過這期間也研究了一下 Linux SPI 子系統,稍微有一些心得,來和各位分享一下。

SPI 是 Serial Peripheral Interface 的縮寫,它是一種串列式的 IO 介面,時脈約 1~ 70MHz,詳細資料可見 [1]。 DaVinci DM6446 上配備了一個 SPI 控制器,支援二個 chip select,時脈可達 33MHz。

Linux SPI 子系統將驅動程式分為三種類型:
  • SPI bus driver:
    主要目的為提供 API 給下層的 master driver 及上層的 protocol driver (稍後會提)來註冊,並傳送封包至下層的 driver。
  • SPI master driver:
    主要工作為初始化控制器,並負責對暫存器寫入以及中斷處理。
  • SPI protocol driver:
    主要為發送 SPI 訊息封包至所選擇的裝置。
從這樣的架構來看,bus driver 扮演了一個抽象層的角色,對上隱藏了硬體的細節,對下則隱藏了對特定裝置的通訊協定。是故 master driver 並不需要知道控制器接了什麼周邊,它只專注在如何操作控制器來將訊息封包送出;而 protocol driver 只需專心於和特定週邊的溝通,而不需了解要如何傳送訊息封包。

在子系統中,訊息封包的格式定義在 spi.h 的 spi_message 結構中。protocol driver 要傳送資料,只需填上 spi_message 結構相對應的欄位,並呼叫 spi_sync 以起始傳送。或者也可直接呼叫 spi_read/spi_write,參數則填入你的 buffer pointer 以及長度即可。

一般在嵌入式系統中,SPI 周邊多是直接固定在板子上,且硬體並無特別的方式可供偵測,因此我們需要在平台初始化時預先定義系統包含那些 SPI 周邊,而子系統也定義一個結構 spi_board_info 提供給開發者填入相對應的資訊,例如:

struct spi_board_info devices[] = {
     {
         .modalias = "mydevice",
         .max_speed_hz = 6000000,
         .bus_num = 0,
         .chip_select = 1,
         .mode = SPI_MODE_1,
     },
     {
         ......
     },
};

接著呼叫 spi_register_board_info 來註冊這些裝置。需要注意的是,modalias 欄位的值必須與 protocol driver 註冊的名字相同;bus driver 會以該值作為比對的依據。若需在執行時期註冊新的裝置,則可呼叫 spi_new_device 來加入。

關於 master driver 的部分留待下一篇來討論。

相關連結:
[1] Serial Peripheral Interface Bus
[2] TMS320DM644x DMSoC Serial Peripheral Interface (SPI) User's Guide

2008年3月18日 星期二

PINMUX patch

前幾天我送了一個 patch 到 mailing list 上,主要為加入檢查其他周邊是否被啟動的函式。檢查的方法即是看 PINMUX 這個暫存器中,代表各個周邊的 bit 是否被設定。由於在 DVEVM 中,很多周邊都有共用 pin 腳的情況發生,因此這個函式可供裝置驅動程式檢查之用。

2008年3月17日 星期一

新建第一篇

在百般思考之下,還是決定要建一個部落格來和網友們分享一下自已的心得。
基本上,本格會定位為一個嵌入式系統開發的筆記,目前主要著重在 DaVinci 平台下 Linux 系統的開發。未來會多放些和 DaVinci Linux 相關的研究筆記和嘗試在其上開發的程式碼。這些程式碼除了放在這外,也會 post 至 mailing list 上,希望大家不吝指教。

相關連結:
TI DaVinci
DaVinci Linux mailing list