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

Timing Problem? (3 UART)

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



Joined: 14 Jul 2004
Posts: 11

View user's profile Send private message

Timing Problem? (3 UART)
PostPosted: Wed Jul 28, 2004 1:40 am     Reply with quote

Hi all,

From my general understanding and searching in the forum, it seems that to be able to reliably implement receive via a SW UART on 9600 baud, the kbhit(stream) function needs to be called 10 times faster than the baud rate so the interrupt needs to overflow in 10 us? Then test kbhit(stream) on overflow?

If my understanding it correct, doesn’t that mean Timer0 can not be used as RTCC_DIV_1 overflows in 51.2 us! (Using 876A with 20 MHz Crystal)

So from the CCS Wizard, if Timer2 is enabled using setup_timer_2(T2_DIV_BY_1,4,10) then the Timer2 will overflow in 10 us and a kbhit(stream of SW UART) can be tested within that interrupt.

And still if my still newbie understanding is correct, then I can use Timer0 for less baud rate SW UART.

I have this slow/lockup problem when using two SW UART and one HW UART together, one of the SW UART is running 300 baud, while the other 9600 Baud, the HW is 9600 UART. When only using the 9600 UART (SW & HW), no problem, even with Timer0, but once I enable the 300 baud SW UART, the whole timing issue (at least what I think it is a timing issue) comes up and lock the system just when it enters the while(1) loop.

Note the timing problem happens without even receiving any data on any UART yet. The ring buffer code also wouldn’t store the incoming byte if the buffer is full anyway but it will still fetch it.

Program works perfect when commenting the #define USE_SLOW_DEVICE, even with the timer0 running, so it seems the kbhit()/fgetc for the slow device is where the problems are.

Will be great if someone can fix my understanding of the UART timings and required overflow interrupt for smooth operation.

Thanx a lot for all the help/hints

Here is the usage code with fuses (note not full code but the relevant code)

Code:


#device *=16
#device adc=8
#use delay(clock=20000000)

#define USE_SLOW_DEVICE

#fuses NOWDT,HS, NOPROTECT, NODEBUG, BROWNOUT, NOLVP, NOCPD,NOWRT

#use fixed_io(a_outputs=PIN_A0,PIN_A2,PIN_A5)

#use rs232(baud=9600,parity=N,xmit=PIN_A0,rcv=PIN_A1,bits=8,stream=PCCOM1)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PCCOM2)

#ifdef USE_SLOW_DEVICE
#use rs232(baud=300,parity=N,xmit=PIN_A2,rcv=PIN_A3,bits=8,stream=SLOW_DEV)
#endif

#int_TIMER2
void TIMER2_isr()
{
char Ch;
if(kbhit(PCCOM1))
   {
   Ch = fgetc(PCCOM1);

//call PCCOM1 32 bytes private ring buffer to store incoming data
   PutCOM1Buffer(Ch);
   }
}

#int_RTCC
void RTCC_isr()
{

#ifdef USE_SLOW_DEVICE

char Ch;
if(kbhit(SLOW_DEV))
   {
   Ch = fgetc(SLOW_DEV);
   
   //call a slow device 32 byte private ring buffer to store incoming data
PutSlowBuffer(Ch);
   }
#endif

}

#int_RDA
void RDA_isr()
{
char InChar;

   InChar = fgetc(PCCOM2);

   //call PCCOM2 32 bytes private ring buffer to store incoming data
   PutCOM2Buffer(InChar);
}

void main()
{
   Char Temp[32];

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_spi(FALSE);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_4);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_1,4,10);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);

   enable_interrupts(INT_RDA);
   enable_interrupts(INT_RTCC);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);

while(1)
   {

   If(GetCOM1Buffer(Temp))  //if COM1 sends command, echo it back (COM1)
      Fprintf(SendCOM1,Temp);
//note SendCOM1 is a redirect to disable interrupt before sending each character

   If(GetCOM2Buffer(Temp)) //if COM2 buffer got data, display it on COM1
      Fprintf(SendCOM1,Temp);

#ifdef USE_SLOW_DEVICE
   If(GetSlowBuffer(Temp)) //if slow device buffer got data, display it on COM1
      Fprintf(SendCOM1,Temp);
   #endif

   }
}

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jul 30, 2004 1:49 pm     Reply with quote

Quote:
It seems that to be able to reliably implement receive via a SW
UART on 9600 baud, the kbhit(stream) function needs to be called 10
times faster than the baud rate.

One standard method is to use Pin B0 for the Rx pin, with the external
interrupt set to trigger on a falling edge. You then use getc() to read
the char in the INT_EXT isr.

Quote:
I have this slow/lockup problem when using two SW UART and one HW UART together, one of the SW UART is running 300 baud, while the other 9600 Baud, the HW is 9600 UART. When only using the 9600 UART (SW & HW), no problem, even with Timer0, but once I enable the 300 baud SW UART, the whole timing issue (at least what I think it is a timing issue) comes up and lock the system just when it enters the while(1) loop.

You could switch the two USARTs. Put the 300 baud stream on the
hardware usart, and the 9600 baud stream on the software usart.

Also, make sure you add the ERRORS directive to the #use rs232()
statement for your hardware usart.
RatherBeFlying



Joined: 14 Jul 2004
Posts: 11

