2022年8月1日 星期一

在 ubuntu 上開發 nuvoton Mini58


這是張帶 MCU 的網卡, 網卡部份下篇 用 RTL8153 自製 USB3 1G 網卡 說明
本篇介紹 MCU 部份功能, 上圖板子只有左上角一小塊是 MCU 的, 剩下的是網卡以及 MCU 的供電
我們裝一顆新唐的 Mini58 上去, 控制 WS2812 LED 以及量溫度後控制風扇
並實做一個簡易 loader 可透過 uart 更新韌體

要燒錄這顆 MCU 用 OpenOCD, 用最新的 0.11.0
本來是打算繼續用舊版, 但由於 ID 不認得需要重編, 結果編譯器報錯
ubuntu 升級後編譯器也換了, 只好再抓新的下來編
新的也不含 Mini58 和我常用的 NUC131, 所以一定是要編譯沒法抓現成的
編譯也不難, 下載後解壓縮完先打個 patch:
--- src/flash/nor/numicro.c    2022-06-02 18:56:48.243412698 +0800
+++ src/flash/nor/numicro.c    2022-07-18 18:17:43.615098130 +0800
@@ -137,8 +137,9 @@
     {NUMICRO_CONFIG_BASE, 1024} }
 
 #define NUMICRO_BANKS_MINI51(aprom_size) \
-    .n_banks = 3, \
-    { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_LDROM_BASE, 2*1024}, {NUMICRO_CONFIG_BASE, 512} }
+    .n_banks = 4, /* should be 3 */ \
+    { {NUMICRO_APROM_BASE, (aprom_size)}, {NUMICRO_DATA_BASE, 1}, /* dummy wrong size to prevent error */ \
+    {NUMICRO_LDROM_BASE, 2*1024}, {NUMICRO_CONFIG_BASE, 512} }
 
 #define NUMICRO_BANKS_NANO(aprom_size) \
     .n_banks = 4, \
@@ -662,6 +663,9 @@
     {"NUC130VC3AN", 0x00013024, NUMICRO_BANKS_NUC100(32*1024)},
     {"NUC130VC2AN", 0x00013025, NUMICRO_BANKS_NUC100(32*1024)},
     {"NUC130VC1AN", 0x00013026, NUMICRO_BANKS_NUC100(32*1024)},
+   
+    /* NUC131 */
+    {"NUC131SD2AE" , 0x10013110, NUMICRO_BANKS_NUC100(64*1024)},
 
     /* NUC140 Version A */
     {"NUC140LE3AN", 0x00014000, NUMICRO_BANKS_NUC100(128*1024)},
@@ -819,6 +823,7 @@
     {"MINI54TDE" , 0x20205404, NUMICRO_BANKS_MINI51(16*1024)},
     {"MINI54FDE" , 0x20205405, NUMICRO_BANKS_MINI51(16*1024)},
     {"MINI55LDE" , 0x20205500, NUMICRO_BANKS_MINI51(16*1024)},
+    {"MINI58FDE" , 0x00a05804, NUMICRO_BANKS_MINI51(32*1024)},
 
     /* NANO100 */
     {"NANO100VF3AN" , 0x00110000, NUMICRO_BANKS_NANO(256*1024)},


接著用以下命令編譯:

sudo apt install pkg-config libusb-1.0-0-dev libhidapi-dev
./configure --exec-prefix=/XXX/openocd/0.11.0 --prefix=/XXX/openocd
make -j10
make install

XXX 自行替換成你的存放路徑
上面這 patch 並不是完美的 patch, Mini58 不像 NUC131 有獨立的 data flash
因此正常應該是回報 3 個 flash, 可是 OpenOCD 燒錄時逐一比對位址, 若不填上一個數字
就會說空間為零報錯退出, 為了讓它可以繼續試別的位址就給它填個 1 byte, 這樣才可以燒 LDROM
比較正確的改法應該是沒有空間的位址要忽略, 但這 flash 列表似乎是回報給上層
numicro.c 裡沒找到比對的程式, 懶得繼續查就出此下策, 有興趣的用戶可以追蹤一下上層
若找到好改法請將 patch 發給 OpenOCD 團隊


