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 Buffer Question
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

RS232 Buffer Question
PostPosted: Sat Apr 22, 2017 3:31 pm     Reply with quote

Does PUTC check if the buffer is full when used with a PIC16F884 built-in RS232?
In my program shown below I am concerned that the transmit buffer is not empty before immediately switching to receive. The PIC at the other end has similar software and replies immediately after receiving. The enable=pin_E2 returns the DS3695 to receive immediately after sending so both ends are usually in ‘listen’ mode and the first unit initiates the send/receive. I am also concerned that there is no check on the receive buffer.
I am sending through a DS3695 differential line driver/receiver on a pair of 300ft long wires to a similar setup at the other end. It works but it is difficult to get the timing right.
I am sure there is a better way to do this and I can get into that later. For now I want to understand what is happening and why the timing seems so critical. This has worked reliably for several years until I made some changes.
My controller (master) program is:

Code:
#use rs232 (baud=9600, parity=N, bits=8, enable = pin_E2, xmit=pin_C6, rcv=pin_C7)

// Start of data transmission
   for (i=0; i<max_s; i++)                             // 10 packets, 0 to 9
    {
     putc (packet_s [i]);                               // send the packet
    }

// Timed Wait for reply
    timeout_error = FALSE;                                                   // so WHILE is not skipped
    while ((packet_r [0] != ACK)&&(!timeout_error))      // wait for ACK or timeout
    packet_r [0] = timed_getc();                                          // in this loop
   if (!timeout_error)                                                            // if no timeout error
    {
     for (i=1;i<max_r;i++)                                                      // get the remaining 9, or timeout
     packet_r [i] = timed_getc();                                         // 1 to 9
    }
     packet_r[0]=0x00;

// function 'timed_getc' waits up to 50 ms for a character
   char timed_getc()
   {
    long timeout;
    timeout_error = FALSE;
    timeout = 0;
    while (!kbhit() && (++timeout<5000))                         // 50 msec
     delay_us(10);
    if (kbhit())
     return (getc());
    else
    {
     timeout_error = TRUE;
     return(0);
    }
   }


My “slave” program is:

Code:
// wait for transmission
   timeout_error = FALSE;
  while ((packet_r[0] != ENQ)&&(!timeout_error))             // wait for enquiry or timeout
   packet_r [0] = timed_getc();                                               // to get first packet
  if (! timeout_error)
   {
   for(i=1;i<max_r;i++)                                                    // 10 packets; 0 to 9
    packet_r[i] = timed_getc();                                      // get other 9 packets
   }
  start_r = 0x00;                                                              // clear ENQ

// shut down if no data received
   if (timeout_error)
    {
     m_motor = p_motor = s_motor = 128;       // all speed to stop
     consws = joysws   = 0xFF;                              // all switches off
     rudder = elevator = 128;                               // center rudder and elevator
     pm_rot = sm_rot   = 128;                              // center side motor rotates
    }

// send reply
   for (i=0; i<max_s; i++)              // 10 packets, 0 to 9
    putc (packet_s [i]);                // send the packet



I could use something like the following to make sure the buffer is empty:

Code:
while (tx_buffer_bytes())
delay_ms(1);


However I get an error "a numeric value must appear here" it also does not accept while(tx_buffer_bytes()>0) and other variations. How do I check if the buffer is empty?


Last edited by rovtech on Wed Apr 26, 2017 3:00 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Apr 22, 2017 9:53 pm     Reply with quote

Quote:

#use rs232 (baud=9600, parity=N, bits=8, enable = pin_E2, xmit=pin_C6, rcv=pin_C7)
.
.
.
while (tx_buffer_bytes())
delay_ms(1);

However I get an error "a numeric value must appear here

Do you think you are using the Transmit Buffer feature of #use rs232() ?
You have not enabled it. That's the reason why you get the message
"A numeric expression must appear here".

To enable it, you need to add the TRANSMIT_BUFFER parameter to your
#use rs232() statement. The CCS manual says:
Quote:

TRANSMIT_BUFFER=x

Size in bytes of UART circular
transmit buffer, default if not
specified is zero.

Put in some suitable buffer length for 'x'. Example:
Code:

#include <16F884.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use RS232(UART1, baud=9600, transmit_buffer=32)

//==========================
void main()     
{
while(tx_buffer_bytes())
  delay_ms(1);
 
while(TRUE);   
}
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Sun Apr 23, 2017 7:27 am     Reply with quote

