LPC-Link causes Interrupt Havoc

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC-Link causes Interrupt Havoc

1,136 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kjhuebner on Sat Sep 25 09:31:23 MST 2010
:DAfter twenty years of writing software and with an MS in computer science, I still prefer printf debug statements in a program -- for reasons I'll mention later.

[B]My problem is Code Red's LPC-Link (which can be used to do a printf output to the LPCXpresso IDE console) corrupts the periodicity of interrupts.[/B]

Setup:
-------
My current goal is to convert an Atmega32 program into an LPC1114 program.  So my foray into the Cortex0 world is to write some interrupt code and understand the best approach for debugging in the LPCXpresso IDE.

So I wrote some test code...

I first defined a 32bit timer-based interrupt to run at 2Khz.  The interrupt handler only toggles an IO pin high and low, then exits.   The handler contains NO printf().

Then in the main() loop I put a printf() for debugging purposes. 

However, when tested, I found that when printf was compiled in main(), the handler ran haphazardly and aperiodic.  Removing the printf, the interrupt ran a perfect 2Khz.

My hunch:  No doubt Code Red's libraries establish one or more interrupts that take precedence over my application's timer interrupt.  Why things are so draconian I don't know. 

Possible Solutions
---------------------
1.  Redefine interrupt priorities.  I'm not sure of the feasibility of this, since I determined that my timer interrupt priority level=0 already, which is the highest priority.

2.  Forgo LPC Link/semi-hosting and add a compact UART library with a printf function.  If anyone is aware of a library for me, please let me know.  I would prefer a library that adds no more than 4-6K as I want to keep a minimum debug overhead.  

3.  Configure the compact Redlib library to use UART, rather than pipe output to the LPC-Link feature.   Code Red's printf library (integer based) is wonderfully compact and ideal for debug purposes, but how do I reconfigure it?

If anyone has any ideas for me -- or if the Code Red support team could lend me their wisdom -- I would much appreciate the help.

Thanks!

Ken Huebner
Software Engineer


As for explaining what's so great about printf(), here's my reasons:

[B][I]:cool:Why is printf() is still the best debugging technique?[/I][/B]

Its simple to use, but more importantly...

I am able to monitor signals and values in real-time.
I am able to review and analyze a debug trace for hours on end if I need to.
I am able to copy and paste a debug trace and keep a historic record, for days or months.

Case in point: 

I recently wrote a very sophisticated software module that reads a 3-axis accelerometer.  I would never have never been able to interpret what was happening with this device in realtime using only a hardware based debugger.  God help the soul that relies solely a hardware based debugger.  I very much needed a historic log of dozens of parameters and sequence of events over many seconds of operation over many spatial movements.  Only printf() can effectively give me this ability.

So my hope is this:  I hope that developers and the Code Red support team recognize that getting printf() to work without creating contention issues with the most basic of functions, such as timer interrupts is crucial to my work, and to the work of other developers like me.
0 Kudos
Reply
4 Replies

1,098 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by kjhuebner on Sun Sep 26 10:16:17 MST 2010
:)I now have printf working along with the timer interrupt WITHOUT issues.

The timer handler code runs periodically at a perfect 2Khz -- even with printf intermittently printing in main().

I followed the approach suggested by the Code Red support team...

Setup UART for writing, "overrode" the __write() function in the Redlib library, and set the target linker to Redlib(no hosting).

I noticed this solution increased my codebase by 500-1000 bytes.  It works for now, but I may replace with a more compact printf library if I run out of dev space.

Thanks everyone!
Ken


Finding source code to setup UART for the LPC1100 is not easy to come by, so I'll share my code snippet to make this happen.

[LEFT]
 
 
// PROTOTYPES

