|
|
View previous topic :: View next topic |
Author |
Message |
DonWare
Joined: 18 Jan 2006 Posts: 43
|
RS232 losing first character transmitted |
Posted: Thu May 25, 2006 8:47 am |
|
|
Hi, I'm using a PIC 16F877, MPLAB IDE, MPLAB Debugger 2, CCS PCWH. The first character I send out does not make it to my terminal program. I've tried stepping and letting it free run, installed delays in various locations.
Basically, I enable xmit interrupts, global interrupts, use putc() to send the first character and then the rest in the xmit interrupt.
Stepping through it, all seems to work ok except for the missing first character. Any ideas ?
Thanks, Don Ware |
|
|
Ttelmah Guest
|
|
Posted: Thu May 25, 2006 10:04 am |
|
|
Multiple possibilities.
First is that the charge pump, on RS232 transceiver chips, in computer terms, takes a _long_ time to get up to full operating voltage. Can easily be several mSec on some units.
Second, is that when the PIC first wakes, the I/O line, will actually be an input for a while, before the serial port is setup. In some cases, the transceiver has sufficient pullup on it's input, for this to be treated as an 'idle' (high) state, but on some other designs, the pin floats low. On these, the receiver at the other end, can see this as a start bit, and then receive a garbage first character.
Third is that on some compiler versions, the line does not get programmed to actually be used as a serial line, till you do some I/O on the pin. This should not be a problem on the 877, since on this, the TRIS pins need to be set as inputs for the serial I/O, and this problem normally appears on chips where they need to be set as outputs. However this would appear, if at some point in your initialisation, you use an 'output_c' instruction (assuming you are using standard_io), since this would set the tris to output mode, and override the serial setting, till a byte is sent...
Best Wishes |
|
|
DonWare
Joined: 18 Jan 2006 Posts: 43
|
rs232 missing first character. |
Posted: Thu May 25, 2006 10:19 am |
|
|
OK thanks. Some things to think about. I'll look into options 2 and 3.
Additionally I notice that when I enable tx buffer empty interrupt, it generates an interrupt immediately before I send any characters. I can handle this though.
Thanks again.
Don |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
Re: rs232 missing first character. |
Posted: Thu May 25, 2006 12:44 pm |
|
|
DonWare wrote: | OK thanks. Some things to think about. I'll look into options 2 and 3.
Additionally I notice that when I enable tx buffer empty interrupt, it generates an interrupt immediately before I send any characters. I can handle this though.
Thanks again.
Don |
The interrupt is _when_ the buffer is empty so it should generate it immediately. Also, take a look at the lst file. putc() adds a few more instructions than necessary. It tests for the interrupt flag bit being set before loading the value into TXREG. You'd be better off defining the transmit register and loading the data _manually_. Also add the "noclear" flag to the interrupt. The compiler adds code to clear the flag bit but this is done in hardware so its just one more instruction.
before:
Code: |
.................... #int_tbe
.................... void tx(void)
.................... {
.................... putc('a');
009C: MOVLW 61
009E: BTFSS F9E.4
00A0: BRA 009E
00A2: MOVWF FAD
.................... }
00A4: BCF F9E.4
00A6: GOTO 0058
|
after:
Code: |
.................... #int_tbe noclear
.................... void tx(void)
.................... {
.................... TXREG = 'a';
009C: MOVLW 61
009E: MOVWF FAD
.................... }
00A0: GOTO 0058
|
|
|
|
DonWare
Joined: 18 Jan 2006 Posts: 43
|
Solved ? |
Posted: Thu May 25, 2006 1:01 pm |
|
|
Thanks for the ideas. I was able to fix the problem by:
(1) Set up my xmit data buffer in RAM.
(2) Enable TX interrupts which causes interrupt, my tx isr starts sending characters from the beginning of the buffer (including the 1st char)
This is what my code had been doing (incorrectly)
(1) Set up my xmit data buffer in RAM.
(2) Enable TX interrupts which causes interrupt, my tx isr start to execute which advanced by tx buffer pointer.
(3) Do a fputc on my first buffer character in an attempt to start the xmit process.
So it was operator error. As usual the best solution was the simplest.
Thanks for all your help!
Don |
|
|
Ttelmah Guest
|
|
Posted: Thu May 25, 2006 2:39 pm |
|
|
I posted the following routines a little while ago, in another thread. They show how to handle an interrupt driven TX.
Code: |
#byte PIR1 = 0xF9E
#byte TXREG = 0xFAD
#define TXIF 4
//Must be binary multiple size for buffer code as written
#define SLBUFF (32)
//Initialise buffers
int RSTcount,RSTin,RSTout;
unsigned int LCDbuff[SLBUFF];
//Buffer tests and handling
#define isempty(buff,free,in,out,size) (free>=size)
#define isfull(buff,free,in,out,size) (free<2)
#define tobuff(buff,free,in,out,size,chr) {buff[in]=chr;\
--free;\
in=((in+1) & (size-1));}
unsigned int RSTfrom()
{
/* Get character from the RS232 TX buffer */
static unsigned int temp;
temp=RSTbuff[RSTout];
RSTout=(RSTout+1) & (STBUFF-1);
RSTcount++;
return(temp);
}
#INT_TBE /* Transmit buffer empty interrupt */
void TXINT(void) {
/* If characters are waiting in the buffer, the next one is transferred
to the UART otherwise the interrupt is disabled, waiting for the next
transmission. */
if (!isempty(RSTbuff,RSTcount,RSTin,RSTout,STBUFF)) {
TXREG=RSTfrom();
}
else
DISABLE_INTERRUPTS(INT_TBE); /* RS232 TX */
}
void tchar(unsigned int chr) {
/* routine to send one character on the RS232.
This puts the specified character into the software transmit buffer
(if data is allready being transmitted), or else sends the single
character to the RS232 UART. */
disable_interrupts(INT_TBE);
/* Hold transmission if the buffer is full */
while (isfull(RSTbuff,RSTcount,RSTin,RSTout,STBUFF)) {
if (BIT_TEST(PIR1,TXIF)==1) {
/* Here the transmit hardware buffer is empty */
TXREG=RSTfrom();
//Copy one character
}
}
/* put character into the output buffer */
tobuff(RSTbuff,RSTcount,RSTin,RSTout,STBUFF,chr);
/* Enable interrupts */
enable_interrupts(INT_TBE);
}
|
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu May 25, 2006 7:16 pm |
|
|
Note that on an initial write, you will get back to back interrupts. This is because on the first load into TXREG, the data is immediately transferred to the transmit shift register and TXREG becomes empty again. To avoid this, I send the first char, set index to point to the next element and then enable interrupts. It saves you the overhead of the second int. |
|
|
DonWare
Joined: 18 Jan 2006 Posts: 43
|
|
Posted: Fri May 26, 2006 6:52 am |
|
|
This is also a good idea.
I set it up and it works fine.
Thanks. |
|
|
|
|
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
|