2025年7月11日 星期五

Ender 3 Max 改 Klipper

參考 https://gist.github.com/neoyagami/5f431928997dbf255e84e4c937983e8e


4.2.2 board,如下圖。

BL_T 接頭,IN (PB0) 當輸出,控制伺服馬達。OUT (PB1) 當輸入,接 probe 信號。


2025年6月26日 星期四

build armbian image,修改 kernel 原始碼

目的,加上 ILI9488 LCD 的驅動程式。

因為建立的 external module,載入時會失敗,只好把驅動程式加入建立 image 時的 kernel source 中,這樣建立的 module 就可以使用。只是很難debug,就找現成的來用 吧。


先 git clone https://github.com/armbian/build

再執行一次 build,不用到最後,只要建立 kernel source 就好

-----------------
./compile.sh \
BOARD=orangepione MAKE_THREADS=4  \
BRANCH=legacy RELEASE=bookworm \
BUILD_MINIMAL=yes BUILD_DESKTOP=no  \
NETWORKING_STACK="network-manager" \
KERNEL_CONFIGURE=no \
INSTALL_HEADERS=yes \
KERNEL_BTF=yes
-----------------

然後把 cache 下的對應的 kernel source,整個複製到新的目錄,如 [6.6_sunxi_armhf_wk]。然後,到新的目錄下,執行 make clean,把編譯的檔案刪掉。刪掉 .git 檔,再執行下列指令,建立啟始的 git 專案。

-----------------
git init
git add .
git commit -m "Initial kernel state for patching"
-----------------

再把驅動程式,如 fb_ili9488.c,複製到對應的目錄下,如 drivers/staging/fbtft,並修改相關的檔案,如 drivers/staging/fbtft 目錄下的 Kconfig 和 Makefile。

然後執行下列指令,提交程式修改。

-----------------
# 首先,提交你的修改
git add drivers/staging/fbtft/fb_ili9488.c drivers/staging/fbtft/Kconfig drivers/staging/fbtft/Makefile
git commit -s -m "Add: FB_TFT ILI9488 driver"
# 然後生成從上次提交到現在的 patch (或者指定範圍)
# 範例:從上一次提交到 HEAD
git format-patch -1 HEAD
# 這會生成一個類似 0001-Add-FB_TFT-ILI9488-driver.patch 的檔案。
-----------------

再將這個 patch 檔,複製到 patch/kernel/archive/sunxi-6.6/patches.armbian/ 下,並修改 series.armbian 和 series.conf,加入這個 patch 檔。

修改 config/kernel/linux-sunxi-legacy.config,加入 CONFIG_FB_TFT_ILI9488=m。

然後,build image,測試結果。

若是加了自己的 patch,或改了 kernel 的 config,重新 build image 的時間,就會花很多時間。

2025年6月20日 星期五

Orange Pi One 連接 ST7796 界面電阻觸控 LCD

成果展示

先展示一下成果,放張照片,當作紀念。要走到這邊,實在不容易。



參考連結

動機與背景

因為貪便宜,也為了改 3D印表機不要花太高的成本,在網路上買了好幾片 Orange Pi One 的單板電腦。

可能因為用的晶片太舊,新的 Kernel 在支援上會有問題。例如目前的 kernel 是 6.12.30,同樣的程式,在 Orange Pi Zero 3 上,可以正常執行,但在 Orange Pi One 就是怪怪的,使用 tinydrm 的 module,完全無法啟動 X window。經反覆測試,確認在較舊的 kernel  6.6.75 上,才能正常執行。另外,armbian/build 的 32位元的 sunxi 的 kernel,沒有把 gpio-backlight 編成 module,dts 中,無法控制背光。

使用 panel-mipi-dbi-spi,在 Orange Pi Zero3 下,可以正常運作,也可以執行 KlipperScreen。但在 Orange Pi One,相同的設定檔,會出現下面的錯誤訊息。後來確認,背光控制要有 gpio_backlight 的 kernel module。

$ dmesg | less
[   18.163593] panel-mipi-dbi-spi spi0.0: supply power not found, using dummy regulator
[   18.163853] panel-mipi-dbi-spi spi0.0: supply io not found, using dummy regulator
[   18.164817] spi spi0.0: deferred probe pending: panel-mipi-dbi-spi: Failed to get backlight

