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

RS232 Interrupt operation mid-range PICS w/o UART hardware

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



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

RS232 Interrupt operation mid-range PICS w/o UART hardware
PostPosted: Fri May 15, 2009 4:11 pm     Reply with quote

The need to poll on non-hardware low end pics makes RS232 can make receiving a bit dicey. Interrupt service for received characters would seem to add a lot of reliability to the process.

has anybody seen/created an RS-232 Receive driver along this line of thought for low end midrange pics w/o UART hardware:

the RX data input pin is connected to a B port edge edge sensitive interrupt pin.

Once the interrupt is taken on leading ( ok falling ) edge of a new character - then the ISR disables the interrupt - and receives the entire character && buffers it circularly like the EX-ISR driver for hardware enabled pics does .

then when the stop bit is IN - the int state is cleared and ints are re-enabled for the next character.

i assume i could code it in short order - if i had access to
the source code that is called with a #USE RS232 - on such devices

but no can find.
any comments ?
or is this a bad idea for some reason i am not getting yet?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri May 15, 2009 4:27 pm     Reply with quote

1. Set the 'rcv' pin to PIN_B0 (Ext. Int pin) in the #use rs232() statement.
Also connect the incoming signal from the PC to Pin B0 (via a Max232
chip).
2. Create an #int_ext isr and do your getc() in the isr.
3. In main(), configure the External interrupt edge to be H_TO_L,
to catch the leading edge of the start bit
4. Then enable External interrupts. (Clear the external interrupt first).
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri May 15, 2009 6:48 pm     Reply with quote

i will post the result after doing the hardware over the W.E.
Ttelmah
Guest







PostPosted: Sat May 16, 2009 2:25 am     Reply with quote

As a further comment, depending on your bps rate, versus CPU clock (if CPU instruction clock is less than perhaps bps * 60), add the option 'SAMPLE_EARLY', to the software UART setup.
The problem is that it takes typically around about 30 instruction times to get 'into' the interrupt handler code, and if the bps rate is relatively high, compared to the instruction clock, this then results in late sampling of the data.
Examples of whether to select this option:

Master clock 4MHz. 9600bps. Master instruction rate = 1MHz, 104 instructions/bit. Should be OK with the standard setup.

Master clock 4Mhz. 19200bps. 52 instructions per bit. This will _need_ to have the sample early option, to have much chance of working right.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

got it going now
PostPosted: Sat May 16, 2009 2:19 pm     Reply with quote

the purpose was to update a 16c715 multiple temp reader ( designed by somebody else) - with intermittant failure to reply, using the simple software code for serial. i did as PCM and TTelmah suggested - the packet is always 12 chars - i set up a 16 char buffer and added a timer based receive stream check feature to TRY to avoid receive collisions - since the commands that come in are a burst - i look for a decent gap in reception before attempting the reply. comments to make it better?
Code:

//     using 4.9152mhz clock for zero err baud division
//     max safe baud rate 9600
//     with 9.83 mhz 19200  MY CTL PACKET IS ONLY 12 CHARS LONG
//     SO USING BUFFER OF 16 in this example
//     timer0 used to be sure incoming packets are complete
//     before attempting reply - to avoid char distortion and loss
//     due to interrupt  - Thanks to PCM and TTelmah !!
//        16c715.c ultimate target using the same rock
#include <16f818.h>
#include <stdlib.h>

#Fuses EC_IO,NOWDT,PUT, MCLR,BROWNOUT,NOLVP,CPD,NOCPD,WRT,NODEBUG,CCPB3,NOPROTECT
#use delay( clock=4915200)
#use rs232(baud=9600 , xmit=PIN_B1, rcv=PIN_B0, sample_early)
#use fast_io(A)
#use fast_io(B)

#bit  T0IF    = 0x0B.2  // flag in INTCON reg
//
#define BUFFER_SIZE 16
BYTE RISR_out;      // global background newchar from ISR BACKGND buffer
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;

#define bkbhit (next_in!=next_out)
void bgetc(void) {
   RISR_out=buffer[next_out];  // using GLObal return char variable
   next_out=(next_out+1) % BUFFER_SIZE;
}
void SIsr_INIT(void){
    clear_interrupt( int_ext );
    EXT_INT_EDGE(H_TO_L);
    enable_interrupts(int_ext);
    enable_interrupts(global);
}
#int_ext
   void serial_isr() {
   int t;
   buffer[next_in]=getc(); t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)  next_in=t;           // Buffer full !!
 } 
