2016年11月23日 星期三

在 ubuntu 上燒錄 RTD2660 韌體

本實驗室導入一顆古董 SoC

這貨是用來點 LCD 螢幕用的, 接受多種輸入, 然後輸出給一片 LCD 螢幕
這螢幕可以是三種規格其中一種:TTL, LVDS, RSDS
我嘗試在 ubuntu 上開發工具來更新韌體, 透過刷不同韌體來支援多張 LCD 面板
這玩具適合對數位影像信號有基礎的用戶使用, 一般用戶建議直接購買螢幕不要自討苦吃XD
尤其完全沒有接觸過面板的用戶, 可能花了錢也不會有結果



這項計畫有前身的, 這是去年中做的, 本實驗室第 14 號版

這計畫已確定死亡, 不會繼續
用德州儀器的 TFP401A 這顆 DVI 轉換器, 它可以把 DVI 訊號轉成 24-bit TTL
接著把這 TTL 信號接給德州儀器的 DS90C383MTD, 把 TTL 信號轉 LVDS 輸出
這是從別人的 Raspberry Pi 的計畫學來的 :
How to connect RaspberryPi to LCD and have fun | Chalkboard Electronics

這樣可以用 HDMI 去點面板
不過這玩具限制非常多, 首先 HDMI 要設定 DMT 模式, 應該就是當 DVI 來使
參考資料:What is the difference between CEA and DMT?
而且輸出解析度和更新率必須符合面板規格, 不能有任何不同
這樣一來就沒有 HDMI audio, 這玩法可能不是每家 SoC 都能這樣搞
或是可能可以, 但是很難改, 驅動可能預設沒有, 現在 arm 外接螢幕幾乎都是 HDMI 了
而 HDMI 就那幾個解析度, 通常不會有什麼 1024x600, 1280x800, 或 1366x768
偏偏市面上這種面板最多

別人做的玩具搜尋一下 datasheet 就大概知道怎麼搞的了
不過我不熟悉這些顯示界面, 就只會照著 datasheet 接, 24-bit 給 24-bit
就一根一根接起來吧? 然後就死了XD
原因有兩個, 第一, DVI 轉換器和 LVDS 轉換器之間需要電阻, 德州儀器方案常常要這樣
前篇 OMAP3530 連接 LCD 中德州儀器 SoC 接德州儀器界面轉換也是要串電阻

一根一根去割銅箔, 然後把電阻補上去, 超費勁
不這樣做的話這 LVDS 轉換器會跑一段時間後就沒有輸出, 感覺像是燒壞了
換一顆然後補電阻可以撐久一點, 但久了還是會異常, 可能要多試幾種阻值
不過我已經是用割銅箔的超難改就不想再試了

接著第二, 18-bit 和 24-bit 問題, 我照 24-bit 接, 以為可以像 TTL 面板那樣
少接幾根線一樣可以點面板, 結果我錯了, TTL 面板可以把 18-bit 輸出 "shift"
也就是直接 RGB 接給高位元的 6-bit, 但是 LVDS 不行, 只能少接高位元通道
沒法把低位元通道接過去, 它們資料排列完全不同, 我到做出來看到現象才想起來

有些時候一股腦的做, 基本知識就丟光了, 這要用文字敘述要寫很多
由於這不是本篇主題就不敘述了, 有興趣的用戶也去做一張板就會懂了XD 這是有點昂貴的教訓XD
這要修正也不難, 就是在 DVI 轉換器輸出那裡
把輸出 RGB 高 6-bit 接給 LVDS 轉換器的 RGB 低 6-bit, 然後 LVDS 只接三對信號
但是這要改線路, 我知道原因後本來想修, 但是後來出差又一堆案子, 就沒繼續搞了
這東西應該比較適合用硬體做影像處理的用戶, 把 DVI 轉成 TTL 以後接 FPGA
硬體處理影像以後再輸出給 LVDS 轉換器顯示到螢幕上, 不過這我目前沒有興趣就跳過了

為了出差準備電腦搞了超小螢幕, 就接觸了這類顯示處理器, 用了感覺不錯
所以就有了這次的計畫:RTD2660 系列影像轉換器
這東西很久了, 網路上資料還蠻多的, 戰鬥民族也有人玩XD
它可以接受各種輸入, 各種解析度的影像, 甚至不同顏色格式的
然後轉換並縮放影像, 變成符合面板規格的信號輸出, 這其實就是 LCD 顯示器的控制晶片
datasheet 日期是 2007 年, 快 10 年的方案了, 不過中間可能有升級
我沒法從 IC 編號區分詳細版本, IC 表面寫 RTD2660H
有人說 2660 只有 VGA/DVI, 2662 才有 HDMI audio
但我拿到兩張板都是 2660H, 一張有 audio, 一張沒有
不知是板子規格還是晶片限制, 還是說是韌體完整度? 這我就不知道了
以下列出一些別人寫的資料:



