У меня есть прерывание UART Idle, которое должно уведомить задачу о завершении действия в UART.
Для этого я использую BinarySemaphore, который в данном случае является просто семафором с максимальным числом 1.
Когда я вызываю функцию освобождения семафора osSemaphoreRelease(semaphore_id_uart4_rx);
Приложение останавливается из-за запуска следующего утверждения.
/* Normally a mutex would not be given from an interrupt, especially if
there is a mutex holder, as priority inheritance makes no sense for an
interrupts, only tasks. */
configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );
Макрос configASSERT
расширяется до
if ((!( ( pxQueue->pcHead == ((void *)0) ) && ( pxQueue->pcTail != ((void *)0) ) )) == 0) {vPortRaiseBASEPRI(); for( ;; );}
Теперь pxQueue-> pcHead имеет значение 0, а pxQueue-> pcTail имеет значение, отличное от 0.Таким образом, сборщик запускается.
Комментарий выше этого утверждения указывает на то, что это предназначено для использования MUTEX в ISR.Тем не менее, я не использую MUTEX, я использую BinarySemaphore!FreeRTOS FAQ сам по себе рекомендует вам использовать семафоры или BinarySemaphores для синхронизации между ISR и Task.Что я и делаю.Но все же двоичный семафор обнаруживается как MUTEX, который вызывает эту проблему.Я даже пытался отключить MUTEX из конфигурации RTOS STM32CubeMX, но он все равно обнаруживает его как MUTEX и вылетает.
Двоичные семафоры для встроенных программных приложений реального времени FreeRTOS
Двоичные семафоры и мьютексы очень похожи, но имеют некоторые тонкие различия: мьютексы включают механизм наследования приоритетов, двоичные семафоры - нет.Это делает двоичные семафоры лучшим выбором для реализации синхронизации (между задачами или между задачами и прерываниями), а мьютексы - лучшим выбором для реализации простого взаимного исключения.
Я использую плату NUCLEO-F429ZI, которая имеетSTM32F429ZIT6 на нем, версия CubeMX: 4.27.0, название и версия пакета микропрограммы: STM32Cube FW_F4 V1.21.0
код:
Основная функция:
int main(void)
{
/* USER CODE BEGIN 1 */
for(int i=0;i<360;i++) {
sine_wave_array[i]=sin(i/180.0 * 3.1416)*1900 + 1900 + 100;
if(sine_wave_array[i]<0) {
sine_wave_array[i]=0;
} else if(sine_wave_array[i]>=4096){
sine_wave_array[i]=4095;
}
}
//Initialize HMI struct
memset(&hmi,0,sizeof(hmi));
/* 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_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_UART4_Init();
MX_UART5_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_SPI1_Init();
MX_I2C1_Init();
MX_ADC3_Init();
MX_USB_OTG_HS_PCD_Init();
MX_USART3_UART_Init();
MX_SPI4_Init();
MX_I2C2_Init();
MX_CAN1_Init();
MX_RTC_Init();
MX_TIM3_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc3,adcData,ADC_CHANNEL_COUNT);
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
// Setting IRQ priority for UART4
HAL_NVIC_SetPriority(UART4_IRQn, 15, 15);
HAL_NVIC_SetPriorityGrouping(0);
/* USER CODE END 2 */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
semaphore_id_uart4_rx = osSemaphoreCreate(osSemaphore(semaphore_uart4_rx), 1);
semaphore_id_uart5_rx = osSemaphoreCreate(osSemaphore(semaphore_uart5_rx), 1);
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the thread(s) */
/* definition and creation of defaultTask */
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
osThreadDef(LWIPTask_, LWIPTask, osPriorityNormal, 0, 1024);
LWIPTaskHandle = osThreadCreate(osThread(LWIPTask_), NULL);
osThreadDef(USBTask_, USBTask, osPriorityNormal, 0, 512);
USBTaskHandle = osThreadCreate(osThread(USBTask_), NULL);
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
ISR:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
if ((isrflags & USART_SR_IDLE) != RESET) {
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
tmp = huart->Instance->SR; /* Read status register */
tmp = huart->Instance->DR; /* Read data register */
HAL_UART_IdleCallback(huart);
}
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if(errorflags == RESET)
{
/* UART in mode Receiver -------------------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/* If some errors occur */
if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* UART parity error interrupt occurred ----------------------------------*/
if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/* UART noise error interrupt occurred -----------------------------------*/
if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/* UART frame error interrupt occurred -----------------------------------*/
if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/* UART Over-Run interrupt occurred --------------------------------------*/
if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/* Call UART Error Call back function if need be --------------------------*/
if(huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/* UART in mode Receiver -----------------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/* Disable the UART DMA Rx request if enabled */
if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if(huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/* Call user error callback */
HAL_UART_ErrorCallback(huart);
}
}
else
{
/* Call user error callback */
HAL_UART_ErrorCallback(huart);
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
HAL_UART_ErrorCallback(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* UART in mode Transmitter ------------------------------------------------*/
if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
}
/* UART in mode Transmitter end --------------------------------------------*/
if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
}
Функции, вызываемые из ISR:
void HAL_UART_IdleCallback(UART_HandleTypeDef *huart) {
HAL_UART_RxGenericCallback(huart,3);
}
void HAL_UART_RxGenericCallback(UART_HandleTypeDef *huart,int type) {
if(type ==3) {
if(UART4 == huart->Instance) {
end4 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
osSemaphoreRelease(semaphore_id_uart4_rx);
} else if (UART5 == huart->Instance) {
end5 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
osSemaphoreRelease(semaphore_id_uart5_rx);
}
}
return;
}