$ sudo modprobe gpio_backlight
[sudo] password for klipper: 
modprobe: FATAL: Module gpio_backlight not found in directory /lib/modules/6.12.23-current-sunxi

另外,Orange Pi Zero3 的 image 裡,有 fb_st7796s 的模組,在 Orange Pi One 則沒有。

使用 6.12.30-current-sunxi,雖然 console 是正常的,但啟動 X window,就會出現 Bus error。

$ X

X.Org X Server 1.21.1.7
X Protocol Version 11, Revision 0
Current Operating System: Linux orangepione 6.12.30-current-sunxi #2 SMP Thu May 22 20:29:54 CST 2025 armv7l
Kernel command line: root=UUID=4c8b2287-edb5-431a-904c-a21f8f213ef8 rootwait rootfstype=ext4 splash=verbose console=ttyS0,115200 console=tty1 hdmi.audio=EDID:0 disp.screen0_output_mode=1920x1080p60 consoleblank=0 loglevel=1 ubootpart=d0be82e5-01 ubootsource=mmc usb-storage.quirks=0x2537:0x1066:u,0x2537:0x1068:u   sunxi_ve_mem_reserve=0 sunxi_g2d_mem_reserve=0 sunxi_fb_mem_reserve=16 cgroup_enable=memory
xorg-server 2:21.1.7-3+deb12u9 (https://www.debian.org/support) 
Current version of pixman: 0.42.2
	Before reporting problems, check http://wiki.x.org
	to make sure that you have the latest version.
Markers: (--) probed, (**) from config file, (==) default setting,
	(++) from command line, (!!) notice, (II) informational,
	(WW) warning, (EE) error, (NI) not implemented, (??) unknown.
(==) Log file: "/var/log/Xorg.0.log", Time: Mon Jun 23 14:36:07 2025
(==) Using config directory: "/etc/X11/xorg.conf.d"
(==) Using system config directory "/usr/share/X11/xorg.conf.d"
(EE) 
(EE) Backtrace:
(EE) 
(EE) Bus error at address 0xb6185000
(EE) 
Fatal server error:
(EE) Caught signal 7 (Bus error). Server aborting
(EE) 
(EE) 
Please consult the The X.Org Foundation support 
	 at http://wiki.x.org
 for help. 
(EE) Please also check the log file at "/var/log/Xorg.0.log" for additional information.
(EE) 
(EE) Server terminated with error (1). Closing log file.
Aborted

另外,使用 6.12.30-current-sunxi,自行編譯的 fb_st7796s 或 fb_ili9488 模組,也不能正常運作,會變得一片白屏。

經過反覆的測試,確認 Orange Pi One 的 32位元的系統,要使用 6.6.75 的 kernel 才能正常運作。

再持續地做各種嘗試,發現使用 edge 的 image,6.15 的 kernel 可以正常運作。比對 6.12 和 6.15 的 driver 原始碼,發現程式有不少的變動,6.12 的可能有一些 bug 吧。那就用最新的吧。

至於 ILI9488界面的 LCD,因為必須使用 666 的格式,6.12 之後可以支援,但是使用 X 仍會當,最好暫時不要用。

自行 build image

後來自行照著 armbian 的 build 說明,自行 build image,終於可以正常安裝執行 KlipperScreen。

複製 armbian/build 的程式。

$ git clone https://github.com/armbian/build

然後修改 build/config/kernel/linux-sunxi-legacy.config,增加 build gpio_backlight 和 fb_st7796s 的 kernel module。

.......
CONFIG_BACKLIGHT_QCOM_WLED=m
CONFIG_BACKLIGHT_RT4831=m
CONFIG_BACKLIGHT_GPIO=m
CONFIG_BACKLIGHT_LED=m
........
CONFIG_FB_TFT_ST7735R=m
CONFIG_FB_TFT_ST7789V=m
CONFIG_FB_TFT_ST7796S=m
CONFIG_FB_TFT_TINYLCD=m
........

執行 compile.sh。

$ ./compile.sh \
BOARD=orangepione \
BRANCH=legacy RELEASE=bookworm \
BUILD_MINIMAL=yes BUILD_DESKTOP=no  \
NETWORKING_STACK="network-manager" \
KERNEL_CONFIGURE=no \
INSTALL_HEADERS=yes \
KERNEL_BTF=yes

編譯完成,產生的 image。

$ ls build/output/images/
Armbian-unofficial_25.08.0-trunk_Orangepione_bookworm_legacy_6.6.75_minimal.img
Armbian-unofficial_25.08.0-trunk_Orangepione_bookworm_legacy_6.6.75_minimal.img.sha
Armbian-unofficial_25.08.0-trunk_Orangepione_bookworm_legacy_6.6.75_minimal.img.txt






2025年5月16日 星期五

SD 卡測試

在網路上購買的便宜裸裝 TF 卡,容量 32GB,一片只要 50元,大約是便宜的威剛同容量的 TF 卡的一半價格。


nexby,沒聽過的品牌,made in Taiwan,好像還不錯。

但是先前曾在淘寶買便宜的 TF卡,結果根本不能用。這次只敢買 3片,湊成免運。等確定可用再多買。

測試軟體,F3 (Fight Flash Fraud or Fight Fake Flash) ,可參考 f3read 及 f3write 指令說明。

安裝

-----------
$
 yay -Ss f3 
aur/f3 9.0-1 (+119 1.49) 
    Simple tool that tests flash cards capacity and performance to see if they live up to claimed specifications

$ yay -S f3
-----------

測試

-----------
# f3write /mnt/sd
F3 write 9.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

Free space: 28.49 GB
Creating file 1.h2w ... OK!                         
Creating file 2.h2w ... 5.93% -- 17.63 MB/s -- 42:07
.....
Creating file 28.h2w ... OK!                         
Creating file 29.h2w ... OK!                        
Free space: 16.00 MB
Average writing speed: 12.23 MB/s

# f3read /mnt/sd
F3 read 9.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

                  SECTORS      ok/corrupted/changed/overwritten
Validating file 1.h2w ... 2097152/        0/      0/      0
Validating file 2.h2w ... 2097152/        0/      0/      0
Validating file 3.h2w ... 7.50% -- 18.15 MB/s -- 24:26
....Validating file 27.h2w ... 2097152/        0/      0/      0
Validating file 28.h2w ... 2097152/        0/      0/      0
Validating file 29.h2w ...  999072/        0/      0/      0

  Data OK: 28.48 GB (59719328 sectors)
Data LOST: 0.00 Byte (0 sectors)
       Corrupted: 0.00 Byte (0 sectors)
Slightly changed: 0.00 Byte (0 sectors)
     Overwritten: 0.00 Byte (0 sectors)
Average reading speed: 18.30 MB/s

-----------

測試結果比較 (2025年 5月)

1) 二手 innodisk 宜鼎工程用 8GB MLC長效記憶卡 
  => Average writing speed: 6.87 MB/s,Average reading speed: 15.66 MB/s

