tech-sjh

2010年5月29日 星期六

linux USB hid driver cypress_m8.c

參考 USB Device Class Definition for Human Interface Devices(HID)
firmware spec version 1.11,範例 driver 是 USB Cypress M8 driver
~linux/drivers/usb/serial/cypress_m8.c,source code 中說有
文件就在 ~linux/Documentation/usb/usb-serial.txt。

主要是看 DeLorme Earthmate USB 的 usb hid 如何設定,她使用的
是 feature report 的方式,在 control pipe 傳送 5 bytes 資料。
對應到 USB HID spec 的 7.2 Class-specific Requests 裡面的 7.2.1
Get_Report Request 跟 7.2.2 Set_Report Request,透過 control
pipe 傳送 host <-> device 資料。

呼叫 usb_control_msg(),定義在 USB core 的實作中
~linux/drivers/usb/core/message.c:


/**
* usb_control_msg - Builds a control urb, sends it off and waits for completion
* @dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @request: USB message request value
* @requesttype: USB message request type value
* @value: USB message value
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
* @timeout: time in msecs to wait for the message to complete before timing
* out (if 0 the wait is forever)
*
* Context: !in_interrupt ()
*
...
*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)



有兩種用法,差異在於傳輸方向,是以 host 為主體而有 in/out, set/get 不同。
一個是 host 傳到 device(out/set),另一個是 device 到 host(in/get)。

host->device 是 USB_DIR_OUT,使用 HID_REQ_SET_REPORT request
建立 send endpoint pipe 是用 usb_sndctrlpipe()

device->host 是 USB_DIR_IN,使用 HID_REQ_GET_REPORT request
建立 receive endpoint pipe 是用 usb_rcvctrlpipe()


retval = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer,
feature_len, 500);

retval = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer,
feature_len, 500);


第一個參數就是 struct usb_device *dev,probe 時就可以取到
第二個是利用 MACRO 從 usb device 找到 usb device 的 endpoint pipe
第三個參數是 message request value,HID_REQ_SET_REPORT 或
HID_REQ_GET_REPORT
第四個是 message request type value,
USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, 或
USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,

第五個參數是 message value 看 device hard code: 0x0300
第六個參數是 message index value hard code: 0

因為採用的是 feature report 的方式傳送 5 bytes 資料存在
第七個參數 feature_buffer 中,
第八個參數是 feature_len 是資料長度。
第九個參數是 500 micro seconds 的 timeout。

相關文章:

TI OMAP3 DM3730 USB host controller high full low speed?



相關連結:

http://www.usb.org/developers/devclass_docs/HID1_11.pdf

~linux/drivers/usb/serial/cypress_m8.c

~linux/drivers/usb/core/message.c

2010年5月28日 星期五

linux kernel read_proc() in procfs

在 ~linux/fs/proc/generic.c 中找 __proc_file_read() 的實作
可以看到相關說明:

/*
* How to be a proc read function
* ------------------------------
* Prototype:
* int f(char *buffer, char **start, off_t offset,
* int count, int *peof, void *dat)
*
* Assume that the buffer is "count" bytes in size.
*
裡面有三種讀 read_proc 的方式說明,底下就是說明的程式碼,
也可以搜尋其他 driver使用 read_proc 的範例。
比如 ~linux/drivers/char/efirtc.c。
*/
n = dp->read_proc(page, &start, *ppos,
count, &eof, dp->data);
...


這邊是當 kernel 讀取 proc 檔呼叫 driver read_proc callback 的
地方,也就是用法。因此可以倒推回去我們的 callback function
如何實作:

第一種是 driver 要回傳的資料量小於 read_proc 中的 buffer size(PAGE_SIZE)。
此時不管 *start,將 driver 要傳給 filesystem 的資料擺在 buffer 的 offset 位置,
我們只看 offset 跟上次 callback 讀到的 buffer size, n 的差值,
在接到的 offset 跟剩餘要傳的 n 差值(n - offset) 為零時,告知
filesystem 我們的 driver 已經傳完資料,才設定 *peof = 1;
否則繼續 callback。

