使用一款国产MCU芯片,使用的是HAL库,在使用串口DMA编写例程,与串口板通信遇到数据错乱和丢失问题。
例程做的事情就是接收数据指定接收6个字节数据,并把数据发送回去,以下是例程代码:
#include "main.h"
#include "string.h"
/* Private define ------------------------------------------------------------*/
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void APP_SystemClockConfig(void);
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef UartHandle;
uint8_t aTxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t aRxBuffer[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static void app_uart_init(void)
{
/* Initialize USART2 */
UartHandle.Instance = USART1;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS;
UartHandle.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&UartHandle);
}
int main(void)
{
/* Reset of all peripherals, Initializes the Systick */
HAL_Init();
/* System clock configuration */
APP_SystemClockConfig();
app_uart_init();
HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aTxBuffer, 12);
while (1)
{
//UartHandle.hdmarx->Instance->CNDTR = 1024;
/* Receive data using DMA */
if (HAL_UART_Receive_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK)
{
APP_ErrorHandler();
}
/* Wait for receiving data to complete */
while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
{
}
/* Send data using DMA */
if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aRxBuffer, 6) != HAL_OK)
{
APP_ErrorHandler();
}
/* Wait for sending data to complete */
while(HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
{
}
}
}
/**
* @brief System clock configuration function
* @param None
* @retval None
*/
static void APP_SystemClockConfig(void)
{
RCC_OscInitTypeDef OscInitstruct = {0};
RCC_ClkInitTypeDef ClkInitstruct = {0};
OscInitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE |
RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSI48M;
OscInitstruct.HSEState = RCC_HSE_OFF; /* Disable HSE */
/* OscInitstruct.HSEFreq = RCC_HSE_16_32MHz; */ /* HSE working frequency range: 16M~32M */
OscInitstruct.HSI48MState = RCC_HSI48M_OFF; /* Disable HSI48M */
OscInitstruct.HSIState = RCC_HSI_ON; /* Enable HSI */
OscInitstruct.LSEState = RCC_LSE_OFF; /* Disable LSE */
/* OscInitstruct.LSEDriver = RCC_LSEDRIVE_HIGH; */ /* Drive capability level: High */
OscInitstruct.LSIState = RCC_LSI_OFF; /* Disable LSI */
OscInitstruct.PLL.PLLState = RCC_PLL_OFF; /* Disable PLL */
/* OscInitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; */ /* PLL clock source: HSE */
/* OscInitstruct.PLL.PLLMUL = RCC_PLL_MUL6; */ /* PLL multiplication factor: 6 */
/* Configure Oscillators */
if(HAL_RCC_OscConfig(&OscInitstruct) != HAL_OK)
{
APP_ErrorHandler();
}
ClkInitstruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
ClkInitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; /* System clock source: HSI */
ClkInitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; /* AHB clock not divided */
ClkInitstruct.APB1CLKDivider = RCC_HCLK_DIV1; /* APB1 clock not divided */
ClkInitstruct.APB2CLKDivider = RCC_HCLK_DIV2; /* APB1 clock divided by 2 */
/* Configure Clocks */
if(HAL_RCC_ClockConfig(&ClkInitstruct, FLASH_LATENCY_0) != HAL_OK)
{
APP_ErrorHandler();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
void APP_ErrorHandler(void)
{
/* Infinite loop */
while (1)
{
}
}
#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,
for example: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif /* USE_FULL_ASSERT */
IO口配置的代码:
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
if (huart->Instance == USART1)
{
/* Enable clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* GPIO Initialization
PA2 ------> USART1_TX
PA3 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
if(huart->Init.HwFlowCtl == UART_HWCONTROL_RTS_CTS)
{
GPIO_InitStruct.Pin = GPIO_PIN_11;//cts
GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_12;//rts
GPIO_InitStruct.Alternate = GPIO_AF2_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* USART1 DMA configuration */
/* USART1_TX initialization */
hdma_usart1_tx.Instance = DMA1_Channel1;
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_tx.Init.Mode = DMA_NORMAL;//DMA_CIRCULAR;
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
APP_ErrorHandler();
}
__HAL_LINKDMA(huart, hdmatx, hdma_usart1_tx);
/* USART1_RX initialization */
hdma_usart1_rx.Instance = DMA1_Channel2;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
{
APP_ErrorHandler();
}
__HAL_LINKDMA(huart, hdmarx, hdma_usart1_rx);
/* Set DMA request mapping */
HAL_DMA_ChannelMap(&hdma_usart1_tx, DMA_CHANNEL_MAP_USART1_WR);
HAL_DMA_ChannelMap(&hdma_usart1_rx, DMA_CHANNEL_MAP_USART1_RD);
/* Enable NVIC */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}
else if (huart->Instance == USART2)
{
/* Enable clock */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* GPIO Initialization
PA2 ------> USART1_TX
PA3 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_USART2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Alternate = GPIO_AF2_USART2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USART2 DMA configuration */
/* USART2_TX initialization */
hdma_usart2_tx.Instance = DMA1_Channel1;
hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_tx.Init.Mode = DMA_NORMAL;
hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
{
APP_ErrorHandler();
}
__HAL_LINKDMA(&UartHandle, hdmatx, hdma_usart2_tx);
/* USART2_RX initialization */
hdma_usart2_rx.Instance = DMA1_Channel2;
hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart2_rx.Init.Mode = DMA_NORMAL;
hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
{
APP_ErrorHandler();
}
__HAL_LINKDMA(&UartHandle, hdmarx, hdma_usart2_rx);
/* Set DMA request mapping */
HAL_DMA_ChannelMap(&hdma_usart2_tx, DMA_CHANNEL_MAP_USART2_WR);
HAL_DMA_ChannelMap(&hdma_usart2_rx, DMA_CHANNEL_MAP_USART2_RD);
/* Enable NVIC */
HAL_NVIC_SetPriority(USART2_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART2_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}
}
我使用的串口板支持CTS RTS功能,也正确连接了,如果把杜邦线断开,串口调试工具就收不到任何数据,说明引脚连接应该没问题。
实验串口调试助手一次发送12个字节,但是MCU没有分两次把数据完整接收。
实验结果的打印如下:
[2024-04-10 19:27:21.880]# RECV HEX>
FF FF FF FF FF FF FF FF FF FF FF FF
[2024-04-10 19:27:25.525]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:25.575]# RECV HEX>
01 02 03 04 05 06
[2024-04-10 19:27:26.784]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:26.847]# RECV HEX>
07 0A 0B 0C 01 02 03 06 07 08 09 0A
[2024-04-10 19:27:27.470]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:27.517]# RECV HEX>
0B 01 02 03 04 05
[2024-04-10 19:27:29.546]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:29.603]# RECV HEX>
06 09 0A 0B 0C 01 02 05 06 07 08 09
[2024-04-10 19:27:30.186]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:30.234]# RECV HEX>
0A 01 02 03 04 05
[2024-04-10 19:27:30.762]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:30.809]# RECV HEX>
06 09 0A 0B 0C 01 02 05 06 07 08 09
[2024-04-10 19:27:31.551]# SEND HEX>
01 02 03 04 05 06 07 08 09 0A 0B 0C
[2024-04-10 19:27:31.612]# RECV HEX>
0A 01 02 03 04 05
并没有按照预期的收到:
01 02 03 04 05 06
07 08 09 0A 0B 0C
01 02 03 04 05 06
07 08 09 0A 0B 0C
这样的数据,是配置的不对,还是硬件流控只能做到这样?请指点。