[STM32L4] STM32L4R5ZIT6用DMA把存储器里的数据发往串口的·问题

[复制链接]
412|46
 楼主| Tom952331 发表于 2026-6-12 16:05 | 显示全部楼层
今天会画卧蚕吗 发表于 2026-6-10 22:04
串口的DMA发送使能位没开,UART层面没允许DMA接管发送,数据发不出去。

谢谢!请问我怎么才能在UART层面允许DMA接管发送呢?
 楼主| Tom952331 发表于 2026-6-12 16:06 | 显示全部楼层
等凌晨日出 发表于 2026-6-11 21:17
用DMA发串口之前先用HAL_UART_Transmit验证过能通,说明串口硬件没问题,问题就在DMA配置上。 ...

HAL_UART_Transmit验证通过了
 楼主| Tom952331 发表于 2026-6-12 16:22 | 显示全部楼层
xch 发表于 2026-6-11 09:55
公布完整的相关的代码才好分析。只有老中医才会摸个脉就能胡说八道开药方。 ...

我贴一下完整代码:
  1. #include "main.h"
  2. //#include "stm32l4xx_hal_usart.h"
  3. /** @addtogroup STM32L4xx_HAL_Examples
  4.   * @{
  5.   */

  6. /** @addtogroup DMA_FLASHToRAM
  7.   * @{
  8.   */
  9. USART_HandleTypeDef UartHandle;
  10. /* Private typedef -----------------------------------------------------------*/
  11. /* Private define ------------------------------------------------------------*/
  12. /* Private macro -------------------------------------------------------------*/
  13. /* Private variables ---------------------------------------------------------*/
  14. /* DMA Handle declaration */
  15. DMA_HandleTypeDef     DmaHandle;

  16. static const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] =
  17. {
  18.   0x01020304, 0x05060708, 0x090A0B0C, 0x0D0E0F10,
  19.   0x11121314, 0x15161718, 0x191A1B1C, 0x1D1E1F20,
  20.   0x21222324, 0x25262728, 0x292A2B2C, 0x2D2E2F30,
  21.   0x31323334, 0x35363738, 0x393A3B3C, 0x3D3E3F40,
  22.   0x41424344, 0x45464748, 0x494A4B4C, 0x4D4E4F50,
  23.   0x51525354, 0x55565758, 0x595A5B5C, 0x5D5E5F60,
  24.   0x61626364, 0x65666768, 0x696A6B6C, 0x6D6E6F70,
  25.   0x71727374, 0x75767778, 0x797A7B7C, 0x7D7E7F80
  26. };
  27. static const uint8_t Buffer[4]=
  28. {
  29.         0x55,0xaa,0x66,0x99
  30. };
  31. static uint32_t aDST_Buffer[BUFFER_SIZE];

  32. static __IO uint32_t transferErrorDetected;    /* Set to 1 if an error transfer is detected */
  33. static __IO uint32_t transferCompleteDetected; /* Set to 1 if transfer is correctly completed */

  34. /* Private function prototypes -----------------------------------------------*/
  35. static void DMA_Config(void);
  36. static void SystemClock_Config(void);
  37. static void Error_Handler(void);
  38. static void TransferComplete(DMA_HandleTypeDef *DmaHandle);
  39. static void TransferError(DMA_HandleTypeDef *DmaHandle);

  40. /* Private functions ---------------------------------------------------------*/
  41. static void DMA_Config(void)
  42. {
  43. //        DMA_InitTypeDef DMA_InitStructure;
  44.   /*## -1- Enable DMA1 clock #################################################*/
  45.   __HAL_RCC_DMA1_CLK_ENABLE();
  46.        
  47.   //DmaHandle.Instance=DMA1_Channel5;
  48.         //HAL_DMA_DeInit(DMA1_Channel5;); // 初始化通道5
  49.   /*##-2- Select the DMA functional Parameters ###############################*/
  50.   DmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH ;          /* M2M transfer mode                */
  51.   DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;               /* Peripheral increment mode Enable */
  52.         //DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;      
  53.   DmaHandle.Init.MemInc = DMA_MINC_ENABLE;                  /* Memory increment mode Enable     */
  54.         //DmaHandle.Init.MemInc = DMA_MINC_DISABLE;  
  55. //  DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  56. //  DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  57. //  DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* Peripheral data alignment : Word */
  58. //       
  59. //  DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    /* memory data alignment : BYTE     */
  60.         DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE  ; /* Peripheral data alignment : BYTE */
  61.   DmaHandle.Init.MemDataAlignment = DMA_PDATAALIGN_BYTE  ;    /* memory data alignment : Word     */
  62.         DmaHandle.Init.Mode = DMA_NORMAL;                         /* Normal DMA mode                  */
  63.   DmaHandle.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */

  64.   /*##-3- Select the DMA instance to be used for the transfer : DMA1_Channel1 #*/
  65.   DmaHandle.Instance = DMA_INSTANCE;

  66.   /*##-4- Initialize the DMA channel ##########################################*/
  67.   if (HAL_DMA_Init(&DmaHandle) != HAL_OK)
  68.   {
  69.     /* Initialization Error */
  70.     Error_Handler();
  71.   }
  72.   
  73.   /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */
  74.   HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
  75.   HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_ERROR_CB_ID, TransferError);

  76.   /*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/
  77.   /* Set Interrupt Group Priority */
  78.   //HAL_NVIC_SetPriority(DMA_INSTANCE_IRQ, 0, 0);

  79.   /* Enable the DMA STREAM global Interrupt */
  80.   //HAL_NVIC_EnableIRQ(DMA_INSTANCE_IRQ);
  81.        
  82.         HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
  83.   HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
  84.   /*##-7- Start the DMA transfer using the interrupt mode ####################*/
  85.   /* Configure the source, destination and buffer size DMA fields and Start DMA Channel transfer */
  86.   /* Enable All the DMA interrupts */
  87.   if (HAL_DMA_Start_IT(&DmaHandle, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&UartHandle.Instance->TDR, 4) != HAL_OK)
  88.   {
  89.     /* Transfer Error */
  90.     Error_Handler();
  91.   }
  92. }
  93. static void MX_GPIO_Init(void)
  94. {
  95.   GPIO_InitTypeDef GPIO_InitStruct = {0};

  96.   /* GPIO Ports Clock Enable */
  97.   
  98.         __HAL_RCC_GPIOA_CLK_ENABLE();
  99.         __HAL_RCC_USART2_CLK_ENABLE();


  100.   /*Configure GPIO pins : PC13 PC14 PC15 */
  101.   GPIO_InitStruct.Pin = GPIO_PIN_2;
  102.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  103.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  104.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  105.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  106.        
  107.         GPIO_InitStruct.Pin = GPIO_PIN_3;
  108.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  109.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  110.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  111.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  112. }

  113. /**
  114.   * [url=/u/brief]@brief[/url]  Main program
  115.   * @param  None
  116.   * @retval None
  117.   */
  118. int main(void)
  119. {
  120.         unsigned int i;
  121.   /* STM32L4xx HAL library initialization:
  122.        - Configure the Flash prefetch
  123.        - Systick timer is configured by default as source of time base, but user
  124.          can eventually implement his proper time base source (a general purpose
  125.          timer for example or other time source), keeping in mind that Time base
  126.          duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
  127.          handled in milliseconds basis.
  128.        - Set NVIC Group Priority to 4
  129.        - Low Level Initialization
  130.      */
  131.   HAL_Init();

  132.   /* Configure the system clock to 120 MHz */
  133.   SystemClock_Config();

  134.   /* Initialize LED */
  135.   BSP_LED_Init(LED1);

  136.   /* Set to 1 if an transfer error is detected */
  137.   transferErrorDetected = 0;
  138.   transferCompleteDetected = 0;

  139.   /* Configure and enable the DMA channel for Memory to Memory transfer */
  140.   MX_GPIO_Init();

  141.   /* Suspend Tick increment to prevent wakeup by Systick interrupt.         */
  142.   /* Otherwise the Systick interrupt will wake up the device within 1ms     */
  143.   /* (HAL time base).                                                       */
  144. //  HAL_SuspendTick();

  145. //  /* Enter sleep mode and wait for DMA interrupt */
  146. //  HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

  147. //  /* Resume Tick interrupt if disabled prior to SLEEP mode entry */
  148. //  HAL_ResumeTick();
  149.         DMA_Config();
  150.        
  151.         UartHandle.Instance        = USARTx;

  152.   UartHandle.Init.BaudRate   = 9600;
  153.   UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  154.   UartHandle.Init.StopBits   = UART_STOPBITS_1;
  155.   UartHandle.Init.Parity     = UART_PARITY_NONE;
  156.   //UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  157.         //UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
  158.         //UartHandle.Init.
  159.   UartHandle.Init.Mode       = UART_MODE_TX_RX;
  160.        
  161.   //UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  162.   if(HAL_USART_DeInit(&UartHandle) != HAL_OK)
  163.   {
  164.     Error_Handler();
  165.   }  
  166.   if(HAL_USART_Init(&UartHandle) != HAL_OK)
  167.   {
  168.     Error_Handler();
  169.   }
  170.   

  171.          HAL_USART_Transmit_DMA(&UartHandle, (uint8_t *)Buffer, 4);
  172.   /* Infinite loop */
  173.   while (1)
  174.   {
  175.                 //
  176.                 HAL_USART_Transmit(&UartHandle, (uint8_t *)Buffer, 4,0);
  177.                 for(i=0;i<60000;i++);
  178.                 //HAL_Delay(1000);
  179. //    if (transferErrorDetected == 1)
  180. //    {
  181. //      /* Toggle LED1 with a period of 200 ms */
  182. //      BSP_LED_Toggle(LED1);
  183. //      HAL_Delay(200);
  184. //    }
  185. //    if (transferCompleteDetected == 1)
  186. //    {
  187. //      /* Turn LED1 on*/
  188. //      BSP_LED_On(LED1);
  189. //      transferCompleteDetected = 0;
  190. //    }
  191.   }
  192. }

  193. /**
  194.   * @brief  Configure the DMA controller according to the Channel parameters
  195.   *         defined in main.h file
  196.   * [url=/u/NOTE]@NOTE[/url]  This function is used to :
  197.   *        -1- Enable DMA1 clock
  198.   *        -2- Select the DMA functional Parameters
  199.   *        -3- Select the DMA instance to be used for the transfer
  200.   *        -4- Select Callbacks functions called after Transfer complete and
  201.                Transfer error interrupt detection
  202.   *        -5- Initialize the DMA channel
  203.   *        -6- Configure NVIC for DMA transfer complete/error interrupts
  204.   *        -7- Start the DMA transfer using the interrupt mode
  205.   * @param  None
  206.   * @retval None
  207.   */
  208. //static void DMA_Config(void)
  209. //{
  210. //  /*## -1- Enable DMA1 clock #################################################*/
  211. //  __HAL_RCC_DMA1_CLK_ENABLE();

  212. //  /*##-2- Select the DMA functional Parameters ###############################*/
  213. //  DmaHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;          /* M2M transfer mode                */
  214. //  DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE;               /* Peripheral increment mode Enable */
  215. //  DmaHandle.Init.MemInc = DMA_MINC_ENABLE;                  /* Memory increment mode Enable     */
  216. ////  DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; /* Peripheral data alignment : Word */
  217. ////  DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;    /* memory data alignment : Word     */
  218. ////        DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD ; /* Peripheral data alignment : Word */
  219. ////  DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD ;    /* memory data alignment : Word     */
  220. //        DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE   ; /* Peripheral data alignment : Word */
  221. //  DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE  ;    /* memory data alignment : Word     */
  222. //  DmaHandle.Init.Mode = DMA_NORMAL;                         /* Normal DMA mode                  */
  223. //  DmaHandle.Init.Priority = DMA_PRIORITY_HIGH;              /* priority level : high            */

  224. //  /*##-3- Select the DMA instance to be used for the transfer : DMA1_Channel1 #*/
  225. //  DmaHandle.Instance = DMA_INSTANCE;

  226. //  /*##-4- Initialize the DMA channel ##########################################*/
  227. //  if (HAL_DMA_Init(&DmaHandle) != HAL_OK)
  228. //  {
  229. //    /* Initialization Error */
  230. //    Error_Handler();
  231. //  }

  232. //  /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */
  233. //  HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_CPLT_CB_ID, TransferComplete);
  234. //  HAL_DMA_RegisterCallback(&DmaHandle, HAL_DMA_XFER_ERROR_CB_ID, TransferError);
  235. //  
  236. //  /*##-6- Configure NVIC for DMA transfer complete/error interrupts ##########*/
  237. //  /* Set Interrupt Group Priority */
  238. //  HAL_NVIC_SetPriority(DMA_INSTANCE_IRQ, 0, 0);

  239. //  /* Enable the DMA Channel global Interrupt */
  240. //  HAL_NVIC_EnableIRQ(DMA_INSTANCE_IRQ);

  241. //  /*##-7- Start the DMA transfer using the interrupt mode ####################*/
  242. //  /* Configure the source, destination and buffer size DMA fields and Start DMA Channel transfer */
  243. //  /* Enable All the DMA interrupts */
  244. ////  if (HAL_DMA_Start_IT(&DmaHandle, (uint32_t)&aSRC_Const_Buffer, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
  245. ////  {
  246. ////    /* Transfer Error */
  247. ////    Error_Handler();
  248. ////  }
  249. //}

  250. /**
  251.   * @brief  DMA conversion complete callback
  252.   * @note   This function is executed when the transfer complete interrupt
  253.   *         is generated
  254.   * @retval None
  255.   */
  256. static void TransferComplete(DMA_HandleTypeDef *DmaHandle)
  257. {
  258.   transferCompleteDetected = 1;
  259. }

  260. /**
  261.   * @brief  DMA conversion error callback
  262.   * @note   This function is executed when the transfer error interrupt
  263.   *         is generated during DMA transfer
  264.   * @retval None
  265.   */
  266. static void TransferError(DMA_HandleTypeDef *DmaHandle)
  267. {
  268.   transferErrorDetected = 1;
  269. }

  270. /**
  271.   * @brief  System Clock Configuration
  272.   *         The system Clock is configured as follows :
  273.   *            System Clock source            = PLL (MSI)
  274.   *            SYSCLK(Hz)                     = 120000000
  275.   *            HCLK(Hz)                       = 120000000
  276.   *            AHB Prescaler                  = 1
  277.   *            APB1 Prescaler                 = 1
  278.   *            APB2 Prescaler                 = 1
  279.   *            MSI Frequency(Hz)              = 4000000
  280.   *            PLL_M                          = 1
  281.   *            PLL_N                          = 60
  282.   *            PLL_Q                          = 2
  283.   *            PLL_R                          = 2
  284.   *            PLL_P                          = 7
  285.   *            Flash Latency(WS)              = 5
  286.   * @param  None
  287.   * @retval None
  288.   */
  289. void SystemClock_Config(void)
  290. {
  291.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  292.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  293.   
  294.   /* Enable voltage range 1 boost mode for frequency above 80 Mhz */
  295.   __HAL_RCC_PWR_CLK_ENABLE();
  296.   HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
  297.   __HAL_RCC_PWR_CLK_DISABLE();

  298.   /* Enable MSI Oscillator and activate PLL with MSI as source */
  299.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  300.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  301.   RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  302.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  303.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  304.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  305.   RCC_OscInitStruct.PLL.PLLM = 1;
  306.   RCC_OscInitStruct.PLL.PLLN = 60;
  307.   RCC_OscInitStruct.PLL.PLLR = 2;
  308.   RCC_OscInitStruct.PLL.PLLQ = 2;
  309.   RCC_OscInitStruct.PLL.PLLP = 7;
  310.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  311.   {
  312.     /* Initialization Error */
  313.     while(1);
  314.   }
  315.   
  316.   /* To avoid undershoot due to maximum frequency, select PLL as system clock source */
  317.   /* with AHB prescaler divider 2 as first step */
  318.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  319.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  320.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV2;
  321.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;  
  322.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  323.   if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  324.   {
  325.     /* Initialization Error */
  326.     while(1);
  327.   }

  328.   /* AHB prescaler divider at 1 as second step */
  329.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK;
  330.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  331.   if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  332.   {
  333.     /* Initialization Error */
  334.     while(1);
  335.   }
  336. }

  337. /**
  338.   * @brief  This function is executed in case of error occurrence.
  339.   * @param  None
  340.   * @retval None
  341.   */
  342. static void Error_Handler(void)
  343. {
  344.   while (1)
  345.   {
  346.     /* Toggle LED1 with a period of 1 s */
  347.     BSP_LED_Toggle(LED1);
  348.     HAL_Delay(1000);
  349.   }
  350. }


  351. #ifdef  USE_FULL_ASSERT
  352. /**
  353.   * @brief  Reports the name of the source file and the source line number
  354.   *         where the assert_param error has occurred.
  355.   * @param  file: pointer to the source file name
  356.   * @param  line: assert_param error line source number
  357.   * @retval None
  358.   */
  359. void assert_failed(uint8_t *file, uint32_t line)
  360. {
  361.   /* User can add his own implementation to report the file name and line number,
  362.      ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  363.   /* Infinite loop */
  364.   while (1)
  365.   {
  366.   }
  367. }
  368. #endif

  369. /**
  370.   * @}
  371.   */

  372. /**
  373.   * @}
  374.   */


 楼主| Tom952331 发表于 2026-6-12 16:22 | 显示全部楼层