第三種跟第一種一樣,只是把 offset 代換成 *start

第二種是當你有大量資料要傳輸時使用。
將 *start 設定為介於 buffer 跟零 之間的值,資料是從 buffer 起始位址
開始填,return 每次要填的資料長度,如果你的資料還沒填完,第二次
進入 read_proc 時 offset 值會增加 *start 的長度,直到你填完資料後再
設定 *peof = 1; 就可以完成傳輸大量資料了。

相關連結:

procfs-guide.pdf 3.1 Reading data

linux kernel source:
~linux/fs/proc/generic.c
~linux/drivers/char/efirtc.c

Linux Modules (3) - procfs

2010年5月27日 星期四

Google 的十項工作哲學

據說 Google 在面對未來的展望時,會以下列十項原則做為行動基準,摘譯如下。

我們奉為真理的十項行動準則:

一、 專注在使用者經驗上,接下來該做的事情自然清楚明白

二、最好是聚焦在一件事情上,然後做到最、最、最好

三、快比慢好,當有技術突破時,我們的搜尋速度每每創新紀錄。

四、民主機制在網路上行得通

五、不一定要在辦公桌才能得到答案,這是行動計算的時代。

六、不一定要黑心才能賺錢

七、永遠有更多的資訊供你去發現

八、對於資訊的渴求沒有 國界 之分

九、不一定要穿西裝才能認真。成功不是因為表面功夫做得好,強調團隊成果與個人
成就感、自尊心才是重點。

十、 偉大仍不夠好。把某件事情做得偉大隻是起點,而非終點。我們總是設定超出目前
能力範圍的工作目標,如此我們才能讓自己永續成長茁壯。

相 關連結:

Ten things we know to be true

boot code, bootloader, and Linux Kernel entry points

菠蘿麵包整理了 Android 開機流程 boot sequence
給個 boot rom, bootloader, Linux kernel, Android Init, Zygote, Dalvik,, System Server, 最後發出
ACTION_BOOT_COMPLETED 的 braodcast intent 觸發需要知道開機啟動的服務,其中從
硬體到使用者接觸到的應用程式的完整流程。

我們關注的是前面這段觀念:
硬體平台上的 boot ROM 儲存了 boot code,boot rom 本身也是在記憶體上執行,arm cpu
藉由 reset 0x0000, 0000 由 chip select 線路連結的開機媒介決定到哪一種 storage (Nor flash,
 Nand flash) 去讀取 boot loader。 將 boot loader 載入到實體記憶體後開始執行 boot loader ...

booting sequence documentation 則提到在 bootloader 到 linux kernel 端的開機介面
與流程:

ARM Linux kernel 對 bootloader 所需要的,就是藉由 bootloader 將 Linux kernel 從
storage 讀出載入到記憶體,設定某些暫存器,並呼叫 Linux kernel entry point,此
時還不需要啟動 MMU。

 Linux kernel 的 zImage 壓縮檔,就必須要跳到 arch/arm/boot/compressed/head.S
會使用  arch/arm/boot/compressed/misc.c (抄自 gzip 的某些函式介面) 裡面的
decompress_kernel() 其中會呼叫 arch_decomp_setup() 設定 debug FF/ST uart port,
或特殊的 Chip Select memory mapping,接著在開機印出 "Uncompressing Linux..."
字串後進行解壓縮。

ARM Linux boot sequence

另外關於 arm linux 的開機流程也有人寫了程式碼分析文:
ARM Linux boot sequence

zImage 解壓縮階段:
從跟 boot loader 串接,關閉 cpu cache, MMU, 設定 stack, kernel entry point 在實體
記憶體位置,設定 cpu 型號辨識,啟用 cpu cache, MMU, 設定 MMU page table
將 kernel zImage 解壓縮並載入到 RAM,進入 kernel start...

