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

Overrun errors using the getc() function

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



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

Overrun errors using the getc() function
PostPosted: Mon Oct 06, 2003 1:07 pm     Reply with quote

I am relatively new to PIC and C programming. I am writing a program that uses the getc() function of the CCS PIC C Compiler to read data on the RC7/RX pin of a PIC16F876. I review with an oscilloscope and the signal is coming OK on that pin (the start bit, the 8 data bits and 1 stop bit with no parity). I am sending the same character again and again but all I get on the receiving PIC is an overrun error and it stops receiving. Sometimes I get a framing error also. Settings of clock speed, baud rate and pins used are specified correctly on the program.

Does anyone know if there is something special I need to do before using the getc() function? Any initialization? Or does anyone think that it could be a "bug" of the compiler?

The versions of the compiler are the following:
PCW Compiler
IDE Version 2.29
PCB Version 2.731
PCM Version 2.731
Made in the year 2000

The code that I am using on the transmitter PIC is the following (the transmitter is working fine):

#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity=N,xmit=PIN_C6,rcv=PIN_C7)
void main() { //aquí inicia el programa principal
char dato;
setup_adc_ports(NO_ANALOGS);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
dato = 65;
while(1)
{
printf("%1c",dato);
}
}

The code that I am using on the receiver PIC is the following (this is the one thatr I get overrun errors):

#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity = N, xmit = PIN_C6,rcv=PIN_C7)
#byte rxdata = 0x1a //Direccion del registro donde se almacena el dato leido de la UART
#byte rxstatus = 0x18 //Direccion del registro donde se controla la recepcion de la UART
#byte txstatus = 0x98 //Direccion del registro donde se controla la transmision de la UART
#bit rxint = 0x0c.5 //Direccion del bit del registro de bandera de interrupcion por recepcion en UART
#byte pir1 = 0x0c //Direccion del registro general que tiene las banderas de las interrupciones
void main() { //aquí inicia el programa principal
char caracter_recibido1; //es el caracter que se recibe por el RS232 del Rx proveniente del recolector
int direccion; //es la dirección en memoria EEPROM interna del PIC
rxstatus = 144; //inicializa el registro de estado del Rx de la UART habilitando el puerto serial (bit 7 en 1=128) y el continuos receive (bit 4 en 1=16). Y 128+16=144
disable_interrupts(global);
enable_interrupts(int_rda); //Habilita únicamente la interrupción por Rx de la UART
setup_adc_ports(NO_ANALOGS);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
caracter_recibido1 = 6;
direccion = 0;
rxstatus = 0x80; //Deshabilita el continuos receive de la UART (bit 4)
rxstatus = 0x90; //Habilita el continuos receive de la UART para inicializarla
do //la letra "A" es un 41h en ASCII
{
while (rxint==0)//Mientras la bandera de dato recibido en FIFO de Rx de la UART no se levante, no haga nada
{}
caracter_recibido1=getc(); // Espera a recibir el caracter por el puerto serial.
write_eeprom(direccion, rxstatus);
direccion++;
write_eeprom(direccion, rxdata);
direccion++;
write_eeprom(direccion, pir1);
direccion++;
}
while (direccion < 100);
}

If anyone can answer one of these questions, please answer to this post

Thanks.

Greetings,

Alonso Roman
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 06, 2003 1:29 pm     Reply with quote

You are writing to a eeprom while you are receiving. This will cause delays and could make you get an overrun. You also have the INT_RDA enabled but no int handler! You should search the board for "ring buffers" and try and do something like that and then process the data in the main loop.
Ttelmah
Guest







Re: Overrun errors using the getc() function
PostPosted: Mon Oct 06, 2003 3:12 pm     Reply with quote

aroman wrote:
I am relatively new to PIC and C programming. I am writing a program that uses the getc() function of the CCS PIC C Compiler to read data on the RC7/RX pin of a PIC16F876. I review with an oscilloscope and the signal is coming OK on that pin (the start bit, the 8 data bits and 1 stop bit with no parity). I am sending the same character again and again but all I get on the receiving PIC is an overrun error and it stops receiving. Sometimes I get a framing error also. Settings of clock speed, baud rate and pins used are specified correctly on the program.

Does anyone know if there is something special I need to do before using the getc() function? Any initialization? Or does anyone think that it could be a "bug" of the compiler?

The versions of the compiler are the following:
PCW Compiler
IDE Version 2.29
PCB Version 2.731
PCM Version 2.731
Made in the year 2000