Using ROVATool with an FTDI FT232H Based board
燒錄器, 用 FTDI 的 USB Serial 晶片的額外功能, 這個最簡單, 應該比較多人用

Альтернативная прошивка для RTD 2662/2660 
戰鬥民族的 blog, 提供一些韌體和燒錄器, 用的也是 FTDI 方案

"Народный контроллер". Разбираем "до винтиков"... 
戰鬥民族的討論串, 有燒錄器線路和板子訊息, 這是 Printport 方案

Realtek RTD2660/2662 programmer
用 Cypress 的 USB MCU 做的燒錄器, 有原始碼

這裡有一堆資料 kolins.cz - /share/RTD2662/
有片段的原始碼以及一堆韌體

Introduction to graphics and LCD technologies
彩色 LCD 基本原理以及時序參數簡介



以上燒錄 RTD2660 的方案都是透過 i2c, VGA 接頭那裡原本是用來讀 EDID 的接腳
這玩法有個限制, 那就是韌體絕對不可以燒錄失敗或是燒錯
這 EDID 進入 RTD2660 以後會交由裡面的 MCU 處理, 收到 ISP 指令後
由 MCU 接收資料存入板上的 Serial Flash, 如果燒錄失敗, MCU 沒有正確運行
它自然就失去了 ISP 的功能, 沒法幫你把韌體寫入 Serial Flash, 它就變磚了
因此本實驗室搞自己的燒錄器, 我的是雙功能, 可以 i2c 燒錄, 也可以寫 Serial Flash
用前篇新唐方案

UART 接電腦, I2C 用來做 VGA 接口燒錄, SPI 則是直接寫入 Serial Flash
實驗發現 VGA 接口燒錄好像不是每次都會動, 有時一燒就有, 有時又沒反應
所以後來我都用 SPI 直接寫, 反正時間差不多
我手邊有兩種板, 正面

上圖右散熱片是我另外買的, 原本沒附

背面:

這兩張板左邊是 PCB8000196, 右邊是 PCB800099, 以下簡稱 196 和 99
99 是比較舊的版本, 也是市面上流通最多的, 有一堆韌體可以刷, 可以支援最多面板
196 是新版, 好像是今年的, 新增 HDMI audio 輸出, 我還沒找到有韌體可刷, 只能找賣家要
把這兩張疊起來比

上面的是 196, 目測可以看到的差別大概是多了一組穩壓, 可以透過跳帽改 LCD 邏輯電壓
用電錶探有 3.3V, 5V, 12V 三種可選, 而且電感改用較好的環形鐵芯電感
然後拔掉了 TTL 面板接頭, 改放 DAC 和 OP 放大器, 應該是 HDMI audio 要用的
從硬體來看 196 肯定是較好的, 但是如果沒有 HDMI audio 需求
韌體比較多的 99 比較可玩, 99 有的韌體幾乎市面上可以弄到的 LCD 都能點
196 什麼時候會有韌體包不知道, 也不保證會不會有



接著先發放源碼:rtd2660.tar.gz   PCB800099.zip

rtd2660.tar.gz 裡面的東西:

programmer, keil-inc 這兩目錄是新唐開發板的韌體原始碼

firmware 底下有兩個韌體, 這是我測過 OK 的
可以點 1920x1080, 18-bit 雙通道 LVDS 面板, 99 和 196 各一個韌體
196 的韌體其實是賣家出貨後我抽出的, 網路上找不到

host-src 目錄下是一些工具, 執行 build.sh 可以一次全編譯出來
sfread, sfprog 是燒錄和讀取 SPI 的工具
fwtool 是 i2c 燒錄工具, 從上面的 Realtek RTD2660/2662 programmer 那裡改來的
hex-find, hex-dump, hex-patch 是十六進位編輯工具
bin2hex 是轉換工具, 把 bin 韌體轉成 intel hex 格式, 並且每 64K 切一份

failed-2660-src 目錄下是參考用的 RTD2660 韌體源碼, 它無法使用, 僅供參考

PCB800099.zip 裡面的東西:

別人寫的 99 的使用手冊, 接腳定義, 以及大量韌體

硬體部份接線請參考別人的資料, 唯一需要注意是新唐 MCU VCC 要接 3.3V
i2c 接 VGA EDID 接法上面那堆參考資料已經都有
SPI Flash 的接法看 datasheet 即可, 把 MOSI, MISO, CLK, CS, VCC, GND 接上即可
最好做個接頭:

這招 196 適用, 若是 99 好像 Serial Flash 的另外兩隻拉高腳要上電阻拉高
我只接六隻腳 99 仍沒法寫, 由於散熱片已黏上難以加線, 所以 99 我是直接解焊燒

