参考https://www.devcoons.com/stm32-uart-receive-unknown-size-data-using-dma-and-freertos/
最近在用STM32F103的单片机,想使用串口接收发送功能, 结果各种坑,已开始使用了中断模式,要么进不了中断,要么就hardfault,
网上看了很多帖子都没有解决,果断放弃
In the end of this page you can find the github links (soon).
Step 1: Create your project using the CubeMX and place both RX/TX DMAs on the serial interface. The Tx DMA should be in Normal Mode and the Rx should be in Circular Mode.
Step 2: Activate the NVIC Interrupt for the serial. (it is needed by the DMA)
Step 3: Basically, what we are going to do is to leave the DMA reading the UART and put them in an array. By changing the Mode to circular the DMA will indefinitely continue this operation without interrupting (circular buffering). On top of this, a thread will collect the data and parse them. For that reason we need the following definitions
#define UART_DMA_BUFFER_SIZE 2048
#define PARSER_MESSAGE_LIST_SIZE 8
#define PARSER_MESSAGE_SIZE 1024
Step 4: Assign and activate the UART reception using the DMA and give a (large enough) buffer. Please note that this approach will never fire an interrupt on RX and the array will be used as a circular buffer.
static uint8_t buffer[UART_DMA_BUFFER_SIZE];
...
...
{
// This should be done before the beginning of our parser,
// you can place it in the main or inside the parser
HAL_UART_Receive_DMA(&huart2, buffer, UART_DMA_BUFFER_SIZE);
}
Step 5: Create a FreeRTOS thread which will monitor the buffer and copy any new data to an intermediate buffer for further processing.
static osThreadId_t uartParserTaskHandle;
...
...
void UARTParser(void* arguments);
...
...
{
const osThreadAttr_t uartParserTask_attributes2 = {
.name = "UARTParserTask",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128};
uartParserTaskHandle = osThreadNew(UARTParser, NULL, &uartParserTask_attributes2);
}
Step 6: Now we will fill the Parser of the UART. As we said before the main purpose is to get all the new available data from the DMA buffer and put them in a list of messages (each complete message should be ended with the ‘\r\n’ characters).
static uint8_t msg_list[PARSER_MESSAGE_LIST_SIZE][PARSER_MESSAGE_SIZE];
...
...
void UARTParser(void* arguments)
{
size_t dma_head = 0, dma_tail = 0;
size_t cur_msg_sz = 0;
size_t cur_msg = 0;
uint8_t found = 0;
for(;;)
{
do
{
__disable_irq();
dma_tail = UART_DMA_BUFFER_SIZE - huart2.hdmarx->Instance->CNDTR;
__enable_irq();
if(dma_tail!=dma_head)
{
if(dma_head < dma_tail)
{
for(register size_t i=dma_head; i<dma_tail; i++)
{
found = (found == 0 && buffer[i] == '\r') ? 1
: (found == 1 && buffer[i] == '\n') ? 2
: 0;
msg_list[cur_msg][cur_msg_sz++]= buffer[i];
if(found==2)
{
cur_msg = cur_msg == PARSER_MESSAGE_LIST_SIZE-1 ? 0 : cur_msg + 1;
memset(msg_list[cur_msg],0,PARSER_MESSAGE_SIZE);
cur_msg_sz=0;
}
}
}
else
{
for(register size_t i=dma_head; i<UART_DMA_BUFFER_SIZE; i++)
{
found = (found == 0 && buffer[i] == '\r') ? 1
: (found == 1 && buffer[i] == '\n') ? 2
: 0;
msg_list[cur_msg][cur_msg_sz++]= buffer[i];
if(found==2)
{
cur_msg = cur_msg == PARSER_MESSAGE_LIST_SIZE-1 ? 0 : cur_msg + 1;
memset(msg_list[cur_msg],0,PARSER_MESSAGE_SIZE);
cur_msg_sz=0;
}
}
for(register size_t i=0; i<dma_tail; i++)
{
found = (found == 0 && buffer[i] == '\r') ? 1
: (found == 1 && buffer[i] == '\n') ? 2
: 0;
msg_list[cur_msg][cur_msg_sz++]= buffer[i];
if(found==2)
{
cur_msg = cur_msg == PARSER_MESSAGE_LIST_SIZE-1 ? 0 : cur_msg + 1;
memset(msg_list[cur_msg],0,PARSER_MESSAGE_SIZE);
cur_msg_sz=0;
}
}
}
dma_head=dma_tail;
}
}while(dma_head!=(UART_DMA_BUFFER_SIZE- huart2.hdmarx->Instance->CNDTR));
osDelay(25); // this should be the minimum time difference between each frame
}
}
Now, if you run this application and send data through UART, you will see them in the messages list separated by ‘\r\n’.
弃,直到看到上面链接这片文章。