甜心puppy 发表于 2026-6-11 18:20
错误回调里没有清DMA的错误标志,错误状态一直挂着,后面的传输全部失败。 ...

谢谢!请问如何清DMA错误标志
 楼主| Tom952331 发表于 2026-6-12 16:23 | 显示全部楼层
没有太阳的晴天 发表于 2026-6-11 14:15
传输长度写的是4,但buffer里实际数据可能不止4个字节,多出来的部分不会发。 ...

我就是要发四个字节
xch 发表于 2026-6-12 18:10 | 显示全部楼层
Tom952331 发表于 2026-6-12 16:22
我贴一下完整代码:

82856a2bd8b116efc.png 这句写法不对,结果可能蒙对了。


没找到你配置DMAMUX1 的代码。漏了配置。DMA1_channel7 就收不到来自UART的 DMA请求,就不会DMA传输了。

593376a2bd9af1bf24.png
没找到你用的是你哪个UART, 260886a2bda95945c8.png
查到编号,把它填入 637496a2bdae2d57c1.png

注意配置顺序。
理想阳 发表于 2026-7-10 08:41 | 显示全部楼层
问题:为什么DMA初始化放在主循环中会导致配置被覆盖?


回答:每次主循环都重新初始化DMA,会覆盖之前的配置,因为DMA只保存一次初始化状态。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部
0