|
楼主 |
发表于 2022-8-15 19:35:27
|
显示全部楼层
善始善终吧,查过相关资料,最终在官方的Demo中找到了办法。在Cube的DMAMUX_RequestGen例程中有相关的例子。/**
@page DMAMUX_RequestGen DMA & DMAMUX request generator Example
@verbatim
******************** (C) COPYRIGHT 2017 STMicroelectronics *******************
* @file DMA/DMAMUX_RequestGen/readme.txt
* @author MCD Application Team
* @brief Description of the DMA & request generator Example.
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
@endverbatim
@par Example Description
This example shows how to use the DMA with the DMAMUX request generator to generate DMA transfer requests upon
an EXTI0 rising edge signal.
The example uses the BDMA channel 0 configured in memory to peripheral mode.
The DMA request is set to the DMAMUX request generator 0.
At the beginning of the main program the HAL_Init() function is called to reset
all the peripherals, initialize the Flash interface and the systick.
The SystemClock_Config() function is used to configure the system clock for STM32H743xx Devices :
The CPU at 400MHz
The HCLK for D1 Domain AXI and AHB3 peripherals , D2 Domain AHB1/AHB2 peripherals and D3 Domain AHB4 peripherals at 200MHz.
The APB clock dividers for D1 Domain APB3 peripherals, D2 Domain APB1 and APB2 peripherals and D3 Domain APB4 peripherals to run at 100MHz.
The BDMA channel 0 is configured in memory to peripheral mode to ensure data transfer from the source transmission
buffer (SRC_Buffer_LED1_Toggle) to the GPIOF ODR register (in order to toggle LED1).
The DMA is configured in circular mode so the transfer will restart automatically each time the amount of data
to be transmitted has been reached.
@note the Domain 3 BDMA has access to Domain 3 SRAMs and peripherals only, thus the source buffer (SRC_Buffer_LED1_Toggle)
has been placed to the D3 SRAM (@0x38000000)
The DMAMUX request generator block is configured using function "HAL_DMAEx_ConfigMuxRequestGenerator"
with the following parameters :
- SignalID : set to HAL_DMAMUX2_REQUEST_GEN_EXTI0 which corresponds to EXTI0 signal.
- Polarity : Set to RISING to use rising edge the EXTI0 for DMA requests generation.
- RequestNumber : 1 i.e on each rising edge of the EXTI0 signal a DMA request is generated.
The DMA request generator is then enabled using function HAL_DMAEx_EnableMuxRequestGenerator?
The function "EXTI0_IRQHandler_Config" is then used to configure the PA.0 pin to
external Interrupt Mode with Rising edge trigger detection.
Note that the example doesn't need to enable and set EXTI 0 NVIC Interrupt as the EXTI0
event signal is used to trigger the DMAMUX only and not the CPU.
Then the DMA transfer is started in non-blocking mode using the HAL function "HAL_DMA_Start_IT"
Note that PA.0 pin is connected to the wakeup button of the evaluation board.
Each time the Wakeup button is pressed an EXTI0 event is generated and the DMAMUX will generate a DMA request
upon the rising edge of the EXTI0 signal.
As consequence the DMA will serve the request and write a new value to the GPIOF ODR register to toggle the LED1
without any CPU intervention.
.
The CPU is only used to intercept a DMA transfer interrupt error or a DMAMUX overrun interrupt error if any,
and sets the LED3 (Red LED) to On in this case.
STM32 board's LEDs can be used to monitor the transfer status:
- LED1 toggles each time the Wakeup button is pressed .
- LED3 is ON when there is an error during the DMA transfer.
@note Care must be taken when using HAL_Delay(), this function provides accurate delay (in milliseconds)
based on variable incremented in SysTick ISR. This implies that if HAL_Delay() is called from
a peripheral ISR process, then the SysTick interrupt must have higher priority (numerically lower)
than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
To change the SysTick interrupt priority you have to use HAL_NVIC_SetPriority() function.
@note The application needs to ensure that the SysTick time base is always set to 1 millisecond
to have correct HAL operation.
@Note If the application is using the DTCM/ITCM memories (@0x20000000/ 0x0000000: not cacheable and only accessible
by the Cortex M7 and the MDMA), no need for cache maintenance when the Cortex M7 and the MDMA access these RAMs.
@note If the application needs to use DMA(or other masters) based access or requires more RAM, then the user has to:
- Use a non TCM SRAM. (example : D1 AXI-SRAM @ 0x24000000)
- Add a cache maintenance mechanism to ensure the cache coherence between CPU and other masters(DMAs,DMA2D,LTDC,MDMA).
- The addresses and the size of cacheable buffers (shared between CPU and other masters) must be properly defined to be aligned to L1-CACHE line size (32 bytes).
?
@Note It is recommended to enable the cache and maintain its coherence.
Depending on the use case it is also possible to configure the cache attributes using the MPU.
牋牋牋Please refer to the AN4838 "Managing memory protection unit (MPU) in STM32 MCUs"
牋牋牋Please refer to the AN4839 "Level 1 cache on STM32F7 Series"
@par Keywords
System, DMA, DMAMUX, Request generator, Data Transfer, Stream
@par Directory contents
- DMA/DMAMUX_RequestGen/Inc/stm32h7xx_hal_conf.h HAL configuration file
- DMA/DMAMUX_RequestGen/Inc/stm32h7xx_it.h DMA interrupt handlers header file
- DMA/DMAMUX_RequestGen/Inc/main.h Header for main.c module
- DMA/DMAMUX_RequestGen/Src/stm32h7xx_it.c DMA interrupt handlers
- DMA/DMAMUX_RequestGen/Src/main.c Main program
- DMA/DMAMUX_RequestGen/Src/system_stm32h7xx.c STM32H7xx system source file
@par Hardware and Software environment
- This example runs on STM32H743xx device.
- This example has been tested with STM32H743I-EVAL board and can be
easily tailored to any other supported device and development board.
@par How to use it ?
In order to make the program work, you must do the following :
- Open your preferred toolchain
- Rebuild all files and load your image into target memory
- Run the example
*/
/**
******************************************************************************
* @file DMA/DMAMUX_RequestGen/Src/main.c
* @author MCD Application Team
* @brief This example shows how to use the DMA with the DMAMUX to
* request generator using the STM32H7xx HAL API.
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/** @addtogroup STM32H7xx_HAL_Examples
* @{
*/
/** @defgroup DMAMUX_RequestGen
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint32_t DMA_TransferErrorFlag = 0;
/*Buffer location and size should aligned to cache line size (32 bytes) */
#if defined ( __ICCARM__ )
#pragma location = 0x38000000
uint32_t SRC_Buffer_LED1_Toggle[2] =
{ 0, /*Value for LED 1 ON */
LED1_PIN /*Value for LED 1 OFF */
};
#elif defined ( __CC_ARM )
ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint32_t SRC_Buffer_LED1_Toggle[2]) =
{ 0, /*Value for LED 1 ON */
LED1_PIN /*Value for LED 1 OFF */
};
#elif defined ( __GNUC__ )
ALIGN_32BYTES(uint32_t __attribute__((section (".RAM_D3"))) SRC_Buffer_LED1_Toggle[2]) =
{ 0, /*Value for LED 1 ON */
LED1_PIN /*Value for LED 1 OFF */
};
#endif
DMA_HandleTypeDef DMA_Handle;
/* Private function prototypes -----------------------------------------------*/
static void MPU_Config(void);
static void SystemClock_Config(void);
static void CPU_CACHE_Enable(void);
static void EXTI0_IRQHandler_Config(void);
static void HAL_TransferError(DMA_HandleTypeDef *hdma);
static void Error_Handler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams;
/* Configure the MPU attributes */
MPU_Config();
/* Enable the CPU Cache */
CPU_CACHE_Enable();
/* STM32H7xx HAL library initialization:
- Systick timer is configured by default as source of time base, but user
can eventually implement his proper time base source (a general purpose
timer for example or other time source), keeping in mind that Time base
duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
handled in milliseconds basis.
- Set NVIC Group Priority to 4
- Low Level Initialization
*/
HAL_Init();
/* Configure the system clock to 400 MHz */
SystemClock_Config();
/* -1- Initialize LEDs mounted on STM32H743I-EVAL board */
BSP_LED_Init(LED1);
BSP_LED_Init(LED3);
/*##-2- Configure the DMA ##################################################*/
/* Enable BDMA clock */
__HAL_RCC_BDMA_CLK_ENABLE();
/* Configure the DMA handler for Transmission process */
/* DMA mode is set to circular for an infinite DMA transfer */
DMA_Handle.Instance = BDMA_Channel0;
DMA_Handle.Init.Request = BDMA_REQUEST_GENERATOR0;
DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
DMA_Handle.Init.Mode = DMA_CIRCULAR;
DMA_Handle.Init.Priority = DMA_PRIORITY_LOW;
DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;
/* Initialize the DMA with for Transmission process */
HAL_DMA_Init(&DMA_Handle);
/* Select Callbacks functions called after Transfer complete and Transfer error */
HAL_DMA_RegisterCallback(&DMA_Handle, HAL_DMA_XFER_CPLT_CB_ID, NULL);
HAL_DMA_RegisterCallback(&DMA_Handle, HAL_DMA_XFER_ERROR_CB_ID, HAL_TransferError);
/* NVIC configuration for DMA transfer complete interrupt*/
HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
/*##-3- Configure and enable the DMAMUX Request generator ####################*/
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0; /* 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 */
HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams);
/* NVIC configuration for DMAMUX request generator overrun errors*/
HAL_NVIC_SetPriority(DMAMUX2_OVR_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(DMAMUX2_OVR_IRQn);
HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);
/*##-4- Configure and enable the EXTI0 used as DMA external request signal #####*/
EXTI0_IRQHandler_Config();
/*##-5- Start the DMA transfer ################################################*/
/* DMA source buffer is SRC_BUFFER_LED1_TOGGLE containing values to be written
to GPIOF ODR register in order to turn LED1 On/Off each time comes a request from the DMAMUX request generator */
HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)SRC_Buffer_LED1_Toggle, (uint32_t)&GPIOF->ODR, 2);
/* Infinite loop */
while (1)
{
if(DMA_TransferErrorFlag != 0)
{
Error_Handler();
}
}
}
/**
* @brief Configures EXTI lines 0 (connected to PA.0 pin) in interrupt mode
* @param None
* @retval None
*/
static void EXTI0_IRQHandler_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure PA.0 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_0;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* the example doesn抰 need to enable and set EXTI 0 NVIC Interrupt as the EXTI0
event signal is used to trigger the DMAMUX only and not the CPU
*/
}
static void HAL_TransferError(DMA_HandleTypeDef *hdma)
{
DMA_TransferErrorFlag = 1;
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* Turn LED3 on */
BSP_LED_On(LED3);
while(1)
{
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 400000000 (CPU Clock)
* HCLK(Hz) = 200000000 (AXI and AHBs Clock)
* AHB Prescaler = 2
* D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
* D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
* D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
* D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
* HSE Frequency(Hz) = 25000000
* PLL_M = 5
* PLL_N = 160
* PLL_P = 2
* PLL_Q = 4
* PLL_R = 2
* VDD(V) = 3.3
* Flash Latency(WS) = 4
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
HAL_StatusTypeDef ret = HAL_OK;
/*!< Supply configuration update enable */
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;
RCC_OscInitStruct.PLL.PLLN = 160;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLQ = 4;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret != HAL_OK)
{
while(1) { ; }
}
/* Select PLL as system clock source and configure bus clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if(ret != HAL_OK)
{
while(1) { ; }
}
}
/**
* @brief CPU L1-Cache enable.
* @param None
* @retval None
*/
static void CPU_CACHE_Enable(void)
{
/* Enable I-Cache */
SCB_EnableICache();
/* Enable D-Cache */
SCB_EnableDCache();
}
/**
* @brief Configure the MPU attributes
* @param None
* @retval None
*/
static void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* Disable the MPU */
HAL_MPU_Disable();
/* Configure the MPU as Strongly ordered for not defined regions */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x00;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enable the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
|
|