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

Dual serial port and string capture

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
[email protected]



Joined: 07 May 2014
Posts: 9
Location: Seattle

View user's profile Send private message

Dual serial port and string capture
PostPosted: Mon Nov 03, 2014 5:43 pm     Reply with quote

Hi All -

I've a problem that I've run into. It must be some sort of Monday thing ;)

Anyway, I have a PIC16F1526 in which I am attempting to use the dual hardware serial port functionality there of. Serial port 1 (UART1) is being used as debug. Serial port 2 is being used to talk to a peripheral. For the sake of argument, let's assume said peripheral can only ever generate 8-byte data, as seen in the code below.

If I hook up two tera-terms (on a PC via TTL converters) to the two serial ports, I can watch data single byte transfer all day long. Yawn. Now if I send the 8-byte chunk all at once, the second serial port only captures the first 2 bytes and misses the next 6. Send again, and again only the first 2 bytes are captured. If I Rinse and repeat 4 times, I can fill the buffer of the second port and get out (albeit wrong) data buffer.

I am monitoring the data in and out of the serial port with a tool called "AccessPort". I can see the data transferred via single bytes as the bytes that make it across. I can see the bytes transferred all at once only receive the first 2. I'm not detecting any RS232_ERRORS if I watch that variable

What poor sap mistake have I made?

Code:

#include <16F1526.h>


//directives
#fuses INTRC_IO,NOWDT,NOPROTECT,NOMCLR,BROWNOUT,PUT, BORV25
#device ADC=10
#use delay(clock=16000000)
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7, stream=PC, STOP=1, UART1)
#use rs232(baud=38400, xmit=PIN_G1, rcv=PIN_G2, STOP=1, bits=8, parity=n, stream=MMB, ERRORS, UART2)


#define LED_GREEN1_ON    output_low(PIN_E0)
#define LED_GREEN2_ON    output_low(PIN_E1)
#define LED_GREEN3_ON    output_low(PIN_E2)
#define LED_GREEN4_ON    output_low(PIN_E3)
#define LED_GREEN5_ON    output_low(PIN_E4)
#define LED_GREEN6_ON    output_low(PIN_G0)
#define LED_GREEN1_OFF    output_high(PIN_E0)
#define LED_GREEN2_OFF    output_high(PIN_E1)
#define LED_GREEN3_OFF    output_high(PIN_E2)
#define LED_GREEN4_OFF    output_high(PIN_E3)
#define LED_GREEN5_OFF    output_high(PIN_E4)
#define LED_GREEN6_OFF    output_high(PIN_G0)

#define LED_RED1_ON    output_low(PIN_F5)
#define LED_RED2_ON    output_low(PIN_F6)
#define LED_RED1_OFF   output_high(PIN_F5)
#define LED_RED2_OFF   output_high(PIN_F6)


#define BUFFER_SIZE   23




char   buffer[BUFFER_SIZE];
int    next_in = 0;
int f=0;

char   mmb_buffer[BUFFER_SIZE];
int    mmb_next_in = 0;




int SET_LEDS(int on, int sled) {
    if (on) {
        if(sled==1){ LED_GREEN1_ON; }
        else if (sled==2) {LED_GREEN2_ON; }
        else if (sled==3) {LED_GREEN3_ON; }
        else if (sled==4) {LED_GREEN4_ON; }
        else if (sled==5) {LED_GREEN5_ON; }
        else if (sled==6) {LED_GREEN6_ON; }
        else if (sled==7) {LED_RED1_ON; }
        else if (sled==8) {LED_RED2_ON; }
    }else{
        if(sled==1){ LED_GREEN1_ON; }
        else if (sled==2) {LED_GREEN2_OFF; }
        else if (sled==3) {LED_GREEN3_OFF; }
        else if (sled==4) {LED_GREEN4_OFF; }
        else if (sled==5) {LED_GREEN5_OFF; }
        else if (sled==6) {LED_GREEN6_OFF; }
        else if (sled==7) {LED_RED1_OFF; }
        else if (sled==8) {LED_RED2_OFF; }
    }


}
int LEDS_OFF(){
    int i =0;
    for(i=0; i<8; i++){  SET_LEDS(0, i); }

}



