文章

[筆記] Dify 開源 AI 模板套件

圖片
安裝 Dify ( 開源 AI 模板套件 ) 硬體需求: CPU 至少雙核,超過 4GB 記憶體 軟體需求: Windows with WSL2 ,安裝 Docker Desktop 步驟: 1.        git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git 從網路下載 Dify ,過程如果需要安裝 jq 指令,請執行 sudo apt install jq –y 。 2.          進到 dify/docker 目錄,並複製 cp .env.example .env ,由於隱藏檔必須 ls –a 才看得到。 3.          執行 docker compose up –d ,便開始下載相關鏡像。 4.          五個核心服務 (api 、 worker 、 worker_beat 、 web 、 plugin_daemon) ,以及六個依賴的元件 (weaviate 、 db_postgres 、 redis 、 nginx 、 ssrf_proxy 、 sandbox) 被 docker 執行。下載的鏡像如下圖所示。   5.          開啟瀏覽器 http://localhost/install ,便開始安裝 Dify 應用程式,設定使用者與密碼。 6.     從 Ubuntu 本地進到 http://localhost/apps ,如...

開發 nRF54L15 低功耗藍芽模組,以 Zephyr 範例程式說明

圖片
前一文章講解 nRF54L15 模組在 VS Code 環境的開發,本文則說明藍芽程式的開發。在 SDK 中,與藍芽相關功能的範例放在 \ncs\v3.1.1\zephyr\samples\bluetooth 目錄,如下所示。我們選擇 peripheral 範例程式,並添加 build configuration 後,開啟 prj.conf 檔案,裡面定義了藍芽服務的參數,如下方圖所示。   BAS 是定義電池的服務, HRS 是定義心律的服務, IAS 是定義即時告警的服務, CTS 是定義目前時間的服務。編譯前,我們可以設 y 或 n 決定啟用或關閉服務,設定好之後,先重新生成 build config ( 最好執行 Clean Build Configuration ,再生成 ) ,然後再重新編譯所有的 code 。底下這個函數 API 是廣播設備的屬性,其中 ad 是屬性內容和 sd 是設備名稱。 bt_le_adv_start (BT_LE_ADV_CONN_FAST_1, ad , ARRAY_SIZE(ad), sd , ARRAY_SIZE(sd)); 在手機端,下載 nRF Connect for Mobile ,安裝後打開 APP 。先掃描藍芽設備,看到藍芽名為 Zephyr Peripheral… ,就是上圖程式中定義的名稱。連線後,如下圖,顯示這設備的屬性,包含 Heart Rate 的屬性 (Notify 、 Read 、 Write) 。 除了藍芽所定義的服務之外,下圖是這設備 GATT 的通用屬性 配置屬性的 API 函數,包含 vnd 變數與 uuid 。 bt_gatt_find_by_uuid ( vnd_svc .attrs,   vnd_svc .attr_count,   &vnd_enc_uuid.uuid); 範例中,開啟藍芽認證模式, API 函數如下,其中 GATT 的某些欄位需要認證才能進行讀與寫。 bt_conn_auth_cb_register ( &auth_cb_display ); 變更 BT 位址 在原始範例所生成的 prj.conf 檔案中,定義 CONFIG_BT_PRIVACY=y ,意思是隨...

開箱 NORA-B2 開發板 -- 核心是低功耗 nRF54L15 藍芽晶片

圖片
NORA-B2 開發板上面有一小塊由  u-blox  公司所製造的低功耗藍芽模組,該模組已經取得無線的認證,可提供給第三方整合使用。目前開發板上的模組型號為 NORA-B206 ,其內部核心為 Nordic 半導體的 nRF54L15 晶片,內建 256kB 記憶體, 1.5MB NVRAM 。此外,這個型號自帶有 PCB 的天線,無須外接天線。開發板的電路圖連結如下: https://github.com/u-blox/evk_designs_sho_altium/tree/main/EVK-NORA-B20/EVK-NORA-B2-C.3/Deliverables 。 開發軟體 VS Code : Nordic Semi 透過這套 IDE 進行開發 SEGGER J-Link/J-Trace Software :開發板上面已經自建 debugger ,但需要安裝這套軟體。                 韌體開發的環境推薦在 VS Code ,然後再安裝 nRF Connect 套件,透過套件才能安裝 SDK 與 toolchains 。安裝最新的 SDK 3.1.1 之後,這塊開發板尚未列入 SDK 裡面 ( 板子太新還來不及支援 ) ,不過我們可以暫時選用 nrf54l15dk 開發板的資料來編譯系統程式碼。所有支援的板卡資訊都存放在這個目錄底下, C:\ncs\v3.1.1\zephyr\boards ,能找到對應的板卡。此外,採用手動的方式來新增這塊開發板,先到 GitHub 網站,如下鏈結 https://github.com/u-blox/u-blox-sho-OpenCPU/tree/master/zephyr/boards/u-blox 。下載 ubx_evknorab2 的資料,放到上述的目錄底下,這樣在 VS Code 環境裡便能列出這開發板了。 需安裝 VS Code 的套件,如下:         nRF Connect for VS Code Extension Pack :這套件會自動安裝其他六個相關套件。  ...

