|
例程说明:
这个例子比较的复杂,应该是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();
- }
-
- }
复制代码
|
|