Reply by jerome_gueunier October 11, 20042004-10-11

Writing 0 to VICVECTADDRESS release interrupt priority level into the
VIC see ARM VIC primecell specification

Je

--- In , Robert Adsett <subscriptions@a...> wrote:
> At 02:33 PM 10/8/04 +0000, you wrote:
> >I do now have the VicVectAddr = 0;, but that doesn't help if it
> >doesn't get called.
>
> Speaking of which, I just reviewed your code. You don't appear to be
> actually calling your uart initialization code anywhere (I don't see
how
> you would get your baud rate right if you hadn't but...). Also you
should
> probably disable interrupts before disabling a specific interrupt via
> VICIntEnClr
>
> Robert
>
> " 'Freedom' has no meaning of itself. There are always restrictions,
> be they legal, genetic, or physical. If you don't believe me, try to
> chew a radio signal. "
>
> Kelvin Throop, III



An Engineer's Guide to the LPC2100 Series

Reply by peterburdine October 9, 20042004-10-09

Thanks, Bill.

I was about to email you about that actually. I had just changed all
the code necessary for it to compile on the Keil's compiler. The
strange thing is that it doesn't work with their simulator, but it
works on the real hardware. All the code I wrote worked on the
simulator, but not the real hardware. Guess I'll have to complain.

Would you like me to email you the changed code for you to post or for
reference? I think the only things that I needed to change were the
inline assembly and I had to make the unions in uartRegs_t non-anonymous.

--Peter

--- In , "Bill Knight" <BillK@t...> wrote:
> Have a look at UT040803A.zip in the files section on Yahoo.
> It contains operational uart code for both polled and interrupt
> modes of operation.
>
> Regards
> -Bill Knight
> www.theARMPatch.com



Reply by Bill Knight October 9, 20042004-10-09
Have a look at UT040803A.zip in the files section on Yahoo.
It contains operational uart code for both polled and interrupt
modes of operation.

Regards
-Bill Knight
www.theARMPatch.com


Reply by Robert Adsett October 8, 20042004-10-08
At 08:44 PM 10/8/04 +0000, you wrote:
> > OK, but where in the interrupt?
>The first line of code that should always be executed.
This may seem obtuse, but first line of C or asm? A good optimizer on the
ARM may change the order of execution in non-obvious ways. > > > > This is potentially a problem. I haven't looked at in detail but
> > >you are
> > > > using the same buffer routine here as you are in the non-interrupt
> > > > code. The ground is very unstable here.
> > >I removed the vectored irq setup, still doesn't work.
> >
> > This is not a matter of vectored or not.
>
>If I removed the vectored setup, then there is only one interrupt left
> to call the isr, so there should not be a problem.

It doesn't matter if it is 1 interrupt or 10 the potential for a problem
still exists, you are calling the same buffer for both the interrupt and
mainline code.
>I gave up on that and started over, and this is what I think I am
>doing. I start by disabling all interrupts globally and for the uart.
> Then I enable only the RBR interrupt, then the uart vic. In the main
>I print out 123 by using a for loop as a delay. I setup the rbr isr
>to print out '!' if it receives a character. Now the problem is when
>I send 2 characters the processor resets. Is there something wrong w/
>my code?

Resetting may actually be a good thing here ;) At least it suggests to me
that you might actually be getting your interrupt this time. >#include <stdio.h>
>#include "../ArmCommon/types.h"
>#include "../ArmCommon/LPC22xx.h"
>#include "../ArmCommon/LPC2294.h"
>
>#define TX_BUFFER_LENGTH 64
>
>static Uint16 txBytes = 0;
>static Uint16 txRdPos = 0;
>static Uint16 txWrPos = 0;
>static Uint16 txBuffer[TX_BUFFER_LENGTH];
>
>void uart0_config (void);
>void uart0_isr (void);
>void uart0_sendByte (Uint8);
>int putchar(int);
>int main (void);
>Uint32 irqBackup;
>
>void disableInterrupts (void);
>void enableInterrupts (void);
>
>void disableInterrupts (void) {
> irqBackup = VICIntEnable;
> VICIntEnable = 0;
>}
>void enableInterrupts (void) {
> VICIntEnable = irqBackup;
>}