要做接頭分離是因為 VCC, MOSI, CLK 會和 RTD2660 衝
所以 SPI 燒錄時 99 和 196 的 12V 電源必須移除, 不能過電
而 I2C 燒錄時 99 和 196 的 12V 則要接上, MCU 運轉下才能燒錄
SPI 燒錄完成後移除燒錄器, 接著 12V 送電, 確認正確就可以把燒錄接的線移除
或是留著接線, 可以再斷電燒錄別的韌體測多片面板

接著燒錄新唐 MCU 韌體, 操作方法請參考前篇 在 ubuntu 上開發 nuvoton m051 實驗板
寫入完成後先測試和燒錄器的連線, 和前篇一樣接上 UART 接 PC, 用 minicom 開啟
然後輸入這串字不用按 Enter

$00001122334455#

正常會回覆

O 001122334455

這功能是 echo, 可以用來測試和燒錄器之間的通訊, 若這裡沒有成功就不要往下做了
繼續試別的是不會有任何結果的, 接著測 i2c 燒錄, 還是 minicom
99 或 196 送電, 然後 VGA EDID 接上, minicom 輸入:

$014a6f#

這意思是指令 01 (i2c 發送), 發送 0x4a 0x6f, 0x4a 即 i2c address
若通信正確會得到:

O i2c send ok

若把 EDID 線拔掉再輸入一次應該會看到:

X i2c error: 20

如果要能燒錄一定要看到 i2c send ok, 不過看到了不一定能燒, 原因不明
有時候很容易就燒了, 有時候怎麼試也不行, 另外, 這工具應該是 99 成功率較高
聽說 196 不能這樣燒, 但我有溝通成功過, 印象中只有一次XD

確認一切正確後就可以開始操作, 若是第一次操作建議先讀出原先韌體備份

$ ./fwtool /dev/ttyS0 r firmware_to_backup.bin

/dev/ttyS0 是 UART 節點, 換成 ttyUSB 應該也行
我的電腦有 com port 所以就沒有加 USB Serial 了
備份後就可以開始寫入新韌體:

$ ./fwtool /dev/ttyS0 w firmware/PCB8000196-LVDS1920x1080-d6.bin

然後它就會開始洗屏XD

這軟體是從別人寫的軟體改來的, 由於該作者有把讀寫的 function 獨立出來
我很容易就可以把我的 UART 專用流程替換進去, 然後它就會動了
所以我並不知道它在寫什麼鬼XD 從訊息看來像是不斷的對某個暫存器寫
然後又從某個暫存器取出狀態判斷, 好像是這樣, 既然會動了我也懶得研究XD

如果很不幸的 i2c 沒反應, 或是手滑刷成磚了, 那就改用 SPI 燒錄吧
接上線以後用這個讀資料:

$ ./sfread /dev/ttyS0 firmware_to_backup.bin

然後這個是寫:

$ ./sfprog /dev/ttyS0 firmware/PCB8000196-LVDS1920x1080-d6.bin
I(main):open uart...
I(main):setup uart...
I(main):open firmware/PCB8000196-LVDS1920x1080-d6.bin ...
Chip ID = ef3013
stat = 3
erasing, wait... (stat = 0)   
Writing address 3ff00 ...
I(main):rom contains only 1024 pages, done

原理是下命令叫燒錄器把 CS 拉低, 然後叫燒錄器送資料給 Serial Flash
送資料有三種, 讀寫, 只讀, 只寫
讀寫就是寫入 N 個 byte, 然後把裝置傳回的 N 個 byte 傳回 PC
只讀則是全部都送 0xFF, 然後把讀到的 byte 傳回
只寫則是只傳送資料, 裝置送回的 byte 全部丟棄不管
一次 SPI 傳輸可能會需要先只寫然後只讀, 或是全部只寫
用這三種傳輸來兜出 Serial Flash 的傳輸協議, 詳細協議請見 datasheet
以我買到的 99 和 196 來說附的是 W25X40CL 這顆

做到這裡, 如果韌體符合你的面板, 背光接線和電壓也都符合, 那應該就會動了

把 1080P 畫面塞到 1024x600 的面板上, 這只是示範用, 正常人(?)是不會這樣接的XD
仔細看像素:

都快辨識不出來啦XD
這是 1080P 螢幕上顯示的:

差很多, 不用試就知道結果XD

如果有韌體包, 加上燒錄工具, 這東西還挺有用的, 尤其對我們這種 "裝備" 比較多的
像是一堆 HDMI 輸出的 arm 板子, 每個都要接螢幕放桌上很擋路
尤其測試也不需要畫質好, 隨便拿個能動的就好啦~
另外, 當選面板時應該就會注意到規格, 市面上能買到的筆電面板通常是 18-bit
這種面板當然不可能顯示出 24-bit 的色彩, 配這種面板輸出的顏色本來就不怎樣
如果拿這種面板去做影像處理用途......調完拿去別人的螢幕看可能會差蠻多的
所以才會一開始就說, 一般用戶請購買螢幕, 眼見為憑, 不要自己兜
這種都是特殊應用, 家裡電腦要用的還是乖乖買現成的吧


