3. QNX操作系统基础

说实话,做嵌入式音频驱动开发,环境搭建这一步要是没弄好,后面全是坑。我见过不少同事,拿到板子就急着写代码,结果编译出来的二进制跑都跑不起来,最后发现是工具链版本不对。咱们这节课,就把这些基础工作一次搞定。

3.1 开发环境全景概览

先看看整个环境长什么样。你想想看,我们的代码是在PC上写的,但最终要跑到R-Car板子上。这就涉及三样东西:SDK(软件开发包)、交叉编译链(把代码翻译成ARM能懂的语言)、调试连接(让PC和板子能对上话)。

开发环境整体架构 PC 开发机 QNX SDK 交叉编译链 以太网 调试主机 GDB / IDE 串口终端 串口 / JTAG R-Car 目标板 说明: 1. PC开发机安装QNX SDK和交叉编译链,用于编译音频驱动代码。 2. 调试主机通过串口或JTAG连接目标板,用于下载和调试。 3. 实际项目中,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 安装步骤

  1. 解压SDP:tar -xzf qnx-sdp-7.1.0.tar.gz -C /opt/qnx710
  2. 设置环境变量:在 ~/.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
  3. 安装BSP:将BSP包解压到 $QNX_TARGET/bsp/rcar 目录下
  4. 验证安装:运行 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 脚本,但我不太喜欢用。我更喜欢手动分区,心里有数:

  1. 分区:用 fdisk 分两个区,第一个FAT32放IPL和UBoot,第二个ext4放QNX镜像
  2. 烧写IPL:dd if=ipl.bin of=/dev/sdX bs=512 seek=1
  3. 烧写UBoot:dd if=u-boot.bin of=/dev/sdX bs=512 seek=131
  4. 复制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 远程调试,流程如下:

  1. 板子上启动gdbserver:gdbserver :2345 ./audio_driver_test
  2. 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音频驱动,就是因为在工具链版本上偷了懒,结果多花了一周时间排查问题。嗯,希望你们别走我的老路。