LJ` Blog - DSMC
type: channel
link: http://www.lj12138.cn/index.php/tag/DSMC/
items: DSMC驱动分析之RTOS
items: DSMC应用分析之DMA读写RTOS
items: DSMC应用分析之DMA读写Linux
items: DSMC驱动分析之Linux
items: 配置DSMC：ROTS与Linux

DSMC驱动分析之RTOS
type: item
date: 2025-08-22T06:47:00+00:00
description: 一 程序位置分布RTOS中DSMC代码，drv_dsmc_host.c是主机驱动代码，drv_dsmc_slave.c是从机驱动代码，dsmc_test.c是测试程序 SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/drivers/drv_dsmc_host.c SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/drivers/drv_dsmc_slave.c SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/tests/dsmc_test.c SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/hal/lib/hal/src/hal_dsmc_host.c SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/hal/lib/hal/src/hal_dsmc_slave.c SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/drivers/dma.c 二 主机驱动代码解析drv_dsmc_host.c -> hal_dsmc_host.c -> drv_dsmc_host.c -> dsmc_test.c2.1 系统如何启动驱动？首先，在drv_dsmc_host.c主机驱动中rockchip_dsmc_host_probe(void)函数下方，使用了INIT_DEVICE_EXPORT(rockchip_dsmc_host_probe)将rockchip_dsmc_host_probe注册到了设备自动初始化函数这是RT-Thread自动初始化机制，听起来似乎很高大上，实际上只是将函数入口地址记录，在board_base.c中的rt_hw_board_init()启动板卡，完成基础初始化后，会在调用rt_components_board_init()，rt_components_board_init()内部实质上是执行函数指针，也就是执行对应的rockchip_dsmc_host_probe函数来启动驱动。2.2 主机驱动初始化代码流向rockchip_dsmc_host_probe -> HAL_DSMC_HOST_Init -> DSMC_HOST_DataInit -> DSMC_HOST_MapInit -> DSMC_HOST_LbInit -> DSMC_HOST_LbCmnConfig -> DSMC_HOST_LbCmnRgnConfig -> DSMC_HOST_LbCsrConfig -> lbReadReg与lbWriteReg在底层lbReadReg与lbWriteReg会去读写寄存器配置，然后逐级返回完成初始化打印HAL_DSMC_HOST_Init OK2.3 主机驱动代码框架drv_dsmc_host.c驱动主要做外设初始化与DMA数据拷贝搬运和直接读写指定地址的用户调用实现在RTOS中drv_dsmc_host.c的rockchip_dsmc_host_probe初始化函数会从RTOS层调用HAL层hal_dsmc_host.c文件的HAL_DSMC_HOST_Init去写寄存器初始化DSMC外设从下图drv_dsmc_host.c函数列表中可以看出来，除了初始化外设，主要就是DMA数据拷贝搬运的实现和直接读写指定地址的实现并且驱动通过ops操作集将DMA数据拷贝搬运和直接读写指定地址函数用作上层调用函数接口在drv_dsmc_host.c中，除了初始化函数，还对dsmc_host_ops这个ops操作集合做读写与底层拷贝等函数的实现，本质上类似 Linux 的 file_operations 或 platform_driver 的 ops，统一抽象了对硬件的访问接口（read/write/copy_from/copy_to等），便于上层调用和适配不同实现，（参考Linux通用的驱动篇）给ops赋值函数指针之后，在上层应用函数，就可以直接使用一个dsmc_host_ops类型的结构体，调用其读写函数，拿到DSMC通信数据struct dsmc_host_ops { rt_err_t (*read)(struct rockchip_rt_dsmc_host *dsmc_host, uint32_t cs, uint32_t region, unsigned long addr, uint32_t *data); rt_err_t (*write)(struct rockchip_rt_dsmc_host *dsmc_…

DSMC应用分析之DMA读写RTOS
type: item
date: 2025-08-22T06:47:00+00:00
description: 一 前言在前面分析了驱动大致走向和函数，驱动细节我们无法分析，因为拿不到底层寄存器相关的细节文档所以我们应用的重中之重，就是需要仔细分析DMA读写，把DMA读写学会，就可以拿到数据给上层应用使用DMA本身没有绑定DSMC，但是使用DMA驱动时，会给DMA配置DSMC的内存地址，这样DMA读写直接按块访问内存中映射的DSMC应用请直接看后面的 三 外部调用例程做库文件 ，例程修改为库文件和头文件作为接口库，提供对外接口调用二 RTOS DMA读写分析2.1 DMA驱动大致内容具体驱动分析请看前面的DSMC代码分析之RTOSdrv_dsmc_host.c驱动主要做外设初始化与DMA数据拷贝搬运和直接读写指定地址的用户调用实现在RTOS中drv_dsmc_host.c的rockchip_dsmc_host_probe初始化函数会从RTOS层调用HAL层hal_dsmc_host.c文件的HAL_DSMC_HOST_Init去写寄存器初始化DSMC外设从下图drv_dsmc_host.c函数列表中可以看出来，除了初始化外设，主要就是DMA数据拷贝搬运的实现和直接读写指定地址的实现并且驱动通过ops操作集将DMA数据拷贝搬运和直接读写指定地址函数用作上层调用函数接口2.2 DMA用户使用流程实际上是实现主控 → DSMC控制器 → Local Bus → FPGA等来做读写测试用户程序主要是通过DMA或直接地址读写向DSMC控制器写入读取数据，数据通过Local Bus总线，读写外部设备下面所有DMA相关函数copy_to、copy_from以及dma_memcpy函数，内部都通过rt_device_control对dma设置状态w完成DMA读写rt_device_control设置的参数最终在SDK/GA3506_Linux_Source/rtos/bsp/rockchip/common/drivers/dma.c文件中的rt_dma_control函数中通过switch来实现DMA具体操作 rt_device_control(dma, RT_DEVICE_CTRL_DMA_REQUEST_CHANNEL, m2m_xfer); //请求 DMA 通道 rt_device_control(dma, RT_DEVICE_CTRL_DMA_SINGLE_PREPARE, m2m_xfer); //DMA 传输准备信号 rt_device_control(dma, RT_DEVICE_CTRL_DMA_START, m2m_xfer); //单次 DMA 传输准备 rt_device_control(dma, RT_DEVICE_CTRL_DMA_STOP, m2m_xfer); //停止 DMA rt_device_control(dma, RT_DEVICE_CTRL_DMA_RELEASE_CHANNEL, m2m_xfer); //释放 DMA 通道程序结构大致就是下方这样的伪代码，从结构上我们就能看出来，主要是初始化后，通过ops操作集来读写内存拿到数据，或者通过DMA完成读写main() └──> dsmc_test() ├──> psram_simple_test() // PSRAM基本功能测试（CPU读写+数据校验） │ ├──> ops->write() // 向PSRAM写入测试数据 │ ├──> ops->read() // 从PSRAM读取测试数据 │ └──> 数据校验 ├──> dma_test_psram() // PSRAM DMA搬运测试（DMA搬运+数据校验） │ ├──> dma_memcpy() // 用DMA搬运数据到/从PSRAM │ └──> 数据校验 ├──> plc_simple_test() // PLC类外设基本功能测试（CPU读写+数据校验） │ ├──> ops->write() // 向PLC外设写入测试数据 │ ├──> ops->read() // 从PLC外设读取测试数据 │ ├──> ops->copy_to // 从DMA拷贝数据到FPGA │ ├──> ops->copy_to_state //拷贝状态 │ ├──> ops->copy_from// 从FPGA拷贝数据到DMA │ ├──> ops->copy_from_state//拷贝状态 │ └──> 数据校验 ├──> dma_test_lb() // Local Bus外设DMA搬运测试（DMA搬运+数据校验） │ ├──> dma_memcpy() // 用DMA搬运数据到/从Local Bus外设 │ └──> 数据校验 ├──> fpga_simple_test() // FPGA外设基本功能测试（C…

DSMC应用分析之DMA读写Linux
type: item
date: 2025-08-22T06:44:00+00:00
description: 一 前言在前面分析了驱动大致走向和函数，驱动细节我们无法分析，因为拿不到底层寄存器相关的细节文档所以我们应用的重中之重，就是需要仔细分析DMA读写，把DMA读写学会，就可以拿到数据给上层应用使用DMA本身没有绑定DSMC，但是使用DMA驱动时，会给DMA配置DSMC的内存地址，这样DMA读写直接按块访问内存中映射的DSMC应用请直接看后面的 三 外部调用例程做库文件 ，例程修改为库文件和头文件作为接口库，提供对外接口调用二 Linux DMA读写分析2.1 DMA驱动大致内容（创龙为dma_memcpy.c，飞凌为dsmc_lb_device.c）首先要写底层DMA读写驱动，提供用户空间与FPGA（localbus）之间的高速数据搬运通道，在dsmc-lb-device.c中增加DMA驱动读写接口（飞凌做法），或者单开一个DMA读写驱动（创龙做法），源码见SDKDMA有个dma_setup_params_stu结构体配置参数transfer_direction决定的读写，由DMA执行内存写到FPGA，还是FPGA读到内存其实在上层，我们只关心DMA读写就可以了，底层驱动已经配置好DSMC的DMA，我们读数据在DMA配置好后由DSMC读取完成再通知DMA读取，写数据由DMA发送后DSMC会完成写数据创建设备文件接口，通常为/dev/dsmc，然后通过ioctl接口进行DMA参数配置、启动、状态获取与关闭。（对应函数：dma_memcpy_ioctl）通过mmap为用户空间提供DMA缓冲区（对应函数：dma_memcpy_mmap）可选通过input事件（GPIO中断）通知用户空间DMA完成（对应函数：dma_irq_handler，上报input事件，创龙做法）ioctl命令（核心控制接口）通过ops调用dma_memcpy_ioctl在dma_memcpy_ioctl做switch分支，用以做DMA不同时机的操作 DMA_MEMCPY_SETUP 配置DMA参数 case DMA_MEMCPY_SETUP: DMA_MEMCPY_START 启动DMA传输 按配置开始一次DMA搬运 case DMA_MEMCPY_START: DMA_MEMCPY_GET_TIME 获取最近一次DMA耗时 返回微秒级耗时 case DMA_MEMCPY_GET_TIME: DMA_MEMCPY_SHUTDOWN 关闭DMA、释放资源 每次传输后调用 case DMA_MEMCPY_SHUTDOWN:上层应用读写必须依次完成setup/start/shutdown流程，完成DMA读写到DSMC实现的流程详细驱动分析参考前面的DSMC代码分析之Linux2.2 DMA用户使用流程用户每次DMA操作都需完整的setup/start/shutdown流程用户操作前置：1 分配读/写缓冲区：malloc等 2 打开设备节点和可选input事件设备（其实是dma_init）：open("/dev/dma_memcpy", O_RDWR)，open("/dev/input/eventX", O_RDONLY) 3 赋值DMAInfo结构：填充读取的地址，大小等写操作（内存→FPGA） dma_write()填充写src_buf缓冲区（写数组之类） 配置DMA参数（ioctl SETUP，方向为写） 执行ioctl(fd, DMA_MEMCPY_SETUP, &setup) mmap映射DMA缓冲区 对应函数：mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0) memcpy数据到DMA缓冲区 对应函数：memcpy(dma_buf, src_buf, size) 启动DMA（ioctl START） 执行ioctl(fd, DMA_MEMCPY_START, 0) 等待input事件（创龙做法，飞凌直接下一步） 对应函数：select/read(input_fd, &event, sizeof(event)) 获取DMA耗时（ioctl GET_TIME） 执行ioctl(fd, DMA_MEMCPY_GET_TIME, 0) 关闭DMA（ioctl SHUTDOWN），释放mmap 执行ioctl(fd, DMA_MEMCPY_SHUTDOWN, 0)、munmap(dma_buf, size) 读操作（FPGA→内存） dma_read()配置DMA参数（ioctl SETUP，方向为读） 执行ioctl(fd, DMA_MEMCPY_SETUP, &setup) 启动DMA（ioctl START） 执行ioctl(fd, DMA_MEMCPY_START, 0) mmap映射DMA缓冲区…

DSMC驱动分析之Linux
type: item
date: 2025-08-22T06:25:13+00:00
description: 一 整体概述1.1 程序文件位置分布RTOS中DSMC代码，dsmc-controller.c是控制器初始化代码，dsmc-host.c是主机驱动代码 dsmc-lb-device.c是总线设备用户接口驱动程序，dsmc-lb-slave.c是从机程序 SDK/GA3506_Linux_Source/kernel-6.1/drivers/memory/rockchip/dsmc-controller.c SDK/GA3506_Linux_Source/kernel-6.1/drivers/memory/rockchip/dsmc-host.c SDK/GA3506_Linux_Source/kernel-6.1/drivers/memory/rockchip/dsmc-lb-device.c SDK/GA3506_Linux_Source/kernel-6.1/drivers/memory/rockchip/dsmc-lb-slave.c 1.2 四个文件整体之间的关系四个文件尽管分为控制器、主机、接口、从机四部分，但总体来说，从功能上来看只有主机和从机两个部分主机dsmc-host.c依赖dsmc-controller.c和dsmc-lb-device.c完成整体功能从机不依赖其他DSMC文件，只在dsmc-lb-slave.c里写寄存器配置DSMC，处理中断等主机端Host dsmc-host.c 注册 platform 驱动，probe 时会： 调用 dsmc-controller.c 的底层初始化接口rockchip_dsmc_ctrller_init，完成控制器硬件初始化 调用 dsmc-lb-device.c 注册 Local Bus 设备，创建 /dev/dsmc/... 字符设备节点，提供用户空间访问接口 注册 DMA 和中断，做好数据搬运准备 用户程序通过 /dev/dsmc/ 下的设备节点，发起 DMA 读写请求open/ioctl ioctl 处理，配置 DMA 参数，调用 dma_memcpy_init/dma_memcpy_trans_start 通过 dsmc-host.c 提供的 ops 接口，最终调用 dsmc-controller.c 的底层 DMA 函数发送出去从机端Slave dsmc-lb-slave.c 注册 platform 驱动，probe 时： 解析 dts，获取资源和内存映射 初始化寄存器，配置为 slave 模式 申请中断，等待主机端的中断操作通知 收到中断（如 S2H），进入中断服务函数 rockchip_dsmc_lb_slave_irq 调用 dsmc_lb_slave_dma_trigger()，触发本地 DMA 硬件搬运 搬运完成后清除中断，等待下一次操作二 控制器驱动代码解析2.1 控制器驱动初始化 dsmc-controller.cdsmc-controller.c主要负责 DSMC 控制器的底层硬件初始化、PSRAM检测与配置、延迟线训练、DMA 触发、寄存器操作等功能。它是整个 DSMC 总线主控端驱动的底层核心,直接操作硬件寄存器，完成对存储器和总线的初始化和管理。在RTOS中与其对应的是HAL_DSMC_HOST_Init中部分内容延迟线（DLL）训练：是为总线采样时钟增加适当延时，使得数据到达时间一致性主要结构体struct rockchip_dsmc：DSMC控制器的核心结构体，包含寄存器基址、配置参数等 struct dsmc_config_cs：描述每个chip select的配置信息，时序、宽度、延迟等 struct dsmc_map：映射的内存区域信息下列函数通过 EXPORT_SYMBOL 导出，可以被其他内核模块调用，比如dsmc-host.c等rockchip_dsmc_dll_training：延迟线训练 rockchip_dsmc_lb_dma_trigger_by_host：主控触发 DMA rockchip_dsmc_lb_dma_hw_mode_dis：关闭 DMA 硬件模式 rockchip_dsmc_ctrller_init：主控控制器初始化 rockchip_dsmc_lb_init：本地总线初始化 rockchip_dsmc_psram_reinit：PSRAM 重新初始化 rockchip_dsmc_device_dectect：设备检测大致调用流程：参考dsmc-host.c1调用rockchip_dsmc_ctrller_init初始化控制器 2调用rockchip_dsmc_device_dectect检测并识别PSRAM 3调用rockchip_dsmc_dll_training进行延迟线训练 4调用rock…

配置DSMC：ROTS与Linux
type: item
date: 2025-08-22T06:09:00+00:00
description: 1 Linux DTS DSMC在/home/linux/rk3506/GA3506_Linux_Source/kernel-6.1/arch/arm/boot/dts/GA3506_dsmc.dtsi中，将DSMC设备的status状态设备为okay，然后编译即可。2 RTOS DSMC**这里有说明如何将Linux设备树下设备如何共享给amp的rtos使用参考手册Rockchip_Developer_Guide_AMP_CN.pdf****首先找到/home/linux/rk3506/GA3506_Linux_Source/kernel-6.1/arch/arm/boot/dts/rk3506.dtsi文件在这个文件里有DSMC的中断编号，引脚等配置，首先将DSMC时钟加入到AMP的时钟配置内，然后把DSMC的引脚加入到AMP的引脚列表中，再把中断编号加上32的偏移放入AMP的中断配置内**然后在/home/linux/rk3506/GA3506_Linux_Source/rtos/bsp/rockchip/ga3506-32目录下打开终端，使用scons --menuconfig命令进入配置窗口，将DSMC HOST的打开并且将测试代码使能最后使用./build.sh命令整体编译打包烧录即可