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 support@ccsinfo.com

RS-232 communication problem. Please help !

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
xavier righetti
Guest







RS-232 communication problem. Please help !
PostPosted: Fri Oct 13, 2006 5:36 am     Reply with quote

Hello,

I'm using a PIC18F6720 to drive 16 servos.
I developed a c++ interface on my pc to control the servos via the rs232 interface. I'm using two aerocomm transceivers for wireless communication.

Each time the PIC receives a message from the pc, it sends an acknowledgement message. But after approximately 35 messages, the pic stops communicating...

Did someone have the same kind of issues ? Could somebody point me to a solution ?

Here is the source code of the embedded software:

pic.c:
------
Code:

#include "C:\Work\PIC_C_SERVO\pic.h"
#include "C:\Work\PIC_C_SERVO\com.h"

#int_TIMER1
TIMER1_isr()
{
      //alert("timer1 has reset...\n");
}


#int_CCP1
CCP1_isr(){
   if (PWMready) {

      if (i >= length) {
         set_timer1(0);
         i = 0;

         if(PWMupdated){
            PWMupdated = FALSE;
            swapStack();
            //PWMack = TRUE;
         }
      }

      output_d(PWMStack[i]);

      CCP_1 = PWMStack[i+1];
      i += 2;
   }
}

#int_RDA2
void RDA2_isr()         // interruption lorsque RS232 reçoit des données
{
   //putc('x');
   //putc(timed_getc());
   RCtreatC(timed_getc());
}

void init() {

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_spi2(FALSE);
   setup_wdt(WDT_ON);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_timer_4(T4_DISABLED,0,1);
   setup_ccp1(CCP_COMPARE_INT);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_RDA2);
   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);
   setup_low_volt_detect(FALSE);
   setup_oscillator(False);

   chgSrvo = FALSE;
   Verbose = TRUE;
   high = TRUE;
   PWMready = FALSE;
   PWMupdate = FALSE;
   PWMstack = PWMstack1;
   PWMPasStack = PWMstack2;

   SET_TRIS_D(0x00);                      //port D output
   output_d(0);

   servoValue = 2000;                 // 1.5 ms : Neutral
   periodValue = 49997;
   i = 0;
}

void main()
{
   int deltaPrec;
   init();

   switch (restart_cause()) {
      case  WDT_TIMEOUT :
         alert("Restarted due to Watchdog overflow\n");
         break;

      case  MCLR_FROM_SLEEP :
         alert("Restarted due to waking up from sleep\n");
         break;

      case  NORMAL_POWER_UP :
         alert("Microcontroller initialized\n");
         break;

      case  BROWNOUT_RESTART :
         alert("Restarted due to low voltage detected\n");
         break;

      default :
         alert("Restarted due to abnormal error\n");
   }

   while(TRUE)
   {
      restart_wdt();

      if(sendMsg){

         //alert("Envoi des donnees\n");
         sendMsg = FALSE;
      }
      if(getPrecision){
         SendMessage(T_GET_PREC,2,(BYTE *)&newTimerVal);
         //SendMessage(T_GET_TOTA,2,(BYTE *)&totalVal);
         getPrecision = FALSE;
      }

      if (PWMcheck) {
         SendMessage(T_PWM_CHK, RCmess.sizedata, RCmess.data);
         PWMcheck = FALSE;
      }

      if(PWMupdate) {
         for (j = 0; j < RCmess.sizedata/2; j++){
            k = j * 2;
            answer = make16(RCMess.data[k],RCMess.data[k+1]);
            PWMPasStack[j] = answer;
         }
         lengthPas = RCmess.sizedata/2;
         PWMack = TRUE;
         PWMready = TRUE;
         PWMupdate = FALSE;
         //PWMupdated = TRUE;
      }
      if(PWMack){
         sendMessage(T_PWM_ACK,0,NULL);
         PWMack = FALSE;
      }
      if(GetPWMS){
         sendMessage(T_GET_PWMS,length,PWMStack);
         GetPWMS = FALSE;
      }
      if(GetPWMP){
         sendMessage(T_GET_PWMS,lengthPas,PWMPasStack);
         GetPWMP = FALSE;
      }
   }
}


pic.h
Code:

#include <18F6720.h>
#device adc=8

#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOOSCSEN                 //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV25                   //Brownout reset at 2.5V
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOCPD                    //No EE protection
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES LVP                      //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOWRTD                   //Data EEPROM not write protected
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected

#use delay(clock=20000000)
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8)
#use fast_io(D)


void generatePWMstack(BYTE * source, BYTE * _message, int * length);
void swapStack();

//global variables

typedef struct {
   BYTE type;
   BYTE sizedata;
   BYTE * data;
} message;

char ch;
BYTE RCi;
message RCmess;

BYTE PWMval[8];
unsigned int16 PWMstack1[64];
unsigned int16 PWMstack2[64];
unsigned int16 * PWMstack;
unsigned int16 * PWMPasStack;

BYTE length,lengthPas;
int i;