組裝後的結果放相簿:
用 RTD2660 組裝 LCD 螢幕

相簿簡介:
想了很久才做完, 主要是考慮成本, 18-bit 面板是便宜貨, 如果訂做外殼最後做出來外殼比面板還貴就太不像話了, 固定這面板意外的有困難, 做太薄容易讓面板變形, 要堅固又容易做太厚, 最後經過多方評估, 做出了這有點怪的架子, 有合理的強度, 而價錢也很便宜, 只是看起來很土砲XD



接著是進階應用, 我有翻過原始碼, 大概知道某些固定的資料長什麼樣子
如果你有一張面板它的解析度符合韌體包裡其中一個檔案, 但是刷上去畫面不正常
可以透過十六進位編輯修改韌體來符合需求, linux 有指令可以比對二進位檔案差異:

http://superuser.com/questions/125376/how-do-i-compare-binary-files-in-linux

cmp -l PCB800099-LVDS1920x1080-d6-X.bin PCB800099-LVDS1920x1080-d8-2av1vga1hdmi-5key-ir2.bin |
    mawk 'function oct2dec(oct, dec) {
        for (i = 1; i <= length(oct); i++) {
            dec *= 8;
            dec += substr(oct, i, 1)
        };
        return dec
    }
    {
        printf "%08X %02X %02X\n", $1, oct2dec($2), oct2dec($3)
    }'

這可以協助找出韌體包中各檔案的差異, 相同解析度的差異都不大, 不同解析度差異就很大
目前已知解析度設定可以這樣找, 以我的 1080P 面板為例, 1920 的 16 進位是 0x780
用我的工具:

$ ./hex-find ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin 0780
I(main):pattern: 07 80
I(main):open ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin ...
0xc31
0x36ea
0x36fd
0x3710
0x3736
0x3749
0x375c
0x73c5
0x962e
0xc496
0x10c31
0x14874
0x158ad
0x20c31
0x2424f
0x247a2
0x2606f
0x26dc9
0x26e08
0x26e3b
0x30c31

這可以掃出所有包含 0780 的位址, 別的十六進位編輯器也可以用
我是發現有些編輯器會位址多一或是少一, 有些又是有整數判斷, 功能很多很雜, 所以自己寫
我只是要掃一串 byte 而已, 寫出來也沒幾行程式就自己寫了
上面那堆位址第一個是 0xc31, 我們可以把附近的 byte 列出來:

$ ./hex-dump ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin c31 20
I(main):open ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin ...
07 80 08 20 08 20 08 20 00 14 04 38 04 60 10 03 00 ad 04 4c 00 64 02 f8 01 ea 00 ff 0c 2d 00 ff

列出附近 0x20 個 byte, 接著比對源碼:

#define _LVDS_MAP2   0x00 //LVDS Bit-Mapping Table 2
#define _DISP_24_BIT   0x00
#define _DISP_SINGLE_PORT   0x00