Thanks PCM Programmer. This confirms how little I know.
I thought I was using the internal buffer and my concern was whether the internal hardware buffer still has data to_be_sent when I switch the RS422 chip from transmit to receive. What I have has been working well for several years but changes to the program alter the timing and the two devices drop out of sync.
The 16F884 has a one character output buffer and a two character input buffer and I think my problems are caused by buffer overflow.
My question was whether PUTC pauses until the character is sent.
I really need a better protocol for sending then listening for a reply all on the same pair of wires. Something like I2C but I can't use it over 300+ft of wire. I send a string of bytes starting with a start character but of course the data can have this same character within the string. The slave looks for the start then reads the string and replies immediately. It will lock reliably every turn-on if the timing is "correct" in the firmware. I would like to make it independent of precise timing if possible. Someone must have done this.
Adding a software buffer is just going to make things more complicated.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Sun Apr 23, 2017 9:00 am     Reply with quote

I looked at EX_RS232_485.C and EX_RS232_BUFFER.C and am now reading (and trying to understand) Ttelmah's response to Forum "universal RS232 communications protocol between controllers"
I don't really want to use RS485 or anything with interrupts because the PICs at either end are already communicating with several other devices via I2C.
It may be just a matter of a delay after sending from the master and a longer delay in the slave to make sure the master is finished and is listening.
I am looking for an example of software to send from a master and get a reply from a slave. I cannot use true RS232 because the PICs are not looking at the RS232 signals directly but through an RS422 chip.
newguy



Joined: 24 Jun 2004
Posts: 1910

View user's profile Send private message

PostPosted: Sun Apr 23, 2017 9:37 am     Reply with quote

I'm not familiar with the PIC you're using but I have seen a maybe-similar issue with other PICs. Have you considered the possibility that your issues could be caused by a different PIC silicon revision that might have an errata relating to the transmit buffer? I've used some PICs that have errata that basically state that the transmit buffer empty interrupt can "prematurely" fire when the buffer isn't actually empty.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Apr 23, 2017 9:43 am     Reply with quote

Quote:
My question was whether PUTC pauses until the character is sent.