ARM 相關的 kernel code:
查詢 cpu 型號,啟用多核心支援,查詢(主機)板子的 machine 型號,MACHINE_DESC
macro 的定義。建立 MMU 的 page table,enable MMU,初始化 cache, write buffer。
繼續 enable MMU,設定 page table pointer (TTB),找到 page table 起始點,切換
MMU 進入 virtual address space, 回到已經過 mmap 過的 switch data。

複製 data segment 到 RAM
清空 BSS(寫零)
跳到 start_kernel 開始執行 Linux kernel 開機程序。也就是接 Intel 文件中的 C 程式碼
起始點。 

Linux kernel entry points

Intel 的 device driver debugging 可以找到幾個 Linux kernel source entry point。

開發新平台(OS Adaptation, OS bring up, customize core components)
其中一項重要的工作就是寫驅動程式,有些多媒體編解碼的最佳化,
也是在驅動程式端實作。

一些有用的 kernel 資訊如:active kernel threads, loaded kernel modules

x86 開機流程中 BIOS->OS boot loader --start_kernel()-->OS

sched_init() 是 scheduler initialization

mwait_idle() 是 OS 主要的迴圈(就像 micro controller 的 main loop)


相關連結:

Device Driver Debugging on Intel Atom processor based devices (pdf)

2010年5月24日 星期一

電影:超速先生

週末尾聲全家看著 MOD 的電影,超速先生,轉到時已經開播不知
多久,但因為是安東尼霍普金斯主演,才繼續看下去。結局也不出
所望的是部好電影,並且是根據真人真事改編而成的電影。

要說劇中主角的人生觀,可以套用安東尼霍普金斯在幕後花絮的一
句話代表:現在的我可以掌控自己的人生,並且是一個非常快樂的人。

在完全無預期下看完本片,只能用驚奇連連來形容本片的劇情鋪設
,每每以為伯特蒙羅即將因為某些挫折、困難而打道回府,但都在
他的堅持、毅力,與樂觀不懈的態度、實際嘗試後迎刃而解,也因
為他不斷的累積並一步一步改進自己的愛車,而在年屆 68 歲,騎
著 47 年車齡的 Indian 達到世界最速車的紀錄頭銜,他在 1967 年創
下的 1000cc 最速紀錄至今無人能破。

伯特蒙羅在家鄉期間,花了 20 年針對在 1920 年買的 Indian 重機
進行改裝提升性能,1938 年起就陸續在紐西蘭創下八項紀錄,並在
後續遠渡重洋到 Bonneville Salt Flats 位在美國猶它州的波尼維鹽原
創下世界紀錄。他在鹽原十次參賽中,總共創下三項紀錄,其中的
1000cc 最速紀錄仍然高掛在榜首位置。

相關連結:

超速先生 電影中文網站

Burt Munro 維基百科

2010年5月19日 星期三

SSH學習日記-好熱

SSH跟我一樣怕熱不怕冷,他睡覺從來不蓋被子,最近天氣漸熱,睡午覺時已經開始開冷氣,每次我要開冷氣時,都會邊抓脖子邊教他說因為好熱,所以開冷氣。抓脖子是教他好熱的肢體動作,我常會用「因為...所以...」這樣的句型來教他。像是因為下雨,所以拿雨傘,聽說常用因果關係教寶寶說話,有助於邏輯能力發展。

今天帶他在外吃飯時,由於非用餐時間,店內客人少,老闆沒開冷氣,我們母子倆邊吃滷肉飯,邊流汗,後來SSH熱到不行,就抓脖子,說「好熱」,然後指著店家的冷氣說「冷氣」。看來SSH已經懂得「好熱」的意思,之前都是教他物品的名稱,大多是名詞,最近開始教他形容詞,好熱就是他最常說的詞,我想是因為他愛吹冷氣的緣故吧!

2010年5月12日 星期三

SSH上超市學單字