BOOLEAN PWMready;
BOOLEAN PWMupdate;
BOOLEAN PWMupdated;
BOOLEAN PWMack;
BOOLEAN PWMcheck;
BOOLEAN getprecision;
BOOLEAN GetPWMS;
BOOLEAN GetPWMP;

BOOLEAN sendMsg;
BOOLEAN chgSrvo;
BOOLEAN Verbose;
BOOLEAN high;

//global functions

void alert(char c);
void RCtreatC(char c);
void RCtreatMess();
void SendMessage(BYTE message_type, BYTE size_data, BYTE * data);



com.h:

Code:

#include <stdlibm.h>
//Start_up Code
#define BOOT_RESET 0xC1
#define BOOT_START 0x90

//RC packet flag
#define RC_START 0x69
#define RC_STOP  0x96

//message type
#define T_TXT        0x05
#define T_GET_PWMS   0x07
#define T_GET_PWMP   0x77
#define T_CHG_SRVO   0x08
#define T_GET_PREC   0x09
#define T_GET_TOTA   0x10
#define T_CHG_PERI   0x11
#define T_PWM_ACK    0x12
#define T_PWM_STA    0x13
#define T_PWM_LST    0x14
#define T_PWM_CHK    0x15

#define PWM_period 16    // set the period of the PWM outputs

//custom data types

BYTE alerti;
char str[64];
unsigned int16 servoValue;
unsigned int16 periodValue;
unsigned int16 newTimerVal;
unsigned int16 totalVal;
int j;
int k;
unsigned int16 answer;

////////////////////////////////////////////////////////
//                     timed_getc()                   //
////////////////////////////////////////////////////////

char timed_getc() {
   long time_out;
   //mnt_error=NOERR;
   time_out=0;
   while(!kbhit()&&(++time_out<10000)) // 0.2 second
     delay_us(20);
   if(kbhit())
      return(fgetc());
   else {
      //mnt_error=TIMEOUT;
      alert("ERROR timeout reception bluetooth\n");
      reset_cpu();
      return(0);
   }
}

////////////////////////////////////////////////////////
//                       RCtreatC                     //
////////////////////////////////////////////////////////

void RCtreatC(char c) {

   //alert("RCtreatC");
   //test header
   if (RCi == 0) {
      if (c == RC_START) {
         RCi ++;
      }
      else  {
        // alert("ERROR : no Start byte\n");
         RCi = 0;
      }

      return;
   }

   if (RCi == 1) {
      RCmess.type = c;
      RCi ++;
      return;
   }

   if (RCi == 2) {
      RCmess.sizedata = c;
      RCmess.data = malloc(RCmess.sizedata);
      RCi++;
      return;
   }


   if ( (RCi-3) <RCmess>= 60) {
      alerti = 0;
      return;
      }


   if (c == '\n') {
         str[alerti] = c;
         alerti ++;

         putc(RC_START);   //0xA6; //start byte
         putc(T_TXT);
         putc(alerti);

         //data
         for(i=0;i<alerti;i++) {
            putc(str[i]);
         }

         //ending
         putc(RC_STOP);

         alerti=0;

        // delay_ms(300);
    }


    else {
          str[alerti] = c;
          alerti ++;

   }

  return;
}


////////////////////////////////////////////////////////
//                     SendMessage()                  //
////////////////////////////////////////////////////////

void SendMessage(BYTE message_type, BYTE size_data, BYTE * data) {

   int i;

   if ((data == NULL) && (size_data != 0)) {
      alert("ERROR SendMessage: NULL pointer data\n");
      return;
   }

   //header
   putc(RC_START);
   putc(message_type);
   putc(size_data);

   //data
   for(i=0;i<size_data;i++) {
      putc(data[i]);
   }

   //ending
   putc(RC_STOP);

   return;

}

////////////////////////////////////////////////////////
//                     swapStack()                    //
////////////////////////////////////////////////////////

void swapStack() {

   BYTE * temp;
   BYTE temp2;

   temp = PWMPasStack;
   temp2 = lengthPas;
   PWMPasStack = PWMstack;
   lengthPas = length;
   PWMstack = temp;
   length = temp2;

   alert("swap!\n");

   return;
}


Thank you very much in advance for your kind answers Smile

xavier
bsodmike



Joined: 05 Aug 2006
Posts: 52

View user's profile Send private message Visit poster's website AIM Address MSN Messenger

PostPosted: Fri Oct 13, 2006 5:40 am     Reply with quote

Code:
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8)


Wouldn't you be better off defining a stream for each one and using fprintf() just to ensure your rs232 coms is taking to the correct UART?

Also, what's inside 'alert();'?
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Oct 13, 2006 6:05 am     Reply with quote

You are missing the errors directive on the #use rs232 line
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
xavier righetti
Guest







PostPosted: Fri Oct 13, 2006 6:22 am     Reply with quote

bsodmike wrote:
Code:
#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8)


Wouldn't you be better off defining a stream for each one and using fprintf() just to ensure your rs232 coms is taking to the correct UART?

Also, what's inside 'alert();'?


Hi mike,

Thank you for your fast answer!

I don't use the first #use rs232 definition, always the second one.

Sorry I didn't copy the entire com.h file, here are the two missing methods:

[code]

