![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
RVR
Joined: 04 Jan 2012 Posts: 18
|
Conflict with I2C com. between Pic 18f2550 and Ds1307 |
Posted: Sat Mar 03, 2012 2:17 pm |
|
|
Hi everyone,
I have a very specifically problem with I2C communication, particularry between 2 pics an RTC ds1307 (will be DS1305 but for the simulation i used ds1307).
The following codes correspond to the master and slave i2c communication.
The mode of operation is as follows, the teacher uses the DS1307 library to ask when the RTC, and then sends 2 data floating (in 8 bytes apart) to the slave. This reads and displays the virtual terminal. When initializing the registers shown i2c slave communication (Figure 1)
Case 1:
It just runs the program the teacher asking the RTC data and displayed on screen.
result1:
(Figure 2), read the time correctly and displayed on the virtual terminal.
SSPSTAT = 0b00110100; observe bit3 (Read / write information bit) = 1: read, waiting for the new instruction of maestro.Al repeat the task, is carried out correctly and maintain the same values of the records shown in (Figure 2) .
Case 2: (probable ERROR)
You run the program only sending data to the slave master and showing them the virtual Terminal.
Result2:
(Figure 3), sent and received data correctly both floating and displayed on screen.
SSPSTAT = 0b00110000; observe bit3 (Read / write information bit) = 1: write in is supposed to control bus, but the rest of the configuration bytes indicate otherwise.
SSPCON1 = 0b00110110 (same as case 1)
bit4 = 1 (releases the clock) waiting condition
By repeating the task is carried out correctly and maintain the same values of the records shown in (figure 3).
case 3:
both routines together, first called for the hour and then send the data to the slave.
resultado3:
Only the first two routines run properly (Figure 4).
Then as is the condition of SSPSTAT = 0b00110000 (is incorrect), the second time running routines run successfully only routine DS1307 but the writing on the slave crashes and crazy.
questions:
bit3 because of SSPSTAT is 0 instead of 1, for communication with the slave if the structure is the same as that of ds1307?
is the bit3 = 0 SSPSTAT the warrants can not be run several times the reading routines in ds1307 RTC and writing the slave, such as in Figure 4?
and fix the problem??
Would greatly appreciate your help since I've been over 1 month with the issue unresolved.
Best REGARDS..
FIG 1
FIG2
FIG 3
FIG 4
FIg5
![](http://img694.imageshack.us/img694/7260/94394787.jpg) |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
Re: Conflict with I2C com. between Pic 18f2550 and Ds1307 |
Posted: Sat Mar 03, 2012 2:18 pm |
|
|
master code
Code: | //DECLARACION DEL CLOCK PARA EL MICRO//
#use delay (clock=48000000)
#zero_ram
//Configuracion parametros, puertos y asignacion de TAGS
#BYTE TRISC=0XF94
//com I2C
#Use I2C(MASTER, SDA=PIN_B0,SCL=PIN_B1,SLOW, force_hw)
int8 Slave_Dir=0xA0;//direccion slave
//serial debugger//
#use Rs232( baud=9600,xmit=Pin_c6,rcv=Pin_c7,parity=n,bits=8)
//math///
#INCLUDE <math.h>
#Include <stdio.h>
#Include <stdlib.h>
#Include <float.h>
#Include <ds1307.c>
//DECLARACION DE VARIABLES GLOBALES
int1 config_init=1;
int1 flag_run;
int8 config_flags_slave;
int1 flag_gt_redundance;
int1 adc_active=0;
int8 eeprom_address=0x00;//es obvio pero se puede usar tb... getenv("EEPROM_address").
//
//constantes de posicion geografica//
const float latitud=-33.425;
const float longitud=-70.566;
int dia;
int mes;
int yr;
long year;
int dow; //dia de la semana
signed long utc=-4;//-3horario verano, -4 invierno
struct tiempo {
int sec;
int min;
int hrs;
} actual,futuro,alba,ocaso,mediodia;
float Azimuth, Elevacion;
//
//SUBRUTINAS DE INTERRUPCIONES
#INT_ext2
void int_RB_isr(void)
{
flag_run=1;//esto significa que la alarma de hora futura se activó
}
//FUNCIONES
void task_write_slave(int8 configuracion,float data1,float data2)
{
printf("\r\r TASK WRITE FUNCTION");
union p {
float data_store;
int8 data_send[4];
} p_servo1,p_servo2; //separa un dato flotante en 4 variables bytes, y viceversa, para senviar (recibir) datos flotantes por i2c.
p_servo1.data_store=data1;
p_servo2.data_store=data2;
int1 response=0;
printf("\r Altitude=%Lx",Elevacion);
printf("\r Altitude=%3.6f",p_servo1.data_store);
printf("\r Altitude[1]=%x",p_servo1.data_send[0]);//menos significativo del float
printf("\r Altitude[2]=%x",p_servo1.data_send[1]);
printf("\r Altitude[3]=%x",p_servo1.data_send[2]);
printf("\r Altitude[4]=%x",p_servo1.data_send[3]);
printf("\r Azimuth=%Lx", Azimuth);
printf("\r Azimuth=%3.6f",p_servo2.data_store);
printf("\r Azimuth[1]=%x",p_servo2.data_send[0]);//menos significativo del float
printf("\r Azimuth[2]=%x",p_servo2.data_send[1]);
printf("\r Azimuth[3]=%x",p_servo2.data_send[2]);
printf("\r Azimuth[4]=%x",p_servo2.data_send[3]);
int c1=0;
i2c_start();
i2c_write(Slave_dir);//el bit0 corresponde al R/W, W=0 para escritura en el bus
i2c_write(configuracion);//configuracion
while ( (!i2c_poll()) &&(response==0) ) //no hay datos en el buffer y no hay respuesta finalizada del slave
{
for (c1=0;c1<5;c1++)
{
i2c_write(p_servo1.data_send[c1]);
i2c_write(p_servo2.data_send[c1]);
}
c1=0;
i2c_start();
i2c_write(Slave_dir+1);//maestro en modo lectura del bus
CONFIG_FLAGS_SLAVE=i2c_read(0);//tiene q ser 0 pq es unica lectura (nack) al ser respuesta del slave.
if (CONFIG_FLAGS_SLAVE==0xF0)
{
i2c_stop();
response=1;
CONFIG_FLAGS_SLAVE=0;
break;
}
else {
i2c_stop();//cierra la comunicacion y la reinicia en busqueda de datos
delay_us(3);
i2c_start();
i2c_write(Slave_dir);//el bit0 corresponde al R/W, W=0 para escritura en el bus
i2c_write(configuracion);//configuracion
}
delay_ms(10);//sino responde F0, esta ocupado, por ende el master espera prudentemente hasta preguntar nuevamente por los datos
}//while
}
void get_time(void)
{
printf("\r\r GET TIME FUNCTION");
ds1307_get_date(dia,mes,yr,dow);
ds1307_get_time(actual.hrs,actual.min,actual.sec);
printf("\rHORA ACTUAL=%02d:%02d:%02d ",actual.hrs,actual.min,actual.sec);
}
//funcion principal//
void main (void)
{
enable_interrupts(int_ext2);
enable_interrupts(global);
set_tris_a(0x1F);
set_tris_b(0xE7);
set_tris_C(0xC0);
while (true)
{
if (flag_run==1)
{
get_time();
Azimuth=89.7;
Elevacion=32.1;
task_write_slave(0x70,Elevacion,Azimuth);
flag_run=0;
}
else
{
printf("\r ESTADO MASTER: sleep");
sleep();
}
}//while
}//main
|
SLAVE code
Code: |
//DECLARACION DEL CLOCK PARA EL MICRO//
#use delay (clock=48000000)
//Configuracion parametros, puertos y asignacion de TAGS
#Define LIMITE_CARRERA_SLAVE PIN_A5
//com I2C
#Define Slave_Dir 0xA0
#Use I2C(SLAVE, SDA=PIN_B0,SCL=PIN_B1,slow, ADDRESS=Slave_Dir,force_hw)//el force hw es para q el maestro use i2c_poll
//serial debugger//
#use Rs232( baud=9600,xmit=Pin_c6,rcv=Pin_c7,parity=n,bits=8)
//math///
#INCLUDE <math.h>
#Include <stdio.h>
#Include <stdlib.h>
#Include <float.h>
#byte PIR1=0xF9E
#bit SSPIF=PIR1.3 //clean flag ssp
#byte SSPCON1=0xFC6
#bit CKP=SSPCON1.4 //releases the clock
#priority int_ad
//DECLARACION DE VARIABLES GLOBALES
//I2C
int8 instruccion_master,respuesta,estado;
union p{ float data_store;
int8 data_send[4];
}p_servo2,p_servo1;
//ADC
int1 adc_active=0;
//flow control
int1 tarea_pendiente=0;
//SUBRUTINAS DE INTERRUPCIONES
#INT_SSP
void SSP_isr(void)
{
tarea_pendiente=1;
estado=i2c_isr_state();
if (estado==0 )//valor de estado indica que el dato enviado por el master es la direccion
i2c_read(0);
else if(estado==0x01)// rango de valores de estados, que se producen luego del envio de la direccion para indicar que la informacion enviada son datos
{
instruccion_master=i2c_read(0);
}
else if (estado==0x02)
{
p_servo1.data_send[0] = i2c_read(0);
}
else if (estado==0x03)
{
p_servo2.data_send[0] = i2c_read(0);
}
else if (estado==0x04)
{
p_servo1.data_send[1] = i2c_read(0);
}
else if (estado==0x05)
{
p_servo2.data_send[1] = i2c_read(0);
}
else if (estado==0x06)
{
p_servo1.data_send[2] = i2c_read(0);
}
else if (estado==0x07)
{
p_servo2.data_send[2] = i2c_read(0);
}
else if (estado==0x08)
{
p_servo1.data_send[3] = i2c_read(0);
}
else if (estado==0x09)
{
p_servo2.data_send[3] = i2c_read(0);
}
else if( (estado>0x09)&&(estado<0x80))
i2c_read(0);
else if (estado==0x80)//la recepcion se hace con el 80, si se pone >= en el estado no aparece el valor 80... pero igual se hace la llamada a la escritura.
{
i2c_write(respuesta);//se escribe el flag de inic en el bus indicando la condicion del slave
CKP=1;
}
SSPIF=0;
}
//MAIN/////
void main (void)
{
enable_interrupts(int_ssp);//com serial
enable_interrupts(global);
set_tris_a(0x00);
set_tris_B(0xE7);//set
set_tris_c(0xC0);
//
while (true)
{
if(tarea_pendiente)
{
if((instruccion_master==0x70)||(instruccion_master==0x90))//seteo de posicion en los servos, 0x90 indica posicion reposo nocturno (luego sleep)
{
respuesta=0xF0;//confirma recepcion
printf("\r Altitude[1]=%x",p_servo1.data_send[0]);//menos significativo del float
printf("\r Altitude[2]=%x",p_servo1.data_send[1]);
printf("\r Altitude[3]=%x",p_servo1.data_send[2]);
printf("\r Altitude[4]=%x",p_servo1.data_send[3]);
printf("\r Altitude=%Lx",p_servo1.data_store);//.data_stoe es un float por tanto se puede maniúlar directamengte
printf("\r Altitude=%3.6f",p_servo1.data_store);
printf("\r Azimuth[1]=%x",p_servo2.data_send[0]);//menos significativo del float
printf("\r Azimuth[2]=%x",p_servo2.data_send[1]);
printf("\r Azimuth[3]=%x",p_servo2.data_send[2]);
printf("\r Azimuth[4]=%x",p_servo2.data_send[3]);
printf("\r Altitud=%Lx",p_servo2.data_store);
printf("\r Azimuth=%3.6f",p_servo2.data_store);
tarea_pendiente=0;
instruccion_master=0x00;
}
}//tarea pendiente
else
{
Printf("\r estado : SLEEP");
sleep( SLEEP_IDLE);//los perifericos siguen funcionando
}
}//while
} |
|
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9173 Location: Greensville,Ontario
|
|
Posted: Sat Mar 03, 2012 3:16 pm |
|
|
get rid of the 'simulator' !!!!
ISIS / Proteus it is FULL of bugs,errors, faulty DRCs,etc.
It is IMPOSSIBLE to get that simulator to correctly work !!!\
Unless you want to tear it apart,find the errors( dozens are known),then correct them.......
get REAL hardware....then we can actually help.
You may have 100% correct C code, the program should work, but ISIS is at fault !!! |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Sun Mar 04, 2012 9:20 am |
|
|
Hi, temtronic
Thanks for your answer,
I agree that it is necessary to actually implement, but leaving aside that, you have any comments about the code? |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9173 Location: Greensville,Ontario
|
|
Posted: Sun Mar 04, 2012 9:47 am |
|
|
from a quick glance...
your program doesn't say which PIC you're 'simulating'....
no 'fuses'....
you include a lot of libraries, are all necessary ??
set_tris()...statements are not required unless you use fast_io()...,and that's not needed for your project...
always add 'errors' to any use rs232()..statement.if using the hardware UART..
The DS1307 RTC driver is very stable with either 16F877 or 18F4550 for past year or so.
I would create 'simple' test programs using known data to verify I2C communications between the PICS before tring to send anything else. Simple known bit patterns from host to slave to turn on LEDs or characters to local LCD.
Your REAL problem as ISIS is full of bugs so you do NOT know whether it's your code or ISIS that is causing the problems! You can easily waste days or weeks only to figure out that your code is good, ISIS is bad.
Spend $20 for real PICs and a white breadboard,only then can we really help in getting your program 'up and running'. |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Mar 04, 2012 9:58 am |
|
|
Also have a look at the CCS manual, the example code for the i2c_isr_state() function.
Here in the comments it says: Quote: | If 0x00 or 0x80 is returned, an i2C_read( ) needs to be performed to read the I2C address that was sent (it will match the address configured by #USE I2C so this value can be ignored) | You are not doing the read for 0x80...
And just a remark:This is difficult to read code, instead use the function clear_interrupt(INT_SSP). But, even better, the compiler already adds code to clear the interrupt for you so the whole line can be left out.
Also, your sleep instruction in the slave is a bit tricky as it is. The printf instruction will take a few ms, what happens when you receive a new I2C command during the printf?
You will go to sleep, but not wake up again unless a new trigger signal is received. |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Sun Mar 04, 2012 12:12 pm |
|
|
hi temtronic
Quote: | your program doesn't say which PIC you're 'simulating'....
no 'fuses'....
you include a lot of libraries, are all necessary ??.... |
yes, i put all the statements to configure the pic 18f2550. All works fine.
Quote: | set_tris()...statements are not required unless you use fast_io()...,and that's not needed for your project... |
I know, but i forgot to delete because i used to do some proves.
Quote: | always add 'errors' to any use rs232()..statement.if using the hardware UART.. |
why? Rs232 could be a error source?
Quote: | The DS1307 RTC driver is very stable with either 16F877 or 18F4550 for past year or so. |
yes i agree
Quote: | I would create 'simple' test programs using known data to verify I2C communications between the PICS before tring to send anything else. Simple known bit patterns from host to slave to turn on LEDs or characters to local LCD. |
Try to explain it before, it could send data of various sizes and several times with test programs between PICS .... but the error comes when I try to connect the RTC programs and communication between pics.
I tried to used a LCD display but it is more inefficient than UART com
Quote: | Your REAL problem as ISIS is full of bugs so you do NOT know whether it's your code or ISIS that is causing the problems! You can easily waste days or weeks only to figure out that your code is good, ISIS is bad. |
Yes I can prove it,
Quote: | Spend $20 for real PICs and a white breadboard,only then can we really help in getting your program 'up and running'. |
this is my final carreer project. This is a design more complex system and i need to be sure how to create the main board, the adc channels, communication between cards, save data ,etc , so the simulation must be clarify my doubt, but at this time Proteus is creating more problems than the i need to solve.[/quote] |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Sun Mar 04, 2012 12:25 pm |
|
|
Hi Ckielstra,
thanks for your comments,
Quote: | You are not doing the read for 0x80... |
When i read the 0x80 address, the communication is stopped because
Moreover, if the 0x80 would have not read the communication in the fig 2, will not happen. But this worked fine.
Quote: | And just a remark:This is difficult to read code, instead use the function clear_interrupt(INT_SSP). But, even better, the compiler already adds code to clear the interrupt for you so the whole line can be left out. |
I prove and the source code doesn't clean the flag.
Quote: | Also, your sleep instruction in the slave is a bit tricky as it is. The printf instruction will take a few ms, what happens when you receive a new I2C command during the printf?
You will go to sleep, but not wake up again unless a new trigger signal is received. |
In sleep mode the processor is up in the SSP interrupt.
Also in communication i2c no more than printf end of the communication was made.
Now, the program does not use rs232 instructions are only for display steps. |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Mon Mar 05, 2012 2:14 pm |
|
|
anyone with another idea? |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Mon Mar 05, 2012 8:17 pm |
|
|
RVR wrote: | Hi Ckielstra,
thanks for your comments,
Quote: | You are not doing the read for 0x80... |
When i read the 0x80 address, the communication is stopped because
Moreover, if the 0x80 would have not read the communication in the fig 2, will not happen. But this worked fine.
|
This is an indicator that something else is wrong. If you don't do a read when the state is 0x80, you can actually hang up the I2C device in real hardware. If if doesn't work with you reading when state==0x80, then you have bigger problems of some sort. Of course it could just be Proteus not working correctly.
What compiler version are you using again? |
|
![](templates/subSilver/images/spacer.gif) |
RVR
Joined: 04 Jan 2012 Posts: 18
|
|
Posted: Wed Mar 07, 2012 8:51 am |
|
|
Quote: | What compiler version are you using again? |
Hi Jeremiah,
Thanks for your answer.
This version was 4.128.
I just received an email from tech support and tell me it's a bug in the compiler clock time with the newest chips. It is assumed that the corrected version in 4.130 (see the updates) ...
The problem is that now, I found a new error, following same tend... |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Wed Mar 07, 2012 3:32 pm |
|
|
Just some suggestions for you:
1. Try to shorten the program some, just down to the I2C routines (you can even shorten those a bit) and see if you can get just I2C code working.
2. I noticed in your code you have a few places where you declare variables after doing function calls and other things. While most C++ compilers are ok with this and the CCS compiler never complains, it has been my experience that sometimes bugs do arise when you do this in CCS. I would suggest moving all variable declarations to the top of the functions rather than afterwards. This may or may not fix your particular problem, but it shoud help prevent some crazy bugs later (as your program increases in size).
3. You called i2c_poll() oddly in your master code. The master drives the clock, so you might want to look at that again. I don't recall you needing to use that function as the master, but maybe a more experienced user can comment on that. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Wed Mar 07, 2012 4:40 pm |
|
|
I don't have your chips nor I have I looked at the data sheets, but just to give you an idea of what I was suggesting about shortening the program some, try something similar to this (UNTESTED mind you). Also note that this isn't meant to be production level code, but just something to test out the I2C to make sure you are sending and receiving data on it.
Master:
Code: |
#case
#include <18LF2550.h>
#use delay (clock=48000000)
#use i2c(master, sda=PIN_B0,scl=PIN_B1,slow,force_hw)
#use rs232( baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=n,bits=8)
#define I2C_SLAVE_ADDR 0x80
void main(void) {
unsigned int8 value;
while(TRUE){
delay_ms(5000);
i2c_start();
i2c_write(I2C_SLAVE_ADDR | 0x01); //Issue the "read" bit
value = i2c_read(0); //nack the last received byte
i2c_stop();
printf("Value Read:\t%x\r\n",value);
}
}
|
Slave
Code: |
#case
#include <18LF2550.h>
#use delay (clock=48000000)
#use i2c(slave, sda=PIN_B0,scl=PIN_B1,ADDRESS=0x80)
#use rs232( baud=9600,xmit=PIN_C6,rcv=PIN_C7,parity=n,bits=8)
//transmit globals
unsigned int8 g_i2c_tx_buffer[] = {0,1,2,3,4,5};
unsigned int8 g_i2c_tx_buf_len = sizeof(g_i2c_tx_buffer);
unsigned int8 g_i2c_tx_buf_index = 0;
//receive globals
unsigned int8 g_i2c_rx_buffer[6];
unsigned int8 g_i2c_rx_buf_len = sizeof(g_i2c_rx_buffer);
unsigned int8 g_i2c_rx_buf_index = 0;
//special flags
int1 g_i2c_data_sent = 0;
#INT_SSP
void SSP_isr(void){
unsigned int8 state;
state = i2c_isr_state();
if(state <= 0x80){
if(g_i2c_rx_buf_index < g_i2c_rx_buf_len){
g_i2c_rx_buffer[g_i2c_rx_buf_index++] = i2c_read();
}else{
i2c_read(); //buffer full, ignore.
}
}
//overlap on 0x80 is intentional
if(state >= 0x80){
i2c_write(g_i2c_tx_buffer[g_i2c_tx_buf_index++]);
//reset the index if at max
if(g_i2c_tx_buf_index >= g_i2c_tx_buf_len){
g_i2c_tx_buf_index = 0;
}
g_i2c_data_sent = 1;
}
}
void main(void) {
unsigned int8 index = 0;
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(TRUE){
if(g_i2c_data_sent){
g_i2c_data_sent = 0;
printf("I2C Data Sent\r\n");
//NOTE: I don't really address syncronization here. This is
//just to see if data is coming across at all. I assume that
//the master puts a lot of time between i2c transactions.
if(g_i2c_rx_buf_index){
printf("I2C RX:\t");
while(index < g_i2c_rx_buf_index){
printf("%x ",g_i2c_rx_buffer[index++]);
}
g_i2c_rx_buf_index = 0;
index = 0;
printf("\r\n");
}
}
}
}
|
Notice that I changed the 8bit version of the address to 0x80. 0xA0 is what EEPROMs tend to use. I don't think anything uses 0x80 to my knowledge. You can make it whatever, but try not using 0xA0 and see.
Also, as an aside, I see you are putting the slave to sleep in your code. I actually had trouble with that on another PIC due to it taking too long to wake up and missing some I2C data. I have no clue how fast your PIC wakes up from idle, but it might be worth seeing just to be sure. It's probably fast enough, but something to check since you are simulating it (and simulators may not be as fast as real hardware anyways). |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 07, 2012 5:04 pm |
|
|
RVR wrote: | Quote: | always add 'errors' to any use rs232()..statement.if using the hardware UART.. |
why? Rs232 could be a error source? | Yes, the hardware UART can generate errors. The hardware UART has a buffer for only up to 3 characters. When more data is received the UART will stop until the error flags are reset. Adding the 'ERRORS' keyword to the #use rs232 line will make the CCS compiler to add code for automatically clearing the UART error flags on every call to getc().
Maybe not important in your posted program because you don't seem to use the rs232 receiver, but it is good practice to always add 'ERRORS' just in case. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|