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

How to kick start UART transmission?
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
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

How to kick start UART transmission?
PostPosted: Fri Jun 25, 2004 9:43 am     Reply with quote

I must transmit to an extremely slow device at 600 bauds. This device will tell me when to transmit by flipping a signal line. I am monitoring this line, and as soon as it flips, i place my byte to be sent in the UART buffer using "fputc".

The problem is that once the byte is sitting in the transmit buffer of the UART, it has to wait until the baud rate generator signals a baud, at which time the UART will latch its start bit on the transmission line. It takes my software under 1ms to recognize the line flipping, and then after placing the byte in the transmit buffer, it takes the UART a variable amount of time between 0 baud and 1 baud (or 0 to 1.6ms). All in all, the transmission will start between 1 and 2.2ms after the send request.

Amusingly, the device i'm transmitting to will give up all hopes of receiving a byte from me (timeout) after 2ms flat.

I have fixed hardware and can not move the send-request line to my hardware interrupt port in orther to react faster.

My only hope is to kickstart the UART, which is what I am trying to do. Now, according to Microchip, if I reload the baud rate generator register, it will restart the timer of the baud rate generator.

I've tried accessing directly the address with #byte, i've tried to set_uart_speed after storing my byte to be sent, nothing seems to kickstart the UART which always wait anything from 0 to 1.6ms before the actual start bit arrives on the transmission line.

Does anyone have any idea on how to resolve this interesting challenge?

The ugliest solution would possibly be for me to create fast timer interrupt and build my very own baud rate generator, all in interrupts, but this jeopardize the responsiveness of the rest of my system, which is pretty busy already.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 25, 2004 2:00 pm     Reply with quote

This problem intrigued me, so I came up with a possible solution.
I think if you can temporarily switch to a software USART, then
the characters can begin transmitting immediately.

So the question is how to do that ? I came up with the following
method. See the program below. I tested it with PCM vs. 3.188
and 3.202. I only tested the transmit side. I didn't test the receive
side. This program displays this output on the terminal window:

Hardware USART
Software USART
Hardware USART line 2

Of course, while the software USART is transmitting characters,
you must not allow interrupts to occur, or it will disrupt the bit timing.
The software USART uses all the CPU cycles when it is sending a
char. You can't do multi-tasking during that time.

Code:
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

// PIC REGISTER BITS
#byte RCSTA = 0x18
#bit  SPEN_BIT = RCSTA.7 

#byte TXSTA = 0x98
#bit  TRMT_BIT = TXSTA.1

// FUNCTION PROTOTYPES
void putc_soft_usart(char c);
char getc_soft_usart(void);
void disable_hardware_usart(void);
void enable_hardware_usart(void);

//==========================================
main()
{
printf("Hardware USART\n\r");

disable_hardware_usart();
putc_soft_usart("Software USART\n\r");

enable_hardware_usart();
printf("Hardware USART line 2\n\r");

while(1);
}

//======================================
// We can create a software USART on the hardware
// pins by declaring the xmit and rcv sections with
// two different #use rs232 statements.
//
// Any characters sent to this function will be
// transmitted by software "bit-banging" on pin C6.
// The hardware usart must be disabled before you call
// this function.

#use rs232(baud=9600, xmit=PIN_C6)

void putc_soft_usart(char c)
{
//output_high(PIN_C6);     // This line doesn't seem to be needed.
putc(c);
}

//--------------------------------------
#use rs232(baud=9600, rcv=PIN_C7)

char getc_soft_usart(void)
{
char c;

c = getc();

return(c);
}

//------------------------------------
void disable_hardware_usart(void)
{
while(TRMT_BIT == 0);  // Wait until any pending chars are transmitted
SPEN_BIT = 0;          // Then disable the hardware USART
}

//------------------------------------
void enable_hardware_usart(void)
{
SPEN_BIT = 1;
}
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

PostPosted: Fri Jun 25, 2004 2:20 pm     Reply with quote

Ahh PCM Programmer. I knew you would probably the only one in here to dare respond to my delicate situation!

Thanks for your suggestion, but as I said at the very end of my post, moving to a software based UART is undesirable, as it will seriously mess up the rest of my system. I'm already multi-tasking a lot of things and I just can't afford to get lost for the incredibly long time that it takes to send one byte at 600 bauds...

I'm starting to think of using timer0 to generate interrupts that will call a function to send my stuff, bit by bit. It might dright slightly because of the rest of the system (which was the beauty of using the hardware uart in the first place), but i might be able to correct it on a per-baud basis by re-reading the timer when entering it's ISR.
Ttelmah
Guest







Re: How to kick start UART transmission?
PostPosted: Fri Jun 25, 2004 2:38 pm     Reply with quote

Laurent Chouinard wrote:
I must transmit to an extremely slow device at 600 bauds. This device will tell me when to transmit by flipping a signal line. I am monitoring this line, and as soon as it flips, i place my byte to be sent in the UART buffer using "fputc".