2) ADATA 32GB,A1 / V10
Average writing speed: 10.96 MB/s,Average reading speed: 17.09 MB/s

3) 無名 nexby 32GB,U1
Average writing speed: 12.23 MB/s,Average reading speed: 18.30 MB/s

看來便宜的無名 SD 卡表現不錯,至於工程卡,終究是早期的產品,有點慢。


2025年4月10日 星期四

Orange Pi One / Zero3 接 ILI9488 / ST7796 LCD

Linux 的 fb-tft 對 ILI9341 有完整的支援,但是解析度只有 320x240。KlipperScreen 要求的最低解析度是 480x320,若解析度低於這要求,雖然還是可以執行,但字跡會變模糊不清。

在淘寶可以找到較多人使用,480x320 的 SPI 界面 LCD,其控制晶片為 ILI9488/9486,另外則是 ST7796。因為搜尋 SPI LCD 的方案,大多會找到 ILI9488 相關的,因此先買 ILI9488 / ILI9486 來測試。很辛苦的改驅動,編譯 kernel module,最後是成功了。但是系統一更新,又變得改的程式都不能用了。

經過交叉測試,發現 Fly PI 的 LCD,使用 ST7796 控制器,用 fb_ili9341 的 driver,竟然能夠點亮,雖然顯示不正常,但可以看到在 320x240 的範圍內,正常顯示。

