cancel
Showing results for 
Search instead for 
Did you mean: 

Struggling with USART1/LIN interrupts on STM32F3

Dazai
Associate III

I have a design using USART1 on an STM32F3 as a LIN slave receiver using the old standard peripheral drivers from ST Micro.  The code is too much to post here, but I have LIN Break Detect and RX Not Empty interrupts enabled, and for some reason under some condition (not sure the cause yet), an interrupt is firing in USART1 and not getting cleared so the code is stuck in the ISR.

My first question: are there any LIN examples from ST Micro using the standard peripheral drivers? E.g. functions like USART_ReceiveData(), USART_GetITStatus(), etc. I have not been successful in finding any.

My second question: what is triggering the USART interrupt and why isn't it getting cleared?

The code for the setup and ISR for USART1 is below.  The idea is, a LIN Break Detect interrupt on USART1 indicates the start of a LIN message, so clear the message buffer and reset the buffer index.  Subsequent RXNE interrupts are for the message bytes being received; after receiving 0x55 (LIN sync) and the address/PID byte, the total expected message length is calculated.  Once the expected number of bytes have been received, the buffer index and total expected bytes should match, so the message buffer is written to a FreeRTOS queue for another task to read.

When I run this code with the debugger, the first interrupt goes into the RXNE case, then immediately enters the ISR again and none of the status checks return true, so the code just keeps entering the ISR repeatedly and none of my RTOS tasks run.  The state of the USART1 ISR, ICR, and CR1 registers while "stuck" in the ISR follow:

Dazai_1-1722377807126.png

Dazai_0-1722377778121.png

Dazai_2-1722377884096.png

I see the Overrun bit set in the ISR register, which makes me think the USART1 is interrupting due to and RX overrun, but why isn't it getting cleared in the interrupt service routine (ORE case)?

USART1 setup:

 

	USART_InitStruct.USART_BaudRate = 19200;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_Parity = USART_Parity_No ;
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

	//Turn on periph clock for UART3
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

	// Initialize USART1 with parameters above.
	USART_Init (USART1, &USART_InitStruct);

	// Enable DMA TX request.
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

	// Enable DMA channel for memory-to-peripheral (transmit) direction.
	DMA_Cmd(DMA1_Channel4, ENABLE);

	// Enable LIN mode
	USART_LINCmd(USART1, ENABLE);

	// Enable LIN break and Rx interrupts
	USART_ITConfig(USART1, USART_IT_LBD, ENABLE);
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

	// Set up NVIC for the UART interrupt
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 10;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 10;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&NVIC_InitStructure);

	//Enable UART
	USART_Cmd(USART1, ENABLE);

 

USART1 interrupt handler:

 

 

void USART1_IRQHandler(void)
{	
    // LIN message format is:
    // LIN Break
    // Address/PID
    // Data
    if (USART_GetITStatus(USART1, USART_IT_LBD))
    {
	USART_ClearFlag(USART1, USART_FLAG_LBD);
	// clear message buffer, reset index and total length variables
	memset(msgBuf.msgBytes, 0, sizeof(msgBuf.msgBytes));
	msgIdx = 0;
	totalMsgLen = 0xFF;
    }
    else if (USART_GetITStatus(USART1, USART_IT_RXNE))
    {
        msgBuf.msgBytes[msgIdx++] = USART_ReceiveData(USART1);
        USART_ClearFlag(USART1, USART_FLAG_RXNE);
    }
    // attempt at clearing overrun interrupt, which may or may not be enabled? But doesn't fix the issue.
    else if (USART_GetITStatus(USART1, USART_IT_ORE))
    {
        USART_ReceiveData(USART1);
    }
    
    // If 2 bytes received, sync (0x55) and PID/address, assign total message length for
    // that address/PID.
    if (msgIdx == 2)
    {
	switch (msgBuf.msgBytes[1])
	{
            // proprietary information, result is totalMsgLen gets set to some value > 2.
	}
    }

    if (msgIdx == totalMsgLen)
    {
        msgIdx = 0;
        totalMsgLen = 0xFF;

        xQueueSendToBackFromISR(xLINRxQueue, &msgBuf, &xHigherPriorityTaskWoken);

        // End the ISR!
        portEND_SWITCHING_ISR( xHigherPriorityTaskWoken);
    }

    return;
}

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Dazai
Associate III

I think my issue was due to enabling the transmit DMA during USART setup.  I don't want to enable it until a LIN message needs to be sent.  Commenting out that line seems to have resolved the problem.

View solution in original post

1 REPLY 1
Dazai
Associate III

I think my issue was due to enabling the transmit DMA during USART setup.  I don't want to enable it until a LIN message needs to be sent.  Commenting out that line seems to have resolved the problem.