The problem is that once the byte is sitting in the transmit buffer of the UART, it has to wait until the baud rate generator signals a baud, at which time the UART will latch its start bit on the transmission line. It takes my software under 1ms to recognize the line flipping, and then after placing the byte in the transmit buffer, it takes the UART a variable amount of time between 0 baud and 1 baud (or 0 to 1.6ms). All in all, the transmission will start between 1 and 2.2ms after the send request.

Amusingly, the device i'm transmitting to will give up all hopes of receiving a byte from me (timeout) after 2ms flat.

I have fixed hardware and can not move the send-request line to my hardware interrupt port in orther to react faster.

My only hope is to kickstart the UART, which is what I am trying to do. Now, according to Microchip, if I reload the baud rate generator register, it will restart the timer of the baud rate generator.

I've tried accessing directly the address with #byte, i've tried to set_uart_speed after storing my byte to be sent, nothing seems to kickstart the UART which always wait anything from 0 to 1.6ms before the actual start bit arrives on the transmission line.

Does anyone have any idea on how to resolve this interesting challenge?

The ugliest solution would possibly be for me to create fast timer interrupt and build my very own baud rate generator, all in interrupts, but this jeopardize the responsiveness of the rest of my system, which is pretty busy already.

I must admit this is an 'interesting' problem!...
Looking at the data sheets for the UART, it says that writing a _new_ value resets the BRG, but not that writing the _same_ value does this.
Hence I suspect you would need to try toggling the value to a 'wrong' value, and immediately back, to get the required reset.
Worth a try.

Best Wishes
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

Re: How to kick start UART transmission?
PostPosted: Fri Jun 25, 2004 2:43 pm     Reply with quote

Ttelmah wrote:

Looking at the data sheets for the UART, it says that writing a _new_ value resets the BRG, but not that writing the _same_ value does this.
Hence I suspect you would need to try toggling the value to a 'wrong' value, and immediately back, to get the required reset.
Worth a try.


I tried and it doesn't seem to have any effect on the time at which the next BRG baud will occur. I tried setting it 1200 bauds then immediately back to 600, and it doesn't seem to "reset (or clear)" the BRG timer as microchip says in the datasheet. I've checked the disassembly and it seems all valid, so i suspect it's something else...
Ttelmah
Guest







Re: How to kick start UART transmission?
PostPosted: Fri Jun 25, 2004 3:47 pm     Reply with quote

Laurent Chouinard wrote:
Ttelmah wrote:

Looking at the data sheets for the UART, it says that writing a _new_ value resets the BRG, but not that writing the _same_ value does this.
Hence I suspect you would need to try toggling the value to a 'wrong' value, and immediately back, to get the required reset.
Worth a try.


I tried and it doesn't seem to have any effect on the time at which the next BRG baud will occur. I tried setting it 1200 bauds then immediately back to 600, and it doesn't seem to "reset (or clear)" the BRG timer as microchip says in the datasheet. I've checked the disassembly and it seems all valid, so i suspect it's something else...


I wonder if you need to wait for one clock of the BRG to occur?. If so, since the chip is programmed to a 'slow' rate, the change would still take as long.
Try setting the BRG to a fast value (9600bps for example), while waiting for the 'edge', then when you see the trigger event, put the byte into the output register, and immediately change the BRG to the 600 bps figure. the way it reads, it should start clocking out the byte at the 'slow' rate (possibly!).

Best Wishes
Gabriel Caffese



Joined: 09 Oct 2003
Posts: 39
Location: LA PLATA, ARGENTINA

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

PostPosted: Fri Jun 25, 2004 4:13 pm     Reply with quote

Laurent,

Where from does that "fliping" signal come from ?
Canīt you pick it up from a previous source ? With a few ms on your side, youīll be able to stablish communication.

Gabriel.-
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Sat Jun 26, 2004 12:11 pm     Reply with quote

Laurent Chouinard wrote:
Quote:

It takes my software under 1ms to recognize the line flipping, and then after placing the byte in the transmit buffer, it takes the UART a variable amount of time between 0 baud and 1 baud (or 0 to 1.6ms). All in all, the transmission will start between 1 and 2.2ms after the send request.


Donīt know why your software take 1ms to recognize a line flipping. Such event could
be handled by an EXT_INT (edge detect) interrupt in less than 50 usec.
Then if the UART needs up to 1.6ms to place a byte in the transmit buffer, you still are
into the 2ms window time needed.

Best wishes


.
Guest








Re: How to kick start UART transmission?
PostPosted: Mon Jun 28, 2004 6:35 am     Reply with quote

Ttelmah wrote:
I wonder if you need to wait for one clock of the BRG to occur?. If so, since the chip is programmed to a 'slow' rate, the change would still take as long.
Try setting the BRG to a fast value (9600bps for example), while waiting for the 'edge', then when you see the trigger event, put the byte into the output register, and immediately change the BRG to the 600 bps figure. the way it reads, it should start clocking out the byte at the 'slow' rate (possibly!).


Your idea makes a whole lot of sense, i will try it this morning and post back the results! thanks for the tip

Gabriel Caffese wrote:
Where from does that "fliping" signal come from? Canīt you pick it up from a previous source ? With a few ms on your side, youīll be able to stablish communication.


