● 警報中斷 alarm interrupt
- alarm 的設置很簡單,只要先設置好警報時間,再設置中斷模式即可。
- 中斷模式有很多種,主要使用 alarm interrupt 模式,即 INT1AE=1,INT1ME=0,INT1FE=0。
- 當警報觸發時,INT1 pin 會從 HIGH 變成 LOW,直到設置 INT1AE=0,INT1 pin 才又恢復成 HIGH。
- 當警報觸發時,register status1 中的 INT1 會變成 1,只要讀取 status1 後自動變成 0,即下次再讀取 INT1 的值為 0。
- 當警報觸發時,而且 INT1AE=1,每隔一秒就會重置 status1(INT1=1)。也就是讀取完 status1 後,再次讀取 INT1 的值為 0,但是在下一秒再次讀取 status1,則 INT1 又會變成 1,每隔一秒就再次變成 1,除非當 INT1AE=0,則此動作就取消。
- 手動設定連接 INT1 pin 的 port 是沒有作用的,也就是手動設定 INT1 並不會觸發中斷。
- S35390A 的 alarm interrupt 剛好符合 8051 的 external interrupt,可以直接用 external interrupt 來偵測。如果沒有多餘的腳位,則可改成讀取 status1 來判斷 interrupt。
- 如果一開始就把 INT1 pin 拉 LOW,就會造成當 alarm interrupt 發生後要取消回 HIGH 時,不會自動回復成 HIGH,而是一直呈現在 LOW 的狀態下。
● free SRAM register
- S35390A 可使用的 SRAM 只有二個 bytes,一個是完整的 Free register,一個是分散在各地的 Scratch bits。
- Scratch bits 中的 SC0/SC1 存在 status1,所以任意時間都可以用。而 SC2~SC7 存在 INTx register,只有當 INTxME=0 and INTxFE=1,才可以使用。
● 簡介
S35390A 是由精工電子有限公司開發製造,Seiko Instruments Inc. 是一家日本公司,台灣也有子公司,網址為 http://www.sii.com.tw/。
● 電源 Power Supply
- 一般來說 S35390A 的電源是由鈕扣電池(CR2032 3V)所提供,一開始我還以為是由主板上的電源所提供,害我一直誤解為啥 Power-on 就要重置時間。原來是說當電池沒電或換了新電池時,才會有 power-on detection。
- BLD 為電壓降低偵測旗標,S35390A 一秒才會做一次電壓降低偵測,所以只要電池拔掉再裝回去的時間在一秒內都不會引起 BLD。
- POC 為 Power-on Detection,只要把電池拔掉約五秒,再次裝上電池就會觸發POC。
- 當 POC or BLD 被設置,都需要做一次 chip reset。
● 協定 protocol
- S35390A 是使用 I2C protocol,在 1.5V 有 100kHz 速度,在 3.0V 有 400kHz 速度,算是快速的 I2C chip。
- 在早期的 datasheet 裏跟現在的 datasheet(Rev.2.5_00) 對於經由 command 所取的 data 描述大不同。主要是早期接收 bit 時,是從 LSB 到 MSB,剛好跟 command 的傳送方式相反,造成一些問題。而新的 datasheet 就把 data 的描述顛倒過來,使得 command 跟 data 的 bit order 剛好一致,但本質是不變的。
- 參數設定 command 對於 bit order 不同是沒有差異的,主要是時間 command 對於 bit order 是很敏感的。由於 bit order 接收是 little endian 而非普遍的 big endian,所以對於 I2C protocol 必須重新設計,不能使用舊的方法。
- 如果是按照新的 datasheet 來說,是不用重新設計 protocol,但是由於接收下來的時間卻 little endian,所以必須另外寫一個轉換函數把 little endian 轉換成 big endian。
- 執行 command(Real-time data 1 access),照原始 I2C protocol 來說,讀取最後一個 byte 回傳 ack=1,讀取中間的 bytes 一律回傳 ack=0。當然 S35390A datasheet 也是如此寫,沒有錯誤。但是實際上在 coding 的過程中卻發現完全相反,讀取中間的 bytes 必須回傳 ack=1,才能得到正確值;如果回傳 ack=0,傳回值卻都是 0。真是奇也怪哉,莫名奇妙,害我玩了好多天才找到問題所在。
- 在設定時間時,必須一次寫入完整 7 bytes,如果漏了一個 byte 就執行 i2c_stop, S35390A 則不會存入這次寫入的時間。
● slave address
S35390A 的 slave address 為 7-bit addressing 變化型,也就是把前 4 bits 固定,後 3 bits 來當做 command。因此在 I2C bus 上的 chip,前 4 bits 不能為 0110,也就是不能為 0x6? 的 slave address,否則會跟 S35390A 相衝突。
● chip init
按照 datasheet 所陳述的初始化流程圖,有下列需要注意的事項。
- 當電源接上時(也就是裝上電池),會設置 POC=1;在此時需要設置 RESET=1,讓 chip reset。
- 當電源拔掉時(也就是突然接觸不良),會設置 BLD=1;在此時需要設置 RESET=1,讓 chip reset。
- 當有不明原因讓 chip 進入 test mode 時,會設置 TEST=1;在此時需要設置 RESET=1,讓 chip reset。
- chip reset 完之後,必需再次檢查上述三項條件。
to be continue...
記錄一下系統開機或是被 reset 時的一些旗標狀態。
旗標狀態
| reset | WTRF | POR | EWT | WDCON | 判斷 |
| power-on reset | 0 | 1 | 0 | 01000000b | POR=1 |
| external reset | x | x | x | 0x0x0xx0b | EWT=1* POR=0# |
| watchdog reset | 1 | x | x | 0x0x01x0b | WTRF=1 |
註解
- x: 保留原值,不會變更。
- *: 系統如果有開啟 watchdog 功能,在發生 external reset 時,EWT 一定是 1。
- #: 一開機時 POR=1,此時把 POR 設成 0,下次發生 external reset 時,POR 一定是 0,以此來區分。適合沒有開啟 watchdog 功能的系統。
判斷順序
- 開啟 watchdog: WTRF=1(watchdog) -> EWT=1(external) -> POR=1(power-on)。
- 關閉 watchdog: POR=1(power-on) -> POR=0(external),watchdog 不用判斷。
reset 開機狀態
- Program Counter 強制跳回 0000h,也就是從頭開始執行。
- SFR 都會返回 reset value,datasheet 有一張表。
- stack point 會變成 07h。
- Vdd 小於 2V 時,RAM 資料會遺失;反之則會保存。
以往在寫 uart 的 putchar 函數時,都是用下列方式來寫。在初始化時還要先把 TI 設成 1。但是如此會造成 ES 中斷一直發生。只適合沒有開啟 ES 中斷程序來用。
若是改用下列方式來寫,初始化時不用把 TI 設成 1,ES 中斷就不會一直發生。但是如此會被 block,等到傳送完才繼續其它工作,對效能來說不是很好。適合需要開啟 ES 中斷程序來用。
W77E352 有一個 register 叫 STATUS(0xC5),它的 SPTA0 位元為 uart 傳送忙碌指標,當 TI 為 1 時,自動清成 0。在 W79E632 也有 STATUS register,但是卻沒有 SPTA0 位元,不知是否可用?
W77E352 可以算是 winbond 系列中中斷最多的一個,而像之前我使用的 W79E632 的中斷似乎也是跟 W77E352 系出同門。比如 watchdog timer 的中斷號碼都是 12,而 W79E632 的中斷就少了中間的 7~11,現在終於在 W77E352 看到影子了。但是奇怪的是 6 號中斷不知是那一個?
| priority / interrupt number | source | flag | addr |
| 0 | external interrupt 0 | IE0 | 0003h |
| 1 | timer 0 overflow | TF0 | 000bh |
| 2 | external interrupt 1 | IE1 | 0013h |
| 3 | timer 1 overflow | TF1 | 001bh |
| 4 | serial port | RI+TI | 0023h |
| 5 | timer 2 overflow | TF2+EXF2 | 002bh |
| 6 | ?? | ?? | 0033h |
| 7 | serial port 1 | RI_1+TI_1 | 003bh |
| 8 | external interrupt 2 | IE2 | 0043h |
| 9 | external interrupt 3 | IE3 | 004bh |
| 10 | external interrupt 4 | IE4 | 0053h |
| 11 | external interrupt 5 | IE5 | 005bh |
| 12 | watchdog timer | WDIF | 0063h |
- INT0,INT1 根據標準的 8051,是可以設定成 edge trigger 或 level trigger,但是由 winbond 提供的 INT2~INT5 卻只能是 edge trigger,而且還各有不同的 edge。
- INT2 is raising edge triggered.
- INT3 is falling edge triggered.
- INT4 is raising edge triggered.
- INT5 is falling edge triggered.
- INT2~INT5 需手動清除中斷旗標,但可以經由設定 T2MOD 的 HCx,變成自動清除。
- INT2~INT5 如果沒有清除中斷旗標,會造成中斷一直重覆,切記。由於 INT0~INT1 會自動清除,所以沒有這個問題。
要做 SDCC code banking 真是有夠麻煩,找不到有人分享成功案例就算了,sdccman.pdf 竟然也只提到一頁而已,完全沒法子去了解如此實做。最後靠著不斷的試驗,總算完成這一件不可能的任務。
- 修改 C:\Program Files\SDCC\lib\src\mcs51\crtbank.asm 來達成 bankswitching 的函數。
- 重新建立 mcs51.lib,把修改好的 crtbank.asm 置換掉舊的 mcs51.lib。
- Project Properties → C/C++ Build → Settings → Tool Settings → SDCC Linker → Command 輸入 sdcc -Wl-r "-Wl-b BANK1=0x18000",千萬不要輸入 sdcc "-Wl-r -Wl-b BANK1=0x18000",為此我花了半天找問題,真是 ooxx。
- 建立一個 c source file,開頭輸入 #pragma codeseg BANK1。
- 建立一個函數 void test1(void) banked { ... },要記得加上 banked。
- 轉換 ihx 成 bin,makebin.exe < test.ihx > test.bin
- 產生出來的 bin,裏面有 common/bank0/bank1,但是在 bank1 裏沒有 common 存在,需要手動加進去,而且也要手動分開這個 bin,才方便 winbond isp writer 燒錄。
- 大功告成,真是幸苦啊,花了一天才完成。
to be continue.... 後面有空再來補一些說明及範例吧。
從今天開始又要開始玩 8051 了,在公司裏被丟來丟去,如浮萍一般飄泊不定,真是可憐啊。
BTW 有人要挖角嗎?歡迎來電喔。
- W77E352 內含二個 serial port,port 0 可以使用 timer 1/2 做 baudreate generator,而 port 1 只能使用 timer1。所以只要設定好 T2CON,port0 就會使用 timer2;如果只有設定 timer1 則 port 0/1 就會共用 timer1。
- W77E352 有 1K 的 On-chip SRAM,使用 xdata(MOVX) 來存取,位置在 0x0000~0x03FF。使用前需把 PMR 的 DME0 開啟,就是 PMR |= 1。
- to be continue....
