Notas de estudio de STM32CubeMX (7) -Uso de la interfaz DMA

1. Introducción a DMA

DMA (Direct Memory Access) es un periférico del microordenador de un solo chip. Su función principal es mover datos, pero no necesita ocupar la CPU. Es decir, la CPU puede hacer otras cosas al transferir datos. Igual que el multihilo. La transmisión de datos admite desde periféricos a memoria o de memoria a memoria, donde la memoria puede ser SRAM o FLASH. El controlador DMA incluye DMA1 y DMA2. Entre ellos, DMA1 tiene 7 canales y DMA2 tiene 5. Los canales aquí se pueden entender como una especie de tubería para la transmisión de datos. Cabe señalar que DMA2 solo existe en microcontroladores de gran capacidad.

Dos, imagen de solicitud de DMA

Imagen de solicitud DMA1 de cada canal Imagen de solicitud DMA2 de
Imagen de solicitud DMA1 de cada canal
cada canal
Imagen de solicitud DMA2 de cada canal
其中 ADC3、SDIO 和 TIM8 的 DMA 请求只在大容量产品中存在,这个在具体项目时 要注意。

3. Nueva construcción

1. Abra el software STM32CubeMX y haga clic en "Nuevo proyecto"

2. Elija MCU y paquete

3. Configure los
ajustes de reloj RCC, seleccione HSE (reloj externo de alta velocidad),

seleccione Configuración de reloj para resonador de cristal / cerámica (oscilador de cristal / resonador de cerámica) , configure el reloj del sistema SYSCLK a 72MHz,
modifique el valor de HCLK a 72, y presiona Enter. Modifica automáticamente todas las configuraciones

4. Es
un paso muy importante configurar el modo de depuración ; de lo contrario, la
configuración SYS del depurador no se reconocerá después del primer programa de programación , seleccione Depurar como cable serial

Cuatro, DMA1

4.1 Configurar el puerto serie

En el conjunto de Connectivityselección USART1, seleccione la velocidad en baudios de Asynchronouscomunicación asíncrona . La longitud de los datos transmitidos es . Paridad , bit de parada , recepción y transmisión son todos . Habilitar la interrupción de recepción del puerto serie

115200 Bits/s8 BitNone1使能


4.2 Configurar DMA


Haga clic en DMA SettingsAgregar USART1 TX DMA1 y USART1 RX correspondientes a los canales 4 y 5.

  • Prioridad :
    cuando ocurren múltiples solicitudes de canal DMA, significa que hay un problema de orden de procesamiento de respuesta secuencial, que también es administrado por el árbitro. El árbitro gestiona las solicitudes de canal DMA en dos etapas. La primera etapa pertenece a la etapa de software y se puede configurar en el registro DMA_CCRx Hay 4 niveles: muy alta, alta, media y baja prioridad. La segunda etapa pertenece a la etapa de hardware. Si dos o más solicitudes de canal DMA tienen la misma prioridad, su prioridad depende del número de canal. Cuanto menor sea el número, mayor será la prioridad. Por ejemplo, el canal 0 es mayor que el canal 1. Entre los productos de alta capacidad y los productos interconectados, el controlador DMA1 tiene una prioridad más alta que el controlador DMA2.
  • Modo :
    Normalindica una sola transmisión, la transmisión finaliza después de una transmisión.
    CircularSignifica transmisión cíclica. Después de que se complete la transmisión, la transmisión se reanudará nuevamente y el ciclo continuo nunca se detendrá.
  • Incremento de dirección :
    Peripheralindica que la dirección del periférico aumenta automáticamente.
    MemoryIndica que se incrementa la dirección de memoria.
    Los datos de envío del puerto serie almacenan datos de forma continua en el registro de datos de envío del puerto serie (USARTx_TDR). Entonces, la dirección externa no se incrementa. La memoria interna almacena los datos que se enviarán, por lo que el puntero de dirección debe incrementarse para enviar todos los datos.
  • Ancho de datos :
    Byteun byte.
    Half WordMedia palabra equivale a dos bytes.
    WordUna palabra equivale a cuatro bytes.
    El registro de envío de datos del puerto serie solo puede almacenar 8 bits y enviar un byte a la vez, por lo que la longitud de los datos es Byte.

4.3 Generar código

Nombres de elementos de ruta y

selección de entrada de elementos de un entorno de desarrollo de aplicaciones IDE MDK-ARM V5

cada periférico genera un ’.c/.h’archivo separado ,
no un gancho: Todo el código de inicialización se genera en main.c
verificado: archivo de código de inicialización generado en el periférico asociado. Por ejemplo, el código de inicialización GPIO se genera en gpio.c.

Haga clic en GENERAR CÓDIGO para generar código

