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

RS232 data corrupt

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



Joined: 02 Jun 2009
Posts: 123
Location: The Netherlands

View user's profile Send private message

RS232 data corrupt
PostPosted: Fri Nov 29, 2013 6:46 am     Reply with quote

CCS version: 5.013

After updating from version 4 to version 5 I have some problems with RS232. The data is corrupt:

<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA|<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>
<ID00><L1><PA><FA><MA~<WC><FA><CJ> 6P39<E>

As you can see after <MA there must be an >, in my case it are 3 different characters. I do use an interrupt routine in my software, is there something changed in version 5 which can cause this problem? And are there things I can try to solve this problem?
oxo



Joined: 13 Nov 2012
Posts: 219
Location: France

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 7:13 am     Reply with quote

post the code, and how big is your serial buffer?
mvanvliet



Joined: 02 Jun 2009
Posts: 123
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 7:21 am     Reply with quote

The problem is with sending RS232 from my microcontroller to a ledbar, but for testing I use my pc at this moment. The ledbar uses an XOR checksum at the end of the string, with this corrupt data the led bar doesn't show the text.

I use the FTDI RS232 to USB convertor for testing with my pc.

Code:
#include <16F1825.H>
#case

#fuses INTRC_IO,NOWDT
#fuses PUT,NOMCLR,PROTECT,CPD                      //CODEPROTECT EN DATAPROTECT AANGEZET
#fuses BROWNOUT,NOCLKOUT,NOIESO
#fuses NOFCMEN,NOWRT,PLL_SW
#fuses NOSTVREN,NODEBUG,NOLVP
#device ADC=8
#use delay(clock=4MHz)                             //Fuses and delay are set, so int osc is set at 4Mhz.
 
#use rs232(baud=9600, uart1, ERRORS, stream=COM_A)
#use rs232(baud=9600, xmit=PIN_C5, ERRORS, stream=COM_B)   //Normal RS232

#define ACP_DATA        PIN_A0         //AN0 ICP_data / TX
#define ICP_CLOCK       PIN_A1         //AN1 ICP_clk  / RX   
//#define MODE          PIN_A2         //AN2 5V spanning       ADC
#define MCLR            PIN_A3         //    MCLR actief
//#define PULS_IN       PIN_A4         //AN3 Charger on
//#define PULS_OUT      PIN_A5         //    Debug
#define SCK             PIN_C0         //AN4 Uitgang voor uitlezen uitgangsspanning en uitgangsstroom
#define SDI             PIN_C1         //AN5 Battery voltage    ADC
#define SDO             PIN_C2         //AN6 Battery on         
#define CONTROL         PIN_C3         //AN7 Battery current 2,5V +/- current
//#define               PIN_C4         //    Control Pin
//#define TX            PIN_C5         //    PWM OUTPUT

#bit TXCKSEL = getenv("BIT:TXCKSEL")               // TX poortje
#bit T1GSEL  = getenv("BIT:T1GSEL")                //

#byte IOCAP  = getenv("SFR:IOCAP")
#byte IOCAN  = getenv("SFR:IOCAN")
#byte IOCAF  = getenv("SFR:IOCAF")
#byte INLVLA = getenv("SFR:INLVLA")

// Oud, werkt niet in V5 compiler

//#bit ResetRequest    = getenv("BIT:IOCAF3")        //Flag of interrupt on pin change RA3
//#bit KoekInDetected  = getenv("BIT:IOCAF4")        //Flag of interrupt on pin change RA4
//#bit PakUitDetected  = getenv("BIT:IOCAF5")        //Flag of interrupt on pin change RA5

// Nieuw

#bit ResetRequest    = IOCAF.3                     //Flag of interrupt on pin change RA3
#bit KoekInDetected  = IOCAF.4                     //Flag of interrupt on pin change RA4
#bit PakUitDetected  = IOCAF.5                     //Flag of interrupt on pin change RA5

