[Linux]overlayroot后无法写入TF卡

1. 进入底层模式 (Chroot)
sudo overlayroot-chroot
2. 彻底清理 /etc/fstab (关键)
执行 vi /etc/fstab,删除或用 # 注释掉所有包含 0018-D0BC 或 /mnt/tfcard 的行。
原理:只要 fstab 里没有它,overlayroot 启动时就不会去“预占”这个目录,这是成功的核心。
3. 创建强力挂载脚本
执行 vi /usr/local/bin/mount-tf.sh,写入以下内容:
#!/bin/bash
# 等待硬件就绪和 overlayroot 初始化完成
sleep 10
# 强制创建物理目录
mkdir -p /mnt/tfcard
# 彻底清除可能存在的任何挂载(包括只读层残留)
umount -f /mnt/tfcard 2>/dev/null
umount -l /mnt/tfcard 2>/dev/null
# 执行物理挂载(加上参数确保读写)
mount -t exfat -o defaults,uid=1000,gid=1000,umask=000,noatime /dev/mmcblk1p1 /mnt/tfcard
赋予权限:chmod +x /usr/local/bin/mount-tf.sh

4. 创建 Systemd 服务文件
执行 vi /etc/systemd/system/mount-tfcard.service,写入:
[Unit]
Description=Mount TF Card for Overlayroot
After=multi-user.target
DefaultDependencies=no

[Service]
Type=idle
ExecStart=/usr/local/bin/mount-tf.sh
# 确保即使脚本退出,挂载依然保留
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
5. 启用并重启
在 chroot 环境内执行:
systemctl daemon-reload
systemctl enable mount-tfcard.service
exit
sudo reboot

///////////////////////////////////////////

要保证 mount-tfcard.service 在上电后自动运行,核心在于 Systemd 的注册机制 和 依赖关系控制。

你只需要在底层模式(chroot)下完成以下三个关键动作:

1. 必须包含 [Install] 区块
在你的 .service 文件末尾,必须有这段代码。它告诉系统:当执行“启用”命令时,要把这个服务挂载到哪个启动阶段(Target)。

代码段
[Install]
WantedBy=multi-user.target
multi-user.target:相当于传统的“运行级别 3”,是系统完成基础引导、进入多用户模式(命令行界面)的标志。

2. 执行启用命令 (最关键的一步)
仅仅写好文件是不够的,你必须在 sudo overlayroot-chroot 环境下运行以下命令:

Bash
# 重新加载系统服务配置
systemctl daemon-reload

# 设置开机自启
systemctl enable mount-tfcard.service
这一步做了什么?
它会在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个指向你 service 文件的软链接。上电后,系统扫描到这个链接,就会自动启动它。

3. 检查服务是否“真的”被设为自启
运行以下命令验证:

Bash
systemctl is-enabled mount-tfcard.service
如果输出 enabled,说明配置正确,上电会运行。

如果输出 disabled 或 static,说明 [Install] 部分有问题或没执行 enable。

4. 解决“运行了但没挂载成功”的问题
很多时候服务运行了,但因为执行太快报错。为了保证 100% 成功,请确保你的 [Service] 区块包含以下参数:

代码段
[Service]
Type=idle
ExecStart=/usr/local/bin/mount-tf.sh
# 即使脚本运行完退出了,也保持服务状态为 active,防止系统回收挂载点
RemainAfterExit=yes
Type=idle:这是 Systemd 的一个“必杀技”。它会等所有其他的启动任务(比如磁盘扫描、网络启动)全部彻底完成后,才最后运行你的脚本。这能有效避开 overlayroot 启动时的各种冲突。

总结:完整的检查清单
如果你已经按照之前的建议写好了文件,请按顺序执行:

sudo overlayroot-chroot

vi /etc/systemd/system/mount-tfcard.service (检查是否有 [Install] 部分)

systemctl daemon-reload

systemctl enable mount-tfcard.service

exit

sudo reboot

重启后,如果还没挂载,执行:
sudo systemctl status mount-tfcard.service
如果看到 Active: active (exited),说明它上电后确实运行了。此时如果还没挂载,那就不是“自动运行”的问题,而是脚本里的 mount 命令报错了(可能是 UUID 没对上或 /dev/mmcblk1p1 路径在那个瞬间还没生成)。

[cat_H618]修改设备树

1.修改设备树后保存
2.在内核目录下 make linux_h618_defconfig ,然后make dtbs
3.在aaw-image-build/下执行 ./build.sh 选Step2 -U boot
4.然后复制到板子scp lubancat-a1-uboot-current_1.2603stable_arm64.deb cat@192.168.0.223:/home/cat
5.在板子上执行 sudo dpkg -i lubancat-a1-uboot-current_1.2603stable_arm64.deb
6.在板子上执行 sudo nand-sata-install 然后重启