Here is what the compiler generates for vs. 5.071. So for that version,
the answer is yes, it does wait until the character is transmitted.
(You didn't post your compiler version).

However, it only adds the "wait" if you have the Enable pin defined
in the #use rs232() statement. If you were to make a #use rs232()
statement without the Enable pin, then the section that polls the TRMT
bit would not be inserted.
Code:

.................... #use rs232 (baud=9600, parity=N, bits=8, enable = pin_E2, xmit=pin_C6, rcv=pin_C7) 
0004:  BSF    STATUS.RP0
0005:  BCF    TRISE.2
0006:  BCF    STATUS.RP0
0007:  BSF    PORTE.2    // Set the enable pin high

0008:  BTFSS  PIR1.TXIF  // Wait until transmit register is empty
0009:  GOTO   008

000A:  BSF    STATUS.RP0
000B:  BCF    TRISE.2
000C:  BCF    STATUS.RP0
000D:  BSF    PORTE.2    // Set enable pin high

000E:  MOVF   param,W  // Move new character into transmit register
000F:  MOVWF  TXREG

0010:  NOP
0011:  BSF    STATUS.RP0

0012:  BTFSS  TXSTA.TRMT  // Wait until character has been transmitted
0013:  GOTO   012


0014:  BCF    TRISE.2
0015:  BCF    STATUS.RP0
0016:  BCF    PORTE.2   // Set Enable pin low

Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Sun Apr 23, 2017 10:27 am     Reply with quote

First big confusion. The hardware buffer, is only two bytes.
tx_buffer_bytes is for the software buffer, not the hardware buffer

Yes, the standard putc (using just the hardware buffer), waits if this is full.

The version using the software buffer does not. When this is enabled, you have to add the testing yourself, using tx_buffer_bytes.
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Wed Apr 26, 2017 2:54 pm     Reply with quote

I set up a DSO to see exactly what is happening.
I also display the first two bytes returned.
The transmitted data is correct. The returned data is correct as long as I have ERRORS in my:
Code:
#use rs232 (baud=9600, parity=N, bits=8, enable = pin_E2, xmit=pin_C6, rcv=pin_C7, ERRORS)
but if it is not there then the first data byte is 0x00 instead of 0x06. All the rest of the reply is correct. A 1ms delay between receiving and sending in the target PIC does not help but makes the DSO display easier to read.
The CCS manual is pretty vague about ERRORS and I have no idea how to use it. Is there another resource where I can read up on this? Where is the variable RS232_ERRORS ?
Are there other options in #use RS232 that I should be using. The ENABLE-pin works well to ensure that my initiating PIC switches to listen immediately after sending. At the other end the PIC is in listen mode until it receives the data, replies, and switches to listen immediately.
I read other threads and see
****************
Warning:
The PIC UART will shut down on overflow (3 characters received by the hardware with a GETC() call). The "ERRORS" option prevents the shutdown by detecting the condition and resetting the UART.
****************
In my case the UART does not shut down, it only misses the first character.
PCM ver 5.055
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Apr 26, 2017 3:47 pm     Reply with quote

rovtech wrote:

The CCS manual is pretty vague about ERRORS and I have no idea how
to use it. Is there another resource where I can read up on this?

http://www.ccsinfo.com/forum/viewtopic.php?t=19759&highlight=framing+overrun

Quote:

Where is the variable RS232_ERRORS ?

Compile your program and look at the .SYM file in your project directory.
You'll see the compiler has allocated a RAM byte for it. This is only done
if you specify ERRORS in the #use rs232() statement.
temtronic



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

View user's profile Send private message

PostPosted: Wed Apr 26, 2017 6:08 pm     Reply with quote

Ok, I have to ask the obvious question..

Is there no chance for just one more wire in this cable to allow full duplex?

I'm assuming you ran out of conductors....just had to ask as sometimes simple hardware fix is easier than cutting code...

I can easily get 15 miles on a single wire plus Mother Earth. Really old school but reliable.

Jay
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Wed Apr 26, 2017 6:32 pm     Reply with quote

Thanks PCM programmer.
Yes, I read that and others but none explain why, without ERRORS in the #use RS232, my program never sees the first character in the reply and always sees the remaining 9 characters.
The initiating PIC sends 10 bytes then immediately switches to looking for a reply and always misses the first byte unless ERRORS is used. The receiving PIC is in the timed_getc loop for over 100ms and always gets the first character.
Another peculiar thing is that the ENABLE pin on the initiating PIC goes to about 2v for some time before it goes to 5v to send data. It does this with and without ERRORS.
Also with ERRORS Rx on the PIC goes low immediately after receiving the data but without ERRORS Rx stays high for about 80ms.
The receiving PIC has a square pulse from 0 to 5v on ENABLE when sending, without the preshoot. I have exchanged the PICs and the DS3695s. It seems to be in the software and has something to do with reading right after sending. The receiving PIC is sending right after reading and works fine.
temtronic



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

View user's profile Send private message

PostPosted: Wed Apr 26, 2017 8:18 pm     Reply with quote

hmm..re: It seems to be in the software and has something to do with reading right after sending

Are you using 'fixed_io()' or 'standard_IO() ?

It almost sounds like some bits on the port are being 'diddled'....

The listing would shed light on what's going on.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19553

View user's profile Send private message

PostPosted: Thu Apr 27, 2017 8:28 am     Reply with quote

With 'ERRORS', the getc, will test the error bits and potentially clear them (or reset the UART if necessary), before getting data if available.
I'd agree with Temtronic. This will also recover if the UART has been disabled, or the RX line has had the TRIS set to output. Suspect something else is affecting the lines. If you are setting TRIS for example yourself (rather than letting the compiler handle it), then are you possibly getting the bits for the UART wrong?.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Apr 27, 2017 10:42 am     Reply with quote

Per Ttelmah, one thing I never liked about this thread is that you have
not shown us your setup code at the start of main(), your #fuses,
#use delay(), and a link to your schematic. A lot can go wrong in any
of those.

Also, what happens if you put a 4.7K pullup resistor on the Rx pin of
each PIC ? Or do you have them already ?
rovtech



Joined: 24 Sep 2006
Posts: 262

View user's profile Send private message AIM Address

PostPosted: Fri Apr 28, 2017 3:39 pm     Reply with quote

Thanks for the replies.
I am preparing to strip my programs down to basics for some tests.
I was wrong in saying that Errors is needed only in the MASTER. If I leave it out in the SLAVE I also get an error in the first byte. All other bytes are OK.
It also works perfectly with ERRORS in each PIC code.
I will post my code when I have it reduced. No one wants to read 4 pages of code that is irrelevant.
No I don't have pullups on any of the pins. They seem clean transitions except for the preshoot but it is there when working. I have been thinking of updating my CCS.
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, 3  Next
Page 1 of 3

 
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