CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

UART ISR?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Tressie



Joined: 07 Apr 2012
Posts: 12

View user's profile Send private message

UART ISR?
PostPosted: Sat Apr 07, 2012 3:22 pm     Reply with quote

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. Smile
jeremiah



Joined: 20 Jul 2010
Posts: 1321

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 4:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 6:32 pm     Reply with quote

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. Crying or Very sad
jeremiah



Joined: 20 Jul 2010
Posts: 1321

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 6:50 pm     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Sat Apr 07, 2012 7:11 pm     Reply with quote

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: 1321

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 7:33 pm     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Sat Apr 07, 2012 8:12 pm     Reply with quote

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: 1321

View user's profile Send private message

PostPosted: Sat Apr 07, 2012 8:27 pm     Reply with quote

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: 19327

View user's profile Send private message

PostPosted: Sun Apr 08, 2012 1:30 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group