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

Soft UART with INT_EXT2 Nuts and Bolts
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
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

Soft UART with INT_EXT2 Nuts and Bolts
PostPosted: Sun Jan 01, 2012 10:39 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 01, 2012 11:15 pm     Reply with quote

What's your PIC oscillator frequency and your compiler verison ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19535

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 5:21 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 8:06 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 2:06 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 6:01 pm     Reply with quote

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: 9237
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 7:59 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 9:27 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 02, 2012 11:09 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 6:34 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 7:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 8:06 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 8:33 am     Reply with quote

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: 19535

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 10:23 am     Reply with quote

Yes.

Best Wishes
jecottrell



Joined: 16 Jan 2005
Posts: 559
Location: Tucson, AZ

View user's profile Send private message

PostPosted: Tue Jan 03, 2012 6:41 pm     Reply with quote

Worked like a champ. Thanks to everyone for the ideas and the help.

Thanks PCM for teaching me to fish.
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