int serial2_handler(){

    //twiddle another led
    output_high(PIN_G3);


    int h=0;
    for(h=0; h<8; h++){
        fprintf(PC, "%x " mmb_buffer[h]);
    }
 
    delay_ms(2);
    //twiddle another led
    output_low(PIN_G3);
    mmb_next_in =0;

    return 0;
}

//
//
//serial interrupt

#int_rda2
void serial2_isr() {

    mmb_buffer[mmb_next_in]=fgetc(MMB);
    mmb_next_in++;
    if(mmb_next_in>7){
        serial2_handler();
    }
    //fputc(RS232_ERRORS, MMB);

   
}

void serial_handler(){
   buffer[next_in]=fgetc(PC);
   fputc(buffer[next_in], PC);
   next_in++;
   if(next_in>=BUFFER_SIZE){
      //full input buffer
      next_in = BUFFER_SIZE;
      buffer[BUFFER_SIZE-1]=0x0D;
   }

        //process serial commands
        if (buffer[next_in - 1] == 0x0D) {
            //serial_decode();
            buffer[next_in] =0;
            fprintf(PC, "%s\n\r", buffer);
            next_in=0;
            buffer[next_in] =0;
        }else if(buffer[next_in - 1] == 0x72){
            fprintf(PC, "RESTTING\n\r");
            reset_cpu();
        }

}


//serial interrupt
#int_rda
void serial_isr() {
//   int t;
    serial_handler();
}



/*
 *
 */
int main(int argc, char** argv) {
    int a=0, b=0;

    int last_restart =0;


    //start up stuff
    delay_ms(100);

    setup_adc_ports(NO_ANALOGS);
    setup_oscillator(OSC_16MHZ | OSC_INTRC);
    set_tris_a(0xF7); //a = 1111 0111
    set_tris_b(0xFC); //b = 1111 1100
    set_tris_c(0x87); //c = 1000 0111
    set_tris_d(0x00); //d = 0000 0000 all outputs
    set_tris_e(0x00); //e = 0000 0000 all outputs
    set_tris_f(0x9F); //f = 1001 1111
    set_tris_g(0xF4); //g = 1111 0100

    setup_vref(VREF_2v048 | TEMPERATURE_INDICATOR_ENABLED);
    setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN16 | sAN19, VSS_FVR);
    setup_adc(adc_clock_div_16);

    LEDS_OFF();

    last_restart = RESTART_CAUSE();
    fprintf(PC, "\n\rstarting 0x%X\n\r", last_restart);

    //turn off led
    output_high(PIN_G3);

    enable_interrupts(int_rda);
    enable_interrupts(int_rda2);
    enable_interrupts(global);

    //turn on an LED to at least see we made it this far
    output_low(PIN_G3);


    //do a whole lot of nothin'
    while (1) {

        //twidle de-dumb led
        delay_ms(200);
        a ^= 1 << 1;
        set_leds(a, 4);
       

    }



    return (0);
}

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Nov 03, 2014 7:01 pm     Reply with quote

This should be a clue:
Quote:
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@PRINTF_X_115200_118_119)
temtronic



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

View user's profile Send private message

PostPosted: Mon Nov 03, 2014 8:54 pm     Reply with quote

also you must add 'errors' to the use rs232(...options...) for every hardware UART you use....


Jay
[email protected]



Joined: 07 May 2014
Posts: 9
Location: Seattle

View user's profile Send private message

PostPosted: Mon Nov 03, 2014 11:07 pm     Reply with quote

PCM programmer wrote:
This should be a clue:
Quote:
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@delay_ms1)
>>> Warning 216 "pcm_test.c" Line 203(1,2): Interrupts disabled during call to prevent re-entrancy: (@PRINTF_X_115200_118_119)