The code that I am using on the transmitter PIC is the following (the transmitter is working fine):

#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity=N,xmit=PIN_C6,rcv=PIN_C7)
void main() { //aquí inicia el programa principal
char dato;
setup_adc_ports(NO_ANALOGS);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
dato = 65;
while(1)
{
printf("%1c",dato);
}
}

The code that I am using on the receiver PIC is the following (this is the one thatr I get overrun errors):

#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity = N, xmit = PIN_C6,rcv=PIN_C7)
#byte rxdata = 0x1a //Direccion del registro donde se almacena el dato leido de la UART
#byte rxstatus = 0x18 //Direccion del registro donde se controla la recepcion de la UART
#byte txstatus = 0x98 //Direccion del registro donde se controla la transmision de la UART
#bit rxint = 0x0c.5 //Direccion del bit del registro de bandera de interrupcion por recepcion en UART
#byte pir1 = 0x0c //Direccion del registro general que tiene las banderas de las interrupciones
void main() { //aquí inicia el programa principal
char caracter_recibido1; //es el caracter que se recibe por el RS232 del Rx proveniente del recolector
int direccion; //es la dirección en memoria EEPROM interna del PIC
rxstatus = 144; //inicializa el registro de estado del Rx de la UART habilitando el puerto serial (bit 7 en 1=128) y el continuos receive (bit 4 en 1=16). Y 128+16=144
disable_interrupts(global);
enable_interrupts(int_rda); //Habilita únicamente la interrupción por Rx de la UART
setup_adc_ports(NO_ANALOGS);
setup_spi(FALSE);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
caracter_recibido1 = 6;
direccion = 0;
rxstatus = 0x80; //Deshabilita el continuos receive de la UART (bit 4)
rxstatus = 0x90; //Habilita el continuos receive de la UART para inicializarla
do //la letra "A" es un 41h en ASCII
{
while (rxint==0)//Mientras la bandera de dato recibido en FIFO de Rx de la UART no se levante, no haga nada
{}
caracter_recibido1=getc(); // Espera a recibir el caracter por el puerto serial.
write_eeprom(direccion, rxstatus);
direccion++;
write_eeprom(direccion, rxdata);
direccion++;
write_eeprom(direccion, pir1);
direccion++;
}
while (direccion < 100);
}

If anyone can answer one of these questions, please answer to this post

Thanks.

Greetings,

Alonso Roman

The heart of your problem is the statement enabling INT_RDA.
You are _polling_ the receive interrupt, and it will never be seen to be set!. By enabling the interrupt, you are not saying to the chip 'enable setting of this bit', but are saying 'call an interrupt handler when this bit is set'. You have not defined a handler, but the compiler will automatically add the 'support' routines for the handler, including the code to clear the interrupt flag. Hence when the flag is set, this routine will clear the interrupt flag, and your 'polling' routine will never see the interrupt flag.
If you disable INT_RDA, the flag will still be set, and the check will now see it...
You are then writing three bytes to the internal EEPROM. These writes may take several mSec to complete, and this makes the problems worse.
You really need to actually use the RDA interrupt, and receive your characters in this, using a buffer.

Best Wishes
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Thu Oct 09, 2003 7:18 pm     Reply with quote

Thanks Mark and Ttelmah for your help. I modified my code based on your recommendations and I got rid off the overrun error.

However, now I have another problem: I am transmiting a 65 in decimal, which corresponds to a 41 in hex and I am receiving a 50 in hex. I analyzed the waveform and I found out that the transmitted waveform is the following:

0 1 0 0 0 0 0 1 0 1 0 1
Start Bit Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Stop Bit Start Bit Bit 0...

There is a "displacement" of 2 bits to the right in the way the UART of the PIC interprets the data. What is happenning, is that the UART interprets this same waveform as follows:

0 1 0 0 0 0 0 1 0 1 0 1
Bit 7 Stop Bit Start Bit Bit 0 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Stop Bit...

Which corresponds to a 50 in hex.