[cmd]拷贝文件

@echo off
setlocal enabledelayedexpansion
echo ================
echo.

if not exist “code\” (
echo Error:code file not exit!
pause
exit /b 1
)

REM 确保目标目录存在
if not exist “D:\decode\” mkdir “D:\decode\”

set BATCH_SIZE=50
set CURRENT_BATCH=0
set TOTAL_FILES=0

echo Scanning code folder…
echo.

REM 先统计code文件夹内的文件总数
for /r “code” %%f in (*) do set /a TOTAL_FILES+=1

echo Find %TOTAL_FILES% Files in code folder…
echo Start Copy…
echo.

set COUNT=0
for /r “code” %%f in (*) do (
set /a COUNT+=1
set /a CURRENT_BATCH+=1

REM 显示进度
set /a PERCENT=COUNT*100/TOTAL_FILES
echo [!PERCENT!%%] [!COUNT!/!TOTAL_FILES!] Copy: %%~nxf

REM 计算相对于code文件夹的路径
set “FULL_PATH=%%f”
REM 去掉前面的”code\”部分
set “REL_PATH=!FULL_PATH:*\code\=!”

REM 在目标目录创建相同结构
set “TARGET_PATH=D:\decode\!REL_PATH!”
set “TARGET_DIR=!TARGET_PATH:\%%~nxf=!”

if not exist “!TARGET_DIR!” mkdir “!TARGET_DIR!”

REM 执行本地复制
copy “%%f” “!TARGET_PATH!” >nul

REM 每复制50个文件显示一次
if !CURRENT_BATCH! equ !BATCH_SIZE! (
echo.
echo Copy !BATCH_SIZE! Files…
set CURRENT_BATCH=0
)
)

echo.
echo Copy Done !COUNT! Files!
@echo off
setlocal enabledelayedexpansion
echo ====== Folder Verification Only ======
echo.

if not exist “code\” (
echo Error: code folder not exist!
pause
exit /b 1
)

if not exist “D:\decode\” (
echo Error: decode folder not exist!
pause
exit /b 1
)

set TOTAL_FILES=0
set SAME_COUNT=0
set DIFF_COUNT=0
set MISSING_COUNT=0
set EXTRA_COUNT=0

echo Scanning folders…
echo.

REM 统计源文件夹文件数
for /r “code” %%f in (*) do set /a TOTAL_FILES+=1

echo Source folder has !TOTAL_FILES! files
echo Starting verification…
echo.

REM 校验每个文件
set COUNT=0
for /r “code” %%f in (*) do (
set /a COUNT+=1

set “FULL_PATH=%%f”
set “REL_PATH=!FULL_PATH:*\code\=!”
set “TARGET_PATH=D:\decode\!REL_PATH!”

set /a PERCENT=COUNT*100/TOTAL_FILES
echo [!PERCENT!%%] Checking: !REL_PATH!

if exist “!TARGET_PATH!” (
fc “%%f” “!TARGET_PATH!” >nul
if errorlevel 1 (
set /a DIFF_COUNT+=1
echo [DIFFERENT]
) else (
set /a SAME_COUNT+=1
)
) else (
set /a MISSING_COUNT+=1
echo [MISSING]
)
)

REM 检查目标文件夹中多出的文件
for /r “D:\decode” %%f in (*) do (
set “FULL_PATH=%%f”
set “REL_PATH=!FULL_PATH:D:\decode\=!”
set “SOURCE_PATH=%cd%\code\!REL_PATH!”

if not exist “!SOURCE_PATH!” (
set /a EXTRA_COUNT+=1
)
)

echo.
echo ====== Verification Result ======
echo Total files in code: !TOTAL_FILES!
echo Files match: !SAME_COUNT!
echo Files different: !DIFF_COUNT!
echo Files missing in decode: !MISSING_COUNT!
echo Extra files in decode: !EXTRA_COUNT!
echo.

if !DIFF_COUNT! equ 0 if !MISSING_COUNT! equ 0 if !EXTRA_COUNT! equ 0 (
echo RESULT: VERIFICATION PASSED
) else (
echo RESULT: VERIFICATION FAILED
)

pause

[FPGA]SDRAM-2

module SDRAM(
input clk,
input rst_n,
input wr_rp,
input rd_rp,
input[23:0] addr_i,
input[15:0] wdata,
output reg wr_ack,
output reg rd_ack,
output reg[15:0] rdata,
output reg rdata_vld,

output reg cke,
output reg cs,
output reg ras,
output reg cas,
output reg we,
output reg[1:0] dqm,
output reg[11:0] addr_o,
output reg[1:0] bank,
inout[15:0] dq,
output debug
);