//***********************************
void InitHDW ( void ) {
//***********************************
     setup_oscillator ( 4915200 ); // same as for rock  8mhz
     output_a (0); output_b (0);  set_tris_a (0xFF);  //  - all INPUT
     setup_timer_0( RTCC_DIV_64);  // set for rollovers ~12 ms holdoff later
     //       USE  RTCC_DIV_128  for 9.93 mhz clock                           
     set_tris_b (0b00000001);  output_b (0);
}
//===================================
void main()
{
    char v;  char t;  unsigned int8 a;   unsigned int8 b; 
    InitHDW();
    SIsr_INIT();
    printf ("*Hello*\r");  // just check output
    delay_ms(12000);  // delay to let me send a packet in
    // now endlessly
    while (1) {           // now get AND send at same time
      a=next_in;          // get mark of buffer position
      T0IF = 0; b=3;      // clear t0if and do 3x12 MS  +/-
      while(b){           // TIMER0 just rolls over endlessly
             if (  T0IF  )  {   // not using INTS - just watching timer
                --b;  T0IF=0;
                if (!b && a==next_in ){ // unload IF no NU chars R caught
                   //              your (safer) xmit routine here 
                   while (bkbhit){ bgetc(); putc(RISR_out);}  //simple test
                }  // Implied ELSE - keep waiting
             } // END : IF t0if
       } //       END : WHILE B 
    }  //         END : while  1
}


Last edited by asmboy on Sat May 16, 2009 3:02 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat May 16, 2009 2:56 pm     Reply with quote

Quote:
#int_ext
void serial_isr() {
int t;
buffer[next_in]=getc(); t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out) next_in=t; // Buffer full !!
clear_interrupt( int_ext ); // do this LAST
}

The compiler already puts in code to clear the interrupt flag at the
end of the routine. You don't need that line.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

duh - sorry
PostPosted: Sat May 16, 2009 2:59 pm     Reply with quote

i shoulda looked at the .LST file -

thanks for the pointer - VERY much appreciated

hopefully somebody else who could benefit will stumble across this thread.
krasi



Joined: 17 Jun 2009
Posts: 9
Location: Bulgaria

View user's profile Send private message

'...to avoid receive collisions..."
PostPosted: Wed Jun 17, 2009 5:48 am     Reply with quote

First of all I want to say "hello" to everybody in this useful forum. This is my first post, so I want to excuse me if I'm wrong with something.
I want to say: "Thank you" to everybody who helps the others in getting more comfortable in PIC embedded software and especially to PCM Programmer and Ttelmah. You guys are the best! I learned a lot from your posts. Keep going this way.

Hi asmboy. Thank you for your post. I was stuck, and your code helps me a lot to get me out of this situation. With little modifications for PIC18F2580 with Timer2, I use it for my project. But I have a question about the timer function. You said that this is a "check feature to TRY to avoid receive collisions". Can you (or somebody else) explain me why? What is the purpose? Because I think it's not necessary. The "getc" function receives all bytes without problem (I already checked it.)

Best regards,
Krasi
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

about collisions
PostPosted: Wed Jun 17, 2009 8:33 am     Reply with quote

the problem with collision is ONLY an issue on PICs that don't have actual serial UART hardware. ( so long as you are using said hardware)

On low end parts w/o UART ihardware- the interrupt to receive chars ,can happen during transmit - and will 'break' the outgoing characters.

if you are using a pic with hardware - ( and using the hardware) - there is no issue with transmit failure from the overlap of Xmit and RECV functions
krasi



Joined: 17 Jun 2009
Posts: 9
Location: Bulgaria

View user's profile Send private message

about collisions
PostPosted: Wed Jun 17, 2009 9:13 am     Reply with quote

Yes, it can be happen as you say, but what if we use "DISABLE_INTS" in #use RS232? As I know it is designed just for this case:
Quote:
Will cause interrupts to be disabled when the routines get or put a character. This prevents character distortion for software implemented I/O and prevents interaction between I/O in interrupt handlers and the main program when using the UART.


Best regards,
Krasi
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Jun 17, 2009 9:33 am     Reply with quote

you are then making a choice - remember - it is the SOFTWARE based serial code. if you disable receive ints - when transmitting - no problem - you will not hurt your transmit stream
BUT
of course you WILL miss ALL receive serial characters that would have come in during the XMIT cycle. and worse - if when you re-enable ints -
should you be mid character on receive - you will get some trash in your receive stream form that partial character.

ALWAYS USE THE HARDWARE UART WHEN SOLID 2 WAY COMM IS REQUIRED.

if you are trying to add an extra serial channel to a PIC with ONE hardware uart in use already - the only SAFE thing to do is use the software uart for RECEIVE only. Overlap on the software channel will get you eventually if you don't





a typical case would be - say- RECEIVING data passively from another gadget that does not need supervision - and using your hardware based serial channel to do 2 way com with a host
krasi



Joined: 17 Jun 2009
Posts: 9
Location: Bulgaria

View user's profile Send private message

thanks
PostPosted: Thu Jun 18, 2009 12:45 am     Reply with quote

Thank you for your good explanation. It is more clear now. I was forgot for the simultaneously transmitting, that's why I couldn't saw the difference.
I use in my application only half duplex, and that's why I was thinking that there is no problem to use "DISABLE_INTS". But you are right for the full duplex - there is no other choice than the hardware channel if you want solid 2 way.

Thank you again,
Krasi
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