這表示 ST7796 可以使用 RGB565 的格式,經測試,只要把 fb_ili9341 的驅動程式的解析度改成 480x320 即可使用,幾乎完全不用改到程式的其他部分。

淘寶買 ili9488 的 LCD,用 fb_ili9341 的驅動程式來改,只會一片白屏。使用 fb_ili9486.c 來改,若 PIXEL_FORMAT 是 0x55,顯示一片白屏。將 PIXEL_FORMAT 是 0x66,會輸出雜亂的顯示。再加上轉換的 function,則可以成功驅動。

這類控制晶片透過 SPI 界面串列的傳送視訊資料,為了減少資料量,一個畫素 (pixel) 通常用 RGB565 或 RGB666 的格式。RGB565 為 R: 5bits, G: 6bits, B:5bits,共 16bits,傳送時,一個畫素佔 2bytes。RGB666 為 R: 6bits, G: 6bits, B:6bits,共 18bits ,傳送時,一個畫素佔 3bytes。相同的頻寬,後者可傳送的資料量只剩 2/3。

ILI9488 / ILI 9486,確定只能使用 RGB666 的格式。因此,較佳的選擇是買 ST7796 控制的 LCD。但 ILI9488 的 LCD,有較小的 3.5" 螢幕的選擇,價格更低。

參考連結

能夠找到的資訊,有的有點過時,或者,更新後,OS 版本太新,舊的方式不能用。因此雜亂地收集了一堆可能用得到的參考,等確定作法,再將沒用的刪除。

  • https://www.kernel.org/doc/Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
  • https://github.com/KungfuPancake/v0_ips_touch_display/tree/main
  • https://github.com/notro/panel-mipi-dbi/wiki
  • https://forum.armbian.com/topic/48441-st7796-display-w-opiz3/
  • https://forums.raspberrypi.com/viewtopic.php?t=380704
  • https://forum.armbian.com/topic/47971-driving-the-ili9488-lcd-40-inch-cheap-chinese-clone/
  • https://github.com/notro/panel-mipi-dbi/issues/2
  • https://forums.raspberrypi.com/viewtopic.php?t=369139
  • https://github.com/raspberrypi/linux/blob/rpi-5.15.y/arch/arm/boot/dts/overlays/mipi-dbi-spi-overlay.dts
  • https://github.com/Vasily-Kapustin/ti9488/blob/master/ili9488.c
  • https://blog.dowhile0.org/2022/06/21/how-to-troubleshoot-deferred-probe-issues-in-linux/,出現 deferred probe 錯誤的原因與處理。

升級至最近的 kernel 6.12.30 之後,可以使用 tiny drm 的 panel-mipi-dbi-spi 模組,不用自行編譯 kernel module 了,方便很多。

SDO 和 T_DO 併聯問題

LCD 的 SDO 和觸控的 T_DO 都是接到 host 的 MISO。這兩支腳都是輸出,若將這兩支腳短路,可能會使得觸控不能運作。

將這兩支腳短路,在 ILI9341 的板子上沒問題,在 ILI9486 或 ILI9488 上,卻使得觸控不能運作。經過不斷的測試,花了好久的時間,才確認問題。

要同時驅動 LCD 和觸控,照著 ILI9341 測試成功的作法,將 SCK, SDO, SDI 三支腳都短路,然後 ILI9486 和 ILI9488 的觸控一直都沒反應。

先前因為 ads7846 驅動的設定改變,花了不少時間才解決。因而一開始也懷疑是 DTS 設定問題,或是某些 MCU 的接腳不能用。把手邊各種不同的 LCD 都拿來測試,包括 Fly Pi 的螢幕。改變各種設定,還是不能動作。

只能懷疑是 IC 壞掉,或是電阻膜被我弄壞。拿一塊新的 ILI9488,還沒把接腳短路,單獨測觸控功能,正常。但將接腳一短路,就掛了。