接著發放源碼和線路圖, 源碼:wt-23-mini58.zip 線路:wt-23-r2.pdf

線路包含網卡部份, 中間一線隔開, 請參考下半部線路, 上半是網卡別管它
編譯用 gcc-arm-none-eabi-4.8.3-2014q1 這編譯器是從 arduino-1.5.7 抽出
下載 arduino-1.5.7-linux64.tgz 這包, 從這路徑抽出:
arduino-1.5.7/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1
總共需編譯三個項目, 指令:

export PATH=$PATH:/XXX/gcc-arm-none-eabi-4.8.3-2014q1/bin
make
make loader
gcc update.c -o update

編譯後把 ST Link v2 接上 Mini58, 啟動 OpenOCD

sudo ./bin/openocd -f interface/stlink-v2.cfg -f target/numicro.cfg -s share/openocd/scripts

然後開另一個 terminal 從 telnet 連進去:

telnet localhost 4444

接著輸入以下命令:

> reset init
> numicro chip_erase
> numicro write_isp 0x300000 0xFFFFFB3F
> flash write_image erase wt-23-loader.bin 0x100000
> reset

以上命令的用途是:

1. 停下 MCU, 初始化
2. MCU 全片清除, 如果你不小心鎖住 flash 時就用這行, 平常不需要
3. 配置 config 區, 從 LDROM 開機
4. 把我們編譯出的 loader 程式放進 LDROM
5. 重置 MCU, 執行程式

若要除錯可參考前篇:在 ubuntu 上開發 STM32F469 Discovery 實驗板
和 STM32 共用工具, CPU 核心也是 ARM 的, 方法可共用
寫入以後接著連接 uart 到 ubuntu, 用 USB Serial 接上 Mini58
然後用我們編譯出的 update.c 這程式把韌體發過去

$ ./update /dev/ttyUSB0 wt-23.bin
open uart...
setup uart...
2022/07/19 19:34:42 ckecking mode...
2022/07/19 19:34:42 sending firmware...
send block 0 OK return : $00
send block 1 OK return : $00
send block 2 OK return : $00
send block 3 OK return : $00
send block 4 OK return : $00
send block 5 OK return : $00
read end
2022/07/19 19:34:42 reset to app... OK
2022/07/19 19:34:42 exit

若順利成功, 就可以看到 LED 被點亮




接著說明程式內容, Cortex-M3 可以透過配置中斷向量位址來切換啟動程式, 但 Cortex-M0 不行
ARM 把這功能割掉了, 然後壓低授權金, 即是老黃刀法
所以用戶想要做 bootloader 就要費點腦, STM32F0 上用的套路是複製中斷向量表到記憶體
然後把記憶體映射到中斷向量所在的位址, 而新唐套路不一樣
新唐套路是到 config 區配置成把 LDROM 的第一個 page 映射到中斷位址, 然後重開機

如上圖, 出自 Mini58 TRM, 因此我們就要修改連結腳本, 可打開源碼裡的 mini58-loader.ld

. = ALIGN(0x80);
_isr_vectors_offs = . - 0x00000000;
KEEP(*(.isr_vectors))
. = ORIGIN(FLASH) + 0x200;
. = ALIGN(4);
CREATE_OBJECT_SYMBOLS
*(.text .text.*)

新唐 Mini58 的 flash 一個 page 是 512-byte, 所以放完中斷向量後後面程式從 0x200 開始放
程式運行是照順序執行, 除非遇到跳躍, 可是我們只有一個 page 被映射到位址 0
為了防止執行到一半斷掉, 所以程式全部推到 0x200 後, 中斷向量表裡只有記憶體位址
就算它的運行空間是在 LDROM 的位址也沒差, 所以我們的 FLASH 配置還是從 LDROM 位址開始
即是從 0x00100000 開始算位址

