USART FIFO Overflow problem LPC54113

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

USART FIFO Overflow problem LPC54113

3,379 次查看
Dozer15
Contributor I

Hello, first time poster.  I'm creating and debugging a project for the LPC54113J256 in the MCUExpresso IDE (v11.6.1) on a PC.  The USART0 FIFO keeps overflowing, and I can't figure out why.  I'm new to both USART and interrupts (and to NXP MCUs in general), so I'm likely missing something simple.

I'm using an Interrupt Service Routine (ISR) to read data from the USART0 FIFO to ring buffer, which is called whenever the FIFO is not empty. In main(), I disable interrupts while extracting data from the ring buffer.  The incoming data is at 9600 baud, so I expect to be receiving roughly 1 byte every 10 milliseconds, and so I figure I should be able to suspend interrupts for up to 150 milliseconds or so without overflowing the FIFO, which is 16 bytes long.

However, I found that even when I keep the ring buffer reading code extremely simple, I'm getting FIFO overflow.  I then added some clock() commands to check before and after running the disabling the interrupts, and it seems that simply calling USART_DisableInterrupts() is taking around 300 milliseconds!  Assuming that I'm applying clock() appropriately, this explains why the overflow error occurs, but I don't understand why this command takes so long to run?  I tried replacing this function call with a straight write of 0xA to the FIFOINTENCLR register, and this similarly took around 300 milliseconds.

I believe I have the clock running at the default 12 MHz (clock diagram from IDE attached); but, I tried changing the clock source to the high frequency FRO at 48 MHz, and still saw that disabling the interrupts took roughly 300 milliseconds.

In the attached code, I have simplified things so that the code (I believe) behaves as follows:

1) In both ISR and main(), I check for FIFO overflow and reset things if error is detected.

2) In the ISR, as data is read from the FIFO, it is placed in the ring buffer as long as the ring buffer is not full; if the ring buffer is full, a flag is set and the data from the FIFO is discarded.

3) In main(), if the ring buffer full flag is set, the program disables interrupts, resets the ring buffer receive and transmit addresses, then re-enables interrupts.  clock commands are used to check different timing.  (I also issue two successive clock commands to check how long it takes clock() to execute (the output shows it takes roughly 60 milliseconds).

Here is typical output:

Hello World
ISR: USART0 Overflow and RX0 Buffer Full
Main: RX0 Buffer Full
Interrupt disable took 260 milliseconds
Commands plus Interrupt re-enable took 90 milliseconds
Call to clock() took 50 milliseconds
ISR: USART0 Overflow and RX0 Buffer Full
Main: RX0 Buffer Full
Interrupt disable took 300 milliseconds
Commands plus Interrupt re-enable took 60 milliseconds
Call to clock() took 90 milliseconds
ISR: USART0 Overflow and RX0 Buffer Full
Main: RX0 Buffer Full
Interrupt disable took 320 milliseconds
Commands plus Interrupt re-enable took 60 milliseconds
Call to clock() took 70 milliseconds
ISR: USART0 Overflow and RX0 Buffer Full
Main: RX0 Buffer Full
Interrupt disable took 310 milliseconds
Commands plus Interrupt re-enable took 60 milliseconds
Call to clock() took 60 milliseconds

Any advice would be appreciated.  It seems odd to me that these commands take so long to run.

Attached are my code (in both plain .txt and in more readable .docx) plus an image of the clock configuration (.png).

0 项奖励
回复
5 回复数

3,367 次查看
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I have checked your code, it appears that the core of LPC54113 runs in 12Mhz, it is a bit low, it can run in 100MHz normally, in this way, the core will have enough capability to deal with ISR.

Regarding your remark " the incoming data is at 9600 baud, so I expect to be receiving roughly 1 byte every 10 milliseconds, and so I figure I should be able to suspend interrupts for up to 150 milliseconds or so without overflowing the FIFO, which is 16 bytes long.", the baud rate is bit rate, assume the byte format is 8 bits data, one start bit, two stop bits, the total bits of one byte is 11 bits.

at 9600 baudrate, a byte transfer frequency is:

9600/11=872Hz, in other words, do not consider the interval between two bytes, the byte transfer frequency is 872Hz.

I have checked the code, I do not suggest you add the printf() function in ISR even if it is error flag, you can set the error flag in ISR and handle it in main. The printf() takes a long time

Your application code is a bit confused, I suggest you read receiver in only ISR, do not read receiver FIFO in both main loop and loop in ISR.

Hope it can help you

BR

XiangJun Rong

 

 

 

0 项奖励
回复

3,346 次查看
frank_m
Senior Contributor III

> I have checked the code, I do not suggest you add the printf() function in ISR even if it is error flag, you can set the error flag in ISR and handle it in main. The printf() takes a long time

I wold second that.
In general, avoid calling functions that take a long time, or relying on interrupts in any way.

All the code called within interrupt context run on the same priority, and cannot be interrupted by itself (or interrupts of identical priority). Follow-up interrupts are only processed once the first invokation is finished. Which causes Rx overflows.

0 项奖励
回复

3,326 次查看
Dozer15
Contributor I

Thank you Xiangjun and Frank for your advice.  Xiangjun, you are of course correct about the baud rate, I made a silly mistake in my head and was off by an order of magnitude.

I switched to using GPIO pins and a scope to check the timing rather than using the clock() function.  (I also upped the system clock to 150 MHz). I learned that:

1) In main(), it appears that any time I call a printf() command (which prints output to the terminal in the IDE's debug session (via the SWDIO/SWCLK pins), that the ISR for "Read data from USART0" fails to execute until that command completes; this printfs take on the order of 300ms, explaining why the FIFO overloads.

2) I noticed that the clock() command similarly takes about 300ms to execute (observed by setting a GPIO high, calling clock(), then setting GPIO low, and viewing the GPIO pin on the scope), and that the ISR similarly fails to execute during this time.

