|
|
View previous topic :: View next topic |
Author |
Message |
maiprog
Joined: 24 Mar 2014 Posts: 7
|
I am using interrupt to control external device |
Posted: Tue Mar 25, 2014 7:01 am |
|
|
This is my code. I need to HIGH and LOW the pin_b2
so i need delay_us... my code is below:
Code: |
#INT_RTCC
void inductor_firing_isr()
{
if(enable_firing_interrupt == 1)
{
output_high(PIN_B2);
delay_us(20);
output_low(PIN_B2);
set_timer0(0);
enable_firing_interrupt = 0;
}
}
|
Is their any way rather than using the delay in interrupts ? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Tue Mar 25, 2014 7:29 am |
|
|
yes, simply set a flag within the ISR then in main(), test that 'flag' and if set, do what you want with pin_b2.
You want ISRs to be small and fast, so NO delays, printf(), or math just simple set/clr flags.
hth
jay |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Mar 25, 2014 7:48 am |
|
|
Timer 0 will be set to zero when the interrupt is taken.
Therefore you can look for a small count greater than zero as your delay,
based on the timer prescalar- master clock etc...
If latency for the pulse you make is critical after the int - then you will have to do it in the isr.
None of this gets around the question of ISR time hogging.
If you have no other foreground or overlapped #int handlers
that could be the alternative to using the ugly delay_us().
Without knowing the PIC - i don't know if you are reading an 8 or 16 bit register for the timer though.
Code: |
# define mydelay 7
#INT_RTCC
void inductor_firing_isr()
{
if(enable_firing_interrupt == 1)
{
output_high(PIN_B2);
while(get_timer0()<mydelay){};
output_low(PIN_B2);
set_timer0(0);
enable_firing_interrupt = 0;
}
} |
|
|
|
maiprog
Joined: 24 Mar 2014 Posts: 7
|
|
Posted: Tue Mar 25, 2014 9:07 am |
|
|
I am using pic18f4520 and int8 |
|
|
maiprog
Joined: 24 Mar 2014 Posts: 7
|
|
Posted: Tue Mar 25, 2014 9:08 am |
|
|
Why mydelay 7, any reason for that |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Tue Mar 25, 2014 10:49 am |
|
|
Because if you put the delay in the ISR, then any delays in your main code could cause interrupts to be disabled (depends on if the compiler inlines the delay or not).
Without knowing much about your hardware situations, some other thoughts:
If your clock is fast enough, you could do a small conditional in your ISR:
Code: |
#INT_RTCC
void inductor_firing_isr()
{
static BOOLEAN pulse = FALSE;
if(enable_firing_interrupt){
if(!pulse)
output_high(PIN_B2);
set_timer0(250); //pick a value here that makes the interrupt happen 20us later
pulse = TRUE;
}else{
output_low(PIN_B2);
set_timer0(0);
pulse = FALSE;
enable_firing_interrupt = FALSE;
}
}
}
|
In this scenario, when you set enable_firing_interrupt to TRUE, the first IF happens setting the line high and the interrupt finishes. The set_timer0() call in the IF section should be selected to account for the time it takes for the interrupt to save registers, etc. The next time the interrupt fires, it goes to the ELSE section, which brings the line low and disables the section. |
|
|
maiprog
Joined: 24 Mar 2014 Posts: 7
|
|
Posted: Tue Mar 25, 2014 12:47 pm |
|
|
K, and i am too getting errors such as:
interrupt disabled call to prevent re-entrancy:[lcd_send_nibble], [lcd_send_nibble] ,
[@mulff],[@delay_ms1] and [synchronize_on_rising_edge]
How to eliminate these errors ? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Tue Mar 25, 2014 1:33 pm |
|
|
You should have posted your entire program, not just the ISR, as I can see those 'errors' come from an LCD function or routine NOT in your original post.
You must understand that the PIC once in a delay function can not be called a second time.Usually you'll get this error with delay code inside an ISR.
If you post your entire code,others can better comment on what's going on....how to fix..
hth
jay |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Tue Mar 25, 2014 4:13 pm |
|
|
maiprog wrote: | K, and i am too getting errors such as:
interrupt disabled call to prevent re-entrancy:[lcd_send_nibble], [lcd_send_nibble] ,
[@mulff],[@delay_ms1] and [synchronize_on_rising_edge]
How to eliminate these errors ? |
This not an error, it is a warning. However, you do need to pay attention to them. It says that you are using functions in your ISR (delay_ms, lcd_send_nibble. synchronize_on_rising_edge) and in your main code. You really should avoid doing this. It means that you cannot fire interrupts while these functions run because of how you placed them in the code. Avoid using ms delays or LCD functions or Floating point operations in your ISR. It can cause a lot of problems for you. |
|
|
maiprog
Joined: 24 Mar 2014 Posts: 7
|
|
Posted: Wed Mar 26, 2014 12:30 am |
|
|
This is my code....
and i am using the LCD.c inbuilt driver of ccs compiler.
Code: | #include <18f4520.h>
//#fuses HS, NOWDT, NOPROTECT, NOPUT, NOBROWNOUT
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#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 NOWRTD //Data EEPROM not write protected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES PBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES NOLPT1OSC //Timer1 configured for higher power operation
#FUSES MCLR //Master Clear pin enabled
//#FUSES XINST //Extended set extension and Indexed Addressing mode enabled
#use delay(clock=25M)
#include <LCD.C>
//#use standard_io(a)
//#use standard_io(b)
#zero_ram
#define ON 1
#define OFF 0
#define NUM_CAP_BANKS 3
#define TCR_LIMIT 10
#define LEADING_LIMIT -28
#define TURN_ON -1
// Unsigned INT (8 bit): 0 -> +256
// Signed INT (8 bit): -128 -> +128
// CCS Compiler makes INTs unsigned by default
//-------------
//Fuzzy System
//-------------
//Input Membership Function
// -20 -15 -10 -5 0 5 10 15 20 25
signed int PhaseAngle_Input[10] = {40, 45, 50, 55, 60, 65, 70, 75, 80, 85};
//Output Membership Function
// 91 95 100 112 115 122 124 126 128 135
unsigned int FiringAngleChange_Output[10] = {1, 5, 10, 22, 25, 32, 34, 36, 38, 45};
//Fuzzy TSK Rules
unsigned int Rules[10] = {0, 1, 2, 3, 4, 5, 5, 7, 8, 9};
// One Input - One Output Fuzzy Function Prototype
unsigned int fuzzy_tsk(float);
//General Prototypes
void turn_capacitors_on();
void turn_capacitors_off();
void turn_inductor_on();
void turn_inductor_off();
signed long int round(float x);
void synchronize_on_rising_edge();
//Globals - little necessary
signed long ticks = 0;
//short int look_for_voltage = 1;
float phase_angle = 0.0;
unsigned long int firing_angle = 90;
short int voltage_state = 0;
short int current_state = 0;
short int bLagging = 0;
short int voltage_initial_state = 0;
short int current_initial_state = 0;
short int enable_firing_interrupt = 0;
float time_delay = -1.0;
int counter_set = 0;
signed long int interrupt_counter = 0;
/* -----------------------------------------------*/
/* Perform Capacitor Bank TSC Initialization Here */
/* -----------------------------------------------*/
int capacitor_banks[NUM_CAP_BANKS];
/* TSC Capacitor Bank Prototypes */
void set_capacitor_banks(void);
void control_capacitor_banks(int, int );
void turn_on_all_capacitor_banks(void);
void turn_off_all_capacitor_banks();
void control_capacitor_banks(int, int );
int find_number_of_cap_banks_on(void);
/* ------------- */
/* TCR Interrupt */
/* ------------- */
#INT_RTCC
void inductor_firing_isr()
{
if(enable_firing_interrupt == 1)
{
output_high(PIN_B2);
delay_us(20);
output_low(PIN_B2);
set_timer0(0);
enable_firing_interrupt = 0;
}
}
/* ------------- */
/* LCD Interrupt */
/* ------------- */
#INT_TIMER2
void timer_2_isr()
{
interrupt_counter++;
if(interrupt_counter >= 100)
{
interrupt_counter=0;
printf(LCD_putc,"\f%3.2f",phase_angle);
lcd_gotoxy(0,1);
printf(LCD_putc, "FA: %ld", firing_angle);
lcd_gotoxy(0,2);
printf(LCD_putc, "Cap: %d", find_number_of_cap_banks_on());
//Synchronize Voltage Since Cycles Missed
synchronize_on_rising_edge();
}
}
/* ---------------*/
/* Main mSVC Code */
/* ---------------*/
void main()
{
signed long int capacitor_counter = TURN_ON;
//Set the LCD
lcd_init();
//Set Up Timer 0
set_rtcc(0);
setup_counters(RTCC_INTERNAL, RTCC_DIV_128);
enable_interrupts(INT_RTCC);
//Set Up Timer 2
set_timer2(0);
setup_timer_2(T2_DIV_BY_16, 0xFF, 16);
enable_interrupts(INT_TIMER2);
//Turn On All Interrupts
enable_interrupts(GLOBAL);
//Set up timer 1
set_timer1(0);
setup_timer_1( T1_INTERNAL | T1_DIV_BY_4);
setup_timer_1( T1_INTERNAL | T1_DIV_BY_8);
//Initialize Capacitor Banks to Off
// turn_off_all_capacitor_banks();
//Synchronize Voltage
synchronize_on_rising_edge();
//------------------------------
//Main While Loop Controls PSVC
//------------------------------
while(ON)
{
//Turn Off the LCD
disable_interrupts(INT_TIMER2);
//Update Capacitor Banks Once Every 5 Seconds
if(capacitor_counter > 300 || capacitor_counter == TURN_ON)
{
//Reset Capacitor Counter
capacitor_counter = 0;
//Set Capacitor Banks Based On Previous phase_angle
set_capacitor_banks();
//Synchronize Voltage
synchronize_on_rising_edge();
}
//Increment Capacitor Counter
capacitor_counter++;
//--------------------------
//Continue Controlling mSVC
//--------------------------
//Determine Leading/Lagging
voltage_state = input(PIN_A0);
voltage_initial_state = voltage_state;
while(voltage_initial_state == voltage_state)
{
voltage_state = input(PIN_A0);
}
//Start Inductor Countdown as Voltage Crosses Zero
if(time_delay != -1.0)
{
set_timer0(counter_set);
enable_firing_interrupt = 1;
}
//Take Current Reading
current_state = input(PIN_A1);
//Going from L->H
if((voltage_initial_state == 0) && (voltage_state == 1))
{
if(current_state == 0)
{
bLagging = 1;
}
else
{
bLagging = 0;
}
}
//Going from H->L
else if((voltage_initial_state == 1) && (voltage_state == 0))
{
if(current_state == 0)
{
bLagging = 0;
}
else
{
bLagging = 1;
}
}
if(bLagging == 1)
{
//Read Voltage First
//Wait for Voltage Zero Crossing
voltage_state = input(PIN_A0);
while(voltage_state == input(PIN_A0))
{
}
//Start Inductor Countdown as Voltage Crosses Zero
if(time_delay != -1.0)
{
set_timer0(counter_set);
enable_firing_interrupt = 1;
}
set_timer1(0);
//Read Current
//Wait for Current Zero Crossing
current_state = input(PIN_A1);
while(current_state == input(PIN_A1))
{
}
ticks = get_timer1();
}
else
{
//Read Current First
//Wait for Current Zero Crossing
current_state = input(PIN_A1);
while(current_state == input(PIN_A1))
{
}
//Set the Timer
set_timer1(0);
//Read Voltage
//Wait for Voltage Zero Crossing
voltage_state = input(PIN_A0);
while(voltage_state == input(PIN_A0))
{
}
//Start Inductor Countdown as Voltage Crosses Zero
if(time_delay != -1.0)
{
set_timer0(counter_set);
enable_firing_interrupt = 1;
}
ticks = get_timer1();
ticks = -ticks;
}
//Calculate Phase Angle from Ticks Counted
phase_angle = ( ((float)ticks * (float)0.0000016) / (1.0 / 60.0)) * 360.0;
//Account for Rollover
if((phase_angle <= -170.0) && (phase_angle >= -180.0 ))
{
phase_angle = -(180.0 + phase_angle);
}
//Weed out False Signals
if((phase_angle > -50.0) && (phase_angle < 130.0))
{
//Ensure Lower Bound is Met
if(phase_angle <= -20)
{
phase_angle = -19;
}
if( phase_angle > -55 && phase_angle < 55 )
{
//Invoke Fuzzy System
//Fuzzy System Returns Updated Firing Angle
firing_angle = fuzzy_tsk(phase_angle);
//Convert Desired Firing Angle to a Delay Time
time_delay = (((float)firing_angle / 360.0) * (1.0 / 60.0));
counter_set = round(time_delay / 0.0000256);
counter_set = 255 - counter_set;
}
//Show the Phase on LCD
enable_interrupts(INT_TIMER2);
}
}
}
//------------------------------
//Set Number of Capacitor Banks
//------------------------------
void set_capacitor_banks()
{
int i=0;
//Check if Phase is Lagging - Only Add More Capacitors
//If Phase Is Lagging
if (phase_angle > 0)
{
//Only Add More Capacitors If Phase > TCR_LIMIT Degrees
//10 Degrees Is the Current Span of the TCR Branch
if (phase_angle > TCR_LIMIT)
{
//Add the Next Available Capacitor Bank
for(i=0; i<NUM_CAP_BANKS; i++)
{
if (capacitor_banks[i] == OFF)
{
//Turn On Capacitor Bank
control_capacitor_banks(i,ON);
break;
}
}
}
}
//Remove a Capacitor Bank If Leading Too Much
else if (phase_angle < LEADING_LIMIT)
{
for(i=NUM_CAP_BANKS-1; i>=0; i--)
{
if (capacitor_banks[i] == ON)
{
//Turn Off Capacitor Bank
control_capacitor_banks(i,OFF);
break;
}
}
}
}
//-----------------------------------------
//Returns the Number Of Capacitor Banks On
//-----------------------------------------
int find_number_of_cap_banks_on(void)
{
int i=0;
int banks_turned_on = 0;
for(i=0; i<NUM_CAP_BANKS; i++)
{
if (capacitor_banks[i] == ON)
{
banks_turned_on++;
}
}
return (banks_turned_on);
}
//----------------------------
//Control Capacitor Banks
//Individual PIC Pins Needed
//----------------------------
void control_capacitor_banks(int bank, int mode)
{
//Wait for Current to Cross Zero Before Switching Capacitor
current_state = input(PIN_A1);
current_initial_state = current_state;
while(current_initial_state == current_state)
{
current_state = input(PIN_A1);
}
//1st Capacitor Bank
if (bank == 0)
{
if (mode == OFF)
{
output_low(PIN_B1);
capacitor_banks[bank] = OFF;
}
else
{
output_high(PIN_B1);
capacitor_banks[bank] = ON;
}
}
//2nd Capacitor Bank
else if (bank == 1)
{
if (mode == OFF)
{
output_low(PIN_B3);
capacitor_banks[bank] = OFF;
}
else
{
output_high(PIN_B3);
capacitor_banks[bank] = ON;
}
}
//3rd Capacitor Bank
else if (bank == 2)
{
if (mode == OFF)
{
output_low(PIN_A2);
capacitor_banks[bank] = OFF;
}
else
{
output_high(PIN_A2);
capacitor_banks[bank] = ON;
}
}
}
//----------------------------------------
//Synchronize on Rising Edge of Voltage
//Set Capacitor Banks
//---------------------------------------
void synchronize_on_rising_edge()
{
//Determine Leading/Lagging
voltage_state = input(PIN_A0);
voltage_initial_state = voltage_state;
//Wait for Voltage to Change State
while(voltage_initial_state == voltage_state)
{
voltage_state = input(PIN_A0);
}
//Take Current Reading
current_state = input(PIN_A1);
//Going from L->H
if((voltage_initial_state == 0) && (voltage_state == 1))
{
if(current_state == 0)
{
bLagging = 1;
}
else
{
bLagging = 0;
}
}
//Going from H->L
else if((voltage_initial_state == 1) && (voltage_state == 0))
{
if(current_state == 0)
{
bLagging = 0;
}
else
{
bLagging = 1;
}
}
//Wait for Rising Edge of Voltage
if(bLagging == 1)
{
if(input(PIN_A0) == 0)
{
while(input(PIN_A0) == 0)
{
//Just Wait for Voltage to Go from H->L
}
}
else
{
if(input(PIN_A1) == 0)
{
while(input(PIN_A1) == 0)
{
//Just Wait for Current to Go from H->L
}
}
}
}}
//-----------------------------
//Rounding Function on a Float
//-----------------------------
signed long int round(float x)
{
//float decimal = 0.0; //Commented to Save RAM
int return_rounded = 0;
if((x - ((signed long int)x)) < 0.5)
{
return_rounded = ((signed long int)x); //This is the floor function
}
else
{
return_rounded = ((signed long int)(x+1)); //This is the ceil function
}
return (return_rounded);
}
//----------------------------------
//One input-output TSK Fuzzy Engine
//---------------------------------
unsigned int fuzzy_tsk(float crisp_in)
{
float fired[2] = {0,0};
int rules[2] = {0,0};
unsigned int out = 0;
signed int a = 0;
signed int b = 0;
signed int c = 0;
signed int d = 0;
signed int e = 0;
signed int f = 0;
signed int g = 0;
signed int h = 0;
signed int i = 0;
signed int j = 0;
a = PhaseAngle_Input[0]; // -40
b = PhaseAngle_Input[1]; // -30
c = PhaseAngle_Input[2]; // -12
d = PhaseAngle_Input[3]; // -5
e = PhaseAngle_Input[4]; // 0
f = PhaseAngle_Input[5]; // 5
g = PhaseAngle_Input[6]; // 12
h = PhaseAngle_Input[7]; // 30
i = PhaseAngle_Input[8]; // 40
j = PhaseAngle_Input[9];
//Scale to Fit Fuzzy Rules
crisp_in += 60.0;
//----------------
//Start Fuzzy TSK
//----------------
if ((crisp_in >= a) && (crisp_in < b))
{
fired[0] = (-1.0) * ( crisp_in / (float)a ) + 1.0;
rules[0] = 0;
rules[1] = 1;
}
else if ((crisp_in >= b) && (crisp_in < c))
{
fired[0] = ((-1.0 )* crisp_in + (float)c) /((float)(c-b));
rules[0] = 1;
rules[1] = 2;
}
else if ((crisp_in >= c) && (crisp_in < d))
{
fired[0] = ((-1.0)* crisp_in + (float)d) / ((float)(d-c));
rules[0] = 2;
rules[1] = 3;
}
else if ((crisp_in >= d) && (crisp_in < e))
{
fired[0] = ((-1.0)* crisp_in+ (float)e) / ((float)(e-d));
rules[0] = 3;
rules[1] = 4;
}
else if ((crisp_in >= e) && (crisp_in < f))
{
fired[0] = ((-1.0)* crisp_in + (float)f) / ((float)(f-e));
rules[0] = 4;
rules[1] = 5;
}
else if ((crisp_in >= f) && (crisp_in < g))
{
fired[0] = ((-1.0)*crisp_in+ (float)g) / ((float)(g-f));
rules[0] = 5;
rules[1] = 6;
}
else if ((crisp_in >= g) && (crisp_in < h))
{
fired[0] = ((-1.0)*crisp_in+(float)h) / ((float)(h-g));
rules[0] = 6;
rules[1] = 7;
}
else
{
rules[0] = 7;
rules[1] = 8;
}
fired[1] = 1 - fired[0];
out = (unsigned int)(FiringAngleChange_Output[Rules[rules[0]]]*fired[0] +
FiringAngleChange_Output[Rules[rules[1]]]*fired[1]);
// Scale Firing Angle from Fuzzy Rules
out += 90;
return out;
}
|
|
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Wed Mar 26, 2014 6:45 am |
|
|
The timer interrupt is your issue. Printing to the LCD and also calling find_number_of_cap_banks_on() will cause most if not all those. It's not a very safe or stable design. Your timer will prevent your other interrupt from firing and causes the disabling of interrupts in the main.
A better approach would be to set a flag in the ISR and handle monitoring that flag in your main, updating as you are able. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Mar 26, 2014 7:40 am |
|
|
These two fuse settings are wrong and can cause a lot of headaches!
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
//#FUSES XINST //Extended set extension and Indexed Addressing mode enabled
99% of programmers do NOT use LVP. so select NOLVP
commenting out the XINST does not necessarily select NOXINST.
You're always best to configure them yourself, do not rely on 'wizards' or 'defaults'. With PICs having more fuses and instructions , always confirm from the listing what the fuses really are.Even compiler versions might change them as well...
Interesting to see 'fuzzy' logic ! I thought it dies 2 decades ago !
hth
jay |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Mar 26, 2014 12:48 pm |
|
|
there are a number of other time wasting features in the program. this one jumped out at me:
Code: | if(time_delay != -1.0) |
rather than a floating point test -it would be simpler to do the test ONCE when you assign a new value to time_delay and use a flag such as :
int1 TDnot1
then you are setting it to zero or one as the present assignment of time_delay might require.
testing IT repeatedly uses VERY few precious clock cycles |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Mar 26, 2014 1:21 pm |
|
|
floats in general are a HUGE waste of time and processing power..
also printf()s inside ISRs is very,very bad programming.
jay |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Wed Mar 26, 2014 1:48 pm |
|
|
let me reinforce what Jay means :
Code: | //Calculate Phase Angle from Ticks Counted
phase_angle = ( ((float)ticks * (float)0.0000016) / (1.0 / 60.0)) * 360.0;
//Account for Rollover
if((phase_angle <= -170.0) && (phase_angle >= -180.0 ))
{
phase_angle = -(180.0 + phase_angle);
}
//Weed out False Signals
if((phase_angle > -50.0) && (phase_angle < 130.0))
{ |
phase_angle need not be a float, since it's underlying "value" is derived from less than half of timer 1's register maximum and after more tedious floating point math to get to be "degrees" -minus your error limit test -the working resolution is less than 16000 counts of timer1!!!
ie: the BEST resolution of the 'float' you are likely to get is one part is
about 16000
using your own phase_angle integer coordinate space could be done with a signed int16 and the math would be so MUCH faster ..
THAT could be converted if need be when it changes for LCD display..
as a rule ONLY use floats when the precision of integers won't do.
HINT: 16 bit signed is all you need for your app!
in your case- INTeger math could do it all, even the LCD display with a bit of creativity . |
|
|
|
|
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
|