自從進入語言爆炸期,SSH看到任何東西都想知道它的名稱。超市經常是我們消磨午後時光的地方,最近他學會「玉米」、「紅蘿蔔」、「豆漿」、「吐司」、「多多」、「菜」(花椰菜簡稱)、「肉粽」(台語)、「瓜瓜」(西瓜簡稱)、「魚」、「肉」、「檸檬」、「apple」、「banana」、「oreo」、「燈泡」、「芭樂」(台語)、「肉鬆」....等。

一進超市會自動去推手推車,再拿籃子,然後開始把他想買的東西通通放進購物籃,我得跟在後頭把東西放回原位。超市有很多東西都用保鮮膜包裝,像是冷藏魚肉等,SSH最愛用手指頭把保鮮膜搓破,我實在很頭疼。像最近盛產西瓜,超市有切好1/4塊的紅色大西瓜,用保鮮住,SSH一看到就一口咬下去,連著保鮮膜一起吃,我只好硬著頭皮把大西瓜買回家。

除了學會很多食物單字外,超市的停車場停放許多車子,SSH也因此學會各大車廠的logo。他最懂得「TOYOTA」、「Nissan」跟「Mitsubishi」,有些我教他中文,像「Volkswagen」我教他念「福斯」,「Ford」就念「福特」,這樣的訓練是想刺激他學習的興趣,加強記憶力及聯想力,就像有些寶寶很會念唐詩一樣,他們不一定認識字,但會模仿大人發音來學習跟記憶很多詞彙。

前幾天SSH說要喝多多,我帶著他去開冰箱,當我說「拿多多」時,他也跟著說,之後幾天只要他想喝,他就會改口說「拿多多」,而不再只是「多多」二字。這表示他已經從單字進入片語階段了。

教寶寶說話的10堂課」書中的第五堂課就是應用篇-把超級市場變成超級教室。書中運用5個方法 ─ 命名、描述、比較、說明、給指令,教導父母如何把上超市購物的例行活動,變成和孩子間學習與互動的特別時間。我買這本書後照著書中方法教SSH學說話,剛開始效果不明顯,但持續一段時間後,SSH說話的能力確實有進步。

2010年5月8日 星期六

cross compile Android native C code

當需要建立一些指令列工具,需要自行 build code 在 Android
command line 上執行,或供應用程式透過 JNI 呼叫的函式庫時,
需要 cross compile android native C program

1. agcc, 一個幫你搞定 cross compile 所需複雜參數的 perl script,依照
Compiling for Android wiki 上的步驟,應該就可以成功

2. 如果幸運的話,你可以不用往下看,不然就繼續吧,假如 agcc
不能達要你的需求,網路上也有神人已經寫了 Makefile 再加上 1. 裡
面的其他設定設好,以及你所使用平台的 C runtime library,在
~android/bionic/libc/arch-arm/bionic 底下 copy crtbegin_dynamic.S,
crtend.S 到你的 utility source 目錄,一起 link 就可以從正確的 entry symbol
__start 執行。否則直接拿 x86 cross compile 給 arm 平台的程式時
會有類似以下的警告訊息:

warning: cannot find entry symbol _start; defaulting to 000082c8

3. add scripts to ease rebuild native C code and installation,要將 utility
包 到 system.img 時需要先移除 ~android/out/target/product/arm/system.img
再將新加的 utility 放到 ~android/out/target/product/arm/system/bin
重新 build android,因為前面已經將其他 object files build 完,所以只剩下
archive system.img 的工作。

因此再借用神人的 my_command_line utility Makefile 改成如下:


# ripped from http://forum.xda-developers.com/archive/index.php/t-623976.html
AR = arm-eabi-ar
AS = arm-eabi-as
CC = arm-eabi-gcc
CXX = arm-eabi-c++
LD = arm-eabi-ld

ANDROID_SOURCE_ROOT = /path/to/your/androidsource
NDK_KIT = $(ANDROID_SOURCE_ROOT)/ndk/
PLATF_KIT = build/platforms/android-4