reg[15:0] wdata_ff0;
reg[15:0] wdata_ff1;
reg[15:0] wdata_ff2;
reg[15:0] wdata_ff3;

reg[3:0] cmd;

reg read_flag_ff0;
reg read_flag_ff1;
reg read_flag_ff2;

reg[3:0] state_c;
reg[3:0] state_n;

reg init_flag;
reg resh_flag;
reg rd_flag;

reg rd_hty;

reg[1:0] resh_cnt;

reg[14:0] cnt;
reg[14:0] x;

reg[10:0] cnt1;

reg[23:0] addr_i_ff0;

//state_c
parameter INIT_NOP =4’b0001; //1
parameter PRECHARGE =4’b0010; //2
parameter REFRESH =4’b0011; //3
parameter MODE =4’b0100; //4
parameter IDLE =4’b0101; //5
parameter ACTIVE =4’b0110; //6
parameter WRITE =4’b0111; //7
parameter READ =4’b1000; //8

//cmd
parameter NOP_CMD =4’b0111; //7H
parameter PRECHARGE_CMD =4’b0010; //2H
parameter REFRESH_CMD =4’b0001; //1H
parameter MODE_CMD =4’b0000; //0H
parameter ACTIVE_CMD =4’b0011; //3H
parameter WRITE_CMD =4’b0100; //4H
parameter READ_CMD =4’b0101; //5H

parameter T_200US =15’d20000;
parameter TRP =14’d4;
parameter TRC =14’d7;
parameter TMRD =14’d2;
parameter TRCD =14’d3;
parameter T_256 =14’d256;
parameter MODE_VALUE =12’b000000110111;

//A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
// 0 0 0 0 0 0 1 1 0 1 1 1
//————————— ————– — —————
//突发读/写 潜伏期=3 顺序 全页
parameter ALL_BANK =12’b001000000000;

