Atmel SAMD21 DMA中止问题

时间:2015-11-17 06:18:46

标签: c arm atmel dma cortex-m

由于一些设计要求,我需要在运行时更改DMA描述符。为此,我遵循以下步骤:

  1. 中止DMA通道。然后,DMA硬件将保存当前正在执行的描述符 write_back相同DMA通道的RAM位置。
  2. 等到中止完成
  3. 修改write_back RAM位置上的DMA描述符。
  4. 再次启用DMA通道
  5. 这是我正在使用的代码段:

    //Select DMA channel
    DMAC->CHID.reg = DMAC_CHID_ID(cSPIDMAResource0.channel_id);
    
    //Abort Selected DMA channel
    DMAC->CHCTRLA.reg &= ~DMA_CHANNEL_ENABLE_BIT_POS;
    
    //Wait until Abort completed
    while((DMAC->CHCTRLA.reg & DMA_CHANNEL_ENABLE_BIT_POS) == DMA_CHANNEL_ENABLE_BIT_POS);
    
    /*
        Modify Descriptor here 
    */
    
    //Enable DMA channel
    DMAC->CHCTRLA.reg |= DMA_CHANNEL_ENABLE_BIT_POS;
    

    上述步骤正常运行没有任何问题,但我长期面对Descriptor腐败问题。

    当执行DMA中止时,DMA硬件将当前正在执行的描述符存储在另一个DMA通道的write_back RAM位置(而不是自己的write_back RAM位置)。

    如果有人知道出了什么问题,或者知道如何彻底避免描述符腐败问题,我想尝试一下。

1 个答案:

答案 0 :(得分:1)

为什么不使用atmel软件框架的dma驱动程序?以下是他们如何进行中止。

void dma_abort_job(struct dma_resource *resource)
{
    uint32_t write_size;
    uint32_t total_size;

    Assert(resource);
    Assert(resource->channel_id != DMA_INVALID_CHANNEL);

    system_interrupt_enter_critical_section();

    DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
    DMAC->CHCTRLA.reg = 0;

    system_interrupt_leave_critical_section();

    /* Get transferred size */
    total_size = descriptor_section[resource->channel_id].BTCNT.reg;
    write_size = _write_back_section[resource->channel_id].BTCNT.reg;
    resource->transfered_size = total_size - write_size;

    resource->job_status = STATUS_ABORTED;
}

可以解释问题的一个区别是在寄存器写入期间通过system_interrupt_leave_critical_section()禁用中断来中止dma通道。