打印

例子MDMA_LTDC_Triggering应该是MDMA里面最复杂的了

[复制链接]
333|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
无幻|  楼主 | 2018-8-10 16:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
例程说明:

这个例子比较的复杂,应该是MDMA里面最复杂的了。实现了一个在不需要CPU参与的情况下,图片的轮番切换功能。
简单的框图如下,通过list模式创建两个三个节点,节点0,节点1和节点3。其中节点0仅执行一次,后面连个节点创建成了循环模式,一直循环执行下去。

               LPTIM1   ----------------------------->   DMA1 Stream0   ---------------------------------->list模式节点1
  100ms触发一次DMA1 Stream0          触发后,切换list模式节点1的源图片地址             通过LTDC的行中断触发节点1
                                                    触发方式是采用的DMAMUX Request generator
                                                                           |
                                                                           |
                                                                           v
                                                                    DMA1 Stream1    ---------------------------------->list模式节点2
                                                 通过DMA1 Stream0的同步触发连接DMA1 Stream1       通过DMA1 Stream1触发节点2
                                                                                                                               从而实现循环模式不断循环执行。

配置如下:/**
  * @brief  Initialize the MDMA For repeat block transfer in linked list circular
    repeat block transfer.
  * @param  None
  * @retval None
  */
static void MDMA_Config(void)
{
  uint32_t hal_status = HAL_OK;  
  MDMA_LinkNodeConfTypeDef mdmaLinkNodeConfig;   
   
  /*##-1- Enable the MDMA clock ###############################################*/  
  __HAL_RCC_MDMA_CLK_ENABLE();  
  
  /*##-2- Select the MDMA instance to be used : MDMA_Channel0 #################*/
  MDMA_Handle.Instance = MDMA_Channel0;  
  
  /*##-3- Configure the MDMA for block transfer in HW request mode ############*/  
  /*
     This is the Node 0 of the linked list, node 0 will be executed only one time
     to clear the LCD frame buffer with default color
  */
  
  MDMA_Handle.Init.Request              = MDMA_REQUEST_LTDC_LINE_IT;
  MDMA_Handle.Init.TransferTriggerMode  = MDMA_REPEAT_BLOCK_TRANSFER;  
  MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;
  MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;
  MDMA_Handle.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                           
  MDMA_Handle.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;
  MDMA_Handle.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;
  MDMA_Handle.Init.BufferTransferLength = 32;
  
  /* Source and Destination data size are word , 4 bytes that correspond to an ARGB8888 pixel 32 bpp */     
  MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;
  MDMA_Handle.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;

  /* Source Increment Disabled as the source is always the LCD_Fill_Color
     that represents the default color used to fill the LCD frame buffer */      
  MDMA_Handle.Init.SourceInc            = MDMA_SRC_INC_DISABLE;
  /* Destination  Increment is word , 4 bytes that correspond to an ARGB8888 pixel 32 bpp */      
  MDMA_Handle.Init.DestinationInc       = MDMA_DEST_INC_WORD;

  /* Source block offset set to Zero : no increment of the source block address */
  MDMA_Handle.Init.SourceBlockAddressOffset  = 0;
  
  /* Destination block offset set to LCD_Offset */
  MDMA_Handle.Init.DestBlockAddressOffset    = LCD_Offset;   
  
  /*##-4- Initialize the MDMA channel ##########################################*/  
  hal_status = HAL_MDMA_Init(&MDMA_Handle);
  
  if(hal_status != HAL_OK)  
  {
    /* Initialization Error */
    Error_Handler();
  }

  /* MDMA Post request address and  Mask set respecetevly to the LTDC Interrupt Clear register address
     and the Clear Line Interrupt Flag mask in order to clear the LTDC Line Interrupt flag
     after each transfer knowing that this last flag is the MDMA transfer trigger
  */
  HAL_MDMA_ConfigPostRequestMask(&MDMA_Handle, (uint32_t)(&(LTDC->ICR)), LTDC_ICR_CLIF);
  
  /*##-5- Create Linked list Nodes ############################################*/
  
  /* Node 1 : First node is used to transfer an image from the flash to the LCD frame buffer
    The MDMA transfer trigger is set to the LTDC Line Interrupt flag.
  */
  mdmaLinkNodeConfig.Init.Request              = MDMA_REQUEST_LTDC_LINE_IT;
  mdmaLinkNodeConfig.Init.TransferTriggerMode  = MDMA_REPEAT_BLOCK_TRANSFER;
  mdmaLinkNodeConfig.Init.Priority             = MDMA_PRIORITY_HIGH;         
  mdmaLinkNodeConfig.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;         
  
  mdmaLinkNodeConfig.Init.SourceInc            = MDMA_SRC_INC_WORD;     
  mdmaLinkNodeConfig.Init.DestinationInc       = MDMA_DEST_INC_WORD;
  
  mdmaLinkNodeConfig.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;      
  mdmaLinkNodeConfig.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;        
  mdmaLinkNodeConfig.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                                 
  mdmaLinkNodeConfig.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;         
  mdmaLinkNodeConfig.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;           
  mdmaLinkNodeConfig.Init.BufferTransferLength = 32;
  
  mdmaLinkNodeConfig.Init.SourceBlockAddressOffset  = 0;
  mdmaLinkNodeConfig.Init.DestBlockAddressOffset    = LCD_Offset;
  
  /* MDMA Post request address and  Mask set respectively to the LTDC Interrupt Clear register address
     and the Clear Line Interrupt Flag mask in order to clear the LTDC Line Interrupt flag
     after each transfer knowing that this last flag is the MDMA transfer trigger
  */  
  mdmaLinkNodeConfig.PostRequestMaskAddress = (uint32_t)(&(LTDC->ICR));
  mdmaLinkNodeConfig.PostRequestMaskData = LTDC_ICR_CLIF;
  
  /* Destination Address is set to the LCD_FRAME_BUFFER address*/
  mdmaLinkNodeConfig.DstAddress      = LCD_FRAME_BUFFER;
  /* BlockDataLength is set to the size in bytes of the image width (line size) */
  mdmaLinkNodeConfig.BlockDataLength = IMAGE_WIDTH * ARGB8888_BYTES_PER_PIXEL;
  /* BlockCount is set to the image height (number of lines) */
  mdmaLinkNodeConfig.BlockCount      = IMAGE_HEIGHT;

  /* Source Address is set to the first image address */  
  mdmaLinkNodeConfig.SrcAddress = Nodes_SourceAddress[0];
  
  /* Create Node 1*/
  HAL_MDMA_LinkedList_CreateNode(&Xfer_Node, &mdmaLinkNodeConfig);
  /*Add created Node to the linkedlist */
  HAL_MDMA_LinkedList_AddNode(&MDMA_Handle, &Xfer_Node, 0);
  
  
  /* Node 2 : Dummy node (inserted to able to wait for Node 1 source address update done by DMA1 stream 0 transfer)
    For this node the MDMA transfer trigger is set to DMA1 stream1 Transfer complete flag.
    Knowing that DMA1 stream1 (circular) transfer is a dummy transfer triggerd by DMA1 Stream0
    transfer event
  */
  mdmaLinkNodeConfig.Init.Request              = MDMA_REQUEST_DMA1_Stream1_TC;
  mdmaLinkNodeConfig.Init.TransferTriggerMode  = MDMA_BUFFER_TRANSFER;
  mdmaLinkNodeConfig.Init.Priority             = MDMA_PRIORITY_HIGH;         
  mdmaLinkNodeConfig.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;         
  
  mdmaLinkNodeConfig.Init.SourceInc            = MDMA_SRC_INC_WORD;     
  mdmaLinkNodeConfig.Init.DestinationInc       = MDMA_DEST_INC_WORD;
  
  mdmaLinkNodeConfig.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;      
  mdmaLinkNodeConfig.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;        
  mdmaLinkNodeConfig.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                                 
  mdmaLinkNodeConfig.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;         
  mdmaLinkNodeConfig.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;           
  mdmaLinkNodeConfig.Init.BufferTransferLength = 32;
  
  mdmaLinkNodeConfig.Init.SourceBlockAddressOffset  = 0;
  mdmaLinkNodeConfig.Init.DestBlockAddressOffset    = 0;
  
  /* MDMA Post request address and  Mask set respectively to the DMA1 stream1 Interrupt Clear register address
     and the DMA1 stream1 Clear Transfer Interrurpt flag mask in order to clear the DMA1 stream1
     Transfer complete flag
  */   
  mdmaLinkNodeConfig.PostRequestMaskAddress = (uint32_t)(&(DMA1->LIFCR));
  mdmaLinkNodeConfig.PostRequestMaskData = DMA_LIFCR_CTCIF1;
  
  /* Source and destination address are dummy , BlockDataLength  is 4 bytes and block count is 1*/
  mdmaLinkNodeConfig.DstAddress      = (uint32_t)(&dummy_destination);
  mdmaLinkNodeConfig.BlockDataLength = 4;
  mdmaLinkNodeConfig.BlockCount      = 1;

  mdmaLinkNodeConfig.SrcAddress = (uint32_t)(&dummy_source);
  
  HAL_MDMA_LinkedList_CreateNode(&Xfer_DummyNode, &mdmaLinkNodeConfig);
  /*Add created Node to the linkedlist */
  HAL_MDMA_LinkedList_AddNode(&MDMA_Handle, &Xfer_DummyNode, 0);  

  
  /* Make the linked list circular */
  HAL_MDMA_LinkedList_EnableCircularMode(&MDMA_Handle);

  /*
    As the MDMA Node descriptor "Xfer_Node" is located in the D1 AXI-SRAM which
    is cacheable, it is necessary to clean the data cache after creating the node
    in order to make sure that the MDMA will load up to date data from the linked list node
  */
  SCB_CleanDCache_by_Addr((uint32_t *)&(Xfer_Node), sizeof(MDMA_LinkNodeTypeDef));
  SCB_CleanDCache_by_Addr((uint32_t *)&(Xfer_DummyNode), sizeof(MDMA_LinkNodeTypeDef));
  
  /*##-6- Select Callbacks functions called in case of  MDMA Transfer error */
  HAL_MDMA_RegisterCallback(&MDMA_Handle, HAL_MDMA_XFER_ERROR_CB_ID, MDMA_TransferErrorCallback);
  
  /*##-7- Configure NVIC for MDMA transfer complete/error interrupts ##########*/
  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriority(MDMA_IRQn, 0, 0);
  
  /* Enable the MDMA channel global Interrupt */
  HAL_NVIC_EnableIRQ(MDMA_IRQn);  
}