The flipping signal comes from the external device that my circuit is communicating with. It's an old antiquated method of serial communication involving an interrupt line, a send line, and a data line. In any case I can't really detect that flipping any sooner than 1ms because the pic is already seriously busy doing other tasks that are uninterruptible, so the code is only available to observe the flipping line every 1ms and no sooner.

I "could" change it so i can see it a bit sooner, but it would force me to rewrite a whole lot of software which we don't want to at this point.

Humberto wrote:
Donīt know why your software take 1ms to recognize a line flipping. Such event could be handled by an EXT_INT (edge detect) interrupt in less than 50 usec. Then if the UART needs up to 1.6ms to place a byte in the transmit buffer, you still are into the 2ms window time needed.


I can not use the EXT_INT line, as I explained in my initial post, because it's already being used by some other purpose that require the interrupt. The reason why my software takes so long to detect the line is explained just above.
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

Oops, that was me
PostPosted: Mon Jun 28, 2004 6:37 am     Reply with quote

This forum should at least inform be before trying to post anonymously when i omitted my username from the post form... oh well!
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

PostPosted: Tue Jun 29, 2004 11:48 am     Reply with quote

IMPOSSIBLE!

That is the verdict of all my testing. One simply can not teach the baud rate generator to start its first baud at predetermined time. The BRG will start its bauds whenever it wants it.

To prove it, i made this test.

1) I set the uart at 19200 bauds with set_uart_speed(19200);

2) I store a byte in the transmission buffer

3) I wait 52uS. While this waiting occur, the UART will put the start bit of my byte. I does so because, at 19200 bauds, one baud = 52uS, so the next baud will forcefully occur while i'm waiting.

4) I set the baud rate to 600 bauds

5) The rest of the start bit will last any time between 52uS and 1.6mS because the BRG did not restart when i put a new baudrate. It kept counting from where it was until it reaches the new limit which is considerably longer because it's 1.6mS instead of 52uS.

Sad

So there. There is just no way of sending a byte IMMEDIATELY when using the uart. One must do that by software.

This will be, in my logbook, the Most Time Consuming Bug Ever(TM)
Guest








PostPosted: Wed Jun 30, 2004 2:04 am     Reply with quote

I would use this:

1. Set up Timer1:
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
2. When the control line fires load e.g. 0xFF00 into Timer1, clear Timer1 IT and enable Timer1 IT:
#INT_EXT
void Trigger()
{
Disable_interupts(INT_EXT); // disable further ITs
Set_Timer1(0xFF00); // to give 256 us to ISR before the next Timer1 IT
Clear_interrupt(INT_TIMER1);
Enable_interrupts(INT_TIMER1);
}

In the Timer1 ISR put out the corresponding bit and load timer1 with the bit time:
#INT_TIMER1
void Timer1_ISR()
{
Set_Timer1(65536-1600); // this is 1.6ms@4MHz clock
if (bitcnt == 0) output_low(DATALINE); // start bit
else if (bitcnt == 9) output_high(DATALINE); // stop bit
else output_bit(DATALINE,bit_test(DataToSend,0));
bitcnt++;
DataToSend >>= 1;
if (bitcnt == 10) { // stop bit already sent
bitcnt = 0;
bytecnt++;
if (bytecnt >= MAXBYTES) { // all bytes sent
Disable_interupts(INT_TIMER1);
Enable_Interrupts(INT_EXT);
return;
}
DataToSend = MyArray[bytecnt]; // load the next byte to send
}
}

Of course there are lot of global variables. Additionally you have to fill out the array and place the first byte into DataToSend before transmission.
You will get an IT every 1.6ms and the service routine is cca. 100us so you have enough time for other tasks.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jun 30, 2004 3:23 am     Reply with quote

The interrupt function contains a bug: DataToSend is shifted in every interrupt, this shouldn't be done for the start bit.

fixed code:
Code:
#INT_TIMER1
void Timer1_ISR()
{
  Set_Timer1(65536-1600); // this is 1.6ms@4MHz clock
  if (bitcnt == 0) output_low(DATALINE); // start bit
  else if (bitcnt == 9) output_high(DATALINE); // stop bit
  else {
    output_bit(DATALINE,bit_test(DataToSend,0));
    DataToSend >>= 1;
  }
  bitcnt++;
  if (bitcnt == 10) { // stop bit already sent
    bitcnt = 0;
    bytecnt++;
    if (bytecnt >= MAXBYTES) { // all bytes sent
      Disable_interupts(INT_TIMER1);
      Enable_Interrupts(INT_EXT);
      return;
    }
  DataToSend = MyArray[bytecnt]; // load the next byte to send
  }
}
Laurent Chouinard



Joined: 12 Sep 2003
Posts: 43

View user's profile Send private message

PostPosted: Wed Jun 30, 2004 6:16 am     Reply with quote

Sounds good, ckielstra. That's basically what PCM Programmer proposed, which i myself considered, to use a software based serial transmission. I happen to have one free timer (0) which could be used for that. It's just a very ugly fix to an otherwise simple problem.

Thanks for your tip.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jun 30, 2004 9:22 am     Reply with quote

Laurent,

Sorry, the above code wasn't donated by me but by an 'anonymous guest'. I only spotted the error in it.
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