I'd feel a lot better about these if you were really disabling and
restoring interrupts at the CPU level rather than just the VIC flags, but I
don't think that's your problem source. >void uart0_config (void) {
> volatile Uint8 x;
> // Setup UART 0
> U0LCR = 0x80; // Enable DLAB
> U0DLL = 0x36; // Setup BGR
> U0DLM = 0x00; // ~57.6 kbps @ 50 Mhz
> U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1 stop bit
>
> // Reset the FIFOs
> U0FCR = 0xC7; // RX FIFO trigger level 8 chars, reset tx and rx fifo,
>enable fifos
>
> // Clear any old irqs
> x = U0LSR;
> x = U0RBR;
> x = U0IIR;
>
> // Setup Interrupts for UART0
> U0IER = 0x1; // Only RBR IRQ on
> VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
> VICVectAddr6 = (Uint32) uart0_isr;
> VICVectCntl6 = 0x20 | 6;
>}
>
>void uart0_isr (void) __irq {
> volatile Uint8 x;
> uart0_sendByte('!');

There are problems here. First you never empty the buffer so the buffer
becomes blocked very quickly. Now watch what happens when you send a
string of bytes through that will fill the buffer up.

- First byte gets written at point A--
- Second byte comes along right behind it and also gets written at point
A-- since the first byte has moved into the shift register.
- The rest of the buffer gets filled up via the else clause (Point B--) and
then
- the next call sits in the infinite loop at point C--
- Shortly after the UART finally catches up and finishes sending the first
character and moves the second character into the shift register while
flagging an interrupt.
- The interrupt fires and the first thing that occurs is a call to
uart0_sendByte which goes into an infinite loop at point C-- since the
buffer is full.

You get two characters out, one interrupt fires and you never exit the
interrupt routine. Unless you have a watchdog enabled I would expect this
to hang, not reset.

Unless the interrupt stack isn't setup correctly. I'm not familiar with
the startup code for your compiler so someone else might be better suited
to suggest if that is an issue. > // Clear IRQ
> x = U0LSR;
> x = U0IIR;
> x = U0RBR;
> VICVectAddr = 0;
>}
>
>void uart0_sendByte(Uint8 a) {
> // Wait until there is room in the buffer

C--

> while(txBytes == TX_BUFFER_LENGTH);

A---

> if(U0LSR&0x20) { // If the chip buffer is empty, put it there
> U0THR = a;
> }

B--

> else { // Put in software buffer
> disableInterrupts();
> txBuffer[txWrPos] = a;
> txWrPos++;
> txWrPos = (txWrPos == TX_BUFFER_LENGTH)?0:txWrPos;
> txBytes++;
> enableInterrupts();
> }
>}
>
>int putchar(int a) {
> uart0_sendByte((int)a);
> return 0;
>}
>
>int main (void) {
> Uint16 x;
> PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
> VPBDIV = 0x1;
> VICIntSelect = 0; // Only IRQs, no FIQs
> VICIntEnClr = 0xFFFFFFFF; // Disable all irqs
> uart0_config();
> // Proof that it can send more than one character
> printf("1");
> for(x = 0; x < 1000; x++);
> printf("2");
> for(x = 0; x < 1000; x++);
> printf("3");
>
> while(1);
>}

Remember there are three places to disable/enable interrupts from the UART

- the uart itself
- the VIC peripheral
- the CPU

To avoid subtle phase problems (especially when first starting to work with
interrupts) it makes sense as a simple precaution to disable interrupts at
the CPU level when enabling or disabling them at the other levels.

Again I'd suggest looking at other UART code for this processor (take a
look at the pointers from an earlier post). " 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III


Reply by peterburdine October 8, 20042004-10-08


> OK, but where in the interrupt?
The first line of code that should always be executed.

>
> No, switch does not work that way. It is an exact match, not a bit
> mask. And having multiple bits set is not only possible but likely,
at the
> very least TEMT and THRE are often on simultaneously.
>
You are correct, I was just being stupid.

> > > This is potentially a problem. I haven't looked at in detail but
> >you are
> > > using the same buffer routine here as you are in the non-interrupt
> > > code. The ground is very unstable here.
> >I removed the vectored irq setup, still doesn't work.
>
> This is not a matter of vectored or not.

If I removed the vectored setup, then there is only one interrupt left
to call the isr, so there should not be a problem. I gave up on that and started over, and this is what I think I am
doing. I start by disabling all interrupts globally and for the uart.
Then I enable only the RBR interrupt, then the uart vic. In the main
I print out 123 by using a for loop as a delay. I setup the rbr isr
to print out '!' if it receives a character. Now the problem is when
I send 2 characters the processor resets. Is there something wrong w/
my code?

#include <stdio.h>
#include "../ArmCommon/types.h"
#include "../ArmCommon/LPC22xx.h"
#include "../ArmCommon/LPC2294.h"