void DMA_Config(void)
{
  HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams;
  HAL_DMA_MuxSyncConfigTypeDef dmamux_syncParams;
  
  /* Enable BDMA clock */
  __HAL_RCC_DMA1_CLK_ENABLE();
  
  /* Configure DMA1_Stream0     */
  /* DMA mode is set to circular for an infinite DMA transfer :
     This transfer is used to update the MDMA Node 1 source address
     to the next image address each time.
     This transfer is triggered by the DMA request generator 0 with Signal ID set to
     LPTIM1 output knoing that the LPTIM1 is configured with 100ms auto-reload
  */  
  DMA_Handlel1.Instance                 = DMA1_Stream0;
  
  DMA_Handlel1.Init.Request             = DMA_REQUEST_GENERATOR0;  
  DMA_Handlel1.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  DMA_Handlel1.Init.PeriphInc           = DMA_PINC_DISABLE;
  DMA_Handlel1.Init.MemInc              = DMA_MINC_ENABLE;
  DMA_Handlel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  DMA_Handlel1.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  DMA_Handlel1.Init.Mode                = DMA_CIRCULAR;
  DMA_Handlel1.Init.Priority            = DMA_PRIORITY_LOW;
  DMA_Handlel1.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
  DMA_Handlel1.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  DMA_Handlel1.Init.MemBurst            = DMA_MBURST_SINGLE;
  DMA_Handlel1.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  
  DMA_Handlel1.XferCpltCallback         = NULL;
  DMA_Handlel1.XferErrorCallback        = NULL;
  
  /* Initialize the DMA with for Transmission process */
  HAL_DMA_Init(&DMA_Handlel1);
  
  /*##-3- Configure and enable the DMAMUX Request generator  ####################*/
  dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_LPTIM1_OUT; /* External request signal is EXTI0 signal */
  dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;      /* External request signal edge is Rising  */
  dmamux_ReqGenParams.RequestNumber = 1;                          /* 1 requests on each edge of the external request signal  */
  
  /* Configure the DMAMUX Synchronization with Synchro disabled and event generation enabled
     in order to generate an evenet on each transfer request that will trig the second DMA (DMA_Handlel2)
  */
  dmamux_syncParams.EventEnable    = ENABLE;                 /* Enable DMAMUX event generation each time  RequestNumber are passed from DMAMUX to the DMA */
  dmamux_syncParams.SyncPolarity  = HAL_DMAMUX_SYNC_RISING;  /* Synchronization edge is Rising  */
  dmamux_syncParams.RequestNumber = 1;                       /* 1 requests are autorized after each edge of the sync signal */
  dmamux_syncParams.SyncSignalID  = 0;                       /* No need for synchro signal as the   Synchronization is disabled */
  dmamux_syncParams.SyncEnable     = DISABLE;                /* Synchronization is disabled */   
  
  HAL_DMAEx_ConfigMuxSync(&DMA_Handlel1, &dmamux_syncParams);
  
  
  HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handlel1, &dmamux_ReqGenParams);
  HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handlel1);
  