準備去買幾顆 IC 來換,發現 ILI9341 板子上的觸控 IC 是 XPT2046,ILI9488 板子上的觸控 IC 是 HR2046,是相容的 IC,才懷疑可能是 IC 的輸出短路造成問題。將 SDO 的短路線剪掉,測試觸控功能,OK。

LCD 沒用到 SDO,那就不要將這支腳短路吧,這樣 LCD 和觸控都正常了。

不能用的 pin

在 Orange PI Zero3,6.6.75-current-sunxi64,PC9 接腳不能用。

overlay 的改變

開始測試時,kernel 版本是 6.6.75,測試成功後。升級後,kernel 版本變 6.12.30,又變成不能驅動 LCD 了,會出現  "cannot register SPI host" 的錯誤。

---------
[    1.551842] ili9341@0 enforce active low on GPIO handle
[    1.551871] sun6i-spi 5011000.spi: cannot register SPI host
------------

經過好久,終於撈到解答。

/dts-v1/;
/plugin/;

/ {
    compatible = "xunlong,orangepi-zero3", "allwinner,sun50i-h616";

    fragment@0 {
        target = <&spi1>;
        __overlay__ {
            status = "okay";
            pinctrl-names = "default"; // new for linux 6.12
            pinctrl-0 = <&spi1_pins>;  // new for linux 6.12
            cs-gpios = <&pio 2 7 0>;  /* PC7 */

            st7796s: st7796s@0 {
                compatible = "sitronix,st7796s";
                reg = <0>;  /* Chip Select 0 */
		#spi-cs-high;
                spi-max-frequency = <40000000>;
                rotate = <180>;
                bgr = <0>;
                fps = <30>;
		width = <480>;
		height = <320>;
                buswidth = <8>;
                reset-gpios = <&pio 2 6 1>; /*RESET=PC6*/
                dc-gpios = <&pio 2 5 0>; /*DC_RS=PC5*/
                led-gpios = <&pio 2 8 0>; /*LED=PC8*/
                debug = <4>;
            };

        };
    };
};

要加上 pinctrl-names = "default"; 和 pinctrl-0 = <&spi1_pins>;





2025年4月8日 星期二

Rapide Lite 200 改 Klipper

 在網路上收的二手機。



建立及燒錄 Firmware

$ cd klipper
$ make menuconfig

[*] Enable extra low-level configuration options
    Micro-controller Architecture (Atmega AVR)
    Processor model (atmega2560)

$ make
  Creating symbolic link out/board
  Building out/autoconf.h
  Compiling out/src/sched.o
  .................
  Compiling out/src/generic/serial_irq.o
  Building out/compile_time_request.o
Version: v0.12.0-458-gd886c1761
  Linking out/klipper.elf
  Creating hex file out/klipper.elf.hex
$ make
$ make flash FLASH_DEVICE=/dev/serial/by-id/usb-RRD__www.ru_RUMBA_-_ATmega_2560_co_55437333437351B0A120-if00 

重新啟動系統。

2025年2月26日 星期三

requireJs 中使用 Vue3 框架


 參考 requireJs中使用Vue3及Vue3框架(viewUIPlus、elementPlus)

目录结构


HTML页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello</title>
    <script src="js/lib/require.js" data-main="js/script/main"></script>
</head>
<body>

main 配置文件

require.config({
    // 加載 js 的目錄,paths 中以此目錄為標準讀取
    baseUrl: 'js',

    // 類庫别名和路徑配置
    paths: {
        jquery: 'lib/jquery-3.7.1',
        // vue 别名必须為 vue,由於其他框架或模块寻找 vue 时查询的是 vue 的别名
        vue: 'lib/vue3/vue.global.prod',
        // viewUIPlus框架
        viewUIPlus: 'lib/viewUiPlus/viewuiplus.min',
        // elementPlus 框架
        elementPlus: 'lib/elementPlus/index.full.min',
        // elementPlus 字体库
        elementPlusIconsVue: 'lib/elementPlus/icons-vue/dist/index.iife.min',
    },

    // 依赖以及导出设置,key值需对应paths中的别名,用于非AMD标准的类库进行导出
    shim: {
        // 由于vue3不是标准的AMD模块,需要手动抛出Vue变量,供其他框架使用
        'vue': {
            exports: 'Vue'
        },
        // viewUIPlus css
        'viewUIPlus': ['vue', 'css!lib/viewUiPlus/styles/viewuiplus.css'],
        // elementPlus 字体库依赖vue 没有这个配置,加载字体库时可能因为vue还未加载而报错
        'elementPlusIconsVue': {
            // 依赖
            deps: ['vue'],
            // 导出变量
            exports: 'ElementPlusIconsVue',
        },
        // elementPlus css 字體庫
        'elementPlus': ['vue', 'css!lib/elementPlus/index.css', 'elementPlusIconsVue',],
    },

    // 插件以及其他模塊配置
    map: {
        '*': {
            // 加載 css 插件
            'css': 'lib/require-css'
        },
    },
});