STM32F0 的載入程式可以稱為 bootloader, 因為它除了擔任韌體更新外, 每次開機都會運行
儘管平時沒有 "loader" 功能, 只幫忙複製 app 中斷向量, 但複製後跳過去, 有 "帶起" 的行為
可是新唐的不是, 或許這樣才稱作 LDROM, 它只有更新的功能, 更新後跳回 APROM 就沒他的事了
之後執行程式都是直接執行 APROM, 不再跳躍, 這樣的設計有好有壞
好處是節省開機時間, 壞處是如果刷進的韌體有問題會卡死, 那你就只能拿燒錄器重燒
不管是 AP 重燒或是只切回 LD 都需要接上燒錄器, 若是做成產品就要拆殼
除非刻意在 APROM 裡一開機留個聽命令窗口供跳回 LDROM, 但這就麻煩, 程式看起來也比較不順
而且新唐的 LDROM 都配得很小, Mini58 只有 2.5K, 512-byte 當中斷向量表, 實際剩 2K
我隨便寫寫就 1.5K 啦, 這要想再搞些額外功能很難哪
例如若我想校驗韌體有沒有傳輸正確, 我就只能用些簡單算法驗概略的, 太複雜的程式塞不下
這或許是 Mini58 的 flash 控制器配了硬體 CRC32 計算器的原因
我的程式沒有去用 CRC32, 因為發送端也要算, 麻煩! 我這只是業餘計畫, 會動就好XD
如果堅持要在 LDROM 裡搞複雜花樣也不是不行, 就用 ld 腳本, 把大程式設定 section
可參考 startup.c 裡配置中斷向量表那種方法, 開個 section 把它關起來
然後把這 section 塞到 APROM 裡, 更新時注意不要更新這 section 即可
燒錄時也要特別獨立燒這 section, 要分離出 bin, 就是各種麻煩
另外, 要把韌體放進 APROM 區並修改 config 設定區需要用 "密技"
一開始我先參考 BSP 包, 裡面有 flash 操作範例但試了沒效
想起 在 ubuntu 上開發 nuvoton m051 實驗板 裡日本人提的密技
到 OpenOCD 的 numicro.c 裡看了一下
嘿嘿, 有耶, 試看看, 這段程式寫在我韌體的 flash.c 的 flash_enable_update()
由於會操作寫入保護暫存器, 使用前記得調用 sys_unlock_reg() 解鎖
一試就通, 讚! 這樣 APROM 和 LDROM 就可以互跳


在開發 uart 傳輸時注意到 uart 暫存器多了傳輸延遲:UART0->TOUT, Time-out Register
可以調整每個 byte 傳輸間的延遲, 由於以前遇過傳輸需間隔的問題
多買幾隻 USB serial 來測, 結果發現之前傳輸間隔是我自己寫錯...
先提供改正後的測試結果:

PL2303, CH340:
完美, 沒有問題, 一大串資料直接灌進去, 全部吐出來都正確, 速度超快

FT232RL, FT4232HL:
一大串純文字資料直接灌進去, 會稍微減速印出, 不知道是驅動裡自動延遲還是晶片裡做的

CP2102:
一大串純文字資料直接灌進去, 會大幅減速印出, 不知道是驅動裡自動延遲還是晶片裡做的
純文字會減速, 減到比 FTDI 的還慢, 但二進制傳輸正常
這顆現象最奇怪, 但有可能是仿的, 因為以上全部我買的測試品只有這顆晶片上沒印字
只印了一個對齊圓點, 這個值得懷疑...

這篇文剛發布時我是直接用以前程式測試, 然後把結果描述出來發文
發了以後越想越奇怪, uart 不是什麼複雜信號, 格式是很複雜, 有許多歷史包袱
但信號就只是單純的拉高低, 沒有什麼線路感測後優先權搶佔等複雜機制
正常來說不應該有這種亂七八糟的相容性問題, 除非拉到 1Mbps 以上才有可能出問題
我只用 115200, 這是普通到不行的設置, 不太可能出錯, 於是又仔細檢視一下程式
才發現原來我把 parity bit 設上了.....我一直以為這配置是沒 parity 的
看來我以前誤會新唐了, 這個以後再發一篇來公開改正...
程式已經更新, 發 uart 不用 delay


目前我這 MCU 做的事情很簡單, 其實不需要做 loader, 也不需要 Mini58 這麼大的 flash
這顆 Mini58 是以前買來想玩看看而已, 最近做網卡需要才順便試看看
實際上我這應用用 Mini51 就夠了, 但是...