ARM_INC = $(NDK_KIT)/$(PLATF_KIT)/arch-arm/usr/include
ARM_LIB = $(NDK_KIT)/$(PLATF_KIT)/arch-arm/usr/lib

PLATF_INC = $(NDK_KIT)/$(PLATF_KIT)/common/include

OUT_DIR = $(ANDROID_SOURCE_ROOT)/out/target/product/arm
OUT_SYSTEM_BIN = $(OUT_DIR)/system/bin/
ALL_SYSTEM_IMG = $(OUT_DIR)/system.img $(OUT_DIR)/obj/PACKAGING/systemimage_unopt_intermediates/system.img

PROJECT = my_command_line
SRCS = $(PROJECT).c util.c
OBJS = $(PROJECT).o util.o crtbegin_dynamic.o crtend.o
EXES = $(PROJECT)

all: $(EXES)
file $(EXES)

install: $(EXES)
cp -afv my_command_line $(OUT_SYSTEM_BIN)
cd ../; rm -fv $(ALL_SYSTEM_IMG)
@echo "Please re-run build_android.sh to rebuild system.img"

$(EXES): $(OBJS)
$(LD) \
--entry=_start \
--dynamic-linker /system/bin/linker -nostdlib \
-rpath /system/lib -rpath $(ARM_LIB) \
-L $(ARM_LIB) -lc $(OBJS) -o $(EXES)

$(OBJS): $(SRCS)
$(CC) -I $(ARM_INC) -I $(PLATF_INC) -c $(SRCS)
$(CC) -mthumb-interwork -o crtbegin_dynamic.o -c crtbegin_dynamic.S
$(CC) -mthumb-interwork -o crtend.o -c crtend.S
#crtbegin_dynamic.S and crtend.S copy from bionic/libc/arch-arm/bionic

clean:
rm -f $(OBJS) $(EXES)


另外寫程式要注意的是 ~android/bionic/libc/README 提到跟 standard C
library 差異處與特性:
- no support for locales
- no support for wide chars (i.e. multi-byte characters)
- its own smallish implementation of pthreads based on Linux futexes
- support for x86, ARM and ARM thumb CPU instruction sets and kernel interfaces

4. Thinker 發表的 Android Build System 分析一文相當值得細讀,善用
Android makefile 的 build system 可以省掉去瞭解這些編譯的細節。

5. Android Source Code 中的 NDK 也詳細介紹了使用 Android Java VM
的 JNI 介面與實作 shared library 的建議,在
~android/ndk/docs/OVERVIEW.TXT 中有說明,Google 一下也可以找到
中文翻譯資料,我就不翻了。 :P

結論是網路上神人很多,Google 搜尋跟這些神人也很熟。:P

相關連結:

Android 原生(Native) C 開發之八: Toolchain 環境搭建篇

從 gpio & I2C 硬體線路對應到檔案讀寫

0. 硬體電路的 schema
找到電路圖上的 gpio, i2c 線路圖上的 block 是接到 datasheet 上哪一個 slot

1. datasheet 中的 gpio chapter
針對 gpio controller 的 register 值依照 in/out, pull up/down, data 值設定

2. board initial entry point,比如 Samsung s3c6410
~linux/arch/arm/mach-s3c64xx/mach-smdk6410.c
MACHINE_START macro 定義 board information
可以看到註冊的 .init_machine 進入點 function 是 smdk6410_machine_init

Qualcomm 的 arm board initial 檔案則是在
~linux/arch/arm/mach-msm/board-msm7x27.c
定義了 QCT MSM7x2x (7225)
~linux/arch/arm/mach-msm/board-msm7x30.c
定義了 QCT MSM7x30
~linux/arch/arm/mach-msm/board-qsd8x50.c
定義了 QCT QSD8X50 (8250)

3. i2c
關於 i2c 參考 Documentation/i2c/instantiating-devices,可以看到
mach-smdk6410.c 定義兩個 i2c slot 0, 1 為 struct i2c_board_info,
裡面定義這個 bus 上接的 i2c slave device(s) 名稱與 slave address 資訊,
透過 S3C_EINT 對應到外部中斷 12,然後在 smdk6410_machine_init():

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

