I'm just getting started with using the Keil uV3 compiler as well as the Phillips lpc2129. The application I am working on requires both UART0 & 1 as well as the I2C and I'm wondering if anyone has some <sample> code for enabling/using interrupts handy for this part that they might could pass along to help me get started. Any links related to writing C code for the lpc2129 would also be appreciated. regards & thanks -mel
I should have mentioned that I've gone through both the blinky and blinky_irq code examples provided by Keil but found them a bit lacking in getting me started writing my own interrupt driven drivers.
I've already been through that phase. I'll try to post some code later (i'm at the office at the moment) that I wrote which is circular buffer interrupt driven serial comms. I suggest you look at the blinky_irq code carefully and read the philips doc in the VIC to understand how the interrupt controller works. Once you've done that the whole thing is fairly simple. Each device has an interrupt number, that has to be set for an interrupt vector you choose (this sets the priority in regards to the other interrupts). Load the vector register with the address of your interrupt service routine, enable the interrupt and you're away. At the end of the interrupt service routine you must put a 0 in the VIC service register to ack the interrupt. You will see this in the blinky_irq code.
Here is my code for interrupt driven comms. The formatting may have been screwed up by me pasting the code! Be sure to add the file syscalls.c to your project for printf to work. The code hasn't been extensively tested but the techniques used are common. To modify the code for the other serial port, change the references from uart0 to uart1 and read the philips doc on the VIC to change the interrupt stuff to use uart1. The interrupts are a little more sophisticated than what you'd find on a 8051. What got me stuck for a little while was putting this line at the end of the service routine: VICVectAddr=0; // Acknowledge Interrupt Without it you won't service another interrupt! Hopefully this code will answer all your questions. If not, come back to the forum! Don't ask me about I2C stuff as I haven't tried that yet! Have fun! // // serial.h // enum tBaudRate {BR_1200,BR_2400,BR_4800,BR_9600,BR_19200,BR_38400}; extern void init_serial (enum tBaudRate baud); /* Initialize Serial Interface */ extern int putchar (int ch); /* Write character to Serial Port */ extern int getchar (void); /* Read character from Serial Port */ void outstr(char *str,int length); //outputs a string via interrupt char add_char_to_tx_buff(char *ch,int count); void puthexw (int hex); void puthex (int hex); void putstr (char *p); // end of file // // main code. // #include <LPC21xx.H> /* LPC21xx definitions */ #include <stdio.h> #include "serial.h" int main(void) { char j; init_serial(BR_19200); for (j =0;j < 10;j++) { printf("testing %04d \n",j); } while(1); //end of file
The forum complained about the text being too long so I had to split it.... /******************************************************************************/ /* This file is part of the uVision/ARM development tools */ /* Copyright KEIL ELEKTRONIK GmbH 2002-2004 */ /******************************************************************************/ /* */ /* SERIAL.C: Low Level Serial Routines */ /* */ /******************************************************************************/ #include <LPC21xx.H> /* LPC21xx definitions */ #include <stdio.h> #include "serial.h" #define CR 0x0D extern int sendchar (int ch); /* in serial.c */ // // vars shared with the interrupt service routine // char tx0_buffer[1000]; volatile char *tx0_tail = tx0_buffer,*tx0_head = tx0_buffer; volatile unsigned int tx0_count = 0; void uart0 (void) __attribute__ ((interrupt)); // Generate Interrupt void puthexw (int hex) { puthex((hex >>12) & 0xf); puthex((hex >>8) & 0xf); puthex((hex >>4) & 0xf); puthex(hex & 0xf); } void puthex (int hex) { /* Write Hex Digit to Serial Port */ if (hex > 9) putchar('A' + (hex - 10)); else putchar('0' + hex); } void putstr (char *p) { /* Write string */ while (*p) { putchar (*p++); } } void init_serial(enum tBaudRate baud) { /* Initialize Serial Interface */ PINSEL0 = 0x00000005; /* Enable RxD0 and TxD0 */ U0LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ switch (baud) { case BR_1200: U0DLL = 0x0d; U0DLM = 0x03; break; case BR_2400: U0DLL = 0x86; U0DLM = 0x01; break; case BR_4800: U0DLL = 0xc3; U0DLM = 0x00; break; case BR_9600: U0DLL = 0x61; U0DLM = 0x00; break; case BR_19200: U0DLL = 0x30; U0DLM = 0x00; break; case BR_38400: U0DLL = 0x18; U0DLM = 0x00; break; } U0LCR = 0x03; /* DLAB = 0 */ //U0IER = 0x02; /* enable tx interrupts */ VICVectAddr1 = (unsigned long)uart0; // set interrupt vector in 1 VICVectCntl1 = 0x20 | 6; // use it for uart0 Interrupt VICIntEnable |= 0x00000040; // Enable Uart0 Interrupt } /* implementation of putchar (also used by printf function to output data) */ int sendchar (int ch) /* Write character to Serial Port */ { char tmp; if (ch == '\n') { tmp = CR; add_char_to_tx_buff(&tmp,1); } tmp = (char)ch; add_char_to_tx_buff(&tmp,1); return ch; } int putchar (int ch) /* Write character to Serial Port */ { char tmp; // if (ch == '\n') { // while (!(U0LSR & 0x20)); // U0THR = CR; /* output CR */ // } // while (!(U0LSR & 0x20)); // return (U0THR = ch); if (ch == '\n') { tmp = CR; add_char_to_tx_buff(&tmp,1); } tmp = (char)ch; add_char_to_tx_buff(&tmp,1); return ch; } int getchar (void) { /* Read character from Serial Port */ while (!(U0LSR & 0x01)); return (U0RBR); } // // inserts chars into the tx circular buffer. enables tx ints if required // count has the number of chars to insert // returns 0 if not enough space in the buffer // returns 1 if successful // char add_char_to_tx_buff(char *ch,int count) { if((tx0_count + count) >= sizeof(tx0_buffer) ) { return 0; // not enough space } VICIntEnClr = 0x00000040; // Disable Uart0 Interrupt if (tx0_head == tx0_tail) //if the buffer was empty { if (U0LSR & 0x20) //if the uart is EMPTY { U0IER = 0x02; // enable tx interrupts U0THR = *ch++; //send the first char out the UART count--; } } while (count!= 0) { *tx0_head++ = *ch++; //insert the char into the buffer if (tx0_head >= (tx0_buffer + sizeof(tx0_buffer)) ) { tx0_head = tx0_buffer; //wrap index if req'd } tx0_count++; count--; } VICIntEnable = 0x00000040; // Enable Uart0 Interrupt return 1; } // // uart0 isr routine // void uart0(void) { if (U0LSR & 0x20)//if tx interrupt { if (tx0_head == tx0_tail) //buffer empty? { U0IER &= ~0x02; //disable the tx interrupt } else //we have something to send { tx0_count--; U0THR = *tx0_tail++; if (tx0_tail >= (tx0_buffer + sizeof(tx0_buffer)) ) { tx0_tail = tx0_buffer; //wrap tail buffer } } } VICVectAddr = 0; // Acknowledge Interrupt } // end of file
Thanks for the code, for the most part what I came up with was (about) the same. I am not using printf and therefor have not added syscalls.c to my project. Also adding that file will require some work on my part as I have three different put/get-char calls (et al. putchar_uart0, putchar_uart1, putchar_i2c) but no get/put char as required in syscalls.c. My code is not performing correctly regarding the interrupts for uart1. I'll post the code here and also in a new thread for possible extra help. First of all, here is the main loop...
while(1) { cTemp = getchar_uart1(); if( cTemp ) putchar_uart1( cTemp ); cTemp = 0; }
void u1_interrupt (void) __attribute__ ((interrupt)); /* generate interrupt */ /*************************************************************************/ /************************** interrupt for uart1 ************************/ void u1_interrupt (void) { char intrpt; intrpt = U1IIR; /* reset U1IIR register */ // for now just trying to echo the Rx'd byte back out uart1... intrpt = U1RBR; // clear Rx buffer, and reset interrupt putchar_uart1( intrpt ); VICVectAddr = 0; /* acknowledge interrupt */ }/*end u1_interrupt() */ void init_uart1( void ) { PINSEL0 |= 0x00550000; /* set P0.8, P0.9, P0.10 and P0.11 as TxD1, RxD1, RTS1, CTS1 */ U1LCR = 0x83; /* set DLAB and word size (8bits), defaults for others yield */ /* no parity, one stop bit, and no break */ U1DLL = 0x61; /* yields 9600 Baud */ U1DLM = 0x00; /* explicit initialization - is also the default */ U1LCR &= 0x7f; /* clear DLAB */ /* set up the interrupts */ U1IER = 0x05; /* enable RBR and RLS interrupts */ VICVectAddr1 = (unsigned long) u1_interrupt; /* set interrupt vector */ VICVectCntl1 = 0x20 | 7; /* use VICVectAddr1 for UART1 interrupts */ VICIntEnable = 0x00000080; /* enable uart1 interrupts */ }/* end init_uart1()
I thought it worth mentioning that I can see the Rx Data Ready interrupt triggering when I am single stepping in the debug mode but flow does NOT jump it my ISR. also FYI: with regards to posting code... use the
</per> tags to retain formatting
"</per> tags to retain formatting" That should be < pre > (to start) and < /pre > (to end) - but without the extra spaces. It's clearly shown at the top of the form when you make a post!
excuse my typos... I got the first one correct which was why it wasn't displayed which is also why you put the spaces between the brackets (I hadn't thought of that either)