typedef struct {
    UINT8 PanelStyle; // 0  Panel Style
        _PANEL_TTL=0 _PANEL_HZ=1 _PANEL_LVDS=2 _PANEL_RSDS=3
        _AUTOCALC_PIXCLK=(1<<2) _LVDS_MAP1=(1<<3) _DISP_18_BIT=(1<<4)
        _RSDS_PN_SWAP=(1<<5) _RSDS_HL_SWAP=(1<<6) _RSDS_GC_SWAP=(1<<7)
    
    UINT8 PanelConfig; // 2  Panel Configuration
        // Definitions for Display Single/Double Port, Even/Odd Swap,
        // Red/Blue Swap, MSB/LSB Swap, Green/Clock Swap,
        // High/Low Swap and PN Swap
        _DEN_INVERT=(1<<0) _DHS_INVERT=(1<<1) _DVS_INVERT=(1<<2)
        _DISP_ML_SWAP=(1<<4) _DISP_RB_SWAP=(1<<5) _DISP_EO_SWAP=(1<<6)
        _DHS_MASK=(1<<7) _DISP_DOUBLE_PORT=(1<<3) 

    UINT16 DHStartPos;   // 9  Display Horizontal Start Position
    UINT16 DHWidth;      // 19 Display Horizontal Width
    UINT16 DHTotal;      // 6  Display Horizontal Total Clock Number in One Display Line
    UINT16 PalDHTotal;   // Display Horizontal Total Clock Number in One Display Line for CVBS PAL
    UINT16 NtscDHTotal;  // Display Horizontal Total Clock Number in One Display Line for CVBS NTSC
    UINT16 DVStartPos;   // 10 Display Vertical Start Position
    UINT16 DVHeight;     // 13 Display Vertical Height
    UINT16 DVTotal;      // 4  Display Vertical Total Line Number in One Frame
    
    UINT8 DHSyncWidth;   // 1  Display H Sync Width
    UINT8 DVSyncHeight;  // 1  Display V Sync Height
    UINT16 PixelClock;   // 1  Typical Pixel Clock in MHz
    
    ...

面板的宣告大概長這樣, 我們只需要看到這些, struct 剩下的資料我比過, 幾乎不變
所以只要關心這些, 細部參數代表啥這個寫起來很多...請自行上網找XD 註解有關鍵詞
1920 是面板有效寬, 相當於 DHWidth 這個成員
它在 struct 中的第四個 byte, 因此往前四個 byte 再列出一次:

$ ./hex-dump ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin c2d 16
I(main):open ./fw-base/PCB800099-LVDS1920x1080-d6-2av1vga1hdmi-5key-ir2.bin ...
12 08 00 20 07 80 08 20 08 20 08 20 00 14 04 38 04 60 10 03 00 ad

0xc31 - 4 = 0xc2d, 列出 0x16 個 byte, 一一對應就知道那是啥, 修改就可以符合面板規格
這樣修正: (注意!!這工具是覆蓋原檔案, 要修改請自行複製一份再改)

$ ./hex-patch fw-gen/PCB800099-LVDS1024x600-s6.bin c2d \
> 120000200400054005400540000c0258027212030033
I(main):patch: 12 00 00 20 04 00 05 40 05 40 05 40 00 0c 02 58 02 72 12 03 00 33
I(main):open fw-gen/PCB800099-LVDS1024x600-s6.bin ...

這樣就可以把 0xc2d 開始的資料換成別的, 直接複製 dump 出來的 byte
把空格刪除就可以 patch, 如果用現成工具就還需要整理數據, 比較麻煩
這個 patch 就是 memory-map 以後改, 程式也沒幾行

修改時請以 64K 為單位去搜尋, 以 c2d 這個來看, 上面搜尋結果
0xc2d, 0x10c2d, 0x20c2d, 0x30c2d 都有一樣的 byte 串, 這些通通都要改
這是 MCU 特性, 切換 page 以 64K 為單位, 原因後面會說
若有才要改, 若沒搜到就不要改, 需要一點人體感覺XD

我有嘗試修改 1080P 的參數, 改成 1024x600 然後刷進去, 結果:

文字顯示正確, 表示面板參數是正確的, 但是一接上 HDMI

它就炸了
若要我來猜應該是影像轉換器那裡, 有些參數是寫死的, 而不是變數計算
以我修改韌體去比對:

00007ECD 04 03
00007FD6 16 14
00007FDF 26 24
00007FE4 06 04
00007FF6 06 04
00008069 08 06
0000982E 08 06

99 的韌體有這一部份資料我無法識別位置, 他們會影響影像轉換, 目前無法正確定位
所以也沒法修正, 因此上面這招只適用相同解析度修正, 可以修的項目像是 18 / 24 bit



99 韌體包的 1920x1080 6-bit 刷進去變這樣, 網路上下載來的其實是錯的
從錯誤畫面感覺就是 bit 數不對, 十六進位修正後, 把 _DISP_18_BIT 加上
然後清掉 _LVDS_MAP1, 就變這樣:



完成!

我還有掃到 EDID 的位置, 用這串 byte 搜尋

$ ./hex-find ./fw-gen/PCB800099-LVDS1024x600-s6.bin 00ffffffffffff
I(main):pattern: 00 ff ff ff ff ff ff
I(main):open ./fw-gen/PCB800099-LVDS1024x600-s6.bin ...
0xc4f
0xccf
0x1e00
0x10c4f
0x10ccf
0x20c4f
0x20ccf
0x30c4f
0x30ccf

可以發現查詢到位置都是 64K 為單位, 但是 0x1e00 那筆除外
接著列出:

$ ./hex-dump ./fw-gen/PCB800099-LVDS1024x600-s6.bin c4f 80
I(main):open ./fw-gen/PCB800099-LVDS1024x600-s6.bin ...
00 ff ff ff ff ff ff 00 12 e5 00 21 50 2d 31 01 1c 13 01 03 68 2f 1a 78 2e 35 85 a6 56 48 9a 24
12 50 54 af ef 00 71 4f 81 80 81 8a 95 00 95 0f b3 00 d1 c0 81 00 02 3a 80 18 71 38 2d 40 58 2c
45 00 dc 0c 11 00 00 1e 00 00 00 ff 00 30 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 00 00 00 fd 00 38
4b 1e 53 15 00 0a 20 20 20 20 20 20 00 00 00 fc 00 4c 4d 32 31 30 30 57 0a 0a 0a 0a 0a 0a 00 af

這堆就是 EDID 了, 由於我沒有東西可以測所以就不試了, 改法也是和面板參數一樣

$ ./hex-patch fw-gen/PCB800099-LVDS1024x600-s6.bin c4f \
00ffffffffffff004a8b0000010101011e0c01010e241b78e88a019a58528b28\
1e5054ffff806140614f6159714f814081598199a940000000fc003137272720\
4c43440a20202020000000fc004d6f6e69746f720a2020202020000000fd002b\
55145c0e000a202020202020000000ff003030303030310a20202020202000bd

把 dump 出的 byte 移除空格後每行後面加 \ 直接貼進 terminal 就可以替換
到這裡, 只要有一包指定解析度的韌體, 相同解析度的面板應該都能點





嗯......如果和我一樣對於轉換器有無止盡的愛(?), 可以接著往下看XD
接下來只有一些研究, 但是沒有成果, 也就是上面源碼包中 failed-2660-src 目錄下的東西
這顆 SoC 包的 MCU 是 8051, 名稱是 DW8051, 4T, 4 個 clock 可以跑一個指令
8051 是我唸書時第一個接觸的 MCU, 但是我對 8051 實際應用並不是非常了解
因為標準的 8051 實在太弱了, 只有 UART 一個通訊功能, 然後兩外部中斷, 剩下都 GPIO
不好玩啊!所以有一段時間我都是碰 AVR, 這也是我 blog 中文章最多的標籤
因此, 看了這東西才了解, 原來 8051 也可以玩的這麼變態XD

程式執行都是從 Serial Flash 中取出, 蠻多家 SoC 有做類似的功能
看別人的文章好像新唐也有類似的產品, SoC 本身不帶儲存設備, 全部程式都外面撈
所以也不會有開不了或燒錄壞的問題, 只要重寫 Serial Flash 或是替換即可
傳統 8051 壞了就要解焊 40 隻腳, 不過這機會也不多就是了
執行時和一般 8051 沒有任何不同, SFR 共通部份都相同, 存取指令也相同
中斷也是六個, 也有外部 64K 位址空間, 用間接定址 DPTR 去存取, 到這裡都一樣
只不過! SFR 多埋了些東西, 例如有兩個 DPTR 可以抓資料
64K 位址空間 0xFD80 到 0xFEFF 拿來存 EDID, 可以有三個 Port EDID
0xFF1B 以後有一堆暫存器, 可以設定 pin function, 標準 8051 沒這種功能
可以轉接中斷, 像是 i2c 的中斷可以接到外部中斷, 程式上外部中斷還是在
但是裡面可能需要跳去處理 i2c 這種 "內部裝置" 的事情
雖然位址空間只有 64K, 但是可以透過 0xFFFC 後的暫存器換頁, 最多 256 頁
也就是可以存取 256 x 64K, 不過換頁時程式要自己處理換頁問題
換頁後整個程式空間都會換掉, 如果每頁都不同程式, 換過去會無法預期
我看過兩家編譯器, Keil 和 SDCC 都說, 你要自己處理這個問題
編譯器會提供一些框架, SoC 廠商需要自己填起來, 而用戶寫程式時也必須手動分割
哪些要共用每頁都有, 哪些是跳頁時才用, 這些要自己規劃好
像是中斷向量的程式, 每頁都要複製一份, 這樣換頁後才可以在相同位址看到相同程式
因此前面才會說, 每 64K 為單位去掃, 有一樣的要跟著改, 否則結果無法預期

在這 64K 空間的暫存器都是一些比較通用的, 影像用的都不在這裡
它們都透過同一窗口去存取:0xFFF3, 0xFFF4, 0xFFF5
F3 設定位址是否自動增加, F4 設定位址, F5 存取資料
打開這扇窗就可以看到新世界XD 所有的轉換器設定幾乎都在這裡面
這三個暫存器已經是要間接存取了, 還要先設定, 然後送位址, 才能撈資料
讀寫轉換器的一個暫存器就要十多條指令啊!這還不是最誇張的
這個轉換器稱作 scaler, 也就是這顆 SoC 最強的功能, 可以縮放影像
不過實際上這 scaler 夾雜了一堆功能, 它就放在 datasheet 很前面的頁面

這方塊圖一長串繞成 S 型才放的下, 活像條串珠一顆一顆塞XD
這裡面所有的功能都透過三個暫存器組成的窗口去設定
而且暫存器裡面還有暫存器!0xFFF4 設定位址, 意思是最多 256 個暫存器
這裡簡稱 SCA 暫存器, 不過看來是不夠用的樣子, SCA 暫存器還分頁!
SCA 暫存器 0x9F 用來換頁, SCA 暫存器 0x9F 以下的稱 Common Page
任何時候都能存取, 但是 SCA 暫存器 0xA0 到 0xFF 就要換頁
要存取第三頁 SCA 暫存器, 就要先對 SCA 0x9F 寫 3
然後才能存取第三頁 0xA0 到 0xFF 的暫存器
RTD2660 datasheet 每頁最上方的 Page 數就是指這個, 研究源碼幾天才了解
換頁完還有更猛的, 每頁裡面有些暫存器只是接口, 例如:

#define P2C9_HDMI_ADDR 0xC9
#define P2CA_HDMI_DATA 0xCA

這寫在 rtd2660.h 裡, 意思是第二頁, 0xC9 暫存器是位址, 0xCA 是資料
這裡面還有暫存器, 位址先送到 0xC9, 選你要寫哪個暫存器
然後送資料到 0xCA 就寫入, datasheet 中寫四位數的位址就是這意思
像設定顯示輸出到面板的 timing 就是 2B-00 開始
意思就是先對 SCA 0x2A 寫 0x00, 然後寫資料到 SCA 0x2B
就是寫資料到暫存器 0x2B-0x00 中!

我參考網路上放出的源碼, 編寫成我習慣的風格, 打算 GPL 放出, 但是踢到鐵板
到 LVDS 輸出這裡都還 OK, 我都有做到, 面板也確實點起來了, 接著是 OSD
就死在這裡, OSD 是 On-Screen Display, 也就是文字選單
它的 OSD 用的字型居然是編碼過的, 雖然是寫 VLC, 我猜是 Variable-length code
但如果是這樣, 最少要有 0 和 1 的編碼吧? 不然遇到 1 結尾的怎麼辦?
我就卡在這裡下不去, 照著源碼抄畫出來變這樣

我也無從除錯, 沒輒, 只好放棄, 這包 code 就只有到點 LVDS 面板為止
缺太多資料玩不下去, 裡面藏的資料太多了, 還有 video codec, 這家方案是可以接選臺器的
和 video 解碼有關的程式都只有 binary, 字型要另外有軟體生成
還有許多組件要塞意義不明的數字串, 像是 10-bit 降轉 6-bit 和 8-bit 的 dithering
就要塞不一樣的數字串, 有些家的方案會用上 DSP, 塞的就是 DSP 的韌體
它的運作就像一間工廠, 上面那串方塊圖就像工廠中一台台的機器
接受前面機器的輸出, 處理後傳給下一台機器
8051 的角色就像員工, 不斷的檢視機器的狀態, 這些機器都是自動運轉
不斷的收下像素資料, 然後處理後往下一站送
8051 不會親自參與處理這些像素, 效能根本不夠, 它只監控這些機器
例如當使用者移除訊號線, 這些機器就會變更狀態, 工人看到了就去操作機器設定
看是要暫停機器還是重新初始化等


由於是標準 8051, 有興趣可以用 8051 模擬器去跑, 不過應該很快就會卡死
因為它會存取 SCA 暫存器, 模擬器把那裡當記憶體, 自然是啥也撈不到
可以用源碼包裡的 bin2hex 工具去轉, 轉成 intel hex 就可以上模擬器
不過因為是多頁, 如果韌體一開始就跳頁, 一樣是寫入模擬器的記憶體, 當然是不會換頁
然後就會看到程式亂跑不知道跑哪去XD 把它丟上模擬器大概就是當反組譯器來玩
看看什麼位址有什麼, 用圖形界面查找方便, 如此而已, 幫助不大

這顆 SoC 似乎和另一顆很有關連, 不知道是技術授權還是競爭對手
我以前有買過一片類似的產品但不會動就丟一旁, 後來突然想起把它挖出來

透過它的型號找到一顆相容的 GM2621, 這裡有篇介紹:gm5621, 出產地是台灣 
然後再看 RTD2660 源碼和 datasheet, 這顆簡直就是 RTD2660 失散多年的親兄弟XD
看這份文件才知道 datasheet 裡那堆縮寫是什麼意思, 都只有縮寫, 沒有任何註解
做了這玩具就更了解整個電腦顯示流程, 再加上工作上看過的一些硬體, 已經全線通車了(?)
所以做不下去好像也沒差了, 如果以後有撿到更詳細的 datasheet 可以再回來看, 若沒有就算了

目前還有一點疑問, 這個 SoC 裡也有, 它們在不同 clock 的硬體之間不知道怎麼交換資料?
以前只學過一點硬體描述語言, 沒有提過這問題, 這 RTD2660 接受數位輸入
gm2621 文件就有提到裡面好幾組 PLL 供應 clock, 像這種外面 HDMI 來的信號也帶有 clock
它的速度無法預測, 面板也是很多種, 它也要 clock, 這兩種速度相差很遠又無法預期的 clock
要把它們串在一起還真是困難, 看過有的 SoC 有提到是超快的 ring buffer 搭配足夠記憶體和仲裁器
那是晶片上網路, 外來的 clock 也能這樣做嗎? 看到方塊圖中的 FIFO 感覺有點像
只是好奇, 不過若知道它怎麼做的, 我好像也不能拿去幹麻XD 我應該是沒機會跳 IC 設計的XD

4 則留言:

  1. 看到fifo和scaler串在一起,有一種隱約的感覺是,fifo每次接收滿一個frame才往scaler丟,讓scaler處理解析度變換。
    fifo的輸入是循序掃描或者隔行掃描的資料,輸出端是一次一張frame(shift in parellel out的感覺xd),所以從fifo切開,他之前的跟著輸入源的速度跑,之後的改跟著面板速度跑,前後的同步應該是以fps為單位來對齊。
    看他操作這些硬體功能的方法,有一種「這些東西該不會在ic裡是用類似spi什麼的專用匯流排接回8051的吧」的感覺

    回覆刪除
    回覆
    1. >fifo每次接收滿一個frame才往scaler丟
      它的最高解析度支援到 1920x1440, RGB 各 1 byte 來算
      一個 frame 要 8MB 的空間, 這個做在晶片上好像有點貴哪XD
      我能想到的是如果 scaler 不是以畫面為單位, 而是像 video 那樣
      以 tile 為單位去處理, 假設輸入 1920x1080, 輸出一半 960x540
      尺寸縮小一半, 那麼輸入像素只要有兩列應該就能先處理出一列了吧?
      加上非線性多擷取幾個鄰近像素, 應該也不用等到整個 frame 進來才算
      小變大也是如此, 進一列一邊進就一邊先吐出兩列, 然後用比較快的速度出
      不過這很複雜, 真能寫出來嗎?XD
      這我就不知了, 不過整個 frame 先進來是肯定做的到的
      我記得有文章說早期 scaler 是要掛記憶體的, 應該就是這種玩法
      這顆卻不用, 肯定有開外掛(?)XD 不知道用什麼方法

      >這些東西該不會在ic裡是用類似spi什麼的專用匯流排接回8051的吧
      我覺得可能性較低, 因為從 datasheet 在 MCU register 那章的介紹
      它的 8051 是可以停用的, 透過外部不明的設備接上
      可以直接對 scaler 下命令, 所以 8051 應該就只是調度員
      有三種模式: embedded MCU mode (8051 運行), external MCU mode
      以及 ISP mode, 後兩模式 8051 停止, 而外部設備可以存取 8051 的暫存器
      這樣看起來比較像是 8051 就是殺低價出貨用的, 如果想要撈畫面或是大量資料
      用別的外接設備去做, 可能是除錯用, 比較像這種感覺, 不過都是猜測
      也說不定 8051 真的可以碰到像素只是沒放源碼中, 不過我不認為有這必要XD

      刪除
    2. 有可能像pc剛進入雙核時代的時候那樣,兩顆chip包成一顆啊xd,這樣的話ram和8051都一起有解了:8051一片,這些影像處理單元可能是分開好幾片,要外掛ram的就掛一片ram進去,最後打在一條8051外部的共同匯流排上(只傳遞控制訊號,並且有拉出可以用外部mcu對這個匯流排送指令)
      外部送指令控制的用法應該可以用在智慧電視,機器就有內藏更高級的gui界面(以圖片展示的亮度與色彩調整,各界面目前的輸入畫面多分割顯示之類的),這樣就不必讓視訊資料經過高階mcu/ap,只要在正確的時間點操作這些硬體功能,就可以包裝得很漂亮

      刪除
    3. >有可能像pc剛進入雙核時代的時候那樣,兩顆chip包成一顆啊xd
      我認為這個可能性趨近於零XD 那個很高貴啊, 相似的技術我聽過三種
      一種就是 intel 那種雙晶上電路板封裝, 一種是 package-on-package, 手機常用
      最後一種是聽演講聽到的, 還沒看過實品的封裝內晶片 3D 堆疊
      不管是哪種, 都是封裝廠算在高階的服務, 這玩具整片電路板掏寶才賣 300 多台幣
      用這種封裝絕對虧死啊XD 我這裡有份文章裡面有提到記憶體訊息:
      https://drive.google.com/file/d/0B_gFNN5W0bYNcWo5YnNOV2J4dHM
      檔案日期 2004 年, 我不知道當年為什麼存這篇, 從我檔案命名就知道我當年肯定不懂XD
      裡面有提到 "而Scalar IC中僅具有儲存幾條掃描線的記憶體(Line memory)"
      所以推測應該是邊進邊算, 但是他寫的幾個算法的關鍵詞我看不懂, 有興趣可以搜尋一下

      >外部送指令控制的用法應該可以用在智慧電視
      那種方案去找晨星
      http://www.mstarsemi.com/tw/products_TV.php
      智慧電視的方案就是手機方案改一改直接上了XD 什麼 2D/3D 都進去了
      在變態高時脈的 ARM 下這種要求不痛不養, 通通在晶片上不用外接

      刪除