【问题标题】:Cyclic DMA transfer stopping after 3 cycles循环 DMA 传输在 3 个周期后停止
【发布时间】:2021-10-10 01:00:49
【问题描述】:

所以我试图在 imx6 上设置与 sai2 fifo 之间的循环传输,但我的 tx 和 rx 完成回调似乎只在传输之前被调用了两次,我的 sai2 寄存器配置和 dmaengine代码如下,任何提示将不胜感激:

Sai2 寄存器(为外部位时钟设置):

tcsr: 3491171329 tcr1:26 tcr2: 0 tcr3:65536 tcr4: 458801 tcr5:522133248 电话:4294967292 rcr2:1073741824 mclk: 0

Dmaengine 代码:

#define HARDWARE_BUFFER_BYTES 64*2 //* 2
#define HARDWARE_BUFFER_PERIOD_BYTES 32*2 

static int imx_tx_pingdma_init(struct pi_dma *master, struct device *dev)
{
    int err;

    dma_addr_t pcm_hardware_reg_base;
    const __be32 *addr;
    addr = of_get_address(dev->of_node, 0, NULL, NULL);
    if (!addr) {
        dev_err(dev, "could not get pcm hardware register address\n");
    }
    pcm_hardware_reg_base = be32_to_cpup(addr);
    master->dma_tx = dma_request_slave_channel(dev, "tx");
    if (!master->dma_tx) {
        dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
        tdm_dma_release(master);
        return -1;
    }


    master->dma_rx = dma_request_slave_channel(dev, "rx");
    if (!master->dma_rx) {
        dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
        tdm_dma_release(master);
        return -1;
    }

    /* configure DMAs */
    master->tx_ping_buffer =
        dma_alloc_coherent(master->dma_tx->device->dev,
        HARDWARE_BUFFER_BYTES,
        &master->tx_ping_buffer_dma,
        GFP_KERNEL);

    if (!master->tx_ping_buffer) {
        dev_err(dev, "could not allocate dma address\n");
        tdm_dma_release(master);
        return -1;
    }

    memset(master->tx_ping_buffer, 0, HARDWARE_BUFFER_BYTES);

    master->rx_ping_buffer =
        dma_alloc_coherent(master->dma_rx->device->dev,
        HARDWARE_BUFFER_BYTES,
        &master->rx_ping_buffer_dma,
        GFP_KERNEL);

    if (!master->rx_ping_buffer) {
        dev_err(dev, "could not allocate rx dma address\n");
        tdm_dma_release(master);
        return -1;
    }

    memset(master->rx_ping_buffer, 0, HARDWARE_BUFFER_BYTES);
    master->dma_tx_slave_config.direction = DMA_MEM_TO_DEV;
    master->dma_tx_slave_config.dst_addr = 0x202c000 + 0x20;
    master->dma_tx_slave_config.dst_maxburst = 1;
    master->dma_tx_slave_config.dst_addr_width = 4;
    master->dma_tx_slave_config.src_addr = master->tx_ping_buffer_dma;
    master->dma_tx_slave_config.src_maxburst = 1;
    master->dma_tx_slave_config.src_addr_width = 4;

    err = dmaengine_slave_config(master->dma_tx,
        &master->dma_tx_slave_config);

    if (err < 0) {
        printk("could not setup slave_tx_config\n");
        tdm_dma_release(master);
        return err;
    }


    master->dma_rx_slave_config.direction = DMA_DEV_TO_MEM;
    master->dma_rx_slave_config.dst_addr = master->rx_ping_buffer_dma;
    master->dma_rx_slave_config.dst_maxburst = 1;
    master->dma_rx_slave_config.dst_addr_width = 4;
    master->dma_rx_slave_config.src_addr = 0x202c000 + 0xa0;
    master->dma_rx_slave_config.src_maxburst = 1;
    master->dma_rx_slave_config.src_addr_width = 4;

    err = dmaengine_slave_config(master->dma_rx,
        &master->dma_rx_slave_config);

    if (err < 0) {
        printk("could not setup slave_rx_config\n");
        tdm_dma_release(master);
        return err;
    }

    master->dma_tx_desc =
        dmaengine_prep_dma_cyclic(master->dma_tx,
        master->tx_ping_buffer_dma,
        HARDWARE_BUFFER_BYTES,
        HARDWARE_BUFFER_PERIOD_BYTES,
        DMA_MEM_TO_DEV,
        DMA_CTRL_ACK | DMA_PREP_INTERRUPT);

    if (!master->dma_tx_desc) {
        printk("could not setup dma_tx_desc\n");
        tdm_dma_release(master);
        return -1;
    }

    master->dma_rx_desc =
        dmaengine_prep_dma_cyclic(master->dma_rx,
        master->rx_ping_buffer_dma,
        HARDWARE_BUFFER_BYTES,
        HARDWARE_BUFFER_PERIOD_BYTES,
        DMA_DEV_TO_MEM,
        DMA_CTRL_ACK | DMA_PREP_INTERRUPT);

    if (!master->dma_rx_desc) {
        printk("could not setup dma_rx_desc\n");
        tdm_dma_release(master);
        return -1;
    }

    master->dma_tx_desc->callback = dma_tx_complete;
    master->dma_tx_desc->callback_param = master;

    master->dma_rx_desc->callback = dma_rx_complete;
    master->dma_rx_desc->callback_param = master;

    printk("DMA configured by success!\n");
    return 0;
}

编辑:我已经尝试增加缓冲区大小,似乎循环 dma 只是在到达缓冲区末尾时停止回调。即如果 period_len=64 且 buff_len 为 64*1024,则 dma 回调将运行 1024 次并暂停。

【问题讨论】:

    标签: c linux-device-driver dma imx6


    【解决方案1】:

    想通了。 sai 驱动程序的函数调用完成后,由于某种原因,总线时钟被禁用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-31
      • 1970-01-01
      • 2012-05-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 1970-01-01
      • 2013-05-31
      相关资源
      最近更新 更多