註冊兩個 i2c bus,0 跟 1。接下來 i2c device 的具體化由 i2c core 完成。
kernel driver 可以在 ~linux/drivers/i2c 目錄找到,可以使用 i2c-dev
,直接 sudo modprobe -a i2c-dev,就可以在 /dev/i2c-0 存取 i2c bus。

參考 ~linux/Documentation/i2c/dev-interface 可以針對 /dev/i2c-0[1]
的 device file 使用 user space driver 的 ioctl 控制 i2c 設定與傳輸。
最簡單的動作是 ioctl(file, I2C_SLAVE, addr),就直接對 file read(),
write() 就可以讀寫 i2c device 資料。

4. gpio
關於取得需要使用的 gpio 方式如下:

gpio_request(S3C64XX_GPN(5), "LCD power");
gpio_request(S3C64XX_GPF(13), "LCD power");
gpio_request(S3C64XX_GPF(15), "LCD power");

這是指取用 GPN pin 5 跟 GPF pin 13, pin 15 操作 LCD power

~linux/Documentation/gpio.txt
可以用 /sys/class/gpio/ 底下針對 gpiochip (controller) 或是 gpioXX (pin)
進行 user driver 的控制 in/out, high/low, trigger mode
/sys/class/gpio/gpiochip0/ 中的 label 可以對應到 datasheet 的 controller
名稱,參考 arch/arm/mach-s3c64xx/include/mach/gpio.h
可以找到 S3C64XX_GPA, S3C64XX_GPB 等 gpio controller
S3C64XX_GPIO_A_NR (8) 定義 Bank A 有 8 根 gpio 腳位,依此類推
對於 /sys/class/gpio/gpioXX/value read/write 就可以讀取 gpio 腳位
high/low 或設定 high/low




2010年5月7日 星期五

Keil C C51 語法

1. 加上記憶體型態的變數宣告順序:

變數型態 記憶體型態 變數名稱;

變數型態指一般 C 語言的 int, char 等
記憶體型態指 code, data, bdata, xdata, pdata 等六種記憶體位置
,各型態記憶體位置,以 Silicon Labs C8051F320/1 為例:

內部記憶體:
0x00~0xFF 都可使用間接定址存取資料的 data 記憶體

data 記憶體內:
0x00 ~ 0x1F 是一般暫存器 0x20~0x2F 給 bit/bytes 直接定址 bdata
0x30~0x7F 是直接定址記憶體
0x80~0xFF 是給 sfr(special function register) 只能間接定址 Stack
Pointer 可以是在 data 記憶體內定址的 256 bytes 區塊

外部記憶體:pdata
0x0000~0x03FF 是 1K 的 pdata
0x0400~0x07FF 是 1K 的 USB FIFO

16K Flash 記憶體:xdata, code

0x0000~0x3DFF 是 16K 的 In-System Programmable 記憶體
也是 firmware update 使用區,參考 PSCTL 暫存器的 PSWE、
PSEE 位元保護寫入與讀取的動作。

0x3DFF~0x3E00 是 Security Lock Byte,理論上可以鎖定 64K
bytes 的連續記憶體

Security Lock Byte 可以指定要鎖定的 512 bytes
(page 0 = 0x0000~0x01FF)

鎖定的區塊比未鎖定區塊有較高優先權,可以讀、寫、刪鎖定與
未鎖定的記憶體區塊。鎖定是防止透過 C2 interface 讀寫 flash 的
燒錄器讀取韌體機密,但無法防止其他介面的讀寫,因此韌體在其
他介面溝通時,如果有機密資料需要做加密傳輸。

鎖定區如果要強制讀取會透過電路先將 flash erase 才可以讀寫,可
以做到保護鎖定區資料機密性的功能。在鎖定區的 loader,在進行
韌體更新時,檢查是否是合法的 firmware,才進行更新,以防止燒
錯 firmware,或是被 crack 修改到鎖定區內資料。

