3. QNX操作系统基础
说实话,做嵌入式音频驱动开发,环境搭建这一步要是没弄好,后面全是坑。我见过不少同事,拿到板子就急着写代码,结果编译出来的二进制跑都跑不起来,最后发现是工具链版本不对。咱们这节课,就把这些基础工作一次搞定。
3.1 开发环境全景概览
先看看整个环境长什么样。你想想看,我们的代码是在PC上写的,但最终要跑到R-Car板子上。这就涉及三样东西:SDK(软件开发包)、交叉编译链(把代码翻译成ARM能懂的语言)、调试连接(让PC和板子能对上话)。
3.2 QNX SDK安装
QNX的SDK安装,说白了就是把开发工具链放到你的Linux或Windows机器上。我个人习惯用Ubuntu 20.04 LTS,踩坑最少。
3.2.1 获取SDK
你需要从QNX官网或瑞萨的合作伙伴门户下载两个东西:
- QNX Software Development Platform (SDP) 7.1 —— 核心开发包
- R-Car Gen3/Gen4 BSP for QNX —— 瑞萨板级支持包
版本匹配很重要:我曾经因为用了SDP 7.0的SDK搭配R-Car Gen4的BSP,结果编译出来的音频驱动在初始化DMA时直接崩溃。查了两天才发现是BSP依赖的libc接口变了。所以,务必确认SDP版本和BSP版本是官方验证过的组合。
3.2.2 安装步骤
- 解压SDP:
tar -xzf qnx-sdp-7.1.0.tar.gz -C /opt/qnx710 - 设置环境变量:在
~/.bashrc中添加:export QNX_HOST=/opt/qnx710/host/linux/x86_64 export QNX_TARGET=/opt/qnx710/target/qnx7 export PATH=$QNX_HOST/usr/bin:$PATH export MAKEFLAGS=-j8 - 安装BSP:将BSP包解压到
$QNX_TARGET/bsp/rcar目录下 - 验证安装:运行
qcc -V,看到版本信息就对了
小技巧:我习惯把环境变量写到一个单独的 qnx_env.sh 文件里,用的时候 source 一下。这样不会污染其他项目的环境。你想想看,要是同时做Linux和QNX开发,来回切环境变量多麻烦。
3.3 交叉编译链配置
交叉编译链,就是让PC生成ARM架构可执行文件的工具。QNX SDK自带了一套,但针对R-Car平台,我们需要做一些微调。
3.3.1 确认工具链
QNX SDP 7.1 默认使用 GCC 8.3 作为交叉编译器。你可以用这个命令查看:
qcc -V
# 输出示例:
# QNX C/C++ Compiler V8.3.0
# Target: aarch64-unknown-nto-qnx7.1.0
注意看 aarch64 这个前缀,它表示64位ARM架构。R-Car Gen3是ARMv8-A,正好匹配。
3.3.2 配置编译参数
在音频驱动项目中,我一般会在 Makefile 里这样配置:
# 交叉编译链配置
CC = qcc
LD = qcc
AR = qar
# 架构和平台标志
ARCH = aarch64
PLATFORM = rcar-gen3
# 编译标志
CFLAGS += -Vgcc_ntoaarch64le
CFLAGS += -D__QNX__
CFLAGS += -DPLATFORM_RCAR
CFLAGS += -I$(QNX_TARGET)/bsp/rcar/include
CFLAGS += -I$(QNX_TARGET)/usr/include
# 链接标志
LDFLAGS += -Vgcc_ntoaarch64le
LDFLAGS += -L$(QNX_TARGET)/bsp/rcar/lib
LDFLAGS += -lasound # ALSA兼容层,音频驱动常用
关键点:-Vgcc_ntoaarch64le 这个标志告诉编译器使用64位ARM little-endian的配置。我见过有人漏掉这个,结果编译出来的驱动在板子上跑起来全是段错误。
3.3.3 验证编译结果
写一个简单的测试程序,编译后检查文件类型:
# test.c
#include <stdio.h>
int main() { printf("Hello R-Car!\n"); return 0; }
# 编译
qcc -Vgcc_ntoaarch64le -o test test.c
# 检查
file test
# 输出:test: ELF 64-bit LSB executable, ARM aarch64, ...
看到 ARM aarch64 就对了。如果显示 x86-64,说明没用上交叉编译链。
3.4 目标板启动与调试连接
环境搭好了,代码也能编译了,接下来要让板子跑起来。R-Car开发板的启动流程,我简单梳理一下。
3.4.1 启动方式
| 启动方式 | 存储介质 | 适用场景 |
|---|---|---|
| SD卡启动 | MicroSD卡 | 开发调试阶段,最常用 |
| eMMC启动 | 板载eMMC | 产品量产阶段 |
| 网络启动 | TFTP/NFS | 快速迭代,不用反复烧卡 |
我个人习惯用SD卡启动。为什么呢?因为方便。代码改完了,重新编译,把镜像拷到SD卡里,插上板子就能跑。网络启动虽然快,但前期配置网络参数也挺折腾的。
3.4.2 制作SD启动卡
瑞萨官方提供了 mksdcard.sh 脚本,但我不太喜欢用。我更喜欢手动分区,心里有数:
- 分区:用
fdisk分两个区,第一个FAT32放IPL和UBoot,第二个ext4放QNX镜像 - 烧写IPL:
dd if=ipl.bin of=/dev/sdX bs=512 seek=1 - 烧写UBoot:
dd if=u-boot.bin of=/dev/sdX bs=512 seek=131 - 复制QNX镜像:把
ifs-rcar-qnx.bin拷到第二个分区
注意:/dev/sdX 是你的SD卡设备,千万别写错了。我曾经有一次把 /dev/sda(系统盘)当成了SD卡,结果...嗯,你们懂的。建议操作前先 lsblk 确认一下。
3.4.3 串口调试连接
板子启动后,我们需要通过串口看日志。R-Car开发板一般带一个USB转串口,插上电脑后会出现 /dev/ttyUSB0 或 /dev/ttyACM0。
我常用的串口工具是 screen:
sudo screen /dev/ttyUSB0 115200
参数说明:115200 是波特率,R-Car的调试串口默认就是这个值。
3.4.4 网络调试连接
串口只能看日志,真要调试驱动,还得靠网络。QNX支持 gdb 远程调试,流程如下:
- 板子上启动gdbserver:
gdbserver :2345 ./audio_driver_test - PC上连接:
aarch64-unknown-nto-qnx7.1.0-gdb audio_driver_test(gdb) target remote 192.168.1.100:2345 (gdb) continue
网络配置小贴士:我习惯把板子的IP设为静态,比如 192.168.1.100,PC的网口设为 192.168.1.2。这样不用每次启动都去查IP,省事。具体配置在QNX的 /etc/system/config/net.cfg 里改。
3.5 验证环境是否就绪
所有东西都配好了,怎么确认环境是OK的?我一般跑一个简单的音频环回测试:
# 在板子上执行
io-audio -d rcar -t speaker
# 如果听到"滴"的一声,说明驱动加载成功,音频通路正常
如果没声音,别慌。先检查 sloginfo 看驱动日志,八成是某个节点没创建或者DMA通道没配好。
环境就绪检查清单:
- ☐ SDK安装完成,
qcc -V能正常输出 - ☐ 交叉编译链配置正确,编译出的二进制是ARM架构
- ☐ SD启动卡制作成功,板子能正常进入QNX系统
- ☐ 串口能打印日志,网络能ping通
- ☐ gdbserver能正常启动,PC能远程连接
到这步,开发环境就算彻底搭好了。接下来就可以开始写真正的音频驱动代码了。记住,环境搭建虽然枯燥,但基础打牢了,后面才能走得顺。我当年第一次做R-Car音频驱动,就是因为在工具链版本上偷了懒,结果多花了一周时间排查问题。嗯,希望你们别走我的老路。