#include <string.h>

#define STATS_UPDATE_RATE     1     // Statistics update rate [minutes]
#define SECONDS_UPDATE_RATE   2     // Secounds counter update rate [seconds]
#define USB_UPDATE_RATE       60    // USB data update rate [minutes]

int8  mode = 0;
int8  ticks = 0;
int8  pak_koeken = 0;
int8  minuteCounterStatsUpdate = STATS_UPDATE_RATE;
int8  secondsCounterDisplay = SECONDS_UPDATE_RATE;
int8  minuteCounterUsb = USB_UPDATE_RATE;
int8  Minuut_teller_array = 0;

//signed int16 Verlies_array[60];
int16 Verlies_array[60];

int8  pakkoeken_array[60];

int8 urenteller = 0;
int8  aantalKoekInPak = 0;

//signed int32 KoekIn_minuut = 0;
//signed int32 KoekUit_minuut = 0;
//signed int16 VerliesPromille_minuut = 0;                  // Use promille instead of procent for an extra digit after the dot precision

int32 KoekIn_minuut = 0;
int32 KoekUit_minuut = 0;
int16 VerliesPromille_minuut = 0;

float pakkengemiddeld = 0;
float Verlies_uur = 0;

char  type[40];


// Timer2 interrupt. Triggers every 40ms
// Handles all software based timers.
// Timers are decremented every second or every minute and stop counting when they reach 0.
// In the main() routine the timer having reached 0 will be detected and action is taken.
// It is the responsibility of the main() function to load a new timer value again after the action is finished.
#INT_TIMER2
void timer2_isr()
{
   static int8  seconds = 0;

   ticks++;
   
   // When 1 second passed
   if (ticks >= 25)     // 25 * 40ms == 1sec.
   {
      ticks = 0;
      seconds++;

      // Update all software based seconds timers
      if (secondsCounterDisplay)    secondsCounterDisplay--;
   }
   
   // When 1 minute passed
   if (seconds >= 60)
   {
      seconds = 0;
     
      // Update all software based minute timers
      if (minuteCounterStatsUpdate) minuteCounterStatsUpdate--;
      if (minuteCounterUsb)         minuteCounterUsb--;
   }
}

void init()
{
   setup_oscillator(OSC_4MHZ | OSC_PLL_OFF);
   setup_dac(DAC_OFF);
   setup_vref(VREF_OFF);
   setup_adc_ports(sAN2 | VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_16);                    // Built-in A/D setup function TAD is 2µSec                                                 
   //setup_timer_0(T0_DISABLED);                   // Timer0 can't be disabled on a PIC16
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);       //
   setup_timer_2(T2_DIV_BY_16, 250, 10);           // Setup for 25Hz (4MHz / 4 Fosc / 16 Prescaler / 250 load value / 10 postscaler = 25Hz)
   setup_ccp1(CCP_OFF);                            // Configure CCP1
   setup_ccp2(CCP_OFF);
   //set_tris_c(0x1A);
   
   T1GSEL = 0;                                     // T1_GATE_A4 instructie doet het niet vandaar handmatig.
   
   IOCAP = 0b00110000;                             // RA4 en RA5 positieve flank
   IOCAN = 0b00001000;                             // RA3 negatieve flank
   IOCAF = 0;
   
   INLVLA = 0b00111000;                            // RA3, A4 and A5 as Schmitt-Trigger
   
   set_adc_channel(2);                             //Check modeswitch
   
   memset(Verlies_array, sizeof(Verlies_array), 0);
   memset(pakkoeken_array, sizeof(Verlies_array), 0);

   // Start up delay. Allow RS232 capacitors to charge, etc.
   delay_ms(2000);
   
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
}   