The code for the transmitter is the same as the one I put before. The new code for the reeceiver is the following:
Code:
#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity = N, xmit = PIN_C6,rcv=PIN_C7,errors)
#byte rxstatus = 0x18 //Direccion del registro donde se controla la recepcion de la UART
void main() { //aquí inicia el programa principal

   char caracter_recibido1; //es el caracter que se recibe por el RS232
                            //del Rx proveniente del recolector
   int direccion; //es la dirección en memoria EEPROM interna del PIC
   disable_interrupts(global);
   enable_interrupts(int_rda); //Habilita únicamente la interrupción por Rx de la UART
   intcon = intcon || 64; //Habilita las interrupciones de periféricos (bit 6 en 1)
   enable_interrupts(global);
   setup_adc_ports(NO_ANALOGS);
   setup_spi(FALSE);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   caracter_recibido1 = 6;
   direccion = 0;
   do
      {
      caracter_recibido1=getch(); // Espera a recibir el caracter por el puerto serial.
      write_eeprom(direccion, rxstatus);
      direccion++;
      write_eeprom(direccion, caracter_recibido1);
      direccion++;
      }
      while (direccion < 100);
}

Any ideas on how to correct this "shifting" of 2 bits ?

Thanks,

Alonso
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Thu Oct 09, 2003 8:06 pm     Reply with quote

You are still enabling interrupts! I don't see any interrupt handlers either. You do not have to enable ints to have the uart function. Also the statement:
Code:

   intcon = intcon || 64; //Habilita las interrupciones de periféricos (bit 6 en 1)

is incorrect. That is a logic OR. What you want is:
Code:

   intcon = intcon | 64; //Habilita las interrupciones de periféricos (bit 6 en 1)

but that does not really matter since I believe CCS enables both and you really do not need ints at all. Try this:

Code:

#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT
#use rs232(baud=2400,parity = N, xmit = PIN_C6,rcv=PIN_C7,errors)
#byte rxstatus = 0x18 //Direccion del registro donde se controla la recepcion de la UART
void main() { //aquí inicia el programa principal

   char caracter_recibido1; //es el caracter que se recibe por el RS232
                            //del Rx proveniente del recolector
   int direccion; //es la dirección en memoria EEPROM interna del PIC
   disable_interrupts(global);
   setup_adc_ports(NO_ANALOGS);
   setup_spi(FALSE);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   caracter_recibido1 = 6;
   direccion = 0;
   do
      {
        if (kbhit())
        {
          caracter_recibido1=getch(); // Espera a recibir el caracter por el puerto serial.
          write_eeprom(direccion, rxstatus);
          direccion++;
          write_eeprom(direccion, caracter_recibido1);
          direccion++;
        }
      }
      while (direccion < 100);
}
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

14th character lost
PostPosted: Sat Oct 18, 2003 3:24 pm     Reply with quote

Thanks again to Mark. I followed his suggestion, and the issue reduced. However, I also had to include a “non-confundible” character (a 0x00, because it has a waveform that cannot be confused with another character), and when I was transmitting the 0x41 character (the letter “A”), more than 99% of the times I received the same character.

However, I made another test and I got a lost character: on the transmitter, I modified my code to transmit not just the same character over and over, but a sequence of characters (characters 0x41 to 0x5B, that corresponds to letters “A” to “Z”). On the receiver program, all the characters are written to internal EEPROM. Analyzing those received characters, I found out that the first 13 characters are correctly written to EEPROM, but the character # 14 is lost. Then again the next 13 characters are good and the next character is lost.

I don’t know if this is a restriction with the getch() function. Does anyone has an idea of what could be the problem and how to correct it?

The code of the transmitting PIC is the following:

Code:
#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP
#use rs232(baud=2400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)

void main() { //aquí inicia el programa principal

   int caracter_transmitido;
   int i;
   disable_interrupts(global);
   setup_adc_ports(NO_ANALOGS);
   setup_spi(FALSE);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   caracter_transmitido = 0x41; //41 es la letra "A" mayuscula
   while(1)
   {
     while(caracter_transmitido < 0x5C) //5B es la letra "Z" mayuscula
          {
       printf("%1c",0x00);
            printf("%1c", caracter_transmitido);
       caracter_transmitido++;
          }
   caracter_transmitido = 0x41;
   }
}


The code of the receiving PIC is the following:

Code:
#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP
#use rs232(baud=2400, parity = N, xmit = PIN_C6,rcv=PIN_C7,bits=8,errors)
#byte rxstatus = 0x18 //Direccion del registro donde se controla la recepcion de la UART

void main() { //aquí inicia el programa principal

   char caracter_recibido1, caracter_recibido2; //es el caracter que se recibe por el RS232
                                                //del Rx proveniente del recolector
   int direccion; //es la dirección en memoria EEPROM interna del PIC
   disable_interrupts(global);
   setup_adc_ports(NO_ANALOGS);
   setup_spi(FALSE);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   direccion = 0;
   do  //la letra "A" es un 41h en ASCII
      {
      caracter_recibido1=getch(); // Espera a recibir el caracter por el puerto serial.
      if ((rxstatus == 0x90)&&(caracter_recibido1!=0x00)){
         write_eeprom(direccion, caracter_recibido1);
         direccion++;
      }
            }
      while (direccion < 100);
}