4.4 Transmisión de datos USART + DMA

Crea una nueva variable

uint8_t sendBuff[] = "USART test by DMA\r\n";

Agregue el siguiente código al bucle principal en man.c:

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */
    HAL_UART_Transmit_DMA(&huart1, (uint8_t *)sendBuff, sizeof(sendBuff));
    HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

A través del asistente de puerto serie, puede ver que hay una impresión continua de datos en el área de recepción.

Nota: Si la interrupción del puerto serie no está activada, el programa solo puede enviar datos una vez y el programa no puede juzgar si la transferencia DMA se completa y el USART siempre está en estado de ocupado.

4.5 Recepción de datos USART + DMA

Agregue variables globales al encabezado de main.c Buffer

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
uint8_t Buffer[1];
/* USER CODE END PV */

Declare variables globales al principio de stm32f1xx_it.c Buffer

/* External variables --------------------------------------------------------*/
extern UART_HandleTypeDef huart1;

/* USER CODE BEGIN EV */
extern uint8_t Buffer[1];
/* USER CODE END EV */

En main.c, antes del bucle while y después de inicializar el puerto serie, agregue la función de habilitación de interrupción de recepción, de modo que la interrupción se active cuando se reciban los datos por primera vez.

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    
    
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_DMA(&huart1, (uint8_t *)Buffer, 1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Al stm32f1xx_it.cagregar la parte inferior de este documentoHAL_UART_RxCpltCallback()

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    
    
    if(huart->Instance == USART1)
    {
    
    
        HAL_UART_Receive_DMA(&huart1, (uint8_t *)Buffer, 1);
        HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Buffer, 1);
    }
}
/* USER CODE END 1 */

Envíe OK a través del asistente del puerto serie y podrá ver que se recibe O. Esto se debe a que el conjunto de datos recibido es de un carácter. Si desea recibir más caracteres, aumente el búfer.

4.6 Puerto serie IDLE interrupción inactiva + recepción de datos DMA

caracteristicas:

  • Puede recibir y generar cualquier cadena de caracteres.
  • Cuando el puerto serie no tiene recepción de datos, no se generará. Después de que se borre la bandera IDLE, el disparador debe iniciarse después de recibir los primeros datos. Una vez que los datos recibidos se interrumpen y no se reciben datos, se genera IDLE. Interrumpido.
    Agregue las siguientes variables en main.c:
uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存数组
volatile uint8_t recvLength = 0;  //接收一帧数据的长度
volatile uint8_t recvDndFlag = 0; //一帧数据接收完成标志

Agregue las siguientes definiciones de macro y variables en main.h:

#define BUFFER_SIZE 256
extern uint8_t recvBuff[BUFFER_SIZE];  //接收数据缓存
extern volatile uint8_t recvLength;  //接收一帧数据的长度
extern volatile uint8_t recvDndFlag; //一帧数据接收完成标志

En main.c, antes del bucle while y después de que se inicialice el puerto serie, agregue las funciones de habilitación de recepción DMA y interrupción inactiva, de modo que la interrupción se active cuando se reciban datos por primera vez.

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    
    
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
  HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Al stm32f1xx_it.cmodificar la parte inferior de este documentoUSART1_IRQHandler()

void USART1_IRQHandler(void)
{
    
    
  /* USER CODE BEGIN USART1_IRQn 0 */
	uint32_t tmpFlag = 0;
	uint32_t temp;
	tmpFlag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmpFlag != RESET))//idle标志被置位
	{
    
     
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
		
		HAL_UART_DMAStop(&huart1); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数   
		recvLength  =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recvDndFlag  = 1;	// 接受完成标志位置1	
		HAL_UART_Transmit_DMA(&huart1, recvBuff, recvLength);
		recvLength = 0;//清除计数
		recvDndFlag = 0;//清除接收结束标志位

		memset(recvBuff,0,recvLength);
		HAL_UART_Receive_DMA(&huart1, recvBuff, BUFFER_SIZE);//重新打开DMA接收,不然只能接收一次数据
	 }
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

Envíe datos de longitud variable a través del asistente de puerto serie

Cinco, asuntos que necesitan atención

El código de usuario se agregará USER CODE BEGIN Ny USER CODE END Nentre, de lo contrario, el próximo uso después de que STM32CubeMX vuelva a generar el código, se eliminará.


Escrito por Leung el 18 de enero de 2021

• Referencia: Tutorial 6 de la serie STM32CubeMX: Acceso directo a memoria (DMA)
    "Guía de desarrollo de Embedded-STM32" Parte dos Conceptos básicos: Capítulo 7 DMA (Biblioteca HAL)

Supongo que te gusta

Origin blog.csdn.net/qq_36347513/article/details/112787605
Recomendado
Clasificación