2015-11-17 115 views
2

由於某些設計要求,我需要在運行時更改DMA描述符。爲了實現這一點,我按照以下步驟操作:Atmel SAMD21 DMA中止問題

  1. 中止DMA通道。然後DMA硬件將保存當前執行的描述符 write_back相同DMA通道的RAM位置。
  2. 等到中止完成
  3. 修改write_back RAM位置上的DMA描述符。
  4. 再次啓用

DMA通道這是代碼片段我使用:

//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; 

上述步驟工作正常,沒有任何問題,但我長期運行過程中面臨的描述腐敗問題。

當執行DMA中止時,DMA硬件正在執行的描述符存儲在另一個DMA通道的write_back RAM位置(而不是自己的write_back RAM位置)。

如果有人對任何問題有任何想法,或者對我如何完全避免描述符腐敗問題有所瞭解,我想嘗試一下。

回答

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通道中的禁用。

+0

我也嘗試禁用DMAC寄存器訪問過程中的中斷,但它沒有解決問題 – GOKU