always@(posedge clk or negedge rst_n)begin
if(rst_n==1’b0)begin
state_c<=INIT_NOP; end else begin state_c<=state_n; end end always@(*)begin case(state_c) INIT_NOP:begin if(ini2pre_start)begin state_n =PRECHARGE; end else begin state_n =state_c; end end PRECHARGE:begin if(pre2ref_start)begin state_n =REFRESH; end else if(pre2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end REFRESH:begin if(ref2ref_start)begin state_n =REFRESH; end else if(ref2mod_start)begin state_n =MODE; end else if(ref2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end MODE:begin if(mod2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end IDLE:begin if(idl2ref_start)begin state_n =REFRESH; end else if(idl2act_start)begin state_n =ACTIVE; end else begin state_n =state_c; end end ACTIVE:begin if(act2wrt_start)begin state_n =WRITE; end else if(act2red_start)begin state_n =READ; end else begin state_n =state_c; end end WRITE:begin if(wrt2pre_start)begin state_n =PRECHARGE; end else begin state_n=state_c; end end READ:begin if(red2pre_start)begin state_n =PRECHARGE; end else begin state_n =state_c; end end default:begin state_n =INIT_NOP; end endcase end assign ini2pre_start =state_c ==INIT_NOP &&end_cnt; assign wrt2pre_start =state_c ==WRITE &&end_cnt; assign red2pre_start =state_c ==READ &&end_cnt; assign pre2ref_start =state_c ==PRECHARGE &&end_cnt &&init_flag; assign pre2idl_start =state_c ==PRECHARGE &&end_cnt &&init_flag==0; assign ref2ref_start =state_c ==REFRESH &&end_cnt &&resh_cnt==0 &&init_flag; assign ref2mod_start =state_c ==REFRESH &&end_cnt &&resh_cnt==1 &&init_flag; assign ref2idl_start =state_c ==REFRESH &&end_cnt &&init_flag==0; assign mod2idl_start =state_c ==MODE &&end_cnt; (* keep *)wire idl2act_start; assign idl2act_start =state_c ==IDLE &&resh_flag==0 &&(rd_req || wr_req); assign idl2ref_start =state_c ==IDLE &&(resh_flag || end_cnt1); assign act2wrt_start =state_c ==ACTIVE &&end_cnt &&rd_flag==0; assign act2red_start =state_c ==ACTIVE &&end_cnt &&rd_flag==1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt<=0; end else if(add_cnt)begin if(end_cnt)begin cnt<=0; end else begin cnt<=cnt+1'b1; end end end assign add_cnt =state_c!=IDLE; assign end_cnt =add_cnt&&cnt==x-1; always @(*)begin if(state_c ==INIT_NOP)begin x =T_200US; end else if(state_c==PRECHARGE)begin x =TRP; end else if(state_c==REFRESH)begin x =TRC; end else if(state_c ==MODE)begin x =TMRD; end else if(state_c ==ACTIVE)begin x =TRCD; end else if(state_c ==WRITE || state_c ==READ)begin x =T_256; end else begin x =0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt1 <=0; end else if(add_cnt1)begin if(end_cnt1)begin cnt1<=0; end else begin cnt1<=cnt1 +1'b1; end end end assign add_cnt1 =init_flag==1'b0; assign end_cnt1 =add_cnt1 &&cnt1==781-1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin resh_flag<=1'b0; end else if(end_cnt1)begin resh_flag<=1'b1; end else if(state_c == REFRESH)begin resh_flag<=1'b0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin init_flag<=1; end else if(mod2idl_start)begin init_flag<=0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin resh_cnt<=0; end else if(add_resh_cnt)begin if(end_resh_cnt)begin resh_cnt<=0; end else begin resh_cnt<=resh_cnt +1'b1; end end end assign add_resh_cnt =init_flag &&state_c ==REFRESH &&end_cnt; assign end_resh_cnt =add_resh_cnt &&resh_cnt ==2-1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rd_hty<=1'b0; end else if(pre2idl_start)begin rd_hty<=rd_flag; end end reg wr_hold; reg rd_hold; always @(posedge clk or negedge rst_n)begin if (!rst_n)begin wr_hold<=1'b0; end else begin if (wr_rp)begin wr_hold<=1'b1; end else if (state_c==WRITE)begin wr_hold<=1'b0; end end end always @(posedge clk or negedge rst_n)begin if (!rst_n)begin rd_hold<=1'b0; end else begin if (rd_rp)begin rd_hold<=1'b1; end else if (state_c==READ)begin rd_hold<=1'b0; end end end (* keep *) wire write_sel; (* keep *) wire read_sel; assign wr_req = wr_rp || wr_hold; assign rd_req = rd_rp || rd_hold; assign write_sel =idl2act_start &&((rd_hty==1'b0 &&rd_req==1'b0)||rd_hty==1'b1) &&wr_req; assign read_sel =idl2act_start &&((rd_hty==1'b1 &&wr_req==1'b0)||rd_hty==1'b0) &&rd_req; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rd_flag<=1'b0; end else if(write_sel)begin rd_flag<=1'b0; end else if(read_sel)begin rd_flag<=1'b1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin addr_i_ff0<=0; end else begin addr_i_ff0<=addr_i; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bank <=2'b00; end else if(idl2act_start)begin bank<=addr_i[23:22]; end else if(act2wrt_start ||act2red_start)begin bank<=addr_i_ff0[23:22]; end else begin bank<=2'b00; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin addr_o<=0; end else if(ref2mod_start)begin addr_o<=MODE_VALUE; end else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin addr_o<=ALL_BANK; end else if(idl2act_start)begin addr_o<=addr_i[21:10]; end else if(act2wrt_start ||act2red_start)begin addr_o<={addr_i_ff0[9:0]}; end else begin addr_o<=0; end end always @(*)begin rd_ack=read_sel; end assign read_flag =state_c==READ; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin read_flag_ff0<=1'b0; read_flag_ff1<=1'b0; read_flag_ff2<=1'b0; end else begin read_flag_ff0 <=read_flag; read_flag_ff1 <=read_flag_ff0; read_flag_ff2 <=read_flag_ff1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rdata<=0; end else if(read_flag_ff2)begin rdata<=dq; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rdata_vld<=0; end else if(read_flag_ff2)begin rdata_vld<=1; end else if(pre2idl_start &&rd_flag)begin rdata_vld<=0; end end always @(*)begin wr_ack =write_sel; end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin wdata_ff0<=0; wdata_ff1<=0; wdata_ff2<=0; wdata_ff3<=0; end else begin wdata_ff0<=wdata; wdata_ff1<=wdata_ff0; wdata_ff2<=wdata_ff1; wdata_ff3<=wdata_ff2; end end (* keep *) wire dq_en; assign dq_en =state_c ==WRITE; assign dq =dq_en?wdata_ff3:16'hzzzz; /* (* preserve *) reg dq_en_debug; always @(posedge clk) dq_en_debug <= dq_en; */ always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cke<=0; end else begin cke<=1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cmd<=NOP_CMD; end else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin cmd<=PRECHARGE_CMD; end else if(pre2ref_start ||ref2ref_start ||idl2ref_start)begin cmd<=REFRESH_CMD; end else if(ref2mod_start)begin cmd<=MODE_CMD; end else if(act2wrt_start)begin cmd<=WRITE_CMD; end else if(act2red_start)begin cmd<=READ_CMD; end else if(idl2act_start)begin cmd<=ACTIVE_CMD; end else begin cmd<=NOP_CMD; end end always @(*)begin {cs,ras,cas,we}=cmd; end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin dqm<=2'b00; end else if(dqm_en)begin dqm<=2'b11; end else begin dqm<=2'b00; end end assign dqm_en =state_c==init_flag; endmodule

[FPGA]SDRAM

module SDRAM(
input clk,
input rst_n,
input wr_req,
input rd_req,
input[21:0] addr_i,
input[15:0] wdata,
output reg wr_ack,
output reg rd_ack,
output reg[15:0] rdata,
output reg rdata_vld,

output reg cke,
output reg cs,
output reg ras,
output reg cas,
output reg we,
output reg[1:0] dqm,
output reg[11:0] addr_o,
output reg[1:0] bank,
inout[15:0] dq
);

reg[15:0] wdata_ff0;
reg[15:0] wdata_ff1;
reg[15:0] wdata_ff2;
reg[15:0] wdata_ff3;

reg[3:0] cmd;

reg read_flag_ff0;
reg read_flag_ff1;
reg read_flag_ff2;

reg[3:0] state_c;
reg[3:0] state_n;

reg init_flag;
reg resh_flag;
reg rd_flag;

reg rd_hty;

reg[1:0] resh_cnt;

reg[13:0] cnt;
reg[13:0] x;

reg[10:0] cnt1;
reg[21:0] addr_i_ff0;

parameter DATA_W =16;
parameter ADDR_W =22;
parameter CMD_W =4;

parameter INIT_NOP =4’b0001;
parameter PRECHARGE =4’b0010;
parameter REFRESH =4’b0011;
parameter MODE =4’b0100;
parameter IDLE =4’b0101;
parameter ACTIVE =4’b0110;
parameter WRITE =4’b0111;
parameter READ =4’b1000;

parameter NOP_CMD =4’b0111;
parameter PRECHARGE_CMD =4’b0010;
parameter REFRESH_CMD =4’b0001;
parameter MODE_CMD =4’b0000;
parameter ACTIVE_CMD =4’b0011;
parameter WRITE_CMD =4’b0100;
parameter READ_CMD =4’b0101;

parameter T_100US =10000;
parameter TRP =3;
parameter TRC =7;
parameter TMRD =2;
parameter TRCD =3;
parameter T_256 =256;
parameter MODE_VALUE =12’b000000110111;
parameter ALL_BANK =12’b001000000000;

always@(posedge clk or negedge rst_n)begin
if(rst_n==1’b0)begin
state_c<=INIT_NOP; end else begin state_c<=state_n; end end always@(*)begin case(state_c) INIT_NOP:begin if(ini2pre_start)begin state_n =PRECHARGE; end else begin state_n =state_c; end end PRECHARGE:begin if(pre2ref_start)begin state_n =REFRESH; end else if(pre2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end REFRESH:begin if(ref2ref_start)begin state_n =REFRESH; end else if(ref2mod_start)begin state_n =MODE; end else if(ref2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end MODE:begin if(mod2idl_start)begin state_n =IDLE; end else begin state_n =state_c; end end IDLE:begin if(idl2ref_start)begin state_n =REFRESH; end else if(idl2act_start)begin state_n =ACTIVE; end else begin state_n =state_c; end end ACTIVE:begin if(act2wrt_start)begin state_n =WRITE; end else if(act2red_start)begin state_n =READ; end else begin state_n =state_c; end end WRITE:begin if(wrt2pre_start)begin state_n =PRECHARGE; end else begin state_n=state_c; end end READ:begin if(red2pre_start)begin state_n =PRECHARGE; end else begin state_n =state_c; end end default:begin state_n =INIT_NOP; end endcase end assign ini2pre_start =state_c ==INIT_NOP &&end_cnt; assign wrt2pre_start =state_c ==WRITE &&end_cnt; assign red2pre_start =state_c ==READ &&end_cnt; assign pre2ref_start =state_c ==PRECHARGE &&end_cnt &&init_flag; assign pre2idl_start =state_c ==PRECHARGE &&end_cnt &&init_flag==0; assign ref2ref_start =state_c ==REFRESH &&end_cnt &&resh_cnt==0 &&init_flag; assign ref2mod_start =state_c ==REFRESH &&end_cnt &&resh_cnt==1 &&init_flag; assign ref2idl_start =state_c ==REFRESH &&end_cnt &&init_flag==0; assign mod2idl_start =state_c ==MODE &&end_cnt; assign idl2act_start =state_c ==IDLE &&resh_flag==0 &&(rd_req || wr_req); assign idl2ref_start =state_c ==IDLE &&(resh_flag || end_cnt1); assign act2wrt_start =state_c ==ACTIVE &&end_cnt &&rd_flag==0; assign act2red_start =state_c ==ACTIVE &&end_cnt &&rd_flag==1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt<=0; end else if(add_cnt)begin if(end_cnt)begin cnt<=0; end else begin cnt<=cnt+1'b1; end end end assign add_cnt =state_c!=IDLE; assign end_cnt =add_cnt&&cnt==x-1; always @(*)begin if(state_c ==INIT_NOP)begin x =T_100US; end else if(state_c==PRECHARGE)begin x =TRP; end else if(state_c==REFRESH)begin x =TRC; end else if(state_c ==MODE)begin x =TMRD; end else if(state_c ==ACTIVE)begin x =TRCD; end else if(state_c ==WRITE || state_c ==READ)begin x =T_256; end else begin x =0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cnt1 <=0; end else if(add_cnt1)begin if(end_cnt1)begin cnt1<=0; end else begin cnt1<=cnt1 +1'b1; end end end assign add_cnt1 =init_flag==1'b0; assign end_cnt1 =add_cnt1 &&cnt1==1562-1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin resh_flag<=1'b0; end else if(end_cnt1)begin resh_flag<=1'b1; end else if(idl2ref_start)begin resh_flag<=1'b0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin init_flag<=1; end else if(mod2idl_start)begin init_flag<=0; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin resh_cnt<=0; end else if(add_resh_cnt)begin if(end_resh_cnt)begin resh_cnt<=0; end else begin resh_cnt<=resh_cnt +1'b1; end end end assign add_resh_cnt =init_flag &&state_c ==REFRESH &&end_cnt; assign end_resh_cnt =add_resh_cnt &&resh_cnt ==2-1; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rd_hty<=1'b0; end else if(pre2idl_start)begin rd_hty<=rd_flag; end end assign write_sel =idl2act_start &&((rd_hty==1'b0 &&rd_req==1'b0)||rd_hty) &&wr_req; assign read_sel =idl2act_start &&((rd_hty &&wr_req==1'b0)||rd_hty==1'b0) &&rd_req; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rd_flag<=1'b0; end else if(write_sel)begin rd_flag<=1'b0; end else if(read_sel)begin rd_flag<=1'b1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin addr_i_ff0<=0; end else begin addr_i_ff0<=addr_i; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin bank <=2'b00; end else if(idl2act_start)begin bank<=addr_i[21:20]; end else if(act2wrt_start ||act2red_start)begin bank<=addr_i_ff0[21:20]; end else begin bank<=2'b00; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin addr_o<=0; end else if(ref2mod_start)begin addr_o<=MODE_VALUE; end else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin addr_o<=ALL_BANK; end else if(idl2act_start)begin addr_o<=addr_i[19:8]; end else if(act2wrt_start ||act2red_start)begin addr_o<={addr_i_ff0[7:0]}; end else begin addr_o<=0; end end always @(*)begin rd_ack=read_sel; end assign read_flag =state_c==READ; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin read_flag_ff0<=1'b0; read_flag_ff1<=1'b0; read_flag_ff2<=1'b0; end else begin read_flag_ff0 <=read_flag; read_flag_ff1 <=read_flag_ff0; read_flag_ff2 <=read_flag_ff1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rdata<=0; end else if(read_flag_ff2)begin rdata<=dq; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rdata_vld<=0; end else if(read_flag_ff2)begin rdata_vld<=1; end else if(pre2idl_start &&rd_flag)begin rdata_vld<=0; end end always @(*)begin wr_ack =write_sel; end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin wdata_ff0<=0; wdata_ff1<=0; wdata_ff2<=0; wdata_ff3<=0; end else begin wdata_ff0<=wdata; wdata_ff1<=wdata_ff0; wdata_ff2<=wdata_ff1; wdata_ff3<=wdata_ff2; end end assign dq_en =state_c ==WRITE; assign dq =dq_en?wdata_ff3:16'hzzzz; always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cke<=1; end else begin cke<=1; end end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin cmd<=NOP_CMD; end else if(ini2pre_start ||wrt2pre_start ||red2pre_start)begin cmd<=PRECHARGE_CMD; end else if(pre2ref_start ||ref2ref_start ||idl2ref_start)begin cmd<=REFRESH_CMD; end else if(ref2mod_start)begin cmd<=MODE_CMD; end else if(act2wrt_start)begin cmd<=WRITE_CMD; end else if(act2red_start)begin cmd<=READ_CMD; end else if(idl2act_start)begin cmd<=ACTIVE_CMD; end else begin cmd<=NOP_CMD; end end always @(*)begin {cs,ras,cas,we}=cmd; end always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin dqm<=2'b00; end else if(dqm_en)begin dqm<=2'b11; end else begin dqm<=2'b00; end end assign dqm_en =state_c==init_flag; endmodule

[H618 SPI]测试数据发送

#include
#include
#include
#include
#include
#include
#include
#include #include

#define SPI_DEVICE “/dev/spidev1.0”
#define SPI_MODE SPI_MODE_0
#define SPI_BITS 8
#define SPI_SPEED 100000000 // 100 MHz
#define CHUNK_SIZE (4 * 1024) // 4 KB per transfer
#define DMA_THRESHOLD_MBPS 5.0 // 判断 DMA 是否启用的速度阈值

int main() {
int fd = open(SPI_DEVICE, O_RDWR);
if (fd < 0) { perror("open"); return -1; } uint8_t mode = SPI_MODE; uint8_t bits = SPI_BITS; uint32_t speed = SPI_SPEED; if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) { perror("SPI_IOC_WR_MODE"); return -1; } if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) { perror("SPI_IOC_WR_BITS"); return -1; } if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { perror("SPI_IOC_WR_MAX_SPEED_HZ"); return -1; } size_t total_len = 1024 * 1024; // 总数据量 1 MB uint8_t *tx_buf = malloc(total_len); uint8_t *rx_buf = malloc(total_len); if (!tx_buf || !rx_buf) { perror("malloc"); return -1; } memset(tx_buf, 0xAA, total_len); memset(rx_buf, 0, total_len); struct spi_ioc_transfer tr; memset(&tr, 0, sizeof(tr)); tr.speed_hz = speed; tr.bits_per_word = bits; tr.delay_usecs = 0; printf("Starting SPI DMA test (%zu bytes in chunks of %zu KB)...\n", total_len, (size_t)CHUNK_SIZE / 1024); struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); size_t offset = 0; while (offset < total_len) { size_t chunk = (total_len - offset > CHUNK_SIZE) ? CHUNK_SIZE : (total_len – offset);
tr.tx_buf = (unsigned long)(tx_buf + offset);
tr.rx_buf = (unsigned long)(rx_buf + offset);
tr.len = chunk;

int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) { perror("SPI_IOC_MESSAGE"); free(tx_buf); free(rx_buf); close(fd); return -1; } offset += chunk; } clock_gettime(CLOCK_MONOTONIC, &end); double elapsed = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec)/1e9; double speed_mbps = total_len / (1024.0*1024.0) / elapsed; printf("Transfer completed in %.6f seconds\n", elapsed); printf("Approximate speed: %.2f MB/s\n", speed_mbps); if (speed_mbps >= DMA_THRESHOLD_MBPS) {
printf(“DMA likely ENABLED (speed above %.1f MB/s)\n”, DMA_THRESHOLD_MBPS);
} else {
printf(“DMA likely DISABLED (speed below %.1f MB/s)\n”, DMA_THRESHOLD_MBPS);
}

free(tx_buf);
free(rx_buf);
close(fd);
return 0;
}

[DSDZ]调试记录

1. 下载解压源码包
1.1 将源码包下载到虚拟机/root/目录下(使用网盘里面的ubuntu22.04虚拟机)
1.2 执行 tar -zxvf longan-h618-2024-12-30.tar.gz
1.3 解压得出/root/longan-h618目录

sudo chmod -R 777 ./root

2. 配置
2.1 执行 cd /root/longan-h618/ 进入目录
2.2 执行 ./build.sh config 输入 1 1 0 0 0

3. 解压根文件
3.1 执行 cd /root/longan-h618/rootfile/ 进入目录
3.1 执行 rm -rf rootfs 删除老文件
3.2 执行 tar -zxvf rootfs-ds-hx1x-server-2024-12-30.tar.gz 解压根文件,如果要编译桌面版,则执行 tar -zxvf rootfs-ds-hx1x-desktop-2024-12-30.tar.gz
3.3 根文件系统目录:/root/longan-h618/rootfile/rootfs/

4. 往根文件增加软件包(如不需要添加则跳过)
4.1 cd /root/longan-h618/rootfile/ 进入目录
4.2 ./ch-mount.sh -m rootfs/ 进入仿真运行环境,使用apt命令,根据需要增加包。
4.3 exit 退出仿真环境
4.4 ./ch-mount.sh -u rootfs/ 取消挂载根文件

5. 如需修改内核配置,执行(如不需要则跳过)
5.1 cd /root/longan-h618/ 进入目录
5.2 加载默认内核配置./build.sh loadconfig
5.3 修改内核配置./build.sh menuconfig
5.4 保存当前配置为默认内核配置文件./build.sh saveconfig

6. 编译固件
6.1 执行 cd /root/longan-h618/ 进入目录
6.2 执行./build.sh 编译SDK,会自动编译内核、设备树、打包根文件系统(u-boot不会编译)

./build.sh 2>&1 | tee build_$(date +%Y%m%d_%H%M%S).log

6.3 执行./build.sh pack 生成固件,固件目录:/root/longan-h618/out/h618_dragonboard_1GB_uart0.img

7.设备树路径

U-BOOT路径
/brandy/brandy-2.0/u-boot-2018/arch/arm/dts

7.1 /root/longan-h618/device/config/chips/h618/configs/…/linux-5.4/board.dts
7.2 /root/longan-h618/kernel/linux-5.4/arch/arm64/boot/dts/sunxi/sun50iw9.dtsi

8.单独编译内核
9.1 ./build.sh kernel

./build.sh kernel 2>&1 | tee kernel_build_$(date +%Y%m%d_%H%M%S).log

9.2 重新执行./build.sh pack打包固件

9.单独编译u-boot
10.1 ./build.sh bootloader
10.2 重新执行./build.sh pack打包固件

apt install build-essential cmake g++ libgl1-mesa-dev
sudo apt install libxcb-xinerama0-dev # 解决可能的依赖问题

用到的dtb

arch/arm/dts/sun50iw9p1-soc-system.dtb
/root/longan-h618/brandy/brandy-2.0/u-boot-2018/arch/arm/dts/.board-uboot.dts
/root/longan-h618/device/config/chips/h618/configs/p1/uboot-board.dts

交叉编译链的位置
/root/longan-h618/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu
/root/longan-h618/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc

ARM-QT路径
/opt/qt-5.15.2/bin/qmake

1.报错信息:

qt.qpa.plugin: Could not load the Qt platform plugin “xcb” in “” even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb.
2.解决方法(deepseek给的解决方法之一)

sudo apt install libxcb-xinerama0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinput0 libxcb-xfixes0 libxcb-randr0 libxcb-shape0 libxcb-sync1 libxcb-xkb1 libxkbcommon-x11-0 libxcb-util1
sudo apt install libxcb-cursor0 libxcb-cursor-dev

/opt/Qt/5.15.2/wasm_32/mkspecs/qconfig.pri
/opt/Qt/5.15.2/gcc_64/mkspecs/qconfig.pri
/opt/Qt/5.15.2/android/mkspecs/qconfig.pri
vi /opt/qt-5.15.2/mkspecs/qconfig.pri

将Qt库复制到ARM
scp /opt/qt-5.15.2/lib/* root@192.168.0.139:/usr/lib/

包含 struct disp_video_timings video_timing[]

//开启后 显示
export DISPLAY=:0
./t3 -platform xcb

//刷机
1:
sudo nmcli –ask dev wifi connect mini_5G password fsw2021fsw ifname wlan0
sudo nmcli –ask dev wifi connect TP-LINK_7787 password yyxlx18396870603 ifname wlan0
2:
//vi /root/.bashrc
vi /root/.profile
# 在文件末尾添加
export DISPLAY=:0
# 保存后立即生效
//source /root/.bashrc
source /root/.profile

3.将Qt库复制到ARM
scp /opt/qt-5.15.2/lib/* root@192.168.0.139:/usr/lib/

4.关闭自动更新

# 编辑自动更新配置
sudo vi /etc/apt/apt.conf.d/20auto-upgrades

将文件内容修改为:
APT::Periodic::Update-Package-Lists “1”;
APT::Periodic::Unattended-Upgrade “0”;

[Net]网络转发

//服务器宿主 cmd下(管理员运行)
netsh interface portproxy reset

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=9100 ^
connectaddress=192.168.200.128 connectport=9100

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=9111 ^
connectaddress=192.168.200.128 connectport=9111

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3111 ^
connectaddress=192.168.200.128 connectport=3111

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3112 ^
connectaddress=192.168.200.128 connectport=3112

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3113 ^
connectaddress=192.168.200.128 connectport=3113

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3114 ^
connectaddress=192.168.200.128 connectport=3114

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3115 ^
connectaddress=192.168.200.128 connectport=3115

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3116 ^
connectaddress=192.168.200.128 connectport=3116

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3117 ^
connectaddress=192.168.200.128 connectport=3117

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=3118 ^
connectaddress=192.168.200.128 connectport=3118

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=5003 ^
connectaddress=192.168.200.128 connectport=5003

netsh interface portproxy add v4tov4 ^
listenaddress=0.0.0.0 listenport=5004 ^
connectaddress=192.168.200.128 connectport=5004

netsh interface portproxy show all