#define TX_BUFFER_LENGTH 64

static Uint16 txBytes = 0;
static Uint16 txRdPos = 0;
static Uint16 txWrPos = 0;
static Uint16 txBuffer[TX_BUFFER_LENGTH];

void uart0_config (void);
void uart0_isr (void);
void uart0_sendByte (Uint8);
int putchar(int);
int main (void);
Uint32 irqBackup;

void disableInterrupts (void);
void enableInterrupts (void);

void disableInterrupts (void) {
irqBackup = VICIntEnable;
VICIntEnable = 0;
}
void enableInterrupts (void) {
VICIntEnable = irqBackup;
}

void uart0_config (void) {
volatile Uint8 x;
// Setup UART 0
U0LCR = 0x80; // Enable DLAB
U0DLL = 0x36; // Setup BGR
U0DLM = 0x00; // ~57.6 kbps @ 50 Mhz
U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1 stop bit

// Reset the FIFOs
U0FCR = 0xC7; // RX FIFO trigger level 8 chars, reset tx and rx fifo,
enable fifos

// Clear any old irqs
x = U0LSR;
x = U0RBR;
x = U0IIR;

// Setup Interrupts for UART0
U0IER = 0x1; // Only RBR IRQ on
VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
VICVectAddr6 = (Uint32) uart0_isr;
VICVectCntl6 = 0x20 | 6;
}

void uart0_isr (void) __irq {
volatile Uint8 x;
uart0_sendByte('!');

// Clear IRQ
x = U0LSR;
x = U0IIR;
x = U0RBR;
VICVectAddr = 0;
}

void uart0_sendByte(Uint8 a) {
// Wait until there is room in the buffer
while(txBytes == TX_BUFFER_LENGTH);
if(U0LSR&0x20) { // If the chip buffer is empty, put it there
U0THR = a;
}
else { // Put in software buffer
disableInterrupts();
txBuffer[txWrPos] = a;
txWrPos++;
txWrPos = (txWrPos == TX_BUFFER_LENGTH)?0:txWrPos;
txBytes++;
enableInterrupts();
}
}

int putchar(int a) {
uart0_sendByte((int)a);
return 0;
}

int main (void) {
Uint16 x;
PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
VPBDIV = 0x1;
VICIntSelect = 0; // Only IRQs, no FIQs
VICIntEnClr = 0xFFFFFFFF; // Disable all irqs
uart0_config();
// Proof that it can send more than one character
printf("1");
for(x = 0; x < 1000; x++);
printf("2");
for(x = 0; x < 1000; x++);
printf("3");

while(1);
}



Reply by Robert Adsett October 8, 20042004-10-08
At 05:55 PM 10/8/04 +0000, you wrote:
>--- In , Robert Adsett <subscriptions@a...> wrote:
> > First a question, you say the interrupt is not being generated, how
>do you
> > know?
> >
>While I was debugging w/ JTAG, I put a breakpoint in the isr, it was
>never reached. I'd turn on an LED if one existed for my dev board.

OK, but where in the interrupt?
> >
> > This is potentially a very big problem. The LSR can (and often
>will) have
> > multiple bits set, so you will almost always be taking the default case
> > even if THRE is set (thus my question above). Given that the
>default case
> > is echoing whatever is in U0RBR (BTW what is CTI?) I would expect
>almost
> > anything if no characters had been sent to the port. Change this
>before
> > trying anything else. Then put a pin toggle or something in so you
>know if
> > the interrupt routine is ever reached.
> >
>I think that it would rarely take the default case since it would
>match the first one and then break.

No, switch does not work that way. It is an exact match, not a bit
mask. And having multiple bits set is not only possible but likely, at the
very least TEMT and THRE are often on simultaneously. >In previous version I tried enabling all of the interrupts in U0IIR,
>the ISR still didn't work, so I was trying something different here.
>
>CTI is character time out. It will generate the RBR interrupt even if
>the threshold has not been reached after 3.5-4.5 character times, so
>you know you have data waiting.

Ah, there is no separate LSR status bit for character timeout. All that
happens is IIR gets set to indicate a received character and trigger an
interrupt. LSR will simply indicate via RBR. The LSR does not 'pay
attention' to the threshold level, RBR will be set as long as at least one
character is waiting.
> >
> > This is potentially a problem. I haven't looked at in detail but
>you are
> > using the same buffer routine here as you are in the non-interrupt
> > code. The ground is very unstable here.
>I removed the vectored irq setup, still doesn't work.

