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 CCS Technical Support

RS232 interrupt not working (Solved)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

RS232 interrupt not working (Solved)
PostPosted: Sat Jun 11, 2011 8:29 pm     Reply with quote

I am trying to use interrupt driven comms on a 12F1822 with no success so far. The thing sends and receives OK without using interrupts, but doesn't seem to recognise the rcv int. What am I missing? (V 4.12)

#include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, xmit= PIN_A4, rcv=PIN_A5)

#define ShntDrv PIN_A2 //balancing shunt driver

//Globals
volatile unsigned int8 StoredVal;

void init(){
port_a_pullups(0b00100000); //internal pullup on rcv pin (RA5)
setup_adc_ports(sAN1, VSS_VDD); //
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv
}

#int_rda
void serial_isr(){
unsigned int8 buffer, Msg=FALSE;
buffer = getc();
putc(buffer); //test - not working!!!!
if (buffer==0xFF) Msg=FALSE; //done rcving message
if (Msg) putc(buffer);
if (buffer==01){ //01 is command to add cell voltage to the string
Msg=TRUE; //receiving message
putc(buffer);
putc(StoredVal);
}
}

void main() {
unsigned int8 i;
unsigned int16 value ;
init();
do{
value=0;
for(i=1;i<=10;i++){
delay_ms(20);
value+=Read_ADC();
}
value/=10 ; //is now average of 10 readings
value-=316;
if(value>=0xFF) value = 0xFE; //is now 0 - 254
StoredVal=(int)value; //
// putc(getc()+1); // test comms - this works OK!!!!!!


}while(TRUE);
}


Last edited by harlequin2 on Sun Jun 12, 2011 6:07 pm; edited 1 time in total
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jun 11, 2011 8:45 pm     Reply with quote

you've got...

enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv


...maybe reverse the order to


enable_interrupts(INT_RDA); //serial rcv
enable_interrupts(GLOBAL);


???
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sat Jun 11, 2011 8:58 pm     Reply with quote

temtronic wrote:
you've got...

enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA); //serial rcv


...maybe reverse the order to


enable_interrupts(INT_RDA); //serial rcv
enable_interrupts(GLOBAL);


???


Thanks, tried that, makes no difference.
Sorry I didn't notice the "Code" button in my original post!
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Sat Jun 11, 2011 11:16 pm     Reply with quote

We all know the RDA interrupt only works with the hardware UART.
It is never a good idea to put a putc in a RDA interrupt. Sure it will work but it takes time to send chars and you can guess it is about the same time as it takes to receive them, RS232 is asynchronous so an inbound char can and will arrive at any time (unless you have a handshake with the transmitter). The RDA needs to be called when the inbound char arrives but if the RDA is busy doing things like outputting a char or two it will not be able to respond. The hardware has a small 2 char receive buffer so you may get one putc char out and have the hardware capture the inbound char. It's still not a good idea. The rule with interrupts is that you should put as little code in them as you can.
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sat Jun 11, 2011 11:26 pm     Reply with quote

Douglas Kennedy wrote:
We all know the RDA interrupt only works with the hardware UART.
It is never a good idea to put a putc in a RDA interrupt. Sure it will work but it takes time to send chars and you can guess it is about the same time as it takes to receive them, RS232 is asynchronous so an inbound char can and will arrive at any time (unless you have a handshake with the transmitter). The RDA needs to be called when the inbound char arrives but if the RDA is busy doing things like outputting a char or two it will not be able to respond. The hardware has a small 2 char receive buffer so you may get one putc char out and have the hardware capture the inbound char. It's still not a good idea. The rule with interrupts is that you should put as little code in them as you can.


Yah, we know all that. The way this works is that all of the characters received are supposed to be transmitted as they come in. If the first one is $01 then an extra character is added to the stream. The 2 char buffer will allow this. But, the interrupt is still not being triggered by the first incoming character - why not is the question.
The following still does not send out a character:

Code:
#int_rda
void serial_isr(){
   unsigned int8 buffer, Msg=FALSE;
   buffer = getc();
   putc(buffer); //test
/*   if (buffer==0xFF) Msg=FALSE; //done rcving message
   if (Msg) putc(buffer);
   if (buffer==01){ //01 is command to add cell voltage to the string
      Msg=TRUE;      //receiving message
      putc(buffer);
      putc(StoredVal);
   }*/
}



It should, shouldn't it?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Jun 11, 2011 11:43 pm     Reply with quote

I'm not at a location where I can test this, but I think it might have a
chance to work: Give the compiler what it wants, to make it generate
code for a hardware UART. Then use APFCON to switch the pins.
That's what I've done below. Try it. See if it works.
Code:

#include <12lf1822.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

#int_rda
void serial_isr()
{
char c;

c = getc();
putc(c);  // Echo back all incoming characters
}

//------------------------------------
// Put the UART on pins A4, A5 for Tx, Rx.
void select_alt_uart_pins(void)
{
#byte APFCON = getenv("SFR:APFCON")

APFCON |= 0x84;  // Select alternate pins for Tx, Rx

}

//================================
void main()
{
 
select_alt_uart_pins();
 
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);

while(1);
}
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 12:22 am     Reply with quote