View user's profile Send private message

PostPosted: Sat Jul 31, 2004 1:49 am     Reply with quote

Thanx PCM programmer for your reply.

I apologize if my questions are still too basic, just started PIC programming since less than a month now, but something that I am not able to understand is why the system would lockup or slow down considerably if I put the If (kbhit(Slower_stream) inside a very fast timer interrupt.

If the timer interrupt already way faster than (10 times the bit rate) for that stream then testing kbhit() within it should be enough? If my calculations are right for the speed, then the 300 baud is about 3.33 ms per bit, which means to achieve 10 times faster for polling then we need to check the kbhit function every 333 uS.

Unless checking kbhit() way faster than required is the problem which means I can still check for 300 baud slower stream within a faster interrupt but put a counter inside the interrupt to test if a 333 uS passed just to check that stream? Is my understanding is right on the stream/bit timing? Would that work?

Thanx again...
Eric Minbiole



Joined: 10 Jun 2004
Posts: 16
Location: USA

View user's profile Send private message Visit poster's website

PostPosted: Sat Jul 31, 2004 11:20 am     Reply with quote

The biggest thing that strikes me is the call to

Code:
   Ch = fgetc(SLOW_DEV);


within the RTCC isr. The call to kbhit() should be very fast, and should not take significant time. However, on a sw UART, the call to fgetc() will wait for the entire character to be received before returning. At 300 baud, this is 33ms. (Perhaps a bit less, since the sw UART does not wait for the last stop bit.) Even still, you'll be waiting here a lonnng time, and will miss characters on the other UARTs / interrupts.

You mentioned that you're seeing the problems even though you aren't receiving anything on the UART yet. If so, I can't expain the problem. Even still, I would still try commenting out the fgetc() call, to see if you're receiving when you don't think you are. (Line inverted, perhaps?)

Doing two software UARTs at the same time is going to be tricky. (Unless you can guarantee that they won't be active at the same time?) Since 300 baud is so slow, you may be able to develop your own interrupt-driven software UART. Your RTCC isr would need to sample the Rx line periodically, reading one bit at a time, rather than waiting for all bits at once, as fgetc() does. This frees up the processor to service the other interrupts.

Hope this helps. Good luck!
RatherBeFlying



Joined: 14 Jul 2004
Posts: 11

View user's profile Send private message

PostPosted: Sat Jul 31, 2004 3:07 pm     Reply with quote

Hi Eric,

Thanx for the post.

Yes, the problem starts just right after power on, the slow serial is not sending or expecting data (same thing with the slow ser. is also off completly). Yes, the fgetc() would be the problem.

The other two 9600 baud (one HW, one SW) working great together, so now i am considering just getting a low-cost PICMicro which does not need an external OSC and only reqauire a cap., so the BoM is low, and dedicate that for this slow device and convert the serial to parallel lines, as this device only transmit 0x00 to 0x0F then only 4 pins + 1 Enable pin is required to interface to the other micro, guess i can try to get 9600 serial baud or faster from the dedicated micro but that still would make us have two SW and one HW into the main micro but maybe when it is faster then another fgetc() inside the RTCC wouldnt be a problem. Though its a few $ more per unit that may not be an option.

Just a question on a different PIC topic, did any one test what will happen if a 50mA or more is being sinked to a PIC PIN when being put into low level output? This was connected to PIN_C0 and it made PIN_B3 output high! i noticed this as B3 is connected to a transistor which controls a Diode, when I issue C0 = 0 (make it low), B3 goes high and activate the diode. I guess internal damage happend from the high current and probably just by chance, unless B3/C0 somehow connected from within the chip.

Thanx again guys for all the help and understanding with all newbies here on the forums.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Aug 01, 2004 4:30 pm     Reply with quote

There's one more thing you should be aware of. In your statement
below, you wanted to have a 10 us interrupt period. It is unlikely that
you can really do this.
Quote:
So from the CCS Wizard, if Timer2 is enabled using setup_timer_2(T2_DIV_BY_1,4,10)
then the Timer2 will overflow in 10 us

When an interrupt occurs, the 16F876A will jump to ROM address 0004.
At this location, you will find the CCS interrupt dispatcher. Look at
the .LST file generated by the compiler to see this code.

At 20 MHz, an instruction cycle is 200 ns. I would estimate that your
program may take 10 us just to execute the first part of the interrupt
dispatcher. This doesn't even count the code in your isr routine.
It will probably take another 10 us to execute the "return" half of the
dispatcher code. So you can't really do a 10 us interrupt period with
standard CCS code. You could use the #priority directive to put your
most important interrupt at the start of the list of interrupts that are
checked by the dispatcher. This would speed things up a little bit.
Or, you could write your own dispatcher by using #INT_GLOBAL, and
possibly speed things up some more. I don't recommend that you try
that at this time.

I think you're probably going to follow Eric's suggestion, or do something
else, but I wanted to let you know about this aspect of CCS.
RatherBeFlying



Joined: 14 Jul 2004
Posts: 11

View user's profile Send private message

PostPosted: Mon Aug 02, 2004 1:44 pm     Reply with quote

Thanx PCM programmer for the hint.

I guess its worth testing the 3 UART on a PIC18Fxxx running 40Mhz to make sure about the 10us for timer2.

Thanx again guys.
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