Ошибка передачи UART после запуска потока приема UART в библиотеке STM32 HAL
Я использую STM32F1 (STM32F103C8T6) для разработки проекта с использованием FreeRTOS.
Ниже приведена моя конфигурация интерфейса GPIO и USART1:
__GPIOA_CLK_ENABLE();
__USART1_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;//115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&huart1);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
Вопрос в том, почему передача UART работает до запуска потоков, а не после запуска потоков или из потоков? Я хочу передавать данные из потоков. т.е.
int main(void)
{
Initializations();
//THIS WORKS!!
uart_transmit_buffer[0] = 'H';
uart_transmit_buffer[1] = 'R';
uart_transmit_buffer[2] = '#';
uint8_t nums_in_tr_buf = 0;
nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);
StartAllThreads();
osKernelStart();
for (;;);
}
static void A_Random_Thread(void const *argument)
{
for(;;)
{
if (conditionsMet()) //Executed once when a proper response received.
{
//BUT NOT THIS :(!!
uart_transmit_buffer[0] = 'H';
uart_transmit_buffer[1] = 'R';
uart_transmit_buffer[2] = '#';
uint8_t nums_in_tr_buf = 0;
nums_in_tr_buf = sizeof(uart_transmit_buffer)/sizeof(uint8_t);
state = HAL_UART_Transmit(&huart1, uart_transmit_buffer, nums_in_tr_buf, 5000);
}
}
}
Я удостоверился, что никакая нить не находится в тупике. Проблема в том, что UART_HAL_Transmit дает состояние HAL_BUSY.
Кроме того, я выделил один поток для получения и анализа информации от UART RX, и я подозреваю, что это может быть причиной проблемы. Ниже приведен код:
static void UART_Receive_Thread(void const *argument)
{
uint32_t count;
(void) argument;
int j = 0, word_length = 0;
for (;;)
{
if (uart_line_ready == 0)
{
HAL_UART_Receive(&huart1, uart_receive_buffer, UART_RX_BUFFER_SIZE, 0xFFFF);
if (uart_receive_buffer[0] != 0)
{
if (uart_receive_buffer[0] != END_OF_WORD_CHAR)
{
uart_line_buffer[k] = uart_receive_buffer[0];
uart_receive_buffer[0] = 0;
k++;
}
else
{
uart_receive_buffer[0] = 0;
uart_line_ready = 1;
word_length = k;
k = 0;
}
}
}
if (uart_line_ready == 1)
{
//osThreadSuspend(OLEDThreadHandle);
for (j = 0; j <= word_length; j++)
{
UART_RECEIVED_COMMAND[j] = uart_line_buffer[j];
}
for (j = 0; j <= word_length; j++)
{
uart_line_buffer[j] = 0;
}
uart_line_ready = 0;
RECEIVED_COMMAND = ParseReceivedCommand(UART_RECEIVED_COMMAND);
if (RECEIVED_COMMAND != _ID_)
{
AssignReceivedData (word_length); //Results in uint8_t * RECEIVED_DATA
}
//osThreadResume(OLEDThreadHandle);
}
//Should be no delay in order not to miss any data..
}
}
Другая причина проблемы, которую я подозреваю, может быть связана с прерываниями системы (также обратите внимание на часть инициализации, я настроил NVIC):
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
Любая помощь или руководство по этому вопросу будет принята с благодарностью. Заранее спасибо.
3 ответа
Проблема оказалась связана с блокировкой операторов. Поскольку UART_Receive_Thread имеет HAL_UART_Receive внутри, и это блокирует поток до тех пор, пока что-то не будет получено, это приводит к занятому HAL (следовательно, состоянию HAL_BUSY).
Решением было использование неблокирующих операторов без каких-либо изменений. т.е. одновременное использование HAL_UART_Receive_IT и HAL_UART_Transmit_IT и игнорирование блокирующих операторов.
Спасибо за все предложения, которые приводят к этому решению.
Из того, что я вижу HAL_UART_Transmit
работал бы с F4 HAL (v1.4.2), если бы не __HAL_LOCK(huart)
, Поток RX блокирует дескриптор, а затем поток TX также попытается заблокировать и вернуть HAL_BUSY. HAL_UART_Transmit_IT
а также HAL_UART_Receive_IT
не блокируйте ручку на время передачи / приема.
Что может вызвать проблемы с State
член, так как он не атомно обновляется вспомогательными функциями UART_Receive_IT
а также UART_Transmit_IT
, Хотя я не думаю, что это повлияет на работу.
Вы можете изменить функцию, чтобы разрешить одновременный прием и передачу. Вам придется обновлять это каждый раз, когда они выпускают новую версию HAL.
Проблема в том, что ST HAL не предназначен для использования с ОСРВ. Так говорится в определении макроса __HAL_LOCK
, Возможно, стоит пересмотреть его, чтобы использовать мьютексы RTOS. То же самое с HAL_Delay()
использовать функцию ожидания потока RTOS.
В целом, хотя отправка через функцию блокировки в потоке должна быть в порядке, но я бы не получил данные, используя функцию блокировки в потоке. Таким образом, вы будете испытывать ошибки переполнения.
Аналогично, если вы добавите слишком много обработки в прерывание приема, вы также можете столкнуться с ошибками переполнения. Я предпочитаю использовать DMA для приема, а затем прерывания, если у меня закончились потоки DMA. Прерывание только копирует данные в буфер, аналогично DMA. processRxData
поток затем используется для обработки фактических данных.
При использовании FreeRTOS вы должны установить приоритет прерывания 5 или выше, потому что ниже 5 зарезервировано для ОС. Поэтому измените свой код, чтобы установить приоритет на:
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);