void read_mode_switch()
{
   int8  mode = 0;
   
   /////////Selectie////////
   set_adc_channel(2);                             //Check modeswitch
   delay_us(20);
   mode = read_adc();
   
   if (mode < 32)                                  //Zou ideaal 0 zijn
   {
      type = "<CJ> 8P";
      aantalKoekInPak = 8;
   }
   else if (mode < 96)                             //Zou ideaal 64 zijn
   {
      type = "<CJ> 6P";
      aantalKoekInPak = 6;
   }
   else if (mode < 143)                            //Zou ideaal 128 zijn
   {
      type = "<CJ> 4P";
      aantalKoekInPak = 4;
   }
   else if (mode < 175)                            //Zou ideaal 159 zijn
   {
      type = "<CJ> 3P";
      aantalKoekInPak = 3;
   }
   else if (mode < 224)                            //Zou ideaal 191 zijn
   {
      type = "<CJ> 2P";
      aantalKoekInPak = 2;
   }
   else                                            //Zou ideaal 255 zijn
   {
      type = "<CJ> 1P";
      aantalKoekInPak = 1;
   }
}

void calculate()
{
   //Koeken in gedetecteerd
   if (KoekInDetected)
   {
      delay_ms(10);
     
      KoekIn_minuut += 12;
     
      KoekInDetected = 0;
   }

   //Pak uit gedetecteerd
   if (PakUitDetected)
   {
      delay_ms(10);
     
      KoekUit_minuut += aantalKoekInPak;
     
      pak_koeken++;
     
      PakUitDetected = 0;
   }

   //Reset
   if (ResetRequest)
   {
      delay_ms(10);
      KoekIn_minuut = 0;
      KoekUit_minuut = 0;
      VerliesPromille_minuut = 0;
     
      pak_koeken = 0;
     
      ResetRequest = 0;
   }

   if(KoekIn_minuut >= KoekUit_minuut)
      {
      VerliesPromille_minuut = ((KoekIn_minuut - KoekUit_minuut) * 1000) / KoekIn_minuut;
      }
   else
      {
      VerliesPromille_minuut = ((KoekIn_minuut - KoekUit_minuut) * 1000) / KoekUit_minuut;
      }

}

void update_long_term_statistics()
{
   int8 i;
   float pakkenTotaal = 0;
   //int16 uurTotaal = 0;      // maximum 60 minutes * 1000 promille loss = 60.000, does fit into an int16
   float uurTotaal = 0;       //delen door int16 maakt geen getal achter de komma,
                              //compiler deelt waarschijnlijk eerst, rond dan af en zet dan pas in float "Verlies_uur".
   
   Verlies_array[Minuut_teller_array] = VerliesPromille_minuut;

   for (i = 0; i <= Minuut_teller_array; i++)
   {
      uurTotaal += Verlies_array[i];         //calculate the total of the numbers in the array
   }
   Verlies_uur = ((uurTotaal/10)/(Minuut_teller_array + 1));


   pakkoeken_array[Minuut_teller_array] = pak_koeken;

   for (i = 0; i <= Minuut_teller_array; i++)
   {
      pakkenTotaal += pakkoeken_array[i];         //calculate the total of the numbers in the array
   }
   pakkengemiddeld = (pakkenTotaal/(Minuut_teller_array + 1));

   if (Minuut_teller_array < 59)
   {
      Minuut_teller_array++;
   }
   else
   {
      Minuut_teller_array = 0;
   }
   
   ResetRequest = 1;    //reset counters after 1 minute
}