/* Config DMA1_Stream1 */
/* DMA mode is set to circular for an infinite DMA transfer.
    This transfer is adummy transfer synchronized with DMA1 Stream0 transfer event.
    The MDMA Node2 is a dummy transfer that is triggered with this DMA1 stream1 transfer compelete
    which indicates that DMA1 Stream0 has updated the Node1 source address with the next image address
*/  
  DMA_Handlel2.Instance                 = DMA1_Stream1;
  
  DMA_Handlel2.Init.Request             = DMA_REQUEST_GENERATOR1;  
  DMA_Handlel2.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  DMA_Handlel2.Init.PeriphInc           = DMA_PINC_DISABLE;
  DMA_Handlel2.Init.MemInc              = DMA_MINC_DISABLE;
  DMA_Handlel2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  DMA_Handlel2.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  DMA_Handlel2.Init.Mode                = DMA_CIRCULAR;
  DMA_Handlel2.Init.Priority            = DMA_PRIORITY_LOW;
  DMA_Handlel2.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
  DMA_Handlel2.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  DMA_Handlel2.Init.MemBurst            = DMA_MBURST_SINGLE;
  DMA_Handlel2.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  
  DMA_Handlel2.XferCpltCallback         = NULL;
  DMA_Handlel2.XferErrorCallback        = NULL;
  
  /* Initialize the DMA with for Transmission process */
  HAL_DMA_Init(&DMA_Handlel2);
  
  /*##-3- Configure and enable the DMAMUX Request generator  ####################*/
  dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH0_EVT; /* External request signal DMAMUX1 CH0 event : i.e DMA1_Steam0 event */
  dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;           /* External request signal edge is Rising  */
  dmamux_ReqGenParams.RequestNumber = 1;                                   /* 1 requests on each edge of the external request signal  */
  
  HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handlel2, &dmamux_ReqGenParams);
  HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handlel2);
  
  /* Start DMAs*/
  HAL_DMA_Start_IT(&DMA_Handlel1, (uint32_t)Nodes_SourceAddress, (uint32_t)(&(Xfer_Node.CSAR)), MDMA_IMAGE_NB);
  HAL_DMA_Start_IT(&DMA_Handlel2, (uint32_t)(&dummy_source), (uint32_t)(&dummy_destination), 1);

}

