View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
RS232 Buffer Question |
Posted: Sat Apr 22, 2017 3:31 pm |
|
|
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
|
|
Posted: Sat Apr 22, 2017 9:53 pm |
|
|
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
|
|
Posted: Sun Apr 23, 2017 7:27 am |
|
|
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
|
|
Posted: Sun Apr 23, 2017 9:00 am |
|
|
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: 1909
|
|
Posted: Sun Apr 23, 2017 9:37 am |
|
|
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
|
|
Posted: Sun Apr 23, 2017 9:43 am |
|
|
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: 19539
|
|
Posted: Sun Apr 23, 2017 10:27 am |
|
|
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
|
|
Posted: Wed Apr 26, 2017 2:54 pm |
|
|
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
|
|
Posted: Wed Apr 26, 2017 3:47 pm |
|
|
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: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Apr 26, 2017 6:08 pm |
|
|
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
|
|
Posted: Wed Apr 26, 2017 6:32 pm |
|
|
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: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Apr 26, 2017 8:18 pm |
|
|
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: 19539
|
|
Posted: Thu Apr 27, 2017 8:28 am |
|
|
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
|
|
Posted: Thu Apr 27, 2017 10:42 am |
|
|
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
|
|
Posted: Fri Apr 28, 2017 3:39 pm |
|
|
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. |
|
|
|