void memory_stick()
{
   
   char  sUur[30];
   char  sData[20];
   char  sVerlies_uur[10];
   int8  size;
   
   TXCKSEL = 1;
   
   sprintf(sUur,"%u,", urenteller);
   sprintf(sData,"%u,", aantalKoekInPak);
   //sprintf(sKoekin, "%g,", KoekIn_minuut);
   //strcat(sData, sKoekin);   
   //sprintf(sKoekuit, "%g,", KoekUit_minuut);
   //strcat(sData, sKoekuit);
   sprintf(sVerlies_uur, "%3.1g%%\r\n", Verlies_uur);
   strcat(sUur, sData);
   strcat(sUur, sVerlies_uur);
   
   size = strlen(sUur);
   
   // create file and open it
   fprintf(COM_A, "OPW Data.txt\r");
   // write to file
   fprintf(COM_A, "WRF ");
   fputc(0x00, COM_A); // number of bytes of data
   fputc(0x00, COM_A);
   fputc(0x00, COM_A);
   fputc(size, COM_A);
   fputc('\r', COM_A);
   fprintf(COM_A, "%s", sUur);
   // close the file
   fprintf(COM_A, "CLF Data.txt\r");
   
   delay_ms(10);     // Allow data in the UART Tx buffer to flush (2 bytes at 9600 baud ~= 2ms)
   
   TXCKSEL = 0;
}

void update_lichtkrant()
{

   int8  checksum;
   char  sVerlies_kort[10];
   char  sVerlies_uur[10];
   char  pretype[28] = "<L1><PA><FA><MA><WC><FA>";
   char  color[5];
   char  color2[5];
   char  totaltype[51];
   
   //sprintf(sVerlies_kort, "%2.1g", pakkengemiddeld);

   //Verlies_lang
   //sprintf(sVerlies_uur, "%5.1g%%", Verlies_uur);
   
   //if (VerliesPromille_minuut <= 30)
   //{
     // strcopy(color,"<CE>");
   //}
   //else
   //{
   //   strcopy(color,"<CC>");
   //}

  // if (Verlies_uur <= 3)
  // {
  //    strcopy(color2,"<CE>");
  // }
  // else
  // {
  //    strcopy(color2,"<CC>");
  // }

   /////////RS232 String////////////////////
   checksum = 0;
   
   //fprintf(COM_B, "%3.0g ", KoekIn_minuut);
   //fprintf(COM_B, "%3.0g\r\n", KoekUit_minuut);
   
   
 
   strcpy(totaltype, pretype);                     //totaltype now contains a copy of pretype
   //strcat(totaltype, color2);                      //add color to string
   //strcat(totaltype, sVerlies_uur);                //add sVerlies_half_uur to string
   strcat(totaltype, type);
   //strcat(totaltype, color);                       //it is now the two strings one after the other
   //strcat(totaltype, sVerlies_kort);               //add sVerlies_kort to string
     
   for(int i = 0; i < strlen(totaltype); i++)
   {
      checksum ^= totaltype[i];
   }
   
   fprintf(COM_B, "<ID00>");
   fprintf(COM_B, "%s",totaltype);
   fprintf(COM_B, "%02X",checksum);
   fprintf(COM_B, "<E>");


}


//////////////////////////////// MAIN LOOP /////////////////////////////////////
/*
<ID00>   = ID
<L1>     = Line
<PA>     = Page
<FE>     = Scroll left
<MA>     = display time
<WC>     = speed
<FE>     = Scroll left
*/

void main()
{
   init();
   
   while(1)
   {
      read_mode_switch();
     
      calculate();

      if (minuteCounterStatsUpdate == 0)
      {
         minuteCounterStatsUpdate = STATS_UPDATE_RATE;    // every minute
         update_long_term_statistics();
      }

      if (minuteCounterUsb == 0)
      {
         minuteCounterUsb = USB_UPDATE_RATE;           //every hour
         urenteller++;
         memory_stick();
      }
   
      if (secondsCounterDisplay == 0)
      {
         secondsCounterDisplay = SECONDS_UPDATE_RATE;       // every 2 seconds
         update_lichtkrant();
      }   
   }
}
mvanvliet



Joined: 02 Jun 2009
Posts: 123
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 8:20 am     Reply with quote

I did some tests with other text and it is not always the same character which is corrupt:

<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>xMA><WC><FA><CJ> 6P€÷4E<E>
<ID00><L1><PA><FA>|MA><WC><FA><CJ> 6P€÷4E<E>

