‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

Category:

worklog: FreeRTOS - всё страньше и страньше.

Не сумев побороть странность с семафорами, отложил поиск источника проблемы до лучших времён и заменил оную механику на рекомендуемый аналог - прямые оповещения. Заработало. Теперь затычка-ожидалка создаётся внутри каждого клиентского процесса и снаружи её не видно. Общая глобальная переменная есть только для очереди сообщений сервера, но тут уже никак не выкрутиться (наверное) - сервер запускается, создаёт очередь и после этого клиенты могут туда слать всякое порно.

В общем, пользуясь этим методом, прикрутил драйвер самой важной штуки, без которой никак - вывод фигни в последовательный порт (то бишь -- консоль)! Попутно пришлось разобраться с шаманизмом установки приоритетов. Вещь далеко не очевидная и для понимания доступная вовсе не сразу. Что-то написал, установил какой-то приоритет прерыванию от UART4 и вот такую вещь намонстрячил:

void UART4_IRQHandler(void) {
	uint8_t b;
	BaseType_t xTaskWokenByReceive = pdFALSE;
	if ((UART4->ISR & USART_ISR_TXE) && (UART4->CR1 & USART_CR1_TXEIE)) { /* TXE: Transmit data register empty */
		if (xQueueIsQueueEmptyFromISR(xConsole_DataToWrite_Queue) == pdFALSE) { /* очередь данных непуста */
			xQueueReceiveFromISR (xConsole_DataToWrite_Queue, &b, &xTaskWokenByReceive); /* читаем очередной байт */
			UART4->CR1 &= ~(USART_CR1_TXEIE); /* глушим "запускающее" прерывание */
			UART4->CR1 |= (USART_CR1_TCIE); /* включаем "продолжающее" прерывание */
			UART4->TDR = b; /* шлём байт */
		} else { /* вообще-то, если сработало именно это прерывание, то очередь не может (не должна) быть пустой! */
			UART4->CR1 &= ~(USART_CR1_TXEIE);
		}
	} else if (UART4->ISR & USART_ISR_TC) { /* TC: Transmission Complete. */
		if (xQueueIsQueueEmptyFromISR(xConsole_DataToWrite_Queue) == pdFALSE) { /* очередь данных непуста */
			xQueueReceiveFromISR (xConsole_DataToWrite_Queue, &b, &xTaskWokenByReceive); /* читаем очередной байт */
			UART4->TDR = b; /* шлём байт */
		} else { /* очередь данных пуста, все данные ушли */
			UART4->CR1 &= ~(USART_CR1_TCIE); /* глушим прерывание */
		}
	};
	if( xTaskWokenByReceive != pdFALSE ) {
		/* We should switch context so the ISR returns to a different task.
		NOTE:  How this is done depends on the port you are using.  Check
		the documentation and examples for your port. */
		//taskYIELD ();
		portYIELD_FROM_ISR(xTaskWokenByReceive);
	}
}


Как ни странно, это даже заработало (текст "сервера", который заполняет очередь xConsole_DataToWrite_Queue байтами для передачи, пропущу, ибо говнокод): периодическая выдача строки на консоль пашет, не мешая паралельно работающей светодиодной мигалке.

Круто!

На будущее: критически важно осознать и усвоить методу выбора и установки этих самых приоритетов. Сейчас я просто что-то скопипастил, не вполне понимая, что это такое. Ибо прерываний у меня в системе будет дохерища и всех (или почти всех) их надо как-то бесшовно склеить с РТОС.
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments