硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1509|回复: 0
收起左侧

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

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106997
QQ
发表于 2018-8-12 02:28:01 | 显示全部楼层 |阅读模式
例程说明:

这个例子比较的复杂,应该是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
                                                                                                                               从而实现循环模式不断循环执行。

配置如下:
  1. /**
  2.   * @brief  Initialize the MDMA For repeat block transfer in linked list circular
  3.     repeat block transfer.
  4.   * @param  None
  5.   * @retval None
  6.   */
  7. static void MDMA_Config(void)
  8. {
  9.   uint32_t hal_status = HAL_OK;  
  10.   MDMA_LinkNodeConfTypeDef mdmaLinkNodeConfig;   
  11.    
  12.   /*##-1- Enable the MDMA clock ###############################################*/  
  13.   __HAL_RCC_MDMA_CLK_ENABLE();  
  14.   
  15.   /*##-2- Select the MDMA instance to be used : MDMA_Channel0 #################*/
  16.   MDMA_Handle.Instance = MDMA_Channel0;  
  17.   
  18.   /*##-3- Configure the MDMA for block transfer in HW request mode ############*/  
  19.   /*
  20.      This is the Node 0 of the linked list, node 0 will be executed only one time
  21.      to clear the LCD frame buffer with default color
  22.   */
  23.   
  24.   MDMA_Handle.Init.Request              = MDMA_REQUEST_LTDC_LINE_IT;
  25.   MDMA_Handle.Init.TransferTriggerMode  = MDMA_REPEAT_BLOCK_TRANSFER;  
  26.   MDMA_Handle.Init.Priority             = MDMA_PRIORITY_HIGH;
  27.   MDMA_Handle.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;
  28.   MDMA_Handle.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                           
  29.   MDMA_Handle.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;
  30.   MDMA_Handle.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;
  31.   MDMA_Handle.Init.BufferTransferLength = 32;
  32.   
  33.   /* Source and Destination data size are word , 4 bytes that correspond to an ARGB8888 pixel 32 bpp */     
  34.   MDMA_Handle.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;
  35.   MDMA_Handle.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;

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

  41.   /* Source block offset set to Zero : no increment of the source block address */
  42.   MDMA_Handle.Init.SourceBlockAddressOffset  = 0;
  43.   
  44.   /* Destination block offset set to LCD_Offset */
  45.   MDMA_Handle.Init.DestBlockAddressOffset    = LCD_Offset;   
  46.   
  47.   /*##-4- Initialize the MDMA channel ##########################################*/  
  48.   hal_status = HAL_MDMA_Init(&MDMA_Handle);
  49.   
  50.   if(hal_status != HAL_OK)  
  51.   {
  52.     /* Initialization Error */
  53.     Error_Handler();
  54.   }

  55.   /* MDMA Post request address and  Mask set respecetevly to the LTDC Interrupt Clear register address
  56.      and the Clear Line Interrupt Flag mask in order to clear the LTDC Line Interrupt flag
  57.      after each transfer knowing that this last flag is the MDMA transfer trigger
  58.   */
  59.   HAL_MDMA_ConfigPostRequestMask(&MDMA_Handle, (uint32_t)(&(LTDC->ICR)), LTDC_ICR_CLIF);
  60.   
  61.   /*##-5- Create Linked list Nodes ############################################*/
  62.   
  63.   /* Node 1 : First node is used to transfer an image from the flash to the LCD frame buffer
  64.     The MDMA transfer trigger is set to the LTDC Line Interrupt flag.
  65.   */
  66.   mdmaLinkNodeConfig.Init.Request              = MDMA_REQUEST_LTDC_LINE_IT;
  67.   mdmaLinkNodeConfig.Init.TransferTriggerMode  = MDMA_REPEAT_BLOCK_TRANSFER;
  68.   mdmaLinkNodeConfig.Init.Priority             = MDMA_PRIORITY_HIGH;         
  69.   mdmaLinkNodeConfig.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;         
  70.   
  71.   mdmaLinkNodeConfig.Init.SourceInc            = MDMA_SRC_INC_WORD;     
  72.   mdmaLinkNodeConfig.Init.DestinationInc       = MDMA_DEST_INC_WORD;
  73.   
  74.   mdmaLinkNodeConfig.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;      
  75.   mdmaLinkNodeConfig.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;        
  76.   mdmaLinkNodeConfig.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                                 
  77.   mdmaLinkNodeConfig.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;         
  78.   mdmaLinkNodeConfig.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;           
  79.   mdmaLinkNodeConfig.Init.BufferTransferLength = 32;
  80.   
  81.   mdmaLinkNodeConfig.Init.SourceBlockAddressOffset  = 0;
  82.   mdmaLinkNodeConfig.Init.DestBlockAddressOffset    = LCD_Offset;
  83.   
  84.   /* MDMA Post request address and  Mask set respectively to the LTDC Interrupt Clear register address
  85.      and the Clear Line Interrupt Flag mask in order to clear the LTDC Line Interrupt flag
  86.      after each transfer knowing that this last flag is the MDMA transfer trigger
  87.   */  
  88.   mdmaLinkNodeConfig.PostRequestMaskAddress = (uint32_t)(&(LTDC->ICR));
  89.   mdmaLinkNodeConfig.PostRequestMaskData = LTDC_ICR_CLIF;
  90.   
  91.   /* Destination Address is set to the LCD_FRAME_BUFFER address*/
  92.   mdmaLinkNodeConfig.DstAddress      = LCD_FRAME_BUFFER;
  93.   /* BlockDataLength is set to the size in bytes of the image width (line size) */
  94.   mdmaLinkNodeConfig.BlockDataLength = IMAGE_WIDTH * ARGB8888_BYTES_PER_PIXEL;
  95.   /* BlockCount is set to the image height (number of lines) */
  96.   mdmaLinkNodeConfig.BlockCount      = IMAGE_HEIGHT;

  97.   /* Source Address is set to the first image address */  
  98.   mdmaLinkNodeConfig.SrcAddress = Nodes_SourceAddress[0];
  99.   
  100.   /* Create Node 1*/
  101.   HAL_MDMA_LinkedList_CreateNode(&Xfer_Node, &mdmaLinkNodeConfig);
  102.   /*Add created Node to the linkedlist */
  103.   HAL_MDMA_LinkedList_AddNode(&MDMA_Handle, &Xfer_Node, 0);
  104.   
  105.   
  106.   /* Node 2 : Dummy node (inserted to able to wait for Node 1 source address update done by DMA1 stream 0 transfer)
  107.     For this node the MDMA transfer trigger is set to DMA1 stream1 Transfer complete flag.
  108.     Knowing that DMA1 stream1 (circular) transfer is a dummy transfer triggerd by DMA1 Stream0
  109.     transfer event
  110.   */
  111.   mdmaLinkNodeConfig.Init.Request              = MDMA_REQUEST_DMA1_Stream1_TC;
  112.   mdmaLinkNodeConfig.Init.TransferTriggerMode  = MDMA_BUFFER_TRANSFER;
  113.   mdmaLinkNodeConfig.Init.Priority             = MDMA_PRIORITY_HIGH;         
  114.   mdmaLinkNodeConfig.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;         
  115.   
  116.   mdmaLinkNodeConfig.Init.SourceInc            = MDMA_SRC_INC_WORD;     
  117.   mdmaLinkNodeConfig.Init.DestinationInc       = MDMA_DEST_INC_WORD;
  118.   
  119.   mdmaLinkNodeConfig.Init.SourceDataSize       = MDMA_SRC_DATASIZE_WORD;      
  120.   mdmaLinkNodeConfig.Init.DestDataSize         = MDMA_DEST_DATASIZE_WORD;        
  121.   mdmaLinkNodeConfig.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;                                 
  122.   mdmaLinkNodeConfig.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;         
  123.   mdmaLinkNodeConfig.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;           
  124.   mdmaLinkNodeConfig.Init.BufferTransferLength = 32;
  125.   
  126.   mdmaLinkNodeConfig.Init.SourceBlockAddressOffset  = 0;
  127.   mdmaLinkNodeConfig.Init.DestBlockAddressOffset    = 0;
  128.   
  129.   /* MDMA Post request address and  Mask set respectively to the DMA1 stream1 Interrupt Clear register address
  130.      and the DMA1 stream1 Clear Transfer Interrurpt flag mask in order to clear the DMA1 stream1
  131.      Transfer complete flag
  132.   */   
  133.   mdmaLinkNodeConfig.PostRequestMaskAddress = (uint32_t)(&(DMA1->LIFCR));
  134.   mdmaLinkNodeConfig.PostRequestMaskData = DMA_LIFCR_CTCIF1;
  135.   
  136.   /* Source and destination address are dummy , BlockDataLength  is 4 bytes and block count is 1*/
  137.   mdmaLinkNodeConfig.DstAddress      = (uint32_t)(&dummy_destination);
  138.   mdmaLinkNodeConfig.BlockDataLength = 4;
  139.   mdmaLinkNodeConfig.BlockCount      = 1;

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

  145.   
  146.   /* Make the linked list circular */
  147.   HAL_MDMA_LinkedList_EnableCircularMode(&MDMA_Handle);

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


  166. void DMA_Config(void)
  167. {
  168.   HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams;
  169.   HAL_DMA_MuxSyncConfigTypeDef dmamux_syncParams;
  170.   
  171.   /* Enable BDMA clock */
  172.   __HAL_RCC_DMA1_CLK_ENABLE();
  173.   
  174.   /* Configure DMA1_Stream0     */
  175.   /* DMA mode is set to circular for an infinite DMA transfer :
  176.      This transfer is used to update the MDMA Node 1 source address
  177.      to the next image address each time.
  178.      This transfer is triggered by the DMA request generator 0 with Signal ID set to
  179.      LPTIM1 output knoing that the LPTIM1 is configured with 100ms auto-reload
  180.   */  
  181.   DMA_Handlel1.Instance                 = DMA1_Stream0;
  182.   
  183.   DMA_Handlel1.Init.Request             = DMA_REQUEST_GENERATOR0;  
  184.   DMA_Handlel1.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  185.   DMA_Handlel1.Init.PeriphInc           = DMA_PINC_DISABLE;
  186.   DMA_Handlel1.Init.MemInc              = DMA_MINC_ENABLE;
  187.   DMA_Handlel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  188.   DMA_Handlel1.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  189.   DMA_Handlel1.Init.Mode                = DMA_CIRCULAR;
  190.   DMA_Handlel1.Init.Priority            = DMA_PRIORITY_LOW;
  191.   DMA_Handlel1.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
  192.   DMA_Handlel1.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  193.   DMA_Handlel1.Init.MemBurst            = DMA_MBURST_SINGLE;
  194.   DMA_Handlel1.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  195.   
  196.   DMA_Handlel1.XferCpltCallback         = NULL;
  197.   DMA_Handlel1.XferErrorCallback        = NULL;
  198.   
  199.   /* Initialize the DMA with for Transmission process */
  200.   HAL_DMA_Init(&DMA_Handlel1);
  201.   
  202.   /*##-3- Configure and enable the DMAMUX Request generator  ####################*/
  203.   dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_LPTIM1_OUT; /* External request signal is EXTI0 signal */
  204.   dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;      /* External request signal edge is Rising  */
  205.   dmamux_ReqGenParams.RequestNumber = 1;                          /* 1 requests on each edge of the external request signal  */
  206.   
  207.   /* Configure the DMAMUX Synchronization with Synchro disabled and event generation enabled
  208.      in order to generate an evenet on each transfer request that will trig the second DMA (DMA_Handlel2)
  209.   */
  210.   dmamux_syncParams.EventEnable    = ENABLE;                 /* Enable DMAMUX event generation each time  RequestNumber are passed from DMAMUX to the DMA */
  211.   dmamux_syncParams.SyncPolarity  = HAL_DMAMUX_SYNC_RISING;  /* Synchronization edge is Rising  */
  212.   dmamux_syncParams.RequestNumber = 1;                       /* 1 requests are autorized after each edge of the sync signal */
  213.   dmamux_syncParams.SyncSignalID  = 0;                       /* No need for synchro signal as the   Synchronization is disabled */
  214.   dmamux_syncParams.SyncEnable     = DISABLE;                /* Synchronization is disabled */   
  215.   
  216.   HAL_DMAEx_ConfigMuxSync(&DMA_Handlel1, &dmamux_syncParams);
  217.   
  218.   
  219.   HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handlel1, &dmamux_ReqGenParams);
  220.   HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handlel1);
  221.   
  222. /* Config DMA1_Stream1 */
  223. /* DMA mode is set to circular for an infinite DMA transfer.
  224.     This transfer is adummy transfer synchronized with DMA1 Stream0 transfer event.
  225.     The MDMA Node2 is a dummy transfer that is triggered with this DMA1 stream1 transfer compelete
  226.     which indicates that DMA1 Stream0 has updated the Node1 source address with the next image address
  227. */  
  228.   DMA_Handlel2.Instance                 = DMA1_Stream1;
  229.   
  230.   DMA_Handlel2.Init.Request             = DMA_REQUEST_GENERATOR1;  
  231.   DMA_Handlel2.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  232.   DMA_Handlel2.Init.PeriphInc           = DMA_PINC_DISABLE;
  233.   DMA_Handlel2.Init.MemInc              = DMA_MINC_DISABLE;
  234.   DMA_Handlel2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  235.   DMA_Handlel2.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;
  236.   DMA_Handlel2.Init.Mode                = DMA_CIRCULAR;
  237.   DMA_Handlel2.Init.Priority            = DMA_PRIORITY_LOW;
  238.   DMA_Handlel2.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
  239.   DMA_Handlel2.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  240.   DMA_Handlel2.Init.MemBurst            = DMA_MBURST_SINGLE;
  241.   DMA_Handlel2.Init.PeriphBurst         = DMA_PBURST_SINGLE;
  242.   
  243.   DMA_Handlel2.XferCpltCallback         = NULL;
  244.   DMA_Handlel2.XferErrorCallback        = NULL;
  245.   
  246.   /* Initialize the DMA with for Transmission process */
  247.   HAL_DMA_Init(&DMA_Handlel2);
  248.   
  249.   /*##-3- Configure and enable the DMAMUX Request generator  ####################*/
  250.   dmamux_ReqGenParams.SignalID  = HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH0_EVT; /* External request signal DMAMUX1 CH0 event : i.e DMA1_Steam0 event */
  251.   dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING;           /* External request signal edge is Rising  */
  252.   dmamux_ReqGenParams.RequestNumber = 1;                                   /* 1 requests on each edge of the external request signal  */
  253.   
  254.   HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handlel2, &dmamux_ReqGenParams);
  255.   HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handlel2);
  256.   
  257.   /* Start DMAs*/
  258.   HAL_DMA_Start_IT(&DMA_Handlel1, (uint32_t)Nodes_SourceAddress, (uint32_t)(&(Xfer_Node.CSAR)), MDMA_IMAGE_NB);
  259.   HAL_DMA_Start_IT(&DMA_Handlel2, (uint32_t)(&dummy_source), (uint32_t)(&dummy_destination), 1);

  260. }

  261. /**
  262.   * @brief  Configure and start the LPTIM1 with 100ms period and 50% duty cycle.
  263.   * @param  None
  264.   * @retval None
  265.   */
  266. void LPTIM_Config(void)
  267. {

  268.   uint32_t periodValue;
  269.   uint32_t pulseValue ;
  270.   
  271.   RCC_OscInitTypeDef RCC_OscInitStruct;
  272.   RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
  273.   
  274.   
  275.   /* Enable the LSE clock source */
  276.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
  277.   RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  278.   RCC_OscInitStruct.PLL.PLLState  = RCC_PLL_NONE;
  279.   HAL_RCC_OscConfig(&RCC_OscInitStruct);
  280.   
  281.   /* LPTIM1 clock source set to LSE*/
  282.   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
  283.   PeriphClkInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
  284.   HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);  

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

  292.   LptimHandle.Init.CounterSource                 = LPTIM_COUNTERSOURCE_INTERNAL;
  293.   LptimHandle.Init.UpdateMode                    = LPTIM_UPDATE_ENDOFPERIOD;
  294.   LptimHandle.Init.OutputPolarity                = LPTIM_OUTPUTPOLARITY_LOW;
  295.   LptimHandle.Init.Clock.Source                  = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
  296.   LptimHandle.Init.Clock.Prescaler               = LPTIM_PRESCALER_DIV4;
  297.   LptimHandle.Init.UltraLowPowerClock.Polarity   = LPTIM_CLOCKPOLARITY_RISING;
  298.   LptimHandle.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
  299.   LptimHandle.Init.Trigger.Source                = LPTIM_TRIGSOURCE_SOFTWARE;
  300.   LptimHandle.Init.Trigger.ActiveEdge            = LPTIM_ACTIVEEDGE_RISING;
  301.   LptimHandle.Init.Trigger.SampleTime            = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;

  302.   if(HAL_LPTIM_Init(&LptimHandle) != HAL_OK)
  303.   {
  304.     /* Initialization Error */
  305.     Error_Handler();
  306.   }
  307.   
  308.   /* Start the timer */
  309.   if (HAL_LPTIM_PWM_Start(&LptimHandle, periodValue, pulseValue) != HAL_OK)
  310.   {
  311.     Error_Handler();
  312.   }  
  313.   
  314. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-14 03:39 , Processed in 0.250043 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表