PCM programmer wrote:
I'm not at a location where I can test this, but I think it might have a
chance to work: Give the compiler what it wants, to make it generate
code for a hardware UART. ]


That is exactly what I have done, if you read the code carefully. The XMIT and RCV pins are what they have to be. And they work fine for non-interrupt comms.
I would assume that the compiler would use the hardware UART if it is present, if it doesn't then it is more useless than I thought! But I stuck UART1 into the use RS232 directive just in case, and it makes no difference.
I've read the CCS C compiler stuff back and forth, looked at their sample programs and I cannot see why this doesn't work.
Thanks for your suggestions so far.
I've started looking at the .lst file, but the reason I used this CCS thing was to get away from assembler.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 12:28 am     Reply with quote

Quote:
V 4.12

Post your exact compiler version and I'll look at it tomorrow.
(Version numbers have three digits after the decimal point).
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 12:55 am     Reply with quote

PCM programmer wrote:
Quote:
V 4.12

Post your exact compiler version and I'll look at it tomorrow.
(Version numbers have three digits after the decimal point).

4.120
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 3:40 pm     Reply with quote

I have reduced the code down to the following and it still doesn't work. Because I initialise buf as true, it transmits a single byte (01) but does not respond to characters sent to it ie no interrupt. I know the thing can receive because if I put "putc(getc())" in main, it sends and receives fine.
Code:
#include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS)

volatile char buf=TRUE;
#int_rda
void serial_isr(){

   buf=getc();
}
void main(){
   enable_interrupts(INT_RDA);
   enable_interrupts(global);   
   do{
      if(buf){
          putc(buf);
         buf = FALSE;
      }
   }while(TRUE);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 3:46 pm     Reply with quote

That's right, because you're not setting the APFCON register bits to
select the alternate UART pins. The compiler won't do that for you
automatically just because you specified the alternate pins in the
#use rs232() statement.

And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.

You have to do it the way I showed in my post.
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 4:19 pm     Reply with quote

PCM programmer wrote:
That's right, because you're not setting the APFCON register bits to
select the alternate UART pins. The compiler won't do that for you
automatically just because you specified the alternate pins in the
#use rs232() statement.

And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.

You have to do it the way I showed in my post.


OK, what you have said makes sense so I added the code you gave for setting the APFCON register bits but sadly the result is still the same. The 1822 has only one uart so you'd think you wouldn't need to specify "uart1". I am at a bit of a loss now.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 4:21 pm     Reply with quote

Post your latest test program.
harlequin2



Joined: 11 Jun 2011
Posts: 21

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 4:45 pm     Reply with quote

PCM programmer wrote:
Post your latest test program.


Here it is: Note that it sends one char when I power it up, as it should since buffer is true (usually 0xFF)

Code:
#include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS)

#define ShntDrv PIN_A2 //balancing shunt driver

//Globals
volatile char StoredVal, buffer;

// Put the UART on pins A4, A5 for Tx, Rx.
void select_alt_uart_pins(void){
   #byte APFCON = getenv("SFR:APFCON")
   APFCON |= 0x84;  // Select alternate pins for Tx, Rx
}

void init(){
    port_a_pullups(0b00100000); //internal pullup on rcv pin (RA5)
    setup_adc_ports(sAN1, VSS_VDD); //
    setup_adc(ADC_CLOCK_DIV_8);
    set_adc_channel(1);
   select_alt_uart_pins();
   enable_interrupts(PERIPH);
    enable_interrupts(INT_RDA); //serial rcv
    enable_interrupts(GLOBAL);
 }




#int_rda
void serial_isr(){
//    unsigned int8 buffer, Msg=FALSE;
    buffer = getc();
//    putc(buffer); //test
/*    if (buffer==0xFF) Msg=FALSE; //done rcving message
    if (Msg) putc(buffer);
    if (buffer==01){ //01 is command to add cell voltage to the string
        Msg=TRUE;  //receiving message
        putc(buffer);
        putc(StoredVal);
 }*/
}

void main() {
    unsigned int8 i;
    unsigned int16 value ;
    init();
    do{
        value=0;
        for(i=1;i<=10;i++){
         delay_ms(20);
         value+=Read_ADC();
     }
     value/=10 ; //is now average of 10 readings
     value-=316;
     if(value>=0xFF) value = 0xFE; //is now 0 - 254
     StoredVal=(int)value; //
     if(buffer){
      putc(buffer); // test comms
      buffer=FALSE;
   }
 
 }while(TRUE);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jun 12, 2011 5:18 pm     Reply with quote

Quote:
#include <12lf1822.h>
#device ADC=10
#fuses INTRC_IO, NOWDT, NOPROTECT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1,xmit= PIN_A4, rcv=PIN_A5, ERRORS)


One last time. From my previous post:
Quote:

And also, putting 'UART1' in the #use rs232() while still keeping the
pin declarations
, does not work. The pin declarations override
the 'UART1' directive. The compiler does not know that the alternate
pins can work with the hardware UART. It will generate code for a
software UART if you specify those pins.

You have to do it the way I showed in my post.

I did not put the 'xmit= PIN_A4' and 'rcv=PIN_A5' statements in the code in my post !
You should NOT do it. You should use 'UART1' ONLY ! (After this I give up).
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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