Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: Problems w/ UART

2004-10-08 by peterburdine

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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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 lpc2000@yahoogroups.com, "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");
> > > > > > }

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.