The contents of the internal EEPROM of the receiving PIC after capturing the transmitted characters, is the following:

00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
0000 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4F 50 51
0010 52 53 54 55 56 57 58 59 5A 5B 42 43 44 45 46 47
0020 48 49 4A 4B 4C 4D 4E 50 51 52 53 54 55 56 57 58
0030 59 5A 5B 41 43 44 45 46 47 48 49 4A 4B 4C 4D 4E
0040 4F 51 52 53 54 55 56 57 58 59 5A 5B 41 42 44 45
0050 46 47 48 49 4A 4B 4C 4D 4E 4F 50 52 53 54 55 56
0060 57 58 59 5A FF FF FF FF FF FF FF FF FF FF FF FF
0070 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0080 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0090 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00A0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00B0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00C0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00D0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00E0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
00F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
Guest








PostPosted: Sun Oct 19, 2003 9:32 am     Reply with quote

I think you must re-distribute the different tasks of your project taking in mind the time needed for each task. Reading your code, I see that after you received one char, inmediatly you try to store it in EEPROM -while the next char is comming- wich is not bad, but require a very thight use of time sharing.

Suggests:
1) Make an isr to handle INT_RDA.
2) Store the incoming chars in RAM (circular buffer).
3) In main(), check if the buffer is full, make your verifications and then
4) Disable INT_RDA.
5) Copy the RAM buffer content into EEPROM.
6) Clear the flag wich tell you the buffer is full.
7) Enable INT_RDA, and wait for incoming chars again.

hope this help,

Humberto
aroman



Joined: 06 Oct 2003
Posts: 12

View user's profile Send private message

PostPosted: Fri Oct 24, 2003 9:17 pm     Reply with quote

Thanks to Humberto for the suggestion. I modified the code of my receiver to use interrupts instead of polling. However, it seems like the UART receives just one "trash" character, stores it into internal EEPROM memory and then it just waits for another character forever. The waveform on the Rx pin is OK, just like is was when I used polling. The code that I am using for interrupt receive is the following:

Code:
#include <16F876.h>
#use delay(clock=76800)
#fuses LP,NOWDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP
#use rs232(baud=2400, parity = N, xmit = PIN_C6,rcv=PIN_C7,bits=8,errors)
#byte rxstatus = 0x18 //Direccion del registro donde se controla la

#int_rda//Rutina de servicio de interrupción por recepción en el puerto
rb_isr ( ) {
   char caracter_recibido, caracter_OK; //caracter_recibido es el caracter
   boolean bandera_caracter_OK;//bandera que indica cuando se ha
   bandera_caracter_OK=0;
   caracter_recibido=getch(); // Espera a recibir el caracter por el puerto
   if ((rxstatus == 0x90)&&(caracter_recibido!=0x00)){//Si rxstatus es
      caracter_OK=caracter_recibido;
      bandera_caracter_OK=1;
   }//del if
}//del rb_isr

void main() { //aquí inicia el programa principal

   int direccion; //es la dirección en memoria EEPROM interna del PIC
   char caracter_OK; //caracter_OK es el caracter recibido correctamente
   boolean bandera_caracter_OK;//bandera que indica cuando se ha
   disable_interrupts(global);
   enable_interrupts(int_rda);//habilita la interrupción de recepción por     
   enable_interrupts(global);
   setup_adc_ports(NO_ANALOGS);
   setup_spi(FALSE);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   direccion = 0; //se posiciona en la primer dirección de la EEPROM
   do {
      if (bandera_caracter_OK){
         disable_interrupts(global);
         disable_interrupts(int_rda);
         enable_interrupts(global);
         write_eeprom(direccion, caracter_OK);
         direccion++;
         bandera_caracter_OK=0;
         disable_interrupts(global);
         enable_interrupts(int_rda);//habilita la interrupción de recepción
         enable_interrupts(global);
      }//del if
   }//del do...while
   while (direccion < 100);
}//del main



On the internal EEPROM, all I get is a character that it is considered "trash" (0x02) and then the rest is empty (0xFF). The code that I am using on the transmitter is the same as the one I posted in my last post. I do not have experience using interrupts. Can somebody please give me a hand?
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