/**
  * @brief  Configure and start the LPTIM1 with 100ms period and 50% duty cycle.
  * @param  None
  * @retval None
  */
void LPTIM_Config(void)
{

  uint32_t periodValue;
  uint32_t pulseValue ;
  
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
  
  
  /* Enable the LSE clock source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.PLL.PLLState  = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);
  
  /* LPTIM1 clock source set to LSE*/
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  PeriphClkInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);  

  periodValue =  (2 * (LSE_VALUE/20))/4;  /* Calculate the Timer  Autoreload value for 100ms period */
  pulseValue  = periodValue/2;            /* Set the Timer  pulse value for 50% duty cycle         */
  
  /* TIM1 Peripheral clock enable */
  __HAL_RCC_LPTIM1_CLK_ENABLE();
  
  LptimHandle.Instance                           = LPTIM1;

  LptimHandle.Init.CounterSource                 = LPTIM_COUNTERSOURCE_INTERNAL;
  LptimHandle.Init.UpdateMode                    = LPTIM_UPDATE_ENDOFPERIOD;
  LptimHandle.Init.OutputPolarity                = LPTIM_OUTPUTPOLARITY_LOW;
  LptimHandle.Init.Clock.Source                  = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
  LptimHandle.Init.Clock.Prescaler               = LPTIM_PRESCALER_DIV4;
  LptimHandle.Init.UltraLowPowerClock.Polarity   = LPTIM_CLOCKPOLARITY_RISING;
  LptimHandle.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
  LptimHandle.Init.Trigger.Source                = LPTIM_TRIGSOURCE_SOFTWARE;
  LptimHandle.Init.Trigger.ActiveEdge            = LPTIM_ACTIVEEDGE_RISING;
  LptimHandle.Init.Trigger.SampleTime            = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;

  if(HAL_LPTIM_Init(&LptimHandle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  
  /* Start the timer */
  if (HAL_LPTIM_PWM_Start(&LptimHandle, periodValue, pulseValue) != HAL_OK)
  {
    Error_Handler();
  }  
  
}

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

431

主题

436

帖子

0

粉丝