檢查是否是合法 firmware 可以用公開金鑰機制防護,在鎖定區內的
loader 存 private key,要燒錄到 flash 上的韌體存 public key。可以
做到韌體加密與驗證合法韌體的功能。

0x3E00~0x3FFF 保留未使用

比如宣告

char xdata GPIO1 _at_ 0x100;

表示宣告為型態 char,在 external data memory 位置 0x100 的
GPIO1 變數

2. 宣告 register 與位元

sfr P0 = 0x80; // 宣告 P0 是 special function register,
// Port 0 位址在 0x80,8 bit constant, 位在 IDATA 型態的
// 0x80~0xFF 直接定址區
// 0x00 ~ 0x7F 位在 DATA 型態記憶體的直接定址區

sfr SCON = 0x98;
// 宣告 SCON 為 register,SCON register 值為 0x98

sbit B1 = SCON ^ 0;
//宣告B1 為 SCON sfr 的第0個位元( 1 byte = 0~7 bits)


3. 中斷函式宣告、註冊與定義

timer0_int() interrupt 1
{
// C codes
}

宣告函式名稱 timer0_int(),註冊在中斷 1,中斷 n 的向量(編號)
公式為 (中斷大小*n +3) + 中斷向量基底位址,中斷向量由 C51
compiler 計算。若一般中斷大小為 8,中斷向量基底位址為 0x4000
,則宣告 timer0_int() 程式碼放在 code memory 位址 0x400B。

4. 在固定記憶體位置宣告 struct, memory mapped struct

struct MyStruct { char data;};

struct MyStruct xdata *sPtr;
// C51 依 xdata 配置視 sPtr 為指向一個 memory mapped struct

sPtr = (void xdata*) 0x8000;
// 這個 struct pointer map 到 0x8000 實體記憶體
// 類比 standard C lib 的 malloc heap memory

相關連結:

Silicon Labs C8051F320, C8051F321 Datasheet (pdf)

The C51 Primer (pdf)

SDCC small device C compiler Open Source 8051 C compiler

SDCC Open Knowledge Resource Open Source C libraries for 8051

Keil C51 第一家在 8051 平台推出 C compiler 的公司

8051 market in 2008

8051 C Compilers

http://o.keil.com/forum/docs/thread356.asp

2010年5月5日 星期三

2010宜蘭綠色博覽會

趕在這周末宜蘭綠博結束前,我帶著SSH去體驗一下大地之美。原來2010宜蘭綠色博覽會3/27就已開始,我根本不知道有這個活動,要不是老爸看電視得知且提議去走走,我可能就這麼錯過了。

非假日去的好處就是不塞車,門票又有優惠,刷中信卡還可打九折。如果你以為平常日遊客少,那可就大錯特錯。我們去的這一天,人還挺多的,很多幼稚園、小學生都是平常日到綠博來戶外教學。我覺得人多比較有玩的感覺。當天天氣晴空萬里,氣溫飆到33度,簡直熱到炸,才買好門票準備進園,就被烈陽曬得頭昏。

2010宜蘭綠色博覽會位於蘇澳鎮武荖坑風景區,依官網園區展示資訊來看,共九個主題館,若照著順序走,第一個是「水上人家」,以休閒農業傳遞出宜蘭的農村美,入口處有全台最大綠雕水車,園區還有一群鴨子悠遊水間,我這個天兵竟然鵝跟鴨子搞不清楚,大聲地叫SSH過來看鵝,後來聽到身旁小學生說:「怎麼鴨子這麼白?!」,我才知道我鬧了大笑話。本來買一包飼料要餵鴨子,希望把鴨子吸引過來靠近我們,結果SSH一拿到飼料就整袋丟進水裡,一群鴨子全嚇跑了,希望鴨子不要連塑膠袋也吃下去。