////////////////////////////////////////////////////////
// RCtreatMess() //
////////////////////////////////////////////////////////

void RCtreatMess() {

if (RCmess.type == T_GET_PREC) {
getPrecision = TRUE;
return;
}

if (RCmess.type == T_PWM_ACK) {
PWMupdate = TRUE;
//PWMack = TRUE;
return;
}

if (RCmess.type == T_PWM_STA) {

PWMready = FALSE;
//check if size is ok
if (RCmess.sizedata == 0) {
alert("ERROR : No data for the PWM stack\n");
return;
}
//PWMupdate = TRUE;
PWMcheck = TRUE;
return;
}

alert("ERROR : Unknown message type\n");

return;
}


////////////////////////////////////////////////////////
// alert() //
////////////////////////////////////////////////////////

void alert(char c){

int i;

if (!Verbose)
return;


if (alerti >= 60) {
alerti = 0;
return;
}


if (c == '\n') {
str[alerti] = c;
alerti ++;

putc(RC_START); //0xA6; //start byte
putc(T_TXT);
putc(alerti);

//data
for(i=0;i<alerti;i++) {
putc(str[i]);
}

//ending
putc(RC_STOP);

alerti=0;

// delay_ms(300);
}


else {
str[alerti] = c;
alerti ++;

}

return;
}

As you can see, the alert method simply sends text messages (message must end with a \n).

I monitored the messages and everything seems, fine. The pic is talking to the correct UART...
Guest








PostPosted: Fri Oct 13, 2006 6:31 am     Reply with quote

asmallri wrote:
You are missing the errors directive on the #use rs232 line


Hi asmallri,

I added the ERRORS directive:

Code:

#use rs232(baud=57600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, ERRORS)
#use rs232(baud=57600,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8, ERRORS)


Everything works fine, but still after 40 messages, The PIC stops answering.. Is there something I have to check using the RS232_ERRORS variable ?

Thank you very much...

xavier
asmallri



Joined: 12 Aug 2004
Posts: 1634
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

PostPosted: Fri Oct 13, 2006 6:40 am     Reply with quote

The errors directive will tell the compiler to add code to deal with lockup of the UART. If you are still getting ewrrors then your bug is elsewhere (but don't delete the errors flag)
_________________
Regards, Andrew

http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!!
Ttelmah
Guest







PostPosted: Fri Oct 13, 2006 6:47 am     Reply with quote

No.
ERRORS, is basically automatic. What it does, is if this is added to the define, then whenever the serial port is read, the compiler adds the small amount of extra code, to check for the OERR bit being set in particular, and clear this (done by disabling, then re-enabling the UART). This is'seperate' from the function of RS232_ERRORS, into which the value of the error bits will be written, so you can 'see' if an error has occurred. OERR, is the important error, since if this is set, the UART stops receiving...
Now some other comments apply. There is no point at all, in using a 'timed getc' function inside a serial interrupt. A timed getc function, is for use 'outside' the interrupt, where you don't want the system to hang if a character has not arrived. If you arrive in the interrupt, then a character _has_ been seen, and this is adding complexity to the interrupt handler. Then the real 'killer', is what you do in the character handler. In the event of seeing the line feed character, you are printing out three characters, plus a whole received string. Don't do this. It will _guarantee_ overrun errors, since as you are inside the interrupt, no character reception can take place fo the whole of this time. Also, you seem to malloc a new buffer for each message, but I then see no sign of you giving the buffer back. This is also a complex and potentially slow thing to do in an interrupt. Instead have a _single_ buffer large enough for the biggest expected message, and keep re-using this. If you must print the reply inside the interrupt, buffer the transmission, as well as reception. Much better though, buffer the incoming data, and do the interpretation in the main loop.
I suspect the actual fault is that malloc is running out of memory.

Best Wishes
Guest








PostPosted: Fri Oct 13, 2006 7:21 am     Reply with quote

Ttelmah, YOU RULE !!!!!!!

Thank you very very very much !!

I changed the struct as you said to the max possible value:

Code:

typedef struct {
   BYTE type;
   BYTE sizedata;
   BYTE data [128];
} message;


and I removed the malloc directive:

Code:

   if (RCi == 2) {
      RCmess.sizedata = c;
      //RCmess.data = malloc(RCmess.sizedata);
      RCi++;
      return;
   }


And now it works !!

I'm working on the other issues you pointed out...

Once again, thank you

xavier

p.s. somebody can change the subject to resolved!
Ttelmah
Guest







PostPosted: Fri Oct 13, 2006 2:29 pm     Reply with quote

This was actually raher a good illustration of how the problem can often not be what it seems.
The original 'comms stopping' fault, is 'classic' for not having the errors statement in the setup, since if more than two characters arrive at any time without handling,this leads to the UART locking up. Asmallri correctly pointed this out. This helped a fraction, but the problem then reappeared a few loops latter, so I found myself thinking 'for some reason, the interrupt code is getting slower (and hence the fault worse), the more it is called'. I found myself thinking 'oh dear far too much in the interrupt handler at times', but then saw one thing that would get slower and slower, which was the malloc. :-)
Glad it is working.

Best Wishes
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