This is not a matter of vectored or not. > >
> > And if U0IIR is read and used you don't need this line. In fact if
>U0IIR
> > is declared volatile (as it should be) you only would need this line
>if the
> > compiler was buggy.
>
>It is defined as volatile (using keil's development tools).

Then the increment is unneeded (and could be optimized out anyway). In any
case there is virtually no chance of this working until you fix the switch
statement (well eliminate the switch statement).

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III



Reply by peterburdine October 8, 20042004-10-08

--- In , Robert Adsett <subscriptions@a...> wrote:
> First a question, you say the interrupt is not being generated, how
do you
> know?
>
While I was debugging w/ JTAG, I put a breakpoint in the isr, it was
never reached. I'd turn on an LED if one existed for my dev board. >
> This is potentially a very big problem. The LSR can (and often
will) have
> multiple bits set, so you will almost always be taking the default case
> even if THRE is set (thus my question above). Given that the
default case
> is echoing whatever is in U0RBR (BTW what is CTI?) I would expect
almost
> anything if no characters had been sent to the port. Change this
before
> trying anything else. Then put a pin toggle or something in so you
know if
> the interrupt routine is ever reached.
>
I think that it would rarely take the default case since it would
match the first one and then break.

In previous version I tried enabling all of the interrupts in U0IIR,
the ISR still didn't work, so I was trying something different here.

CTI is character time out. It will generate the RBR interrupt even if
the threshold has not been reached after 3.5-4.5 character times, so
you know you have data waiting. >
> This is potentially a problem. I haven't looked at in detail but
you are
> using the same buffer routine here as you are in the non-interrupt
> code. The ground is very unstable here.
I removed the vectored irq setup, still doesn't work.

>
> And if U0IIR is read and used you don't need this line. In fact if
U0IIR
> is declared volatile (as it should be) you only would need this line
if the
> compiler was buggy.

It is defined as volatile (using keil's development tools).



Reply by Robert Adsett October 8, 20042004-10-08
First a question, you say the interrupt is not being generated, how do you
know?

A few comments on the code below, probably more when I get a chance to
review it properly.

At 05:12 PM 10/8/04 +0000, you wrote:
>It was a small oversite that it wasn't posted. I was copying stuff
>out that I didn't need. Since then I've made another small project
>that just tests the UART. I am now trying non vector irqs, and they
>still don't work. Here is the correct code: >#include <stdio.h>
>#include "../ArmCommon/types.h"
>#include "../ArmCommon/LPC22xx.h"
>#include "../ArmCommon/LPC2294.h"
>
>#define TX_BUFFER_LENGTH 64
>
>static Uint16 txBytes = 0;
>static Uint16 txRdPos = 0;
>static Uint16 txWrPos = 0;
>static Uint16 txBuffer[TX_BUFFER_LENGTH];
>
>void uart0_config (void);
>void uart0_isr (void);
>void uart0_sendByte (Uint8);
>int putchar(int);
>int main (void);
>
>void uart0_config (void) {
> // Setup UART 0
> U0LCR = 0x80; // Enable DLAB
> U0DLL = 0x36; // Setup BGR
> U0DLM = 0x00; // ~57.6 kbps @ 50 Mhz
> U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1 stop bit
>
> // Reset the FIFOs
> U0FCR = 0xC7; // RX FIFO trigger level 8 chars, reset tx and rx fifo,
>enable fifos
>
> // Setup Interrupts for UART0
> VICIntSelect &= 0xFFFFBFFF; // Make sure 6 is IRQ not FIQ
> VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
> VICDefVectAddr = (unsigned long) uart0_isr; // Use Non vectored irq
> U0IER = 0x7;
>}
>
>void uart0_isr (void) __irq {
> Uint8 dummy;
> switch(U0LSR) {

This is potentially a very big problem. The LSR can (and often will) have
multiple bits set, so you will almost always be taking the default case
even if THRE is set (thus my question above). Given that the default case
is echoing whatever is in U0RBR (BTW what is CTI?) I would expect almost
anything if no characters had been sent to the port. Change this before
trying anything else. Then put a pin toggle or something in so you know if
the interrupt routine is ever reached.

> case 0x01: // RDR
> break;
> case 0x02: // OE
> break;
> case 0x04: // PE
> break;
> case 0x08: // FE
> break;
> case 0x10: // BI
> break;
> case 0x20: // THRE
> if(txBytes != 0) {
> U0THR = txBuffer[txRdPos];
> txRdPos++;
> txRdPos = (txRdPos ==
> TX_BUFFER_LENGTH)?0:txRdPos;
> txBytes--;
> }
> break;
> case 0x40: // TEMT
> break;
> case 0x80: // FXFE
> break;
> default: // Must be CTI
> uart0_sendByte(U0RBR); // Echo back

This is potentially a problem. I haven't looked at in detail but you are
using the same buffer routine here as you are in the non-interrupt
code. The ground is very unstable here.

> }
> dummy = U0IIR; // read to clear IRQ
UOIIR is what you should be using to determine the interrupt source. > dummy += 1; // keep compiler from optimizing dummy out

And if U0IIR is read and used you don't need this line. In fact if U0IIR
is declared volatile (as it should be) you only would need this line if the
compiler was buggy.

> VICVectAddr = 0;
>}
>
>void uart0_sendByte(Uint8 a) {
> // Wait until there is room in the buffer
> while(txBytes == TX_BUFFER_LENGTH);
> if(!(U0LSR&0x20)) { // Put it in the software buffer
> txBuffer[txWrPos] = a;
> txWrPos++;
> txWrPos = (txWrPos == TX_BUFFER_LENGTH)?0:txWrPos;
> txBytes++;
> }
> else { // If the chip buffer is empty, put it there
> U0THR = a;
> }
>}
>
>int putchar(int a) {
> uart0_sendByte((int)a);
> return 0;
>}
>
>int main (void) {
> PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
> VPBDIV = 0x1;
> uart0_config();
> printf("piece of crap!");
> while(1);
>}
>
>The output of this is "pep" when I run it on hardware. The Keil
>simulator of course says it is fine.

There are multiple examples of working serial interrupt code around, some
in the files section and the newlib support on
http://www.aeolusdevelopment.com has some as well. Most are GNU based, but
the concepts and pitfalls are the same for all compilers.

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III



Reply by peterburdine October 8, 20042004-10-08

It was a small oversite that it wasn't posted. I was copying stuff
out that I didn't need. Since then I've made another small project
that just tests the UART. I am now trying non vector irqs, and they
still don't work. Here is the correct code: #include <stdio.h>
#include "../ArmCommon/types.h"
#include "../ArmCommon/LPC22xx.h"
#include "../ArmCommon/LPC2294.h"

#define TX_BUFFER_LENGTH 64

static Uint16 txBytes = 0;
static Uint16 txRdPos = 0;
static Uint16 txWrPos = 0;
static Uint16 txBuffer[TX_BUFFER_LENGTH];

void uart0_config (void);
void uart0_isr (void);
void uart0_sendByte (Uint8);
int putchar(int);
int main (void);

void uart0_config (void) {
// Setup UART 0
U0LCR = 0x80; // Enable DLAB
U0DLL = 0x36; // Setup BGR
U0DLM = 0x00; // ~57.6 kbps @ 50 Mhz
U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1 stop bit

// Reset the FIFOs
U0FCR = 0xC7; // RX FIFO trigger level 8 chars, reset tx and rx fifo,
enable fifos

// Setup Interrupts for UART0
VICIntSelect &= 0xFFFFBFFF; // Make sure 6 is IRQ not FIQ
VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
VICDefVectAddr = (unsigned long) uart0_isr; // Use Non vectored irq
U0IER = 0x7;
}

void uart0_isr (void) __irq {
Uint8 dummy;
switch(U0LSR) {
case 0x01: // RDR
break;
case 0x02: // OE
break;
case 0x04: // PE
break;
case 0x08: // FE
break;
case 0x10: // BI
break;
case 0x20: // THRE
if(txBytes != 0) {
U0THR = txBuffer[txRdPos];
txRdPos++;
txRdPos = (txRdPos == TX_BUFFER_LENGTH)?0:txRdPos;
txBytes--;
}
break;
case 0x40: // TEMT
break;
case 0x80: // FXFE
break;
default: // Must be CTI
uart0_sendByte(U0RBR); // Echo back
}
dummy = U0IIR; // read to clear IRQ
dummy += 1; // keep compiler from optimizing dummy out
VICVectAddr = 0;
}

void uart0_sendByte(Uint8 a) {
// Wait until there is room in the buffer
while(txBytes == TX_BUFFER_LENGTH);
if(!(U0LSR&0x20)) { // Put it in the software buffer
txBuffer[txWrPos] = a;
txWrPos++;
txWrPos = (txWrPos == TX_BUFFER_LENGTH)?0:txWrPos;
txBytes++;
}
else { // If the chip buffer is empty, put it there
U0THR = a;
}
}

int putchar(int a) {
uart0_sendByte((int)a);
return 0;
}

int main (void) {
PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
VPBDIV = 0x1;
uart0_config();
printf("piece of crap!");
while(1);
}

The output of this is "pep" when I run it on hardware. The Keil
simulator of course says it is fine.

--- In , Robert Adsett <subscriptions@a...> wrote:
> At 02:33 PM 10/8/04 +0000, you wrote:
> >I do now have the VicVectAddr = 0;, but that doesn't help if it
> >doesn't get called.
>
> Speaking of which, I just reviewed your code. You don't appear to be
> actually calling your uart initialization code anywhere (I don't see
how
> you would get your baud rate right if you hadn't but...). Also you
should
> probably disable interrupts before disabling a specific interrupt via
> VICIntEnClr
>
> Robert
>
> " 'Freedom' has no meaning of itself. There are always restrictions,
> be they legal, genetic, or physical. If you don't believe me, try to
> chew a radio signal. "
>
> Kelvin Throop, III




Reply by peterburdine October 8, 20042004-10-08

Use __fiq instead of __irq.

From Keil help:

Fast Interrupt Functions (__fiq)
Fast Interrupt Functions can be directly defined using the __fiq
function attribute:

void funcname (void) __fiq
Where

funcname
is the name of the function.
__fiq
indicates the function as fast interrupt function.

The __fiq attribute affects the generated code of the function as follows:

The function is generated using ARM instructions, even when the THUMB
directive is specified.
On function entry the registers R0 - R7 (when modified) are saved on
the stack.
When exiting the function all register contents saved on the stack are
restored.
The instruction SUBS PC,R14,#4 is used to return from the __fiq function.
The ARM device jumps to the __fiq vector location (some ARM devices
provide an Vectored Interrupt Controller that supports also fiq
interrupts). By default, the CPU startup code (STARTUP.S) jumps to the
function FIQ_Handler. When the __fiq function in the application code
is named FIQ_Handler no modification to the STARTUP.S file is required.

The following sample program shows how to use the __fiq attribute. The
code sequences generated are shown in the Assembler Listing section.

stmt level source

1 /*
2 * IRQ Handler for ADuC7000 Timer0 Interrupt
3 */
4
5 #include <ADuC7024.H>
6
7 volatile int T0_ticks;
8
9 void IRQ_Handler (void) __fiq {
10 1 if (IRQSIG & 0x00000004) { // Timer0 Interrupt
11 2 T0CLRI = 1;
12 2 T0_ticks++;
13 2 }
14 1 }

ASSEMBLY LISTING OF GENERATED OBJECT CODE

*** PUBLICS:
PUBLIC IRQ_Handler?A
PUBLIC T0_ticks
*** DATA SEGMENT '?DT0?irq':
00000000 T0_ticks:
00000000 DS 4
*** CODE SEGMENT '?PR?IRQ_Handler?A?irq':
9: void IRQ_Handler (void) __irq {
00000000 E92D0003 STMDB R13!,{R0-R1}
10: if (IRQSIG & 0x00000004) { // Timer0 Interrupt
00000004 E5100000 LDR R0,=0xFFFF0004
00000008 E5900000 LDR R0,[R0,#0x0]
0000000C E3A01004 MOV R1,#0x4
00000010 E1100001 TST R0,R1
00000014 0A000006 BEQ L_1 ; Targ=0x34
11: T0CLRI = 1;
00000018 E3A01001 MOV R1,#0x1
0000001C E5100000 LDR R0,=0xFFFF030C
00000020 E5801000 STR R1,[R0,#0x0]
12: T0_ticks++;
00000024 E5100000 LDR R0,=T0_ticks ; T0_ticks
00000028 E5901000 LDR R1,[R0,#0x0] ; T0_ticks
0000002C E2811001 ADD R1,R1,#0x0001
00000030 E5801000 STR R1,[R0,#0x0] ; T0_ticks
13: }
00000034 L_1:
00000034 E8BD0003 LDMIA R13!,{R0-R1}
00000038 E25EF004 SUBS R15,R14,#0x0004
0000003C ENDP ; 'IRQ_Handler?A'
Note

The __fiq attribute is not allowed when declaring or prototyping
external functions. For example, the following function prototype is
invalid:
extern void func (void) __fiq;
Passing parameters to interrupt function is not possible. Any attempt
to define an interrupt function with arguments generates an error
message.
Interrupt function declarations may not include a return value. They
must be declared with a void return type. The compiler generates an
error message if an attempt to define a return value for the interrupt
function is made.
The run-time library of the CARM Compiler contains a default
FIQ_Handler that generates an end-less loop using the instruction B $.
--- In , "Pete" <peterbrown_abroad@y...> wrote:
>
> Hi Peter
> Interesting to hear this as I too am using Keil, but wasnt aware
> that you could do this!
>
> For my info, how do you tell Keil that you want the interrupt to be
> a Fast interrupt rather than the normal type?
>
> sorry i didnt help fix the problem, and hope someone else can help u
> out.
> rgds
> pete
>
> --- In , "peterburdine" <lordofdawn@h...>
> wrote:
> >
> > Pete,
> >
> > The Keil's compilier does not require such initialization. I have
> a
> > timer isr that works just fine being declared as
> >
> > void timer_isr (void);
> >
> > void timer_isr (void) __irq {....}
> >
> > I do now have the VicVectAddr = 0;, but that doesn't help if it
> > doesn't get called.
> >
> > --Peter
> >
> > --- In , "Pete" <peterbrown_abroad@y...>
> wrote:
> > >
> > > peter
> > >
> > > i think also that you need to initialise the isr function
> > > differently...
> > > something like this:
> > > void uart0_isr(void) __attribute__ ((interrupt("IRQ")));
> > >
> > > rather than:
> > > void uart0_isr (void);
> > >
> > > see the user manual section on interrupt handling....
> > >
> > > also, add the:
> > > VICVectAddr = 0;//Dummy write to signal end of interrupt
> > >
> > > to the end of the isr...
> > > does this help?
> > >
> > > kind regards
> > > Pete
> > >
> > >
> > > --- In , "peterburdine" <lordofdawn@h...>
> > > wrote:
> > > >
> > > > I am sure the might help, if the ISR was called in the first
> > > place.
> > > > But it isn't.
> > > > Also, according to the user manual I have,, it states that
> only
> > > U0IIR
> > > > must be accessed to clear the IRQ (for TXRE anyways).
> > > >
> > > > --Peter
> > > >
> > > > --- In , "Pete"
> <peterbrown_abroad@y...>
> > > wrote:
> > > > >
> > > > > In an interrupt service routine:
> > > > > in order to exit it properly you must, Clear the interrupt
> flag
> > > that
> > > > > triggered it (write a 1 to the flag?) eg:
> > > > > U0IIR = 0x0000000A; //Clear the interrupt register
> > > > >
> > > > > anyway, most importantly you also need to write to teh
> vector
> > > > > address register:
> > > > > eg:
> > > > > VICVectAddr = 0x00000000;//Dummy write to signal end of
> > > interrupt
> > > > >
> > > > > failure to do these will lead to continuous interrupts.....
> > > > >
> > > > >
> > > > > Does this help???
> > > > >
> > > > > rgds
> > > > > pete
> > > > >
> > > > >
> > > > > --- In , "peterburdine"
> <lordofdawn@h...>
> > > > > wrote:
> > > > > >
> > > > > > I think I may be missing something stupid, but can anyone
> help
> > > me?
> > > > > > I am tring to write to UART0, but it doesn't seem to
> work. I
> > > am
> > > > > > trying to write a software buffer to help out the one byte
> > > hardware
> > > > > > buffer. Specifically I am using the LPC 2294. Below is
> my
> > > code.
> > > > > >
> > > > > > I am using the Keil toolset
> (compiler/debugger/simulator).
> > > The
> > > > > code
> > > > > > works perfectly fine when running it on the simulator, but
> > > when I
> > > > > try
> > > > > > to run it on the chip, I will only get "ho" instead
> > > of "hello". I
> > > > > put
> > > > > > some break points in it when using JTAG to debug, but the
> ISR
> > > is
> > > > > never
> > > > > > called when running on the real hardware, it is called on
> the
> > > > > > simulator. Also, when I debug on JTAG I never se the THRE
> or
> > > TEMT
> > > > > > clear. Can you see anything obviously wrong? I think I
> put in
> > > > > > everything that you need to compile it.
> > > > > >
> > > > > > #include <stdio.h>
> > > > > > #define TX_BUFFER_LENGTH 64
> > > > > > #define UART0_THRE (U0LSR & 0x20)
> > > > > > #define PINSEL0_00_TxD (0x01)
> > > > > > #define PINSEL0_01_GPIO (0x00 << 2)
> > > > > > #define U0RBR (*((volatile unsigned char *)
> > > 0xE000C000))
> > > > > > #define U0THR (*((volatile unsigned char *)
> > > 0xE000C000))
> > > > > > #define U0IER (*((volatile unsigned char *)
> > > 0xE000C004))
> > > > > > #define U0IIR (*((volatile unsigned char *)
> > > 0xE000C008))
> > > > > > #define U0FCR (*((volatile unsigned char *)
> > > 0xE000C008))
> > > > > > #define U0LCR (*((volatile unsigned char *)
> > > 0xE000C00C))
> > > > > > #define U0MCR (*((volatile unsigned char *)
> > > 0xE000C010))
> > > > > > #define U0LSR (*((volatile unsigned char *)
> > > 0xE000C014))
> > > > > > #define U0MSR (*((volatile unsigned char *)
> > > 0xE000C018))
> > > > > > #define U0SCR (*((volatile unsigned char *)
> > > 0xE000C01C))
> > > > > > #define U0DLL (*((volatile unsigned char *)
> > > 0xE000C000))
> > > > > > #define U0DLM (*((volatile unsigned char *)
> > > 0xE000C004))
> > > > > > #define VICVectAddr6 (*((volatile unsigned long *)
> > > 0xFFFFF118))
> > > > > > #define VICVectCntl6 (*((volatile unsigned long *)
> > > 0xFFFFF218))
> > > > > > #define VICIntSelect (*((volatile unsigned long *)
> > > 0xFFFFF00C))
> > > > > > #define VICIntEnable (*((volatile unsigned long *)
> > > 0xFFFFF010))
> > > > > > #define VICIntEnClr (*((volatile unsigned long *)
> > > 0xFFFFF014))
> > > > > > static Uint16 txBytes = 0;
> > > > > > static Uint16 txRdPos = 0;
> > > > > > static Uint16 txWrPos = 0;
> > > > > > static Uint16 txBuffer[TX_BUFFER_LENGTH];
> > > > > >
> > > > > > void uart0_config (void);
> > > > > > void uart0_isr (void);
> > > > > > void uart0_sendByte (Uint8);
> > > > > > int putchar(int);
> > > > > > int main (void);
> > > > > >
> > > > > > void uart0_config (void) {
> > > > > > // Setup UART 0
> > > > > > U0LCR = 0x80; // Enable DLAB
> > > > > > U0DLL = 0x16; // Setup BGR
> > > > > > U0DLM = 0x05; // ~2400 Bit/s @ 50 Mhz
> > > > > > U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1
> stop bit
> > > > > >
> > > > > > // Reset the FIFOs
> > > > > > U0FCR = 0xC7; // RX FIFO trigger level 8 chars,
> reset tx and
> > > > > rx fifo,
> > > > > > enable fifos
> > > > > >
> > > > > > // Setup Interrupts for UART0
> > > > > > U0IER = 0x7;
> > > > > > VICIntSelect &= 0x0;
> > > > > > VICVectCntl6 = 0x20 | 6;
> > > > > > VICVectAddr6 = (unsigned long) uart0_isr;
> > > > > > VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
>
> > > > > > }
> > > > > >
> > > > > > void uart0_isr (void) __irq {
> > > > > > switch((U0IIR>>1)&0x7) {
> > > > > > // THRE
> > > > > > case 001:
> > > > > > if(txBytes != 0) {
> > > > > > U0THR = txBuffer[txRdPos];
> > > > > > txRdPos++;
> > > > > > txRdPos = (txRdPos ==
> > > > > TX_BUFFER_LENGTH)?0:txRdPos;
> > > > > > txBytes--;
> > > > > > }
> > > > > > break;
> > > > > > }
> > > > > > }
> > > > > >
> > > > > > void uart0_sendByte(Uint8 byte) {
> > > > > > // Wait until there is room in the buffer
> > > > > > while(txBytes == TX_BUFFER_LENGTH);
> > > > > > VICIntEnClr |= (1 << 6);
> > > > > > if(!UART0_THRE) { // Put it in the software buffer
> > > > > > txBuffer[txWrPos] = byte;
> > > > > > txWrPos++;
> > > > > > txWrPos = (txWrPos == TX_BUFFER_LENGTH)?
> 0:txWrPos;
> > > > > > txBytes++;
> > > > > > }
> > > > > > else { // If the chip buffer is empty, put it there
> > > > > > U0THR = byte;
> > > > > > }
> > > > > > VICIntEnable |= (1 << 6);
> > > > > > }
> > > > > >
> > > > > > int putchar(int a) {
> > > > > > uart0_sendByte((int)a);
> > > > > > }
> > > > > >
> > > > > > int main (void) {
> > > > > > PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
> > > > > > printf("hello");
> > > > > > }