才逛完第一館,我們這群大人就熱到懶得走,只有SSH依然熱情不減,不畏酷陽,在大草坪上狂奔,後來看到有遊園車可坐,乾脆花個20元坐車直接殺到最後面,從後面玩回來。遊園車是直接開到最後面,中間的館不停,單程每人20元。但後來發現其實每個主題館之間距離並不遠,用走的當作散步應該還好,只是天氣太熱,我們偷懶不想走罷了。

坐車到最後區,一下車就有二個主題館-「綠色奧林匹克館」與「森活林場」,我都以視線帶過就當作參觀過,因為我們最有興趣的是「夢的迷宮」,這也是我們坐遊園車的主因。因為「夢的迷宮」位在最後區,這座以綠雕及花牆方式設計而成的大型花園迷宮,是將畢卡索的名畫-The Dream《夢》,放大4100倍,用各種花材布置,讓遊客走在花叢裡,也走進畢卡索的想像世界裡。剛開始我們一行人團體行動,後來漸漸走散,我跟著SSH後面走,看他走在迷宮裡,即使遇到叉路,也不加思索地憑直覺選定其中一條走,一下子就走到出口。倒是其他人真的迷失在花園裡,還靠手機聯絡才找到我們。原來畢卡索的抽象藝術,純真的二歲兒才懂。在迷宮前,有一以廢棄貨櫃改置成的觀景台,可讓遊客於平台上,欣賞整幅畫作。我們只在觀景台一樓買便當吃,因為當時不知道爬到最上層可以看整幅畫,以為那只是讓遊客休息吃東西的歇腳處,後來在綠博官網才知道,觀景台是主辦單位的用心,在最上層可以把整個「夢的迷宮」拍下來。

走完「夢的迷宮」,就跟烈陽投降,直接又坐遊園車回去,「開心牧場」與「蒲公英的悠活」就沒去參觀,以為這兩館很遠,其實後來看地圖,就在「夢的迷宮」附近,「開心牧場」是我很想去的其中一館,現場有擠羊乳活動,SSH很愛看動物,沒去成真的很可惜。

坐遊園車回到最前面,前區除了參觀過的「水上人家」,還有「幸福單車館」及「靓水旅域」,單車館展示各種年代單車,充分傳達綠博理念,講求環保,以騎單車代替開汽車。

「靓水旅域」則是以愛護水資源,認識水再生利用為主題。SSH應該是最不懂得水環保的小遊客,他在家超愛玩水,無形中很多水就被浪費掉。在SSH腦裡,水就是用來洗手、洗澡,他也已經會講水這個字,所以他在「靓水旅域」這個館倒是玩得挺愉快,看到水就把手伸進去洗一洗。

回家前去逛逛「綠色市集」,本來想買網友推薦的三星蔥,聽說一大把才80元,可惜沒看到在賣。市集裡有幾攤賣蘭花的,一小盆50元,喜歡園藝的倒是不錯選擇。

整個遊園時間大約2-3小時,看了六個主題館。我覺得有帶小朋友去要4小時才夠,因為總共九個館,我們有三個館沒去-「開心牧場」、「蒲公英的悠活」、「綠野舞台」。2010宜蘭綠博活動只到 5/9母親節,想去要快,母親節當天,媽媽免費喔!


藍天白雲正是遊綠博的好日子


2010宜蘭綠博3/27 ~ 5/9


第一館- 「水上人家」


綠雕水車


園區內處處可見花海


「水上人家」館內大水車


藍天 白雲 綠地


「綠色奧林匹克館」


「夢的迷宮」


「夢的迷宮」靈感來源


SSH努力走出迷宮

版權宣告、免責聲明


姓名標示、非商業性、相同方式分享3.0台灣授權條款授權。
免責聲明: 本文所載資料僅供參考,並不構成投資建議,
讀者閱讀或使用該資料所導致結果需要自擔風險與責任,
作者概不承擔閱讀人行為之任何風險與責任。
除非有特別宣稱,作者言論並不代表所屬任何團體、公司、或其他人意見。