cancel
Showing results for 
Search instead for 
Did you mean: 

GPDMA Linked List Circular Buffering: Correct Transfer Event Mode?

cubett
Associate

I want to capture images larger than 0xFFFF via DCMI using double buffering with two GPDMA1 linked list nodes. As guidance, I'm following the DCMI_ContinuousCap_EmbeddedSynchMode example. However, it seems that the DCMI_DMAXferCplt function is written as if it should be called after every node completes, but the example configures:

 

  handle_GPDMA1_Channel12.Instance = GPDMA1_Channel12;
  handle_GPDMA1_Channel12.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
  handle_GPDMA1_Channel12.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
  handle_GPDMA1_Channel12.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT1;
  handle_GPDMA1_Channel12.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
  handle_GPDMA1_Channel12.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;

 

Am I misunderstanding TransferEventMode, or why is it not set to DMA_TCEM_EACH_LL_ITEM_TRANSFER?

2 REPLIES 2
Sarra.S
ST Employee

Hello @cubett

In the example, the event is triggered only after the last linked list item transfer is completed, so the completion of the entire linked list transfer is considered as a single event

If TransferEventMode is set to DMA_TCEM_EACH_LL_ITEM_TRANSFER, this will trigger the transfer complete event after each linked list item transfer, so you handle each node's completion individually

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

That matches my understanding. But in that case, the example DCMI_ContinuousCap_EmbeddedSynchMode must be wrong? I can't see how the DCMI_DOUBLE_BUFFER Mode (data size > 0xFFFF) with two linked list nodes could work if DCMI_DMAXferCplt is only triggered after the last node (second node).

static void DCMI_DMAXferCplt(DMA_HandleTypeDef *hdma)
{

  DCMI_HandleTypeDef *hdcmi = (DCMI_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  uint32_t tmp1;
  uint32_t tmp2;
  DMA_NodeTypeDef *pnode;
  uint32_t pbuff;
  uint32_t transfernumber;
  uint32_t transfercount;
  uint32_t transfersize ;

  /* Update Nodes destinations */
  if (hdcmi->XferSize != 0U)
  {
    pbuff          = hdcmi->pBuffPtr;
    transfernumber = hdcmi->XferTransferNumber;
    transfercount  = hdcmi->XferCount;
    transfersize   = hdcmi->XferSize;

    tmp1 = hdcmi->DMA_Handle->Instance->CLLR & DMA_CLLR_LA;
    tmp2 = hdcmi->DMA_Handle->Instance->CLBAR & DMA_CLBAR_LBA;
    pnode = (DMA_NodeTypeDef *)(uint32_t)(tmp1 | tmp2);

    if (hdcmi->XferCount > 1U)
    {
      pnode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = pbuff + ((transfernumber - transfercount + 2U) * transfersize);
      hdcmi->XferCount--;
    }

    else if (hdcmi->XferCount == 1U)
    {
      pnode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = hdcmi->pBuffPtr;
      hdcmi->XferCount--;
    }
    else
    {
      pnode->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] = hdcmi->pBuffPtr + hdcmi->XferSize;

      /* When Continuous mode, re-set dcmi XferCount */
      if ((hdcmi->Instance->CR & DCMI_CR_CM) == DCMI_MODE_CONTINUOUS)
      {
        hdcmi->XferCount = hdcmi->XferTransferNumber ;
      }
      /* When snapshot mode, set dcmi state to ready */
      else
      {
        hdcmi->State = HAL_DCMI_STATE_READY;
      }

      __HAL_DCMI_ENABLE_IT(hdcmi, DCMI_IT_FRAME);
    }
  }
  else  /* Snapshot Mode */
  {
    /* Enable the Frame interrupt */
    __HAL_DCMI_ENABLE_IT(hdcmi, DCMI_IT_FRAME);

    /* When snapshot mode, set dcmi state to ready */
    if ((hdcmi->Instance->CR & DCMI_CR_CM) == DCMI_MODE_SNAPSHOT)
    {
      hdcmi->State = HAL_DCMI_STATE_READY;
    }
  }
}