Mini51~54 QFN 4x4 封裝的全部缺貨, 只有 Mini58 有貨, QFN 5x5 的則是剩 Mini51 其餘缺貨
尺寸不同無法代換我的 Mini58, 所以如果現在要買也沒得選, 除非修改板子
58 和 51 差蠻多的, 最高速度提升到 50MHz, 內建一個可變速 PLL, 51~54 沒有 PLL
像 NUC131 雖有 PLL 但只能固定 50MHz 不可改, 雖然我也沒興趣改它就是了XD

我的韌體 AP 部份主要做三件事:

1. 聽 uart, 可以 echo, 讀 ADC, 跳至 LDROM
2. 控制 8 顆 WS2812 LED
3. 量測 ADC, 讀取 NTC 電阻測溫, 溫度高時打開風扇, 至少吹 10 秒

這張板有另一板型是 8 顆 LED 的, 所以控制 8 顆, 由於是串列輸出
就算只裝 1 顆也會亮, 程式維持 8 顆沒差, WS2812 控制方式可參考前文:用 AVR 控制 WS2812 LED
聽說有新版 LED, 我的是用庫存燈條拆下了, 庫存很多, 等用完再找新規格的試 (應該是等不到了XD)
8 LED 版本點起來的樣子:

RGB 網卡 超智障XD
和以前不同的是點亮的過程, 點亮時不是直接送, 而是算時間慢慢加亮或減暗
細節全在 ws2812.c 裡, 因為如果突然打亮會突然抽走電流, 會影響網卡
可能是我線畫得不夠寬, 或是沒有從源頭隔開, 網卡會隨機罷工
點亮 LED 也不可以太亮, 這 USB 是要接電腦的, 不是接變壓器, 兩顆 LED 還好
接到八顆時, 全部點亮到全白會觸發電腦短路保護, 直接慘遭斷電XD

以上就是程式比較重要的部份說明, 剩下的就都很簡單, 細節自行參考源碼




我們在 Linux 平台上架設開發環境, 有許多東西是需要手動處理
這些東西在 Windows 上會簡單很多, 不過各有優缺點
我有看別人寫用 IDE 操作來完成 bootloader 配置, 但是看內容...我還真看不懂
工具到最後還是以相同手法達到目的, 但因為不是了解細節只是照做
很多時候只是在背流程, 實際上用戶可能不知道自己在幹麻
對廠商來說, 叫你按一按就能打發是最輕鬆好過的
至於哪個好? 我想還是依自己等級而定吧
入門用戶肯定是先求會動, 至於要不要往下挖, 就看個人造化了

Windows 系統和 Linux 在 uart 這部份差很多, 有專案客戶跟我們要過 Windows 工具
我們整一個給他, 做的過程就發現 Windows 的 uart 會偷偷做 delay, 傳輸速度往往慢很多
例如 115200, 實際速度是 bit 間 115200, 但是 byte 間自動加上 delay
總傳輸量不是 115200, 會少很多, 後來有看到說明, 這延遲好像可以手動修改
Linux 就不一樣了, 你設 115200, 就對硬體配置 115200
接著資料進來, 就 TM 塞! 塞到你叫不要為止 (block 住的意思XD)
除非驅動裡故意等, 不然驅動框架都是很直接的, 不像微軟系統會偷加料
(不過近年來似乎有些改變, Linux 也會偷加料, 但不是減慢, 而是加快, DMA 塞!XD)
微軟系統會這樣我猜是生態不一樣, 微軟平台上大多商業軟體, 以 binary 散播
如果有硬體相容上的問題, 程式已經寫死硬塞了, 要延遲就只能從系統去改
而自由世界大多是源碼散播, 使用後不會動? 改一下重編唄! 是自立自強的世界XD
因此就使用難度來說 Linux 肯定是比較高...不, 是超高, 動不動就要修改編譯
沒有足夠電腦知識是開不了這台車的, 而且最近還有新的議題:

名嘴扯「Linux是林姓商人發明的」 網傻眼…秒登Google熱搜
注意了! 使用 Linux 可能會扣光你的台灣價值, 因為黨媒說那是大陸人做的
若被黨查到用這系統當心被網軍圍剿, 自己小心!XD

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。