void UART0_Init(int baudrate);
void UART0_Sendchar(char c);
char UART0_Getchar();
void UART0_PrintString(char *pcString);

 
/**
* Init stdio serial data stream.
*/
void init_stdio(void)
{
UART0_Init(38400);

}

 
/*
* Function to set up UART.
*
* @param baudrate baud rate eg. 38400
*
source: copied from lpc1114 uart source snippet I downloaded.
*/
void UART0_Init(int baudrate)
{
uint32_t Fdiv;
uint32_t regVal;
#ifdef COMPILE_DEBUG_UART_READ
LPC_IOCON->PIO1_6 &= ~0x07; // UART I/O config
LPC_IOCON->PIO1_6 |= 0x01; // UART RXD
#endif
LPC_IOCON->PIO1_7 &= ~0x07;
LPC_IOCON->PIO1_7 |= 0x01; // UART TXD

LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
LPC_SYSCON->UARTCLKDIV = 0x1; // divided by 1

LPC_UART->LCR = 0x83; // 8 bits, no Parity, 1 Stop bit
regVal = LPC_SYSCON->UARTCLKDIV;
Fdiv = (((SystemCoreClock*LPC_SYSCON->SYSAHBCLKDIV)/regVal)/16)/baudrate ;
LPC_UART->DLM = Fdiv / 256;
LPC_UART->DLL = Fdiv % 256;
LPC_UART->LCR = 0x03; // DLAB = 0
LPC_UART->FCR = 0x07; // Enable and reset TX and RX FIFO.

// Read to clear the line status.
regVal = LPC_UART->LSR;

&#12288;
// Ensure a clean start, no data in either TX or RX FIFO.
while (( LPC_UART->LSR & (UART_U0LSR_THRE|UART_U0LSR_TEMT)) != (UART_U0LSR_THRE|UART_U0LSR_TEMT) )
;

// Dump data from RX FIFO
while ( LPC_UART->LSR & UART_U0LSR_RDR_DATA )
{
regVal = LPC_UART->RBR;
}
}

&#12288;
/*
Function to prints the string out over the UART
*/
void UART0_PrintString(char *pcString)
{
int i = 0;
// loop through until reach string's zero terminator
while (pcString != 0)
{
UART0_Sendchar(pcString); // print each character
i++;
}
}
/*
Function to send character over UART
*/
void UART0_Sendchar(char c)
{
while( (LPC_UART->LSR & UART_U0LSR_THRE) == 0 ); // Block until tx empty

LPC_UART->THR = c;
}

&#12288;
// Function __write()
//
// Called by bottom level of printf routine within RedLib C library to write
// a character. With the default semihosting stub, this would write the character
// to the debugger console window . But this version writes
// the character to the UART.
int __write (int iFileHandle, char *pcBuffer, int iLength)
{
unsigned int i;
for (i = 0; i<iLength; i++)
{
UART0_Sendchar(pcBuffer); // print each character
}
return iLength;
}

&#12288;
// Function __readc()
//
// Called by bottom level of scanf routine within RedLib C library to read
// a character. With the default semihosting stub, this would read the character
// from the debugger console window (which acts as stdin). But this version reads
// the character from the UART.
int __readc (void)
{
#ifdef COMPILE_DEBUG_UART_READ
char c = UART0_Getchar();
return (int)c;
#else
return 0;
#endif
}

&#12288;
#ifdef COMPILE_DEBUG_UART_READ
/*
Function to get character from UART
*/
char UART0_Getchar()
{
char c;
while( (LPC_UART->LSR & UART_U0LSR_RDR_DATA) == 0 )
; // Nothing received so just block
c = LPC_UART->RBR; // Read Receiver buffer register
return c;
}
#endif

&#12288;
[/LEFT]
0 Kudos
Reply

1,098 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by igorsk on Sun Sep 26 08:35:41 MST 2010
Here's a small printf library.
http://code.google.com/p/format/
0 Kudos
Reply

1,098 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by CodeRedSupport on Sat Sep 25 11:57:04 MST 2010
There is some information on how the semihosting mechanism behind printf works in this thread:

http://knowledgebase.nxp.com/showthread.php?t=190

but basically by default when you use printf the core will stop executing whilst the semihosting  operation takes place.

Thus if you want to use printf with interrupts continuing to execute, you need to provide you own "bottom" layer which writes your characters out via an alternative channel to the semihosting one, such as a UART. The function you need to reimplement is [FONT=Courier New][SIZE=1]__write [/SIZE][/FONT](if you are using LPCXpresso 3.5 on Windows) or [FONT=Courier New][SIZE=1]__sys_write[/SIZE][/FONT] (if you are using the LPCXpresso 3.7 beta on Linux).

There is a simple example showing how this can be done in the LPC1768 examples (RDB1768cmsis_UARTprintf IIRC). It should be fairly straightforward to use this as a template for doing something similar using LPC13 too.

Regards,
CodeRedSupport.
0 Kudos
Reply

1,098 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Ex-Zero on Sat Sep 25 10:15:41 MST 2010
I've used several times a simple UART debug function to reduce code size (LPC1343). A simple UART init and string output function combined with itoa() helped to output basic data without a lot of overhead :).
A simple itoa() is described in:

http://knowledgebase.nxp.com/showthread.php?t=644&highlight=itoa
0 Kudos
Reply