Baahaw! If I had just clicked one tab over on the build/program, I would have seen that! I told you I was having a Monday. That's also what I get for grabbing old code from another project as a base start without reviewing it ALL first. What a total bone-headed mistake.

And yes, I should include ERRORS in the #use def of the uart. Even better would be to check those errors and act upon them. But being this is all hardware bring up testing, I may cut some corners before handing off to the firmware team (oh wait, that's me this time too).

Thanks all. +5 points to PCM.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Nov 04, 2014 5:17 am     Reply with quote

Just some nit-picking review comments:
- You are setting the TRIS registers, but you are not specifying the CCS IO-mode. By default the compiler will then set the TRIS registers for you. Best practice is to not mix both methods; either have the compiler handle the TRIS registers for you, or you specify the TRIS in combination with the directive #USE FAST_IO.
-
Code:
set_tris_a(0xF7); //a = 1111 0111
I don't like it when the same information is presented twice, sooner or later they will mismatch and create confusion. Combine into a single statement:
Code:
set_tris_a(0b11110111);

-
Code:
int main(int argc, char** argv) {

This is an embedded program, so you'll never receive command line arguments and you'll never exit to an OS to return a value to.
Code:
void main(void) {

-
Code:
a ^= 1 << 1;
Even after 30 years the EXOR command takes me too much time to understand what this line is doing. A little bit of comment is nice to your fellow programmers. Strange is that you are toggling bit1 where the set_leds() function expects true or false, i.e. bit0.
- NEVER put a delay in interrupt routines. Now you have a 2ms delay call in serial2_handler(). This will cause overflows on the 38400 UART2 receiving.
- Add #case to your program to avoid capitalization mismatches. Now you are mixing set_leds() and SET_LEDS(). Personally I prefer only constants and macro's to be in all capitals.
- serial2_handler is returning a value. Why? It always returns 0 and the calling function isn't testing the returned value. Simplify your code by ridding the return value.
-
Code:
int serial2_handler(){
You are not returning a value, so declare the function void.
- same for SET_LEDS().
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Nov 04, 2014 8:27 am     Reply with quote

Hi,

A couple of other things:

Code:

#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7, stream=PC, STOP=1, UART1)


You should specify the pin assignments (eg. xmit=, rcv=) or the use the UART keyword(s), UART1/UART2, but not both in the #use rs232 directive.

IMO, a much more fundamental problem is that your serial interrupts are too complicated. This will ultimately cause your program to fail as you receive more data. Never put delays or print statements, etc. inside an ISR, and for that matter, never have the ISR call another subroutine. The serial ISR(s) should be simple and fast, only buffering data, and possibly setting flags (such as that a complete data 'packet' has been received). Everything else should be processed outside of the interrupt(s), such as in Main().

John
[email protected]



Joined: 07 May 2014
Posts: 9
Location: Seattle

View user's profile Send private message

PostPosted: Tue Nov 04, 2014 9:57 am     Reply with quote

ckielstra and ezflyr -

All good observations and points. I certainly like the 0bxxxx TRIS setting idea. I'm going to steal it. My firmware guys would hang me if I tried to release code like this after a design review. My forte is high speed analog and RF design, not programming. Sometimes the hardware can't wait for the firmware ;)

Has anyone ever collected up all the "good" tips and tricks on this forum? You guys should write a tutorial and post it here! I'm sure I'd learn something new and I'd bet others would too.

The point of this code was to test hardware, to at least get the pins to wiggle and make *something* happen. By no means would any of this ever make it out into "the real world". I got wrapped around the Monday morning axle for a dumb mistake.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Nov 04, 2014 12:02 pm     Reply with quote

Hi,

The forum and the CCS supplied example programs comprise the 'tutorial' that you are looking for. Spend a little bit of time reading the forum, and studying the forum archives, and your CCS 'C' programming skills will improve immeasurably! Anything you can't answer, you can ask here, but we expect a certain 'minimum effort' (BTW, you already seem to be above that threshold!) on the users part first!

John
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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