// 單獨使用 vue
require(['vue'], function (Vue) {
    const {createApp} = Vue
    const app = createApp({
        data() {
            return {
                message: 'Hello Vue!',
            }
        },
        methods: {}
    })
    app.mount("#app");
})

// viewUIPlus vue依赖已在shim中配置,无需再次引入
require(['viewUIPlus'], function (ViewUIPlus) {
    const {createApp} = Vue
    const app = createApp({
        data() {
            return {
                message: 'Hello viewUiPlus!',
            }
        },
        methods: {}
    })
    app.use(ViewUIPlus);
    app.mount("#viewUi");
})

// elementPlus 字体库和vue依赖已在shim中配置,无需再次引入
require(['elementPlus'], function (ElementPlus) {
    const {createApp} = Vue
    const app = createApp({
        data() {
            return {
                message: 'Hello elementPlus'
            }
        },
        methods: {}
    })
    // 字体库组件
    for ([name, comp] of Object.entries(ElementPlusIconsVue)) {
        app.component(name, comp);
    }
    app.use(ElementPlus);
    app.mount("#ele");
})

效果

Vue2 及 Vue3 同時存在

require.config({
  baseUrl: ntuweb.baseUrl+'/assets',
  paths: {
    "jquery": "jquery-1.12.4.min",
    "jqueryform": "jquery.form.4.2.2.min",
    "jqueryui": "jquery-ui/jquery-ui-1.10.4.custom.min",
    "vue": "vue_2.6.14",  
    'vue3': "vue.global-3.5.12.min",
    "showModalDialog": "showModalDialog",
    'corejs': 'corejs-2.6.12_shim.min'
    , 'swal': 'sweetalert2-10.min'
  },
  // 以下為非 AMD 程式,有固定的載入順序
  shim : {
    // 由於 vue3 不是準的 AMD 模塊,需要手動拋出 Vue 變量,用於非AMD標準類庫進行導出
    'vue3': {
      exports: 'Vue'
    },
    "jqueryui": ["jquery"],
    "jqueryform": ["jquery"]
    , 'swal': ['corejs']
    , "showModalDialog": ["jqueryui"]
    , 'wbSingle': ['swal']
  }
});

使用 Vue2

require(['jquery', 'vue', 'showModalDialog', 'jqueryform'], function($, Vue)
{
    vm = new Vue({
        el: '#main-div',
        data: {
            dat: <?= json_encode($gdat) ?>,
            frm_label: '',
            LbState: 0, 
        },
        computed: {
            .....
        },
        methods: {
            .....
        }
    });
});

使用 Vue3

rrequire(['jquery', 'vue3', 'showModalDialog', 'jqueryform'], function($, Vue)
{
    const { createApp, ref ,reactive, computed} = Vue;

    vm = createApp({
        setup() {
            const dat = reactive({
                cou_code: ref(''),
                cou_cname: ref(''),
                credit: ref(0),
		..........
            });

            const frm_label = ref('');
            const LbState = ref(0); 

            return {
                dat, frm_label, LbState,
            }
        },
        computed: {
            ..........
        },
        methods: {
            ...........
        }
    }).mount('#main-div');
});

更新物件 dat 的屬性的值

Object.keys(vm.dat).forEach(function (kk) {
    vm.dat[kk] = ret[kk];
});











網誌存檔