View previous topic :: View next topic |
Author |
Message |
Tressie
Joined: 07 Apr 2012 Posts: 12
|
UART ISR? |
Posted: Sat Apr 07, 2012 3:22 pm |
|
|
Hi,
Writing my own UART code, but need help with CCS compiler interrupt service routines...
On a PIC24F I have enabled both UART TX and RX interrupts, and selected TX interrupt to fire on transmission complete, and also selected RX interrupt to fire on any character reception.
Now how do I tell the CCS compiler that my UART ISR function is for a TX interrupt event, RX interrupt event, or both. Up until now I've been using '#int_default', but that won't help if I need more ISR's.
Also, I'd like the CCS compiler to preserve any registers it might need to for me, but I don't want it to reset any interrupt flags. How do I manage that?
Thanks for any help.
Tressie. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1355
|
|
Posted: Sat Apr 07, 2012 4:16 pm |
|
|
Take a look at #INT_RDA and #INT_TBE in the manual. They are used for UART1.
As far as saving registers and not clearing the flag:
I think you have to clear the flag for hardware reasons?. If you are needing to know an interrupt happened, I would suggest setting up a global variable. I tend to do something like:
Code: |
union{
unsigned int16 value;
struct{
unsigned int8 isr1 : 1; //I name these more appropriately
unsigned int8 isr2 : 1;
unsigned int8 isr3 : 1;
unsigned int8 isr4 : 1;
unsigned int8 isr5 : 1;
unsigned int8 : 3; //might be able to do this as : 11...I forget the rules
unsigned int8 : 8;
}bits;
} g_isr_flags;
|
Then I set individual bits when an interrupt has occurred and clear individual bits or the whole thing (using value) in my main once I have handled them.
I *think* the compiler saves important registers to the stack for you (maybe a more experienced person can comment?), but if not, you can always insert a #ASM block to do it yourself (can even make a macro for it so you don't have to retype code for every ISR). |
|
|
Tressie
Joined: 07 Apr 2012 Posts: 12
|
|
Posted: Sat Apr 07, 2012 6:32 pm |
|
|
Hi Jeremiah,
Thanks for the prompt reply.
jeremiah wrote: | Take a look at #INT_RDA and #INT_TBE in the manual. They are used for UART1. |
Nope, I don't want to use the CCS interrupt declaration methods. They're too restrictive for my bug workaround and error recovery code.
jeremiah wrote: | I *think* the compiler saves important registers to the stack for you (maybe a more experienced person can comment?), but if not, you can always insert a #ASM block to do it yourself (can even make a macro for it so you don't have to retype code for every ISR). |
Hmm...I'd be real interested in knowing which registers need to be saved before I enter an ISR, and restored after exit.
Okay, it's looking like I might have to register my UART ISR in the controller's interrupt vector table myself. Anyone clued-up as to how to get the address of an ISR from it's function name, and to load it into the IVT in CCS compiler C (and maybe some inline assembler)?
Tressie. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1355
|
|
Posted: Sat Apr 07, 2012 6:50 pm |
|
|
use #org <start addr>,<stop addr> before your ISR to place it in a specific memory location.
use #build(interrupt=<some other address than the IVT area>) to move the IVT away and allow you to use #ROM statements
Then use #ROM to place the address in the IVT location. Something like:
Code: |
#define PIC24_RDA_IVT_LOC 0x002A //from the data sheet
#define YOUR_RDA_ADDR 0x0400 //pick this yourself
#define YOUR_RDA_SIZE 0x001F //make this what you need for size
#BUILD (interrupt=0x200) //moves IVT to this location to get it out of the way
#ROM PIC24_RDA_IVT_LOC = {YOUR_RDA_ADDR}
#ORG YOUR_RDA_ADDR,YOUR_RDA_ADDR+YOUR_RDA_SIZE
void rda_isr(){
//your code here
}
|
You may also have to follow the #ROM statement with another to fill the 0x0000 in the next word depending on your compiler. Mine puts it in for me (4.131). I haven't checked that for compilability. I just typed it out for example.
I think you will need to insert your own return from interrupt instruction at the end as well. Don't forget that! |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Apr 07, 2012 7:11 pm |
|
|
Quote: |
the CCS interrupt declaration methods. They're too restrictive
|
when i was a noobie - i believed that too.
however experience changed my mind.
what restriction are you meaning ? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1355
|
|
Posted: Sat Apr 07, 2012 7:33 pm |
|
|
Yeah, it confuses me too. The CCS interrupts do exactly what you need to do typically. Here's an example of one for the PIC24:
Code: |
.................... #INT_TIMER1
.................... void timer1_isr(){
*
0A26: PUSH 42
0A28: PUSH 36
0A2A: MOV W0,[W15++]
0A2C: MOV #2,W0
0A2E: REPEAT #C
0A30: MOV [W0++],[W15++]
.................... }
....................
0A32: BCLR.B 84.3
0A34: MOV #1A,W0
0A36: REPEAT #C
0A38: MOV [--W15],[W0--]
0A3A: MOV [--W15],W0
0A3C: POP 36
0A3E: POP 42
0A40: RETFIE
|
Saves all the working registers, status register, etc.
Clears the interrupt flag (which I think you have to do...any comments on that?)
Restores all the registers at the end
Calls RETFIE
That's about as bare minimum as you can get aside from not saving all the registers, but that gets pretty dangerous. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sat Apr 07, 2012 8:12 pm |
|
|
Quote: |
not saving all the registers
|
SFRs for sure -
but i'm just not at all sure about implications or need to of protect
hardware multiply operation results for example -
and/or avoiding ISR code that could mess with those.
what registers would be meant by "all the registers anyway" ??? |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1355
|
|
Posted: Sat Apr 07, 2012 8:27 pm |
|
|
All the registers in reference to what that list file entry saved, Status, W regs, etc.
I could see just saving the W regs you use in the ISR in addition to the status reg, etc. I'm just not experienced enough to say 100% it is safe to leave the others out. I could easily be not thinking of some reason that is needed for saving all of them. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19546
|
|
Posted: Sun Apr 08, 2012 1:30 am |
|
|
and, of course if _you_ want to take control of clearing the interrupt flag - perhaps clearing it earlier in the code, you can always declare the interrupt with 'NOCLEAR', which then leaves you to do it.
Best Wishes |
|
|
|