演示如何使用Zephyr RTOS的DMA功能进行高效的内存拷贝。运行该代码后,将比较DMA和标准memcpy的性能。
DEVICE_DT_GET ( node_id )
从 devicetree 节点标识符获取设备引用。
如果驱动程序分配了任何设备,则返回指向从 devicetree 节点创建的设备对象的指针。
参数说明
字段 | 说明 |
---|---|
node_id | devicetree 节点标识符 |
返回值说明
指向为该节点创建的设备对象的指针
如果未分配此类设备,则在链接时将失败。如果收到类似 defined reference to __device_dts_ord_<N>
的错误,检查以确保您的设备驱动程序正在编译中,通常是通过启用它所需的 Kconfig 选项。
. uint32_t source_address
uint32_t dest_address
uint32_t source_gather_interval
uint32_t dest_scatter_interval
uint16_t dest_scatter_count
uint16_t source_gather_count
uint32_t block_size
struct dma_block_config * next_block
uint16_t source_gather_en: 1
uint16_t dest_scatter_en: 1
uint16_t source_addr_adj: 2
uint16_t dest_addr_adj: 2
uint16_t source_reload_en: 1
uint16_t dest_reload_en: 1
uint16_t fifo_mode_control: 4
uint16_t flow_control_mode: 1
uint16_t reserved: 3
DMA 块配置结构。
如果驱动程序分配了任何设备,则返回指向从 devicetree 节点创建的设备对象的指针。
参数说明
字段 | 说明 |
---|---|
source_address | 源头的块起始地址 |
source_gather_interval | Gather 边界处的地址调整 |
dest_address | 目标的块起始地址 |
dest_scatter_interval | 散射边界处的地址平差 |
dest_scatter_count | 散射边界之间的连续传输计数 |
source_gather_count | 收集边界之间的连续传输计数 |
block_size | 要为此块传输的字节数 |
config是一个位字段,包含以下部分:
source_gather_en [ 0 ] - 0-disable, 1-enable.
dest_scatter_en [ 1 ] - 0-disable, 1-enable.
source_addr_adj [ 2 : 3 ] - 00-increment, 01-decrement,
10-no change.
dest_addr_adj [ 4 : 5 ] - 00-increment, 01-decrement,
10-no change.
source_reload_en [ 6 ] - reload source address at the end of
block transfer
0-disable, 1-enable.
dest_reload_en [ 7 ] - reload destination address at the end
of block transfer
0-disable, 1-enable.
fifo_mode_control [ 8 : 11 ] - How full of the fifo before transfer
start. HW specific.
flow_control_mode [ 12 ] - 0-source request served upon data
availability.
1-source request postponed until
destination request happens.
reserved [ 13 : 15 ]
dma_config ( const struct device * dev, uint32_t channel, struct dma_config * config )
从 devicetree 节点标识符获取设备引用。
参数说明
字段 | 说明 |
---|---|
dev | 指向驱动程序实例的设备结构的指针 |
channel | 要配置的通道的数字标识 |
config | 包含所选通道的预期配置的数据结构 |
返回值说明
字段 | 说明 |
---|---|
0 | 成功 |
Negative | 如果失败,则为无代码 |
dma_start ( const struct device * dev, uint32_t channel )
实现必须检查传入的通道 ID 的有效性,如果无效,则返回 -EINVAL。
允许在已启动的频道上启动,并且必须报告成功。
参数说明
字段 | 说明 |
---|---|
dev | 指向驱动程序实例的设备结构的指针 |
channel | 要配置的通道的数字标识 |
返回值说明
字段 | 说明 |
---|---|
0 | 成功 |
Negative | 如果失败,则为无代码 |
更多DMA Interface API接口可查看Zephyr官网DMA Interface APIs。
SDK 中提供了 dma_memcpy 的示例。
演示如何使用Zephyr RTOS的DMA功能进行高效的内存拷贝。运行该代码后,将比较DMA和标准memcpy的性能。
{SDK}\.sdk\csk\samples\driver\dma_memcpy
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk/csk/samples/driver/dma_memcpy/ -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
烧录完成后,连接串口终端,按下开发板复位按钮,可看到串口有对应的信息输出。
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
在工程目录prj.conf
文件中需配置以下模块:
CONFIG_DMA=y
CONFIG_HEAP_MEM_POOL_SIZE=40960
CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_NOCACHE_MEMORY=y
1. 从设备树中获取DMA设备
const struct device *dma = DEVICE_DT_GET(DT_NODELABEL(dma0));
2. 配置并启动DMA进行内存拷贝
test_dma_copy(dma, src_buffer, dst_buffer, BUFFER_SIZE);
3. 使用标准的memcpy进行内存拷贝
test_std_memcpy(src_buffer, dst_buffer, BUFFER_SIZE);
4. 输出DMA和memcpy操作的耗时
5. 循环执行各种内存拷贝操作
按下开发板复位按钮,运行程序。程序将间隔性地执行DMA和标准memcpy操作,并通过串口输出各自的耗时数据,以此来比较两者的性能。
int main(void)
{
const struct device *dma = DEVICE_DT_GET(DT_NODELABEL(dma0));
for (int i = 0; i < BUFFER_SIZE; i++) {
src_buffer[i] = i % UINT8_MAX;
}
while (1) {
sample_dma_scatter(dma, src_buffer, dst_buffer, 16);
sample_dma_gather(dma, src_buffer, dst_buffer, 16);
sample_dma_dest_decrement(dma, src_buffer, dst_buffer, 16);
sample_dma_source_decrement(dma, src_buffer, dst_buffer, 16);
sample_dma_dest_data_width(dma, src_buffer, dst_buffer, 16);
sample_dma_source_data_width(dma, src_buffer, dst_buffer, 16);
test_dma_copy(dma, src_buffer, dst_buffer, BUFFER_SIZE);
test_std_memcpy(src_buffer, dst_buffer, BUFFER_SIZE);
k_msleep(1000);
}
return 0;
}