So, it appears to me that both printf() and clock() block this ISR while executing.  Does this make sense?  If so, I can avoid the issue by simply not using these functions (which is fine, since I was only using for test purposes anyway).  Unless there is something I can change to prevent this blocking of the ISR.

0 项奖励
回复

3,292 次查看
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I suppose that you have to replace the while with if. Pls have a try.

BR

XiangJun Rong

 

void FLEXCOMM0_IRQHandler(void)
{
uint8_t data;

/* USART0 FIFO Overflow detection and handling */
if (kUSART_RxError & USART_GetStatusFlags(USART0))
{
// Report overflow condition
printf("ISR: USART0 Overflow");
if(rx0bufferfullflag == 1) printf(" and RX0 Buffer Full");
printf("\n");
// Reset ring buffer and clear flags
rx0index = 0;
tx0index = 0;
rx0bufferfullflag = 0;
USART0overflowflag = 0;
// Clear FIFO
while(kUSART_RxFifoNotEmptyFlag & USART_GetStatusFlags(USART0)) USART_ReadByte(USART0);
// Clear overflow status bit
USART_ClearStatusFlags(USART0, kUSART_RxError);
}

// Read data from USART0 FIFO
while (kUSART_RxFifoNotEmptyFlag & USART_GetStatusFlags(USART0))
{
data = USART_ReadByte(USART0);

if(((rx0index + 1) % RX0BUFFERSIZE) != tx0index) // If ring buffer is not full, add new data
{
rx0buffer[rx0index] = data;
rx0index++;

}
else rx0bufferfullflag = 1; // If ring buffer is full, set flag
}

SDK_ISR_EXIT_BARRIER;
}

0 项奖励
回复

3,309 次查看
frank_m
Senior Contributor III

> So, it appears to me that both printf() and clock() block this ISR while executing.  Does this make sense?  If so, I can avoid the issue by simply not using these functions (which is fine, since I was only using for test purposes anyway).

I think yes, avoiding those functions seems the best solution.
I suppose with clock(), you mean the ANSI compatible clib function.
You can check if you find the sources for both function, and check how they are implemented. But I suppose they are provided as a link library only.

In basically all commercial MCU projects I had participated in different companies, the C standard libs were avoided in general, both because of size and runtime issues. When such clib functionality was required, it was implemented by ourselves, tailored to our specific needs.

In private projects I occasionally use printf() and similiar functions in the implementation and testing phase, but quickly learned to avoid it in interrupt context.

By the way, the MCUXpresso SDKs usually provide a debug console implementation that seems capable of running in non-blocking mode. In my MCUXpresso projects, it comes in utilities/fsl_debug_console*.* functions. I never needed it yet, though.

0 项奖励
回复