逐飞 RT1064 RT-Thread 库 GCC (VSCode) 移植踩坑

本文所记录的是我整个过程的踩坑经历,关于项目和其使用说明请参考项目主页:hilookas/SeekFree_RT1064_RTThread_Library_GCC_Porting | GitHub

关于逐飞 RT1064 库的移植项目请参考其项目主页:hilookas/SeekFree_RT1064_Library_GCC_Porting | GitHub

更多内容请参见另一篇博文: 逐飞 RT1064 库 GCC (VSCode) 移植踩坑 | lookas

统一文件编码为 UTF-8

这些文件本来就是 UTF-8:

./Libraries/rttherad_libraries/examples/*
./Libraries/rttherad_libraries/components/drivers/can/readme-zh.txt

有无 RT-Thread 逐飞库的区别(逐飞库 RT-Thread 移植修改了的文件)

使用命令 diff --brief --recursive dira dirb

nxp_libraries:
Libraries/nxp_libraries/drives/fsl_lpuart.c
Libraries/nxp_libraries/middleware/sdmmc/port/fsl_sdmmc_event.h
Libraries/nxp_libraries/middleware/sdmmc/port/usdhc/interrupt/fsl_sdmmc_event.c

seekfree_libraries:
Libraries/seekfree_libraries/board/board.c
Libraries/seekfree_libraries/board/board.h
Libraries/seekfree_libraries/common/common.c
Libraries/seekfree_libraries/common/common.h
Libraries/seekfree_libraries/headfile.h
Libraries/seekfree_libraries/zf_systick.c
Libraries/seekfree_libraries/zf_systick.h

seekfree_peripheral:
Libraries/seekfree_peripheral/SEEKFREE_IPS200_PARALLEL8.h
Libraries/seekfree_peripheral/SEEKFREE_MT9V03X.c
Libraries/seekfree_peripheral/SEEKFREE_MT9V03X_CSI.c

修改启动文件使 RT-Thread 启动

RT-Thread 要求通过设置 -eentry 到编译参数,使 main 函数运行前,先运行 entry 函数以初始化 RT-Thread。(Libraries/rttherad_libraries/src/components.c:157 objdump -d 可反汇编)

如果在 startup_MIMXRT1064.s 中使用 GCC 自带的 _start (来自 GCC 自带的 crt0.o),_start 在初始化 c 运行环境之后,会直接进入 main 函数,不会经过 entry 函数。故需要在启动文件中,手动初始化 c 运行环境(初始化 bss 段,调用 __libc_init_array 函数),并跳入 entry 函数。

ref:

解决 context_gcc.S 中的编译错误

Libraries/rttherad_libraries/libcpu/arm/cortex-m7/context_gcc.S 中有错误:

Error: thumb conditional instruction should be in IT block -- `vstmdbeq r1!,{d8-d15}'

解决方案:在 flags.cmake 增加 -mimplicit-it=thumb flag

ref:

解决符号冲突导致的编译错误

C 标准库里和 RT-Thread 库中有重复定义,需要配置 RT-Thread 以让出符号。

解决方案:添加了 Libraries/rttherad_libraries/bsp/cconfig.h 文件(来自 Github),添加到了 files.cmake 中的头文件搜索目录,在 flags.cmake 中添加了 HAVE_CCONFIG_H flag

ref:

解决一些链接错误

增加了 .rti_fn (用于 RT-Thread 自动初始化) .FSymTab .VSymTab (用于 FinSH)段的配置。

.heap(底)和 .stack(顶)间配置了 heap_start heap_end 作为 RT-Thread 的堆内存(用于分配线程栈等)。

ref:

解决线程不切换的问题

如默认项目里的 rt_thread_mdelay(100); ,在 100ms 后 LED 并没有切换状态。

发现是由于 Libraries/nxp_libraries/middleware/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c 里的 SysTick_Handler 覆盖掉了 Libraries/seekfree_libraries/board/board.c 文件中的 SysTick_Handler,其中 board.c 负责配置 SysTick 并且在 SysTick 定时结束时调用 RT-Thread 继续线程(初始化板子)。

解决方案:在 files.cmake 里注释掉 Libraries/nxp_libraries/middleware/sdmmc/port/usdhc/polling/fsl_sdmmc_event.c (该错误解决后我根据 IAR 的配置继续注释掉了其他不需要的文件)

Tips:修改 Libraries/rttherad_libraries/include/rtdebug.h 可以开启内核功能调试输出

ref:

RT-Thread 移植参考

逐飞 RT1064 库 GCC (VSCode) 移植踩坑

Summary: 该文介绍了在 MacOS 下,使用 GCC 工具链在 VSCode 中利用 Cortex Debug 插件编译调试逐飞 RT1064 库的踩坑过程。(Linux 下类似,但是具体步骤本文并没有写)

本文所记录的是我整个过程的踩坑经历,关于项目和其使用说明请参考项目主页:hilookas/SeekFree_RT1064_Library_GCC_Porting | GitHub

关于逐飞 RT1064 RT-Thread 库的移植项目请参考其项目主页:hilookas/SeekFree_RT1064_RTThread_Library_GCC_Porting | GitHub

从山外 K60 库开始,我开始了我的漫漫智能车之路。山外库只支持 IAR,但是可惜 IAR 并不支持 MacOS/Linux,逐飞 RT1064 库增加了对 Keil 的支持,但是 Keil 仍然只支持 Windows。我不甘心与在 Mac 上与嵌入式无缘,同时好在开源工具链 GCC 支持(几乎)所有平台,故有了这篇折腾文章。

单片机相关

现在的微控制单元(单片机)一般会有两个文档,一个是 Data Sheet ,负责介绍芯片电气相关的参数,另一个是 Reference Manual ,负责介绍硬件上一些功能如何使用,寄存器布局等。

初次之外厂商提供一些 Application Note,用于介绍特定的功能是如何使用,这个文档一般比较口语化,而且部分还提供中文翻译,推荐要实现一个功能的时候可以优先参考。

NXP 提供 SDK ,SDK 提供了许多样例供参考,和一些芯片的基础库,将寄存器封装起来,避免用户自己直接操作寄存器(太头疼)。

CMSIS 是一个 ARM 的标准,用于标准化来自不同厂商的 ARM 芯片差异。将芯片的 ARM 内核相关的寄存器封装起来。

CMSIS 还提供 CMSIS Pack,其中包含了不同厂商自己外设的驱动程序。

NXP 的 SDK 包含了 NXP 的 CMSIS Pack (SDK 的 SDK_2.9.1_MIMXRT1064xxxxA/devices/MIMXRT1064 里的内容其实就是 NXP 的 CMSIS Pack 的)

ref:

核心板启动基本流程

RT1064 芯片有内嵌的 BootROM (直接刻在芯片上的那种),其会根据启动引脚和内部保险丝的情况决定从哪个位置启动。同时 RT1064 芯片内部有一颗使用 FlexSPI2 的 Flash (即 RT1064 的 4 意义所在),没有特殊配置,芯片会从这个 Flash 启动。

BootROM 会从 Flash 的 IVT(Image Vector Table) 读取 BootROM 配置信息(如 PC 指针的值,和配置 SEMC SDRAM 的“脚本”)

ref:

芯片的寄存器

寄存器有两种,一种是处理器寄存器,ARM 核心使用,一种是外设寄存器,用于控制芯片中的外设的(如 UART)。后者被映射到处理器的内存空间中,可以被寻址,具体地址参见芯片手册。

ref:

统一文件编码为 UTF-8

逐飞的库文件编码是乱的,强迫症的我不能对此坐视不管。库里的绝大多数文件是使用 GB2312 编码,但是有两个文件是同时使用了 UTF-8 和 GB2312 编码,更加神奇的是,还有三个文件中参加了几个中文符号!这导致 iconv 的转换编码进程被卡住。这主要涉及到以下几个文件:

UTF-8 和 GB2312 编码混在一起:
Libraries/seekfree_libraries/common/SEEKFREE_PRINTF.c
Libraries/seekfree_libraries/common/SEEKFREE_PRINTF.h
混有中文标点符号:
Libraries/nxp_libraries/middleware/usb/host/class/usb_host_cdc.c
Libraries/nxp_libraries/drives/fsl_semc.h
Libraries/nxp_libraries/utilities/debug_console/fsl_debug_console_conf.h
本来就是用 UTF-8 编码的:
./Project/RT1064智能车推荐引脚分配.txt
./Project/CODE/本文件夹作用.txt

为了加快修改所有源代码文件编码为 UTF-8 的进程,我简单的写了一个脚本,供各位参考:

#!/bin/bash

# Convert GB2312 to UTF-8 (MacOS) and CRLF to LF
# from https://docs.moodle.org/310/en/Converting_files_to_UTF-8
# from https://gist.github.com/jappy/2012320
# change * to *.c to specify only code files
# for x; do
# 涉及到 *.c *.h *.s *.S *.txt
find . -type f -name "*" | while read x; do
  iconv -f GB2312 -t UTF-8 < "$x" | tr -d '\015' > "$x.tmp"
  mv "$x.tmp" "$x"
done

改了 deceive typo

Libraries/nxp_libraries/deceive 目录名错了,是 device

IAR 和 Keil 的配置也做了相应的调整

确定需要编译的文件

逐飞库里并不是所有的文件都需要编译的,有些文件加入编译后会导致编译不通过(如引用的头文件不存在),甚至导致运行时错误(错误覆盖了某些函数),具体可以参见 files.cmake (根据 IAR program/RT106X.ewp 配置文件进行了注释)

但是,相对于 IAR 的配置,有些文件是仍旧需要的,否则会导致编译不过(引用的头文件不存在)。以下头文件是需要的:

Libraries/nxp_libraries/xip/
Libraries/nxp_libraries/CMSIS/Include/
Libraries/nxp_libraries/CMSIS/Driver/Include/

ref:

移植链接文件

链接文件负责将代码合适的摆放在芯片所需要的位置上(如下文提到的 IVT 必须放到指定位置上,芯片才能正常启动)

MIMXRT1064xxxxx_seekfree.ld 文件修改自 NXP SDK 的 SDK_2.9.1_MIMXRT1064xxxxA/devices/MIMXRT1064/gcc/MIMXRT1064xxxxx_flexspi_nor.ld

逐飞核心板所需要的内存布局可以参考 IAR 的链接文件 Project/IAR/icf/MIMXRT1064xxxxx_flexspi_nor.icf 和逐飞的 Libraries/doc/read me.txt 说明文档。

ref:

关于链接的加载地址(LMA)与运行地址(VMA)

一段代码的加载地址并不一定与运行地址相同,比如,在程序运行前,先从 ROM 里加载代码到 RAM 中,再在 RAM 中执行代码,速度会比直接从 ROM 中执行快很多。GCC Linker 默认情况下,加载地址为运行地址,但是其也支持自行使用 AT 执行指定加载地址。

ref:

加载地址设置这里有坑,设置了 AT 之后的代码好像并不会自动与前面的代码错开放置,需要自行计算排好。

Linker output.map 是一个很好的调试工具

ref:

移植启动文件

主要涉及到芯片上电启动后 Reset_Handler 和,在其中运行的 SystemInit

需要配置 DTCM 和 ITCM 的内存分配,以及复制全局变量等到对应的位置。

Libraries/nxp_libraries/startup/GCC-ARM/startup_MIMXRT1064.s 文件修改自 NXP SDK 的 SDK_2.9.1_MIMXRT1064xxxxA/devices/MIMXRT1064/gcc/startup_MIMXRT1064.S

同时还修改了 Libraries/nxp_libraries/device/system_MIMXRT1064.cLibraries/seekfree_libraries/common/common.h (代码放置位置的快捷宏)

ref:

解决 GCC 并不帮助我初始化全局变量的问题

IAR 提供了 __iar_program_start 函数,拷贝在 icf 链接文件中定义的需要拷贝的数据。GCC 提供的相同地位的函数 _start 好像不帮我拷贝那些 LMA 与 VMA 不同的块。

解决方案:在 startup_MIMXRT1064 手动把变量初始化了。

ref:

移植 CMake 文件

NXP SDK 提供的样例是是使用 CMake 编译的,逐飞的核心板由于其外置 RAM ,需要手动开启一些编译 Flag,具体可以参见 flags.cmakeLibraries/doc/read me.txt

CMakeLists.txt*.cmake*.sh 修改自 NXP SDK 的 SDK_2.9.1_MIMXRT1064xxxxA/boards/evkmimxrt1064/demo_apps/led_blinky/armgcc 下相关文件。

ref:

关于 GDB 直接使用不好使的问题

在使用 Cortex Debug 之前,我有尝试直接使用 GDB (通过 JLinkGDBServer)一段时间,但是 GDB 直接使用好像不是特别好使,continue monitor halt 很烦,并且使用 GDB 的自带寄存器显示功能 info registers 的显示好像是错的。Cortex Debug 用完后,感觉还不错,就没有再继续研究 GDB 了。

ref:

解决 JLink 调试器启动芯片后外置 RAM 访问出错的问题

现象是使用 Cortex Debug 插件启动芯片后,程序会第一次死在 Libraries/nxp_libraries/device/system_MIMXRT1064.c 的复制向量表(到外置 RAM)过程中,进入 HardFault 中断,使用 JMem 查看后发现对应位置(0x80000000 外置 RAM)没有数据(显示为 -)。在 Reset_Handler 中设置断点的情况下,芯片自动重启后会恢复正常(进入到 main 函数)。

芯片自带的 BootROM 负责根据内置 Flash 上的 IVT 区域的 DCD(Device Configuration Data) 配置信息配置 SEMC 与外置 RAM 的通信。猜测 JLink 启动芯片的时候并不会运行芯片自带的 BootROM ,故需要 JLinkScript 在每次启动芯片的时候,手动配置一下外置 RAM 相关的数据。

使用从 NXP SDK 中提取到的 evkmimxrt1064_sdram_init.jlinkscript (来自 SDK_2.9.1_MIMXRT1064xxxxA/boards/evkmimxrt1064/sdmmc_examples/sdcard_interrupt/evkmimxrt1064_sdram_init.jlinkscript),附加到 Cortex Debug JLink 启动选项(文件 launch.json)后,可以正常调试运行了。

ref:

关于 CMSIS-DAP

CMSIS-DAP 可以用 pyOCD 与其通讯。在 MacOS 下,运行 pyOCD 与 CMSIS-DAP 通讯是“免驱”的。OpenOCD 好像也可以与它通讯,但是没有继续尝试…另外根据 Cortex Debug 的文档,Homebrew 的 OpenOCD 版本比较老,推荐使用编译方式安装或者直接从官网下载

ref:

解决 Cortex Debug 调试界面,外设寄存器无法正常显示的问题

复制 RT1064 的 SVD 文件即可

MIMXRT1064.xml 即 SVD 文件来自 NXP SDK 的 SDK_2.9.1_MIMXRT1064xxxxA/devices/MIMXRT1064/MIMXRT1064.xml ,也是 NXP CMSIS-Pack 的 NXP.MIMXRT1064_DFP.13.0.0.pack/MIMXRT1064.xml

ref:

解决没有初始化无线的时候,无线中断处理函数内无法正常打断点的问题

rt,经过测试发现,如果没有调用初始化函数,Cortex Debug 反汇编根本无法找到中断处理函数,只有在初始化后才能找到。故认为是如果没有调用初始化函数,编译器自动优化掉了处理函数。

在使用断点功能的时候需要注意并不是所有位置打了断点都能生效的。

ref:

JLink 和核心板之间的连接

DIO CLK GND 是必须连接的,VCC 可以连接(这四根引脚即为核心板调试引脚最靠近 Type-C 口的那四个),RST 实测不连也可以 Reset (该功能不依赖该引脚)

如果有转换板的话,板子上其实有一个四线的口,用那个口即可

使用串口调试

核心板上调试口的串口(标注 TX RX 字样),默认是要连到 UART1_TX_B12 UART1_RX_B13 两个脚上,但是实际上空了两个 0R 电阻位作为跳线。如果需要使用调试口上的串口,需要手动用一坨锡或者电阻连上。或者在主板上引出这两个口

Tips:修改 Project/USER/inc/RT106X_config.h 可以配置默认串口。 Tips:使用 screen /dev/tty.xxx 115200 可以连接到串口

ref:

Cortex Debug 参考

解决 Mac 上 Chrome CPU 占用率高的问题

TL;DR: 如果硬盘快满了,删除硬盘上的一些文件,使其有一定空余空间

最近电脑风扇狂转,发现 Chrome CPU 占用率非常高,使用 Chrome 内任务管理器发现“浏览器”一项占用很高。

经过一次浏览器重置后,占用率有所下降,但是使用一段时间后,占用率又保持非常高的状态,尤其是在看视频的时候,这现象更为严重。

使用 Safari 后,有所缓解,但是由于缺少许多插件,使用起来比较难受,故又换回 Chrome。

经过一些搜索,删除硬盘上一些文件,让硬盘有一定空闲空间后,占用率下降了许多,问题解决。

Ref

解决 Proxmox VE 无法安装到 eMMC 上的问题

最近在折腾锐角云…

看到商家的介绍,8g 内存 64g 存储只要 200 多?!赶紧剁手下单,结果到手后才发现,内存和存储都是焊接到主板上的…不禁感叹,买的还是没有卖的精啊。

这个设备原装是两个存储设备,一个板载 64G 的 eMMC 另外一个是采用 mSATA 口的 SSD ,到手的时候这台机器只剩下板载的存储了,那个 SSD 已经不翼而飞了,为这设备再添购一个 SSD 实在是不划算,同时为了最大化利用这个硬件,我在这台设备上折腾了一下,尝试使用 PVE,结果安装的过程中提示 unable to get device for partition 1 on device /dev/mmcblk1

解决

经过一天的尝试,通过以下方式可以绕开官方的限制,在 eMMC 上安装 Proxmox VE 6.3:

⚠️警告:PVE 并未针对这种设备优化,eMMC 也并非针对这种使用设计。PVE 每天要往存储设备中写入一定量的日志信息,USE AT YOUR OWN RISK!

  1. 启动 PVE 安装程序,进入安装初始界面
  2. 启动后点击 Install Proxmox VE (Debug mode)
  3. 在第一次提示你可以输入命令的时候输入 Ctrl-D ,继续安装过程
  4. 在第二次提示你可以输入命令的时候输入 vi /usr/bin/proxinstall 编辑文件(或者使用其他文字编辑器如 nano)
  5. 输入 /unable to get device 定位到对应位置
  6. 你可以看到类似下方的内容:
    ...
        } elsif ($dev =~ m|^/dev/[^/]+/hd[a-z]$|) {
            return "${dev}$partnum";
        } elsif ($dev =~ m|^/dev/nvme\d+n\d+$|) {
            return "${dev}p$partnum";
        } else {
            die "unable to get device for partition $partnum on device $dev\n";
        }
    ...
    
    将其修改(添加)为:
    ...
        } elsif ($dev =~ m|^/dev/[^/]+/hd[a-z]$|) {
            return "${dev}$partnum";
        } elsif ($dev =~ m|^/dev/nvme\d+n\d+$|) {
            return "${dev}p$partnum";
        } elsif ($dev =~ m|^/dev/mmcblk\d+$|) {
            return "${dev}p$partnum";
        } else {
            die "unable to get device for partition $partnum on device $dev\n";
        }
    ...
    
  7. 然后输入 Ctrl-D ,继续安装过程
  8. 此时应该进入了正常的安装程序,硬盘选择的时候选择 /dev/mmcblk1 (没有 bootX 后缀)(建议关闭 swap)
  9. 最后安装完成后输入 Ctrl-D ,重启系统

另外,也可以使用官方提供的方式,先安装 Debian 再安装 PVE,只不过那样安装很慢,而且网卡和分区并没有提前配置好,需要自己手动配置。具体参见:Install Proxmox VE on Debian Buster – Proxmox VE

网上还有使用 bin 等类似 ghost 的方法直接 dd 进 eMMC,或者先安装到另外一个硬盘上再使用 DiskGenius 乾坤大挪移到 eMMC 等方法在此不再做过多叙述,可以参见下方文章:

原理

Install Proxmox VE (Debug mode) 提供了在安装过程中各个阶段执行脚本的能力。

修改的文件是为安装程序提供 MMC 设备检测支持。

没有直接修改 ISO 主要是由于,一是该文件在 pve-installer.squashfs 中,由安装程序在运行的时候加载,修改需要解包后重新打包,二是这样更透明,避免使用一个来源不是很明确的二进制文件。

安装过程中,配置信息那里使用了 Linux 的图形界面,类似于 Ubuntu 的使用,按下 Ctrl+Alt+F1/F2 为相应的日志信息,按下 Ctrl+Alt+F3 可以切换出命令行,按下 Ctrl+Alt+F4 可以切换回图形界面。

Ref

人,讨厌的不是强权,而是自己没有得到强权。

高考成绩下来了,与我而言可能并不能去自己非常想去的学校,于是抱怨社会,为什么大家都认同985/211,而不认同双非?

其实说自己在翻找去年的学校录取分数表时,尝试“捡漏”,这何尝不是一种歧视呢?

拿着重点学校的名字,哈,我多么强大,去看不起对方的时候,有曾想过自己也会成为“被看不起的”那一方呢?

所以啊,人,要学会遇到强者,能安然面对,面对弱者,能保持敬畏之心。

这也算是这次高考给我带来的一个深刻的教训吧。

人文社科类学科其实是蛮重要的,不仅仅体现在成绩,而且体现在人的文化修养上。

每次想到一些头疼的事情,总是想,如果多读一点书,是不是现在心态就会稍微好一点呢?

CDN是一种多播

之前在接触到多播这个概念的时候一直在想这么美好的东西为什么不在互联网上使用,后来想了想,现在一直在说的 CDN 不就是做到这一点了嘛,减少骨干网络上重复数据的传输,在近用户端复制成多份分发。

今天看到腾讯云的这个演讲,同时也印证了这个观点:腾讯云PCDN:从P2P到万物互联框架

另外,P2P真的是一个很有趣的东西,与人斗,其乐无穷~

永远不要对他人的不幸落井下石,因为你无法确保你自己不会遇到类似情况。

什么是 Web 2.0 ?

Web 本质就是一个传递信息的工具,Web 有着用于传递信息的方法 HTTP,Web 有着用于表示信息的方法 HTML,那 Web 2.0 到底特殊在哪里?

我的理解, Web 2.0 将如何传递信息以及如何表达信息与用户的使用做了隔离,也就是说,在Web 2.0 时代,用户没有必要去考虑如何做出一个美观的网页,如何将自己的信息一直放在网上,如何用flash嵌入自己的视频作品,他只需要去做的是写一段文字,或者上传一些视频,其余的内容由计算机城区去帮忙处理。

Web 2.0 使得互联网的分工进行了细化,界面的美观设计有专业的设计师去处理,信息的保存有专门的运维去处理,解决各种疑难问题有程序员去做等等。

Web 2.0 其实就是应用程序这个概念的互联网延伸。

Web 2.0 的特性导致为了完成上述事宜,以及某些决策人员恬不知耻的产品“护城墙”战略,导致了互联网的中心化,从互联网变成了互联树,让用户的信息成为了一些公司的摇钱树,以及让控制信息的传播成为了[censered]。

将程序与数据分开吧!去掉那些本来就没有必要存在的中心化节点吧!还网络一个自由、开放的世界吧!

#拥抱IPFS ~~hashtag…~~