STM32H7x 最佳化的數學運算,採用 CMSIS-DSP 函數庫

圖片
        STM32H750 的晶片核心是  ARM Cortex-M7,它是以  Armv7-M 架構所設計而成。內建浮點運算單元 (FPU - Floating Point Unit),以及數位訊號處理(DSP)模組,不過需要搭配適合的函數庫才能編譯成適合機器執行的指令碼。ARM 提供一套開源的 CMSIS-DSP 函數庫,支援 Cortext-M 系列的數學運算,能提升運算的速度。在 Keil IDE 開發環境下,STM32H750 的項目中打開下圖的選單,將CMSIS Core 和 DSP 模組載入,完成第一步驟。         接下來,我們要了解 CMSIS-DSP 有支援三種 ARM 的核心架構,這將影響程式碼的定義。 ARM_MATH_NEON 是第一種定義,代表 Neon 的核心, ARM Neon 技術是一種先進單指令多資料 (SIMD) 架構延伸,應用於 Arm Cortex-A 系列及 Cortex-R 系列處理器。 ARM_MATH_HELIUM 是第二種定義 ,代表 Helium 的核心 , ARM Helium  技術是 Arm Cortex-M 處理器系列的 M 系列向量擴充方案 (MVE)。Helium 為 Armv8.1-M 架構的延伸,可協助機器學習 (ML) 與數位訊號處理 (DSP) 應用大幅提升效能。STM32H750 並不屬於前面兩種的定義,就不用將它們放進編譯的過程裡。不過,我們要將這三個定義放進編譯,分別是 ARM_MATH_DSP ︑ ARM_MATH_MATRIX_CHECK ︑ ARM_MATH_ROUNDING 才行 。因為 STM32H750 晶片支援浮點運算,所以下圖的選單要開啟,如果不開啟的話,數學運算將會花費數倍的時間,甚至更多。         最後我們測試三角函數的運算,Cos(x)*Cos(x) + Sin(x)*Sin(x),運算一百萬次後,比較有無採用 DSP 的兩者效能。 下圖的程式碼,上半段是採用一般數學函數的運算,沒有 DSP 優化。下半段是採用 DSP 優化的函數,然後比較兩者的效能差異。     ...

[筆記] RAG 檢索增強生成的技術概念

圖片
Q :為何需要 RAG 資料檢索? A :光靠 LLM 大語言模型無法準確回答問題,反而出現一本正經地胡說八道,專業術語稱為 LLM 的幻覺 (Hallucination) 。為了解決這問題,有兩種方法:第一種是對 LLM 的預訓練模型進行微調訓練,第二種是加入 RAG 做資料檢索和 LLM 的語句生成。前者需要花費硬體設備進行訓練,後者採用 LLM+RAG 架構可大幅節省成本,市面上比較接受後者方案。其系統架構如下: Q : RAG 的開發與架構? A :初期 RAG 開發階段,需要對資料進行多模態的處理,比如對 PDF 檔案擷取文字、表格、圖片 … 等多種模態,過程包含資料清洗,剔除一些符號、重複語句、無意義文字 … 等。然後,對清洗後的資料進行分塊和向量化,最後寫入向量資料庫。這裡的分塊和向量化會使用到現有的演算法來實現,向量資料庫也有現有的架構可使用。 前面是前期 RAG 的資料處理階段,後期是指 RAG 運行階段,需要對接到 LLM 模型,如下圖。 Q :如何資料擷取與清洗? A :客戶提供技術文件,可能是 TXT 或 PDF 檔案。首先,將檔案的文字擷取下來存放成自訂格式 (JSON) ,對於 PDF 檔案而言,內容包含文字、表格、圖片都必須分別寫 python 程式處理。即使把文字從檔案取出,在這一大堆文字裡面包含換行符號,語句切割不連續,無意義的詞或標題數字 … 等問題,這些問題需要靠程式來做清洗後才能進到下階段。 Q :如何向量化? A :資料清洗後,資料要進行切塊 (chunk) ,再將其向量化,這過程稱為 embedding 。有人研究中文 embedding 的檢索能力,參考 https://ihower.tw/blog/archives/12167 ,需要導入有支援多語言的 embedding model 效果最好。 切塊採用 Jieba 分詞的算法,文本會切成小的詞彙,以便之後檢索。這些詞彙換算成向量,而典型檢索的演算法為 BM25 ,優點為方法簡單效果不錯,因此使用廣泛,缺點是單純根據詞頻等統計和關鍵字檢索做判斷,無法理解語意。而 Word2Vec 使用高維向量來表示單詞,能分辨細微語意之差別。 向量化的數據要存放在向量資料庫,基礎型的有 ChromaDB 、 MilvusDB… 等可本地部署。

