|
|
View previous topic :: View next topic |
Author |
Message |
aroman
Joined: 06 Oct 2003 Posts: 12
|
Overrun errors using the getc() function |
Posted: Mon Oct 06, 2003 1:07 pm |
|
|
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
|
|
Posted: Mon Oct 06, 2003 1:29 pm |
|
|
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 |
Posted: Mon Oct 06, 2003 3:12 pm |
|
|
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
|
|
Posted: Thu Oct 09, 2003 7:18 pm |
|
|
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
|
|
Posted: Thu Oct 09, 2003 8:06 pm |
|
|
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
|
14th character lost |
Posted: Sat Oct 18, 2003 3:24 pm |
|
|
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
|
|
Posted: Sun Oct 19, 2003 9:32 am |
|
|
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
|
|
Posted: Fri Oct 24, 2003 9:17 pm |
|
|
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? |
|
|
|
|
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
|