<ID00><L1><PA><ŽA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><ŒA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><FA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA>|FA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA>xFA><MA><WC><FA><CJ> 6PAKKEN73<E>
<ID00><L1><PA><ŒA><MA><WC><FA><CJ> 6PAKKEN73<E>
temtronic



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

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 8:26 am     Reply with quote

maybe, just maybe....
...thinking out loud here as I don't use that chip but...

#use rs232(baud=9600, xmit=PIN_C5, ERRORS, stream=COM_B) //Normal RS232


If this is the hardware UART by NOT specifying a rcv pin, CCS generates a 'software' UART and the program doesn't use the builtin hardware UART ?
If this is true , it could account for the 'corrupt' data due to timing issues.

hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19359

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 8:54 am     Reply with quote

He will get corrupted data on COM_B, every time the timer ticks, while a character is being sent. COM_A should be fine ('uart1', specifies both pins for you).

It is the COM_B data that is corrupted, so this is what is happening, but this would have happened with the old compiler as well. Not changed with V5....

Are you sure your timer was running?. There was a bug in certain V4 versions, and present in the early V5 versions, where printf/sprintf. could leave the GIE bit disabled. This would have stopped the timer from interfering with the serial, but would have left the timer not running. This was fixed at about 5.011.

Add the keyword 'DISABLE_INTS' to the COM_B rs232 declaration, which will then delay the timer interrupt to the end of the character.

Best Wishes
mvanvliet



Joined: 02 Jun 2009
Posts: 123
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 9:03 am     Reply with quote

It seems that disable_ints is solving my problem, but why I noticed it first with my update to version 5....I don't know. I'm going to try it on the lightbar in an hour. Thank you Ttelmah.

With version 4 I had 4.113 or so, so the GIE bit bug was solved, but can be inserted again in version 5...
Ttelmah



Joined: 11 Mar 2010
Posts: 19359

View user's profile Send private message

PostPosted: Fri Nov 29, 2013 9:21 am     Reply with quote

It is one of these 'there', 'not there', 'there again', 'not there' bugs.
It was reported at one point in V4. Fixed, for a few versions, then re-appeared. Then was fixed again, then re-appeared again. Then was fixed again, and then re-appeared slightly changed in V5.
The fact that the data was not being corrupted with V4, really does tend to imply the GIE was disabled.
When I started trying to find which versions didn't have this problem, I was surprised at how many did....

Update.
I realise this is the core of your problem.

On the older compilers, they appeared on several versions to disable interrupts during printf, which (of course), meant your timer didn't interfere with the transmission, but (unfortunately), means that your timer interrupt would have been delayed for the entire transmission, and serial interrupts and other things that needed to happen, would also get delayed, with the possibility of characters being missed...
The faulty compilers then failed to turn the interrupts back on.
Then with the fix on V5, the interrupts are not disabled at all, which then (of course - again), introduces your problem.
So anyone who is using software serial with anything that uses interrupts, now needs to use the 'DISABLE_INTS' option.

Best Wishes
jgschmidt



Joined: 03 Dec 2008
Posts: 184
Location: Gresham, OR USA

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

PostPosted: Fri Nov 29, 2013 10:15 pm     Reply with quote

Jumping in with a followup question...

I see that mvanvliet is running the processor at 4mhz when he could be running at 32mhz. Would there be less chance of corruption running at higher speeds?
_________________
Jürgen
www.jgscraft.com
Ttelmah



Joined: 11 Mar 2010
Posts: 19359

View user's profile Send private message

PostPosted: Sat Nov 30, 2013 12:33 am     Reply with quote

The corruption might not be bad enough to cause problems at higher speeds.
Basically the time taken to handle the interrupt would drop by a factor of 8, which given the 'margins' in async serial, might make it short enough to 'get away' with.
Currently the interrupt would take perhaps 100uSec, which then gives a 10% timing error. At 32MHz, the error would only be perhaps 1.5%.

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