[筆記] 製作一個 STM32H750 的外部 Flash 燒錄器

圖片
        STM32H750這顆晶片是 Cortex-M7 核心,內部時脈 480MHz,在同級的 STM32 系列中屬於高效能晶片。不過,它有個問題就是內部 Flash 容量太小,只有 128MB 而已,為了解決這問題,通常外部會掛一顆 Flash 晶片。此時,我們需要自製一個燒錄程式,如下圖所示,紅線標示的 On-chip Flash 是官方提供的燒錄程式,而另一紅線標示的 Ext Flash SPI 就是我們要提供給 Keil IDE 的燒錄程式。         如何自製一套燒錄程式給 Keil IDE 使用呢?放心,IDE 有提供一個範例項目,放在 \Keil_v5\ARM\Flash\_Template 目錄底下,我們工作就是將 FlashDev.c 和 FlashPrg.c 兩個檔案的函數給實現了即可。在 FlashDev.c,我們填入外掛 Flash 的屬性,比如容量大小﹑STM32 存取的位址﹑Sector size, Sector Addr...等,如下。         在 FlashPrg.c,我們必須實現底下幾個函式的驅動。由於外掛 Flash 晶片型號為 W25Q256,也就是寫一套驅動這顆晶片的程式碼。不必擔心!這部分可以從網路的開源找到相關的驅動程式碼 ( https://pan.baidu.com/s/1LuH_zhXgZMqHJcKoLcepdQ   提取码:kmbf )。         筆者下載後,還是會遇上驅動的問題,必須再進行 debug 後才能使用。這裡有一點要注意的,W25Q256 預設的 SPI 通訊指令是 3-byte Address Mode,但是整個驅動程式都採用 4-byte 模式,於是在初始化過程要先設定為 4-byte Addr Mode 才能成功使驅動程式執行,如下圖。         最後,將這個 Flash 項目編譯後,產生的 .axf  複製成 .FLM 檔案,再把這檔案放到  \Keil_v5\ARM\Flash 目錄底下,這樣就完成自製外部燒錄器的功...

[筆記] STM32H750 如何宣告一塊外部記憶體? 而不發生 HardFault 異常。

圖片
        STM32H750 內部記憶體不到 1MB,在記憶空間使用大的情況下,我們需要在晶片外部增加外部 SRAM 以滿足空間需求。如何宣告一個變數映射到這外部記憶體?對於編譯器版本 AC5 或 AC6 最安全的做法是底下這樣宣告:                 uint16_t    *myTest = (uint16_t *) 0xC0000000;   直接將變數的位址映射到外部記憶體位址上,然後計算好這個變數的 array 長度大小。 另一個宣告方式,如下,但僅適用於 AC5 版本,                     uint8_t myTest[128] __attribute__((section(" .exsram "))); 這樣宣告後,需要在 Keil IDE 的 scatter 檔案中,添加一個記憶體空間,如下圖所示。上面變數宣告的 section 名稱為 .exsram ,正好對應到下面 scatter 檔裡面的定義空間。如此一來,變數與外部記憶體的綁在一起了。 不過,光這樣做還不夠,因為在系統 SystemInit 函數執行後,跳到 main 函數前會對變數進行初始化,此時的外部記憶體與晶片之間的介面還未配置好,系統就直接存取外部記憶體會發生硬體異常,掉進 HardFault_Handler( ) 中斷裡面。因此,在 跳到 main 函數前必須執行 FMC 介面的初始化,把外部 SRAM 介面參數配置好,這樣就能存取外部空間了,而不發生異常情況。