Jump to content

    

Утечка стека в задаче

Пишу под FREErtos для sam3s (Cortex-M3). В одной из задач, которая общается через UART возможно происходит утечка стека(возможно потому, что я не могу это пока подтвердить). Программа работает некоторое время, затем начинает сбоить передача в UART, при этом остальные задачи работают нормально. Увеличение размера стека приводит к увеличению времени нормальной работы. С помощью внутрисхемной отладки выяснил, что сбои передачи заключается в опережении указателя чтения(pxReadFrom) указателя записи(pcWriteTo) очереди на передачу в UART. Есть подозрение на прерывание UART. Я не использую никаких атрибутов для функции-обработчика прерывания(в примере их не было), хотя когда писал для sam7 использовал naked. Функция vTaskList показывает, что использование стека стоит на месте. Пытаюсь вставить в код процесса критическую секцию - все зависает.

Код процесса:

void vShellThread(HANDLE xPort) {
SHELL xShell = { xPort, xShellCommands };
char pcInputLine[sHELL_MAX_INPUT_LEN];
char *pcToken, *pcNextToken;
char *pcArgs[sHELL_MAX_ARGUMENTS + 1];
char *pcCmd;
uint32_t uiArgsCount = 0;

if (!xSerialIsOpen(xShell.xSerialPort))
	assert(!"Serial port for shell not opened.");
// print shell header
xSerialPutString(xShell.xSerialPort, "Shell command interface v0.1.\n",
		1000);
// set local echo enabled
xSerialSetEchoEnabled(xPort, pdTRUE);
while (pdTRUE) {
	xSerialPutString(xShell.xSerialPort, "shell$ ", 1000);

	if (xSerialGetLine(xShell.xSerialPort, pcInputLine,
			SHELL_MAX_INPUT_LEN, 6000) != pdPASS) {
		xSerialPutString(xShell.xSerialPort,
				"\nERR: too long input line.\n", 1000);
		//continue;
	}

	// get command
	pcToken = strtok_m(pcInputLine, pcShellSeparators, &pcNextToken);
	if (pcToken == NULL)
		continue;
	pcCmd = pcToken;
	uiArgsCount = 0;
	// get arguments
	while (pcNextToken != NULL) {
		pcToken = strtok_m(NULL, pcShellSeparators, &pcNextToken);
		if (uiArgsCount > SHELL_MAX_ARGUMENTS) {
			xSerialPutString(xShell.xSerialPort,
					"\nERR: max arguments limit\n", 1000);
			pcCmd = NULL;
			break;
		}
		pcArgs[uiArgsCount++] = pcToken;
	}
	pcArgs[uiArgsCount] = NULL;
	if (pcCmd != NULL) {
		if (!prvShellExec(&xShell, pcCmd, uiArgsCount, pcArgs))
			xSerialPutString(xPort,
					"Unknown cmd. Type help for information.\n", 100);
	}
	xSerialPutString(xPort, "Unknown cmd. Type help for information.\n",
			1000);
}
}

 

Код используемых функций:

signed portBASE_TYPE xSerialPutString(HANDLE xPort, char *pcString,
	portTickType xBlockTime) {
while (*pcString != '\0') {
	if (xSerialPutChar(xPort, *pcString++, xBlockTime) != pdPASS)
		return pdFAIL;
}
return pdPASS;
}

 

signed portBASE_TYPE xSerialPutChar(HANDLE xPort, const char cOutChar,
	portTickType xBlockTime) {

USART_PORT *port = (USART_PORT*) xPort;
assert (xPort != NULL);

if (xQueueSend(port->xTransmitQueue, &cOutChar, xBlockTime) != pdPASS)
	return pdFAIL;
USART_EnableIt(port->xHwPort, US_IER_TXRDY);

return pdPASS;
}

 

signed portBASE_TYPE xSerialGetLine(HANDLE xPort, char *pcDest,
	uint32_t iMaxLen, portTickType xBlockTime) {
char c;
uint32_t len = 0;
while (xSerialGetChar(xPort, &c, xBlockTime) == pdPASS) {
	if ((c != '\n') && (c != '\r') && (c != '\b')) {
		if (++len == iMaxLen)
			return pdFAIL;
		*pcDest++ = c;
	} else if ((c == '\b') && (len > 0)) {
		pcDest--;
		len--;
	} else if (c == '\n') {
		*pcDest = 0;
		return pdPASS;
	}
}
return pdFAIL;
}

 

signed portBASE_TYPE xSerialGetChar(HANDLE xPort, char *pcRxedChar,
	portTickType xBlockTime) {

USART_PORT *port = (USART_PORT*) xPort;
assert(xPort != NULL);
if (!(port->uiOpened))
	return pdFAIL;

if (xQueueReceive(port->xReciveQueue, pcRxedChar, xBlockTime) == pdPASS) {
	if (port->uiEcho)
		xSerialPutChar(xPort, *pcRxedChar, xBlockTime);
	return pdPASS;
}
return pdFAIL;
}

 

Код прерывания:

void UART1_IrqHandler(void) {
portBASE_TYPE xHigerPrioritTaskWoken = pdFALSE;

prvSerialExchange(1, &xHigerPrioritTaskWoken);

portEND_SWITCHING_ISR(xHigerPrioritTaskWoken);
}

void prvSerialExchange(uint32_t iPortIndex,
	portBASE_TYPE *xHigerPrioritTaskWoken) {
portBASE_TYPE status;
char cChar;
// get status
status = xSerial_ports[iPortIndex].xHwPort->US_CSR;

if ((status & US_CSR_TXRDY) == US_CSR_TXRDY) {
	// transmit symbol
	if (xQueueReceiveFromISR(xSerial_ports[iPortIndex].xTransmitQueue,
			&cChar, xHigerPrioritTaskWoken) == pdTRUE) {
		xSerial_ports[iPortIndex].xHwPort->US_THR = cChar;
		// disable interrupt if nothing to send anymore
		if (xQueueIsQueueEmptyFromISR(
				xSerial_ports[iPortIndex].xTransmitQueue))
			USART_DisableIt(xSerial_ports[iPortIndex].xHwPort,
					UART_IER_TXRDY);
	}
}
if ((status & US_CSR_RXRDY) == US_CSR_RXRDY) {
	// receive symbol
	cChar = xSerial_ports[iPortIndex].xHwPort->US_RHR;
	xQueueSendFromISR(xSerial_ports[iPortIndex].xReciveQueue, &cChar, xHigerPrioritTaskWoken);
}
}

 

Share this post


Link to post
Share on other sites

Утечки стека не бывает, бывает переполнение стека.

Share this post


Link to post
Share on other sites

С приоритетом прерывания не напутали случайно?

Share this post


Link to post
Share on other sites
С приоритетом прерывания не напутали случайно?

 

Да. Проверил приоритет прерывания USART. Он был выше чем у системных прерываний FreeRTOS. Исправил - все заработало. Спасибо.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this