添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

1 功能概述

dma_m2m sample Memory to Memory 传输为例,演示了 Zephyr DMA Driver 在 PAN1080 SoC 上的使用方法。

2 环境准备

  • PAN1080 EVB 一块

  • USB-TypeC 线一条(用于供电和查看串口打印 Log)

  • 硬件接线:

  • 使用USB线,将 PC USB 与 EVB USB-TypeC(USB->UART)相连

  • 使用 杜邦线 将 EVB 上的:

  • TX0 与 P00 相连

  • RX0 与 P01 相连

  • 3 编译和烧录

    例程位置: zephyr\samples_panchip\drivers\dma_m2m

    使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考: Zephyr APP Launcher 工具介绍

    4 演示说明

    本例程中,进行了2次 DMA Block 传输:

  • 首先从 Flash Address 1 中读取一个大数组,将其通过 DMA 的方式搬移的 SRAM 上,并确认搬移成功;

  • 然后使用 dma_reload() 接口,重新配置源地址为 Flash Address 2 ,并将此地址对应的大数组通过 DMA 的方式搬移到同一块 SRAM 上,再确认是否搬移成功。

  • 本例程涉及如下的 DMA Driver APIs:

  • dma_request_channel()

  • dma_release_channel()

  • dma_config()

  • dma_start()

  • dma_reload()

  • dma_get_status()

  • 例程执行成功的 Log 如下所示:

    *** Booting Zephyr OS build zephyr-v2.7.0-481-ge520fced9ef8  ***
    [00:00:00.000,000] <inf> dma_dw: Device DMA_0 initialized
    [00:00:00.000,000] <inf> app: DMA M2M (Memory to Memory) demo start..
    [00:00:00.001,000] <inf> app: Configure and start the 1st DMA transfer procedure, chan_id=0
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.001,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.002,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.003,000] <inf> app: dma_transfer_cb: DMA transfer done
    [00:00:00.003,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.003,000] <inf> app: DMA status: direction=0, busy=0
    [00:00:00.009,000] <inf> app: Reload and start the 2nd DMA transfer procedure, chan_id=0
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.009,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.010,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.011,000] <inf> app: dma_transfer_cb: DMA transfer done
    [00:00:00.011,000] <inf> app: DMA status: direction=0, busy=1
    [00:00:00.011,000] <inf> app: DMA status: direction=0, busy=0
    [00:00:00.017,000] <inf> app: DMA Data transfer OK, and channel 0 is now ready again for later use.
    [00:00:00.017,000] <inf> app: DMA M2M (Memory to Memory) demo end.
    

    5.1 PAN1080 DMA Controller 硬件特性介绍

  • PAN1080 SoC 内置一个 DMA Controller (DMAC),其具有 3 个可用的通道(通道编号为 0 ~ 2),并支持通道优先级配置;

  • PAN1080 DMAC 仅支持单 Block 传输,一个 Block 最大可传输 4095 个 Item,每个 Item 最大支持 4 字节数据(即 32-Bits,与系统总线宽度一致),换句话说,在一次典型的 DMA Memory-to-Memory 传输过程中,最大可以搬移 4095 * 4 = 16380 字节的数据(Peripheral-to-Memory 传输方式达不到此值);

    :PAN1080 DMAC 不支持 Chaining Multi-Block 传输和 Scatter/Gather 传输

  • PAN1080 DMAC 支持 Memory-to-Memory、Memory-to-Peripheral、Peripheral-to-Memory、Peripheral-to-Peripheral 等四种传输方式;

  • PAN1080 DMAC 支持寄存器配置数据传输源地址和目的地址,并支持地址递增、递减或不变;

  • PAN1080 DMAC 每个通道均有一个深度为 4、宽度为 32-bit 的内部 FIFO,其内部逻辑支持自动包装或拆解数据以适应 FIFO 位宽;

  • PAN1080 DMAC 支持硬件握手和软件握手接口,并支持 single transaction 和 burst transaction;

  • PAN1080 DMAC 支持流控,但其只支持 DMA 作为流控,不支持 Peripheral 作为流控;

  • PAN1080 DMAC 支持组合或分开的中断请求,支持中断使能与屏蔽,可在以下事件触发时产生中断:DMA Transfer 结束、Block Transfer 结束、Single/Burst Transaction 结束、传输出错;

  • 5.2 Zephyr DMA Driver 配置项详解

    Zephyr DMA Driver API (zephyr/include/drivers/dma.h) 中,有两个重要的结构体(dma_configdma_block_config)用于 DMA 配置,其为了做到通用,提供了非常多的配置参数,而对于 PAN1080 DMA 来说,只需用到其中的一部分即可。

    struct dma_configstruct dma_block_configdma.h 中的定义如下:

    * @struct dma_block_config * @brief DMA block configuration structure. * @param source_address is block starting address at source * @param source_gather_interval is the address adjustment at gather boundary * @param dest_address is block starting address at destination * @param dest_scatter_interval is the address adjustment at scatter boundary * @param dest_scatter_count is the continuous transfer count between scatter * boundaries * @param source_gather_count is the continuous transfer count between gather * boundaries * @param block_size is the number of bytes to be transferred for this block. * @param config is a bit field with the following parts: * 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 ] struct dma_block_config { #ifdef CONFIG_DMA_64BIT // PAN1080地址总线为32位,因此CONFIG_DMA_64BIT宏不会被定义 uint64_t source_address; uint64_t dest_address; #else uint32_t source_address; // * 必须配置 uint32_t dest_address; // * 必须配置 #endif 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; // * 必须配置(固定为0) 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; // 不用配置(硬件支持,但Driver未实现) uint16_t dest_reload_en : 1; // 不用配置(硬件支持,但Driver未实现) uint16_t fifo_mode_control : 4; // 不用配置(硬件支持,但用户无需配置) uint16_t flow_control_mode : 1; // 不用配置(硬件不支持) uint16_t reserved : 3; * @struct dma_config * @brief DMA configuration structure. * @param dma_slot [ 0 : 6 ] - which peripheral and direction * (HW specific) * @param channel_direction [ 7 : 9 ] - 000-memory to memory, * 001-memory to peripheral, * 010-peripheral to memory, * 011-peripheral to peripheral, * ... * @param complete_callback_en [ 10 ] - 0-callback invoked at completion only * 1-callback invoked at completion of * each block * @param error_callback_en [ 11 ] - 0-error callback enabled * 1-error callback disabled * @param source_handshake [ 12 ] - 0-HW, 1-SW * @param dest_handshake [ 13 ] - 0-HW, 1-SW * @param channel_priority [ 14 : 17 ] - DMA channel priority * @param source_chaining_en [ 18 ] - enable/disable source block chaining * 0-disable, 1-enable * @param dest_chaining_en [ 19 ] - enable/disable destination block * chaining. * 0-disable, 1-enable * @param linked_channel [ 20 : 26 ] - after channel count exhaust will * initiate a channel service request * at this channel * @param reserved [ 27 : 31 ] * @param source_data_size [ 0 : 15 ] - width of source data (in bytes) * @param dest_data_size [ 16 : 31 ] - width of dest data (in bytes) * @param source_burst_length [ 0 : 15 ] - number of source data units * @param dest_burst_length [ 16 : 31 ] - number of destination data units * @param block_count is the number of blocks used for block chaining, this * depends on availability of the DMA controller. * @param source_peripheral_id is the ID of a hardware peripheral which * acts as DMA source of current channel, note this is only valid when * the source_handshake bit is 0 (means HW handshake). * @param dest_peripheral_id is the ID of a hardware peripheral which * acts as DMA destination of current channel, note this is only valid when * the dest_handshake bit is 0 (means HW handshake). * @param user_data private data from DMA client. * @param dma_callback see dma_callback_t for details struct dma_config { uint32_t dma_slot : 7; // 不用配置(Driver不支持) uint32_t channel_direction : 3; // * 必须配置 uint32_t complete_callback_en : 1; // # 可选配置(根据实际需要决定是否配置) uint32_t error_callback_en : 1; // 不用配置(Driver不支持) uint32_t source_handshake : 1; // 不用配置(硬件支持,但用户无需配置) uint32_t dest_handshake : 1; // 不用配置(硬件支持,但用户无需配置) uint32_t channel_priority : 4; // # 可选配置(根据实际需要决定是否配置) uint32_t source_chaining_en : 1; // 不用配置(硬件不支持) uint32_t dest_chaining_en : 1; // 不用配置(硬件不支持) uint32_t linked_channel : 7; // 不用配置(硬件不支持) uint32_t reserved : 5; uint32_t source_data_size : 16; // * 必须配置 uint32_t dest_data_size : 16; // * 必须配置 uint32_t source_burst_length : 16; // * 必须配置 uint32_t dest_burst_length : 16; // * 必须配置 uint32_t block_count; // * 必须配置(固定为1) uint16_t source_peripheral_id; // # 可选配置(根据实际需要决定是否配置) uint16_t dest_peripheral_id; // # 可选配置(根据实际需要决定是否配置) struct dma_block_config *head_block; // * 必须配置 void *user_data; // # 可选配置(根据实际需要决定是否配置) dma_callback_t dma_callback; // # 可选配置(根据实际需要决定是否配置)

    上述两个结构体定义中的参数,在 DMA 配置过程中关注以下原则即可:

  • 标记为 必须配置 的参数,是必须正确填写的,否则 DMA 将无法正常工作;

  • 标记为 可选配置 的参数,需要根据实际需求决定是否需要进行配置;

  • 标记为 不用配置 的参数,无需关注之;

  • 下面两个表格中详细列出了 struct dma_configstruct dma_block_config 中各个参数的详细含义及 PAN1080 DMAC 的使用说明:

    dma_block_config 结构体参数详解
  • 若 DMA 源端是 Memory,则应填待传输 Memory 的起始地址,注意此地址有对齐要求,需能被 source_data_size 整除

  • 若 DMA 源端是 Peripheral,则应填此外设 Data FIFO 的寄存器地址,各寄存器定义详见: include\drivers\dma\dma_panchip.h

  • dest_address

    DMA 目的端地址

    需要注意:

  • 若 DMA 目的端是 Memory,则应填待传输 Memory 的起始地址,注意此地址有对齐要求,需能被 dest_data_size 整除

  • 若 DMA 目的端是 Peripheral,则应填此外设 Data FIFO 的寄存器地址,各寄存器定义详见: include\drivers\dma\dma_panchip.h

  • source_gather_interval

    DMA Gather 源端地址到达边界后的调整值

    PAN1080 DMAC 不支持 Gather 特性,此参数无意义

    dest_scatter_interval

    DMA Scatter 目的端地址到达边界后的调整值

    PAN1080 DMAC 不支持 Scatter 特性,此参数无意义

    dest_scatter_count

    DMA Scatter 目的端地址调整次数

    PAN1080 DMAC 不支持 Scatter 特性,此参数无意义

    source_gather_count

    DMA Gather 源端地址调整次数

    PAN1080 DMAC 不支持 Gather 特性,此参数无意义

    block_size

    当前 DMA Block 预期传输的数据长度(字节)

    需要注意此处待传输的数据长度必须同时满足以下几个条件:

  • block_sizesource_data_size 的整数倍

  • block_sizedest_data_size 的整数倍

  • block_size / dest_data_size 不可超过 4095

  • next_block

    指向下一个 DMA Block 的配置参数

    PAN1080 DMAC 不支持 Chaining Multi-Block 特性,所以此参数必须配置为0

    source_gather_en

    DMA Source Gather 使能控制

    PAN1080 DMAC 不支持 Gather 特性,此参数无意义

    dest_scatter_en

    DMA Destination Scatter 使能控制

    PAN1080 DMAC 不支持 Scatter 特性,此参数无意义

    source_addr_adj

    DMA 源端地址步进规则(递增、递减、或不变)

    PAN1080 DMAC 支持此特性,但用户无需在此处配置,原因是 DMA Driver 会根据实际传输类型,自动按如下规则配置步进:

  • 若源端为 Memory,则 Source Address 步进会被配置为递增

  • 若源端为 Peripheral,则 Source Address 步进会被配置为不变

  • dest_addr_adj

    DMA 目的端地址步进规则(递增、递减、或不变)

    PAN1080 DMAC 支持此特性,但用户无需在此处配置,原因是 DMA Driver 会根据实际传输类型,自动按如下规则配置步进:

  • 若目的端为 Memory,则 Destination Address 步进会被配置为递增

  • 若目的端为 Peripheral,则 Destination Address 步进会被配置为不变

  • source_reload_en

    DMA 源端地址自动重新加载使能控制

    PAN1080 DMAC 支持此特性,但 PAN1080 DMA Driver 未实现此特性,因此无需配置

    dest_reload_en

    DMA 目的端地址自动重新加载使能控制

    PAN1080 DMAC 支持此特性,但 PAN1080 DMA Driver 未实现此特性,因此无需配置

    fifo_mode_control

    决定 DMA 执行一个 Burst Transaction 之前,DMA FIFO 中需要有多少空间或数据

    PAN1080 DMAC 支持此特性,但用户无需在此处配置,原因是 DMA Driver 强制将此特性配置为“只要 FIFO 空间或数据足够一次 Single Transfer,就可以传输”

    flow_control_mode

    决定目的端 Peripheral 作为流控时,源外设如何给数据

    PAN1080 DMAC 不支持 Peripheral 作为流控,自然也不支持此特性,此参数无意义

    DMA Peripheral 传输方式下的外设 ID

    PAN1080 DMAC 支持此特性,但 DMA Driver 使用另外两个单独的参数来分别指示源端和目的端外设 ID:

  • source_peripheral_id

  • dest_peripheral_id

  • channel_direction

    DMA 传输类型

    PAN1080 DMAC 支持以下 4 种传输类型:

  • MEMORY_TO_MEMORY

  • MEMORY_TO_PERIPHERAL

  • PERIPHERAL_TO_MEMORY

  • PERIPHERAL_TO_PERIPHERAL

  • complete_callback_en

    决定 dma_callback 函数是在每个 Block 传输完成后触发,还是所有数据传输完成后触发

    PAN1080 DMA Driver 支持此特性,但由于 PAN1080 DMAC 硬件仅支持单个 Block 传输,因此在概念上,“每个 Block 传输完成”与“所有数据传输完成”是相同的,在实际应用中,建议直接将此参数配置为0即可

    error_callback_en

    DMA 传输出错的 Callback 函数使能控制

    PAN1080 DMAC 支持Error中断,但 PAN1080 DMA Driver 未实现此特性,因此无需配置

    source_handshake

    决定 DMA 源端握手方式为硬件握手还是软件握手

    PAN1080 DMAC 支持此特性,但用户无需在此处配置,原因是 DMA Driver 强制将此特性配置为“硬件握手”

    dest_handshake

    决定 DMA 目的端握手方式为硬件握手还是软件握手

    PAN1080 DMAC 支持此特性,但用户无需在此处配置,原因是 DMA Driver 强制将此特性配置为“硬件握手”

    channel_priority

    当前 DMA 通道的优先级

    PAN1080 DMAC 支持此特性,3个通道的优先级可以独立配置,优先级可选范围为 0 ~ 3,其中数字越大表示优先级越高,在实际应用中,如果没有特殊需求,建议直接将此参数配置为0即可

    source_chaining_en

    DMA 源端 Block-Chaining (Multi-Block) 特性使能控制

    PAN1080 DMAC 硬件不支持,此参数无意义

    dest_chaining_en

    DMA 目的端 Block-Chaining (Multi-Block) 特性使能控制

    PAN1080 DMAC 硬件不支持,此参数无意义

    linked_channel

    DMA 衔接通道

    PAN1080 DMAC 硬件不支持,此参数无意义

    source_data_size

    DMA 源端数据宽度(字节)

    PAN1080 DMAC 支持的源端数据宽度有 1、2、4 字节:

  • 若 DMA 源端是 Memory,则此参数可以任意配置为上述 3 个可选参数之一

  • 若 DMA 源端是 Peripheral,则此参数应与对应外设传输的 Data 宽度保持一致

  • dest_data_size

    DMA 目的端数据宽度(字节)

    PAN1080 DMAC 支持的目的端数据宽度有 1、2、4 字节:

  • 若 DMA 目的端是 Memory,则此参数可以任意配置为上述 3 个可选参数之一

  • 若 DMA 目的端是 Peripheral,则此参数应与对应外设传输的 Data 宽度保持一致

  • source_burst_length

    DMA 源端 Burst 长度

    PAN1080 DMAC 支持的源端 Burst 长度有 1、4、8 字节:

  • 若 DMA 源端是 Memory,则此参数可以任意配置为上述 3 个可选参数之一

  • 若 DMA 源端是 Peripheral,则此参数不应超过对应外设的 FIFO 深度大小

  • dest_burst_length

    DMA 目的端 Burst 长度

    PAN1080 DMAC 支持的目的端 Burst 长度有 1、4、8 字节:

  • 若 DMA 目的端是 Memory,则此参数可以任意配置为上述 3 个可选参数之一

  • 若 DMA 目的端是 Peripheral,则此参数不应超过对应外设的 FIFO 深度大小

  • block_count

    DMA 待传输的 Block 数量

    PAN1080 DMAC 不支持 Chaining Multi-Block 特性,所以此参数必须配置为1

    source_peripheral_id

    DMA 源端 Peripheral ID

    当 DMA 源端被配置为 Peripheral 时(即 Peripheral-to-Memory 或 Peripheral-to-Peripheral 方式),此处用于指定对应外设的 Peripheral ID,PAN1080 所有支持 DMA 功能的外设 Periphal ID 定义详见: include\drivers\dma\dma_panchip.h

    dest_peripheral_id

    DMA 目的端 Peripheral ID

    当 DMA 目的端被配置为 Peripheral 时(即 Memory-to-Peripheral 或 Peripheral-to-Peripheral 方式),此处用于指定对应外设的 Peripheral ID,PAN1080 所有支持 DMA 功能的外设 Periphal ID 定义详见: include\drivers\dma\dma_panchip.h

    head_block

    指向第一个 DMA Block 的配置参数

    需要先定义一个 struct dma_block_config 类型的变量用于存放 Block 配置参数,然后将其指针赋给此 head_block 参数

    user_data

    DMA Callback 的用户数据,

    此参数会作为函数参数传进 dma_callback 指向的函数中,作为用户数据使用,在实际应用中,如果没有特殊需求,建议直接将此参数配置为0即可

    dma_callback

    DMA Callback 函数的指针,

    当 DMA 传输完成(或 Block 传输完成)后,会自动触发此参数指向的函数,在实际应用中,建议实现callback函数,以方便确认DMA传输成功

    6 RAM/Flash资源使用情况

    Memory region         Used Size  Region Size  %age Used
    FLASH:       62068 B      1020 KB      5.94%
    SRAM:       26936 B        64 KB     41.10%
    IDT_LIST:          0 GB         2 KB      0.00%