|
|
View previous topic :: View next topic |
Author |
Message |
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
Soft UART with INT_EXT2 Nuts and Bolts |
Posted: Sun Jan 01, 2012 10:39 pm |
|
|
I've used soft UARTs before and never run into this problem. Now that I'm seeing it, I'm wondering two things: how soft UARTs work and possible reasons mine isn't.
I've got 2 18F2620s tied together with three wires: TX, RX and GND. They are running at 10mHz. I've got a hardware UART transmitting a single byte 0x55 to the second part's soft UART. It is receiving a 0xAA. So, the first bit appears to be missed. Originally, I thought I was sending an 0xAA and getting a 0x55 and the H_to_L interrupt was losing the first bit.
Here are the pertinent pieces of code:
Code: |
#use rs232(baud=9600,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8,stream=MASTER_TO_SLAVE,sample_early)
int8 buffer[16];
int8 next_in = 0;
int8 next_out = 0;
#INT_EXT2
void soft_serial_isr()
{
int8 t;
buffer[next_in] = fgetc(MASTER_TO_SLAVE);
t = next_in;
next_in = (next_in+1) % sizeof(buffer);
if(next_in == next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in != next_out)
int8 bgetc()
{
int8 c;
while(!bkbhit);
c = buffer[next_out];
next_out = (next_out+1) % sizeof(buffer);
return c;
}
ext_int_edge( H_TO_L );
enable_interrupts(INT_EXT2);
clear_interrupt(INT_EXT2);
if (bkbhit)
{
clear_and_home_lcd();
fprintf(LCD, "%X",bgetc());
}
|
I'm going to continue to pare it down, but at this point I think my problems are even beyond simplification.
So, ultimately, the question is what would cause a bit shift when receiving?
Thanks,
John
EDIT:
The B6 pin is tied to the B2 pin to enable the INT_EXT2 for receiving. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jan 01, 2012 11:15 pm |
|
|
What's your PIC oscillator frequency and your compiler verison ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19544
|
|
Posted: Mon Jan 02, 2012 5:21 am |
|
|
At 10MHz, it'll take about 12uSec to get into an interrupt. Given that the bit time at 9600bps, is 0.104mSec, I'd start by getting rid of 'sample_early'. This is needed when the time to reach the interrupt is more than perhaps 1/4 a bit time, since otherwise you read far too late in the byte. At 10MHz/9600bps this is not needed.
Now the bit patterns don't quite 'work' for you 'missing the first bit'. The bit patterns are:
.....1111100101010111111..... sent for 'AA'
.....1111101010101011111..... seen for '55'
If you were sampling 'late' in the 'AA' pattern, you'd receive the MSb set in the received byte, and get D5.
Do you know what silicon revision your master 2620 is?. The early 2620 revisions (A3, and A4), have a lot of errata on the EUSART module, including one that might cause problems. If you master is set to generate parity, then 9bit transmission mode is used (since the hardware doesn't do this), and if you send a second byte without a pause on these chips in this mode, the second byte may be corrupted.....
So start by setting both ends to 'parity=none', and removing the sample_early, and see if things change.
Best Wishes
Last edited by Ttelmah on Mon Jan 02, 2012 8:34 am; edited 1 time in total |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Mon Jan 02, 2012 8:06 am |
|
|
PCM programmer wrote: | What's your PIC oscillator frequency and your compiler verison ? |
10mHz
3.249
Ttelmah wrote: | If you were sampling 'late' in the 'AA' pattern, you'd receive the MSb set in the received byte, and get D5.
Do you know what silicon revision your master 2620 is?.
So start by setting both ends to 'parity=none', and removing the sample_early, and see if things change. |
Currently getting a D5 with and without sample_early.
I couldn't find a legend for determining silicon revisions. The markings on the chips are -
TX: 10321SV
RX: 1035R5T
I even tried the receiver at 40mHz and still get a D5.
Here is the current iteration of code for troubleshooting. Note, the term master and slave is slightly confusing. The slave is transmitting to the master. A hardware UART is transmitting to a software.
Master/Receiver:
Code: | #include <18F2620.h>
#use delay(clock=10000000)
#fuses HS,NOPROTECT,NOLVP,NOBROWNOUT,NOWDT
// software UART for serial comms slave to master controller
#use rs232(baud=4800,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8,stream=MASTER_TO_SLAVE)
// software UART for LCD display
#use rs232(baud=9600,parity=N,xmit=PIN_A4,bits=8,stream=LCD)
#define LED_GREEN PIN_A0
#define LED_YELLOW PIN_A1
#define LED_RED PIN_A2
////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SerLCD_V2_5.C"
int8 buffer[16];
int8 next_in = 0;
int8 next_out = 0;
#INT_EXT2
void soft_serial_isr()
{
int8 t;
buffer[next_in] = fgetc(MASTER_TO_SLAVE);
t = next_in;
next_in = (next_in+1) % sizeof(buffer);
if(next_in == next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in != next_out)
int8 bgetc()
{
int8 c;
while(!bkbhit);
c = buffer[next_out];
next_out = (next_out+1) % sizeof(buffer);
return c;
}
//================================================
//
// MAIN
//
//================================================
void main() {
int8 temp_char;
setup_timer_0(RTCC_OFF | RTCC_DIV_64 | RTCC_8_BIT);
setup_timer_1(T1_DISABLED | T1_DIV_BY_1);
setup_timer_1(T2_DISABLED | T2_DIV_BY_1);
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_adc(ADC_OFF);
ext_int_edge( H_TO_L );
enable_interrupts(INT_EXT2);
clear_interrupt(INT_EXT2);
enable_interrupts(GLOBAL);
output_low(LED_RED);
output_low(LED_YELLOW);
output_low(LED_GREEN);
while (TRUE)
{
if (bkbhit)
{
temp_char = bgetc();
clear_and_home_lcd();
fprintf(LCD, "%X",temp_char);
}
} //while (TRUE)
} //main()
|
Slave/Transmitter:
Code: | #include <18F2620.h>
#use delay(clock=10000000)
#fuses HS,NOPROTECT,NOLVP,NOBROWNOUT,NOWDT
// MASTER SLAVE
// TX B7 ---------> RX C7
// RX B6 <--------- TX C6
// hardware UART for serial comms slave to master controller
#use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors,BRGH1oK,stream=SLAVE_TO_MASTER)
// software UART for LCD display
#use rs232(baud=9600,parity=N,xmit=PIN_A4,bits=8,stream=LCD)
#define LED_GREEN PIN_A0
#define LED_YELLOW PIN_A1
#define LED_RED PIN_A2
////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SerLCD_V2_5.C"
//================================================
//
// MAIN
//
//================================================
void main() {
setup_timer_0(RTCC_OFF | RTCC_DIV_64 | RTCC_8_BIT);
setup_timer_1(T1_DISABLED | T1_DIV_BY_1);
setup_timer_1(T2_DISABLED | T2_DIV_BY_1);
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_adc(ADC_OFF);
while (TRUE)
{
fputc(0x55, SLAVE_TO_MASTER);
delay_ms(1000);
output_toggle(LED_YELLOW);
} //while (TRUE)
} //main()
|
Thanks for the help,
John
EDIT:
Even at 1200 baud I get 0xD5 instead of 0x55. Transmission/reception the other direction (soft--->hard UART) is good.
Would it be worth it to "fake" a software transmit of the 0x55 from the "suspect" part and see if it solves the problem? What would the bit spacing on the 0s and 1s be? I'll need to read up on RS232 to make sure I get it right. I've got a scope handy, but until I know what I'm looking for, it's not much use.
EDIT2:
Scope of 0x55 transmit by the hardware UART looks perfect.
111110101010101111111 |
|
|
Jerry I
Joined: 14 Sep 2003 Posts: 96 Location: Toronto, Ontario, Canada
|
|
Posted: Mon Jan 02, 2012 2:06 pm |
|
|
I see that you are using EXT2 for soft serial interrupt
rcv=PINB6 is not EXT2
You should be using rcv=PINB2
Code: |
#use rs232(baud=9600,parity=N,xmit=PIN_B7,rcv=PIN_B6,bits=8,stream=MASTER_TO_SLAVE,sample_early)
int8 buffer[16];
int8 next_in = 0;
int8 next_out = 0;
#INT_EXT2
void soft_serial_isr()
{
int8 t;
buffer[next_in] = fgetc(MASTER_TO_SLAVE);
t = next_in;
next_in = (next_in+1) % sizeof(buffer);
if(next_in == next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in != next_out)
int8 bgetc()
{
int8 c;
while(!bkbhit);
c = buffer[next_out];
next_out = (next_out+1) % sizeof(buffer);
return c;
}
ext_int_edge( H_TO_L );
enable_interrupts(INT_EXT2);
clear_interrupt(INT_EXT2);
if (bkbhit)
{
clear_and_home_lcd();
fprintf(LCD, "%X",bgetc());
}
|
|
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Mon Jan 02, 2012 6:01 pm |
|
|
Jerry I wrote: | I see that you are using EXT2 for soft serial interrupt
rcv=PINB6 is not EXT2
You should be using rcv=PINB2
|
Jerry,
Sorry, that was one of the things I had meant to add to one of my edits. I've got B6 jumpered to B2 to use the interrupt.
John |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Mon Jan 02, 2012 7:59 pm |
|
|
Mulling this one over and ...
Well I've got a couple of questions.
Have you tried the hardware UART of the 2nd unit ? If so with what results? If the hardware UART works 100%, gotta be a 'software' issue..
I'll assume the HW UART is dedicated to another function and can't be used..
Have you tried other data other than the 'magical' 55 and AA ?
Not some silly 'bad ground' issue ? Power supply OK ? Bad solder joint ?All those normal,taken for granted things we sometimes miss ! |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Mon Jan 02, 2012 9:27 pm |
|
|
temtronic wrote: |
Have you tried the hardware UART of the 2nd unit ? If so with what results? If the hardware UART works 100%, gotta be a 'software' issue.. |
Just tried it. The hardware UART works fine.
Quote: |
I'll assume the HW UART is dedicated to another function and can't be used..
|
Yes, it is dedicated to a Bluetooth radio. This is a modification to an existing board that controls 480 LEDs. The latest project has a requirement for 600+ LEDs so I need to have two controllers tied together.
Quote: |
Not some silly 'bad ground' issue ? Power supply OK ? Bad solder joint ?All those normal,taken for granted things we sometimes miss ! |
I don't think so because every other option works normally, just not the softUART. I put an output_high in the beginning of the interrupt handler and an output_low at the end. I then looked at when the interrupt was handled during the byte transmission. The output_high occurred precisely at the low to high at the end of the start bit. I wish I could do the same thing and see when the last bit is being sampled. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jan 02, 2012 11:09 pm |
|
|
Quote: |
The output_high occurred precisely at the low to high at the end of the start bit.
|
That information now points to this line as the problem:
Quote: |
ext_int_edge( H_TO_L );
enable_interrupts(INT_EXT2);
clear_interrupt(INT_EXT2);
enable_interrupts(GLOBAL);
|
|
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Jan 03, 2012 6:34 am |
|
|
I was assuming there delay to get into the interrupt handler, but now that you mention it, it shouldn't be that long, right? Especially when I have slowed the baud to 1200 to see if I can find my problem. Wait, is there a specific EXT2_INT_H_TO_L? I'll have to see if I can find that. Sometimes the documentation is tough to find. I'll look in the part datasheet and go from there. EDIT: Just saw that there is. Thanks, Iam assuming that is what you were alluding to in your previous post? Now I've got to wait until this afternoon to try it. It's going to be a long day.
Am I correct thinking that it is sampling very late in each bit and by the time it reaches the last bit it is actually sampling the stop bit? I tried slowing the baud on the receiver to try to "trick" it into seeing the last bit and not the stop bit (if this was the case) but it didn't appear to work.
Is the interrupt on high to low incorrect? That is the beginning of the start bit, no? I will do some searching this afternoon when I have a chance. I also have a v4 compiler on my other laptop that I will try this evening, in case it's a compiler issue. But, I haven't had problems with soft UARTs in the past.
What is the earliest v4 that is considered stable? I'll double check my maintenance expiration and update it if need be.
Thanks for all the help,
John |
|
|
Jerry I
Joined: 14 Sep 2003 Posts: 96 Location: Toronto, Ontario, Canada
|
|
Posted: Tue Jan 03, 2012 7:22 am |
|
|
are you using a RS232 driver chip between the 2 micros, or are you connecting at TTL levels. If it is TTL levels then the interrupt should be testing L_TO_H transition. The RS232 driver inverts the output. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Tue Jan 03, 2012 8:06 am |
|
|
Find what the state of the serial line is when it is idle. The ISR should be called when it LEAVES this idle state. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Jan 03, 2012 8:33 am |
|
|
Yes, it's TTL (PIC directly to PIC).
It idles high. I'm detecting the leading edge... but with the wrong interrupt setting as PCM has alluded to?
Looks like I should use this syntax:
Code: | ext_int_edge( 2, H_TO_L); |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19544
|
|
Posted: Tue Jan 03, 2012 10:23 am |
|
|
Yes.
Best Wishes |
|
|
jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
|
Posted: Tue Jan 03, 2012 6:41 pm |
|
|
Worked like a champ. Thanks to everyone for the ideas and the help.
Thanks PCM for teaching me to fish. |
|
|
|
|
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
|