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

External Interrupt Problem

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



Joined: 01 Apr 2012
Posts: 5
Location: Edinburgh

View user's profile Send private message Visit poster's website

External Interrupt Problem
PostPosted: Sun Apr 01, 2012 8:19 am     Reply with quote

I am trying to get the External Interrupt (on RB0) to work on a PIC16LF877.

Unfortunately my code will not work or simulate as I would like it to - in fact the interrupt just doesn't work!

I am using MPLAB V8.84 and the PCW C Compiler.

My interrupt code is written as below:

Code:

#INT_EXT
void ext_isr(void)
{
if (psuState == DELAY_WAIT)
{
   disable_interrupts(INT_EXT);  // Disable future interrupts on RB0

   PROCESSOR_ON;           // Enable logic supplies
   psuState = DELAY_BOOT;  // Move to next stage
}
   return;


I am enabling the interrupt using the code below:

Code:

/* Switch off all supplies except PIC supply, enable
interrupt at PIC RB0 pin and enter wait state */
PROCESSOR_OFF;
enable_interrupts(INT_EXT);
psuState = DELAY_WAIT;


When the low to high transition occurs on RB0, nothing happens. I have ensured that the interrupt enabling code is being executed during simulation.

The enable_interrupts (GLOBAL) function is executed at the beginning of the code which is why it is not listed above. I also have the INT_TIMER1 interrupt working away quite happily.

Can anyone see what I am missing here?

Thank you.
temtronic



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

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 8:49 am     Reply with quote

Without seeing the whole, real program ,it's hard to tell....

Since you disable the interrupt within itself, it could have executed before you think it should and is now disabled...

What triggers the ISR? Are you sure that it can or is being triggered?

hmm..simulation....if Proteus...throw it away, it doesn't work ! See ANY previous 'simulation' posts.
neilelph



Joined: 01 Apr 2012
Posts: 5
Location: Edinburgh

View user's profile Send private message Visit poster's website

PostPosted: Sun Apr 01, 2012 9:10 am     Reply with quote

The interrupt is to allow a delayed start feature to my tool. It is only ever required once.

My tool is controlled by an ARM Processor and the PIC Monitors vital functions. If a delayed start has been configured by the user, the ARM Processor programs an alarm into an RTC and then tells the PIC to shut everything down apart from its own power supply. At this point the PIC arms the External Interrupt which is connected to the RTC and then waits. When the RTC alarms, the PIC turns on all other power supplies and the ARM Processor resumes overall control. The PIC External Interrupt is never required again.

Full code below.

Code:

/*
 *******************************************************************************
 **
 **  Project:     ATEX SAAM (D741)
 **  Filename:    atex_saam.c
 **  Author:     
 **  Created:     
 **  Description:
 **
 **  Firmware for ATEX SAAM logger control
 **
 **  Revision History
 **  ----------------
 **
 **  Version    Date       Author   Comments
 **  -------    ----       ------   --------
 **   0.1      26/09/11    ajs      Release to debug
 **   0.2      21/11/11    nae      MEM_FULL polarity inverted and sounder timer
 **                                 counter ammended
 **   0.3      12/03/12    nae      User Delay code added. Sets up External
 **                                 interrupt
 **   0.4      xx/xx/12    ajs      Interrupt edge on pin interrupt now setup
 **                                 before global interrupts enabled
 **
 **
 **  COPYRIGHT 2011 WEATHERFORD. All Rights Reserved.
 **
 *******************************************************************************
 */


#include "atex_saam.h"

/*
 * Function Name:       ext_isr() - interrupt handler to enable logic supplies
 *                                  following user delay
 * Parameters:          None
 * Returns:             None
*/
#INT_EXT
void ext_isr(void)
{
if (psuState == DELAY_WAIT)
{
   disable_interrupts(INT_EXT);  // Disable future interrupts on RB0

   PROCESSOR_ON;           // Enable logic supplies
   psuState = DELAY_BOOT;  // Move to next stage
}
   return;
}
//----------------------------End of isr----------------------------------------


/*
 * Interrupt Routine:   sounder_mode() - interrupt routine to manage the
 *                                     sounder output
 * Parameters:          none
 * Returns:             none
 *
*/
#INT_TIMER1
void sounder_mode(void)
{
   /* Overflow approx. once every second
   (ie. period(sec)=(65535-64503)/(32.768(OSC freq in kHz)/32)) */
   set_timer1(64503);

   // Update timer counter
   if (sounderCount==1)
      sounderCount = 6;
   else
      --sounderCount;

   // Control ON/OFF status of sounder
   switch(psuState)
   {
      case DELAY_QUERY:    // Drop thru'
      case DELAY_WAIT:     // Drop thru'
      case DELAY_BOOT:     // Drop thru'
      case LOG:
         if (loopCount < 20)
         {
            if (sounderCount < 4)
               SOUNDER_ON;
            else
               SOUNDER_OFF;
         }
         else
            SOUNDER_OFF;

         break;

      case USB_FAULT:   SOUNDER_ON;
                        break;

      case LOG_FAULT:   // Drop thru'
      case USB_COMMS:   // Drop thru'
      case READ_ADC:    // Drop thru'
      case START:       // Drop thru'
      case SHUTDOWN:    SOUNDER_OFF;
                        break;

      default:          break;
   }

   if (loopCount < 25)
      loopCount++;

  return;
}
//-------------------------------End of isr-------------------------------------


/*
 * Function Name:       proc_config() - function initiates PSU microcontroller
 *                      ports and features following power on reset
 * Parameters:          none
 * Returns:             none
*/
void proc_config(void)
{
   setup_adc(ADC_OFF);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);

   /* Port A
   RA0:  Not used          INPUT
   RA1:  SOUNDER           OUTPUT
   RA2:  Not used          INPUT
   RA3:  Not used          INPUT
   RA4:  Not used          INPUT
   RA5:  Not used          INPUT */
   SOUNDER_OFF;
   TRISA=0x3d;

   /* Port B
   RB0:  /RTC_INT          INPUT
   RB1:  PS_CNTRL          OUTPUT
   RB2:  PS_IF             INPUT
   RB3:  Not used          INPUT
   RB4:  /P3V3_EN          OUTPUT
   RB5:  SENSORS_EN        OUTPUT
   RB6:  PGC               INPUT/OUTPUT
   RB7:  PGD               INPUT/OUTPUT   */
   TRISB = 0xcd;
   PSW_OFF;
   SUPPLY_OFF;
   PROCESSOR_ON;

   /* Port C
   RC0:  BATTERY_GOOD      INPUT
   RC1:  P3V3_GOOD         INPUT
   RC2:  P1V8_GOOD         INPUT
   RC3:  /USB_DET          INPUT
   RC4:  DP_GOOD           INPUT
   RC5:  /MEM_FULL         INPUT
   RC6:  LOG_EN            OUTPUT
   RC7:  PSU_STATUS        OUTPUT   */
   TRISC = 0x3f;
   LOGGING_OFF;
   PSU_OFF;

   /* Port D
   RD0:  AP_GOOD           INPUT
   RD1:  DP_EN             OUTPUT
   RD2:  AP_EN             OUTPUT
   RD3:  Not used          INPUT
   RD4:  USB_HIPWR         OUTPUT
   RD5:  Not used          INPUT
   RD6:  Not used          INPUT
   RD7:  Not used          INPUT   */
   TRISD = 0xe9;
   DP_OFF;
   AP_OFF;
   USB_OFF;

   /* Port E
   RE0:  Not used          INPUT
   RE1:  Not used          INPUT
   RE2:  Not used          INPUT  */
   TRISE = 0x07;

   return;
}
//----------------------------End of HW_Init------------------------------------


void main()
{
   proc_config();   // Initialise PIC

   while(1)
   {
      switch(psuState)
      {
         case START: // Select startup state
            delay_ms(50);

            // Setup pin interrupt edge and timer, and enable interrupts
            set_timer1(64503);
            setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
            enable_interrupts(GLOBAL);
            enable_interrupts(INT_TIMER1);

            /* Select operating state upon powerup or restart: USB_COMMS,
            DELAY_QUERY or USB_FAULT */
            if ((PORTC & 0x0f) == 0x07)
               psuState = USB_COMMS;
            else if ((PORTC & 0x0f) == 0x0f)
            {
               delay_ms(100);
               psuState = DELAY_QUERY;
            }
            else
            {
               PROCESSOR_OFF;
               psuState = USB_FAULT;
            }
            break;


         case DELAY_QUERY:   // Query if user delay is requested
            // Check for Pressure Switch Latch first
            if ((PORTB & 0x04) != 0x04)
               PSW_ON;
             else
                PSW_OFF;

            /* Check battery and logic supply levels */
            if ((PORTC & 0x07) == 0x07)
            {
               /* Has ATMEL uC flagged memory as not full? If so, enable
               sensor supply and logging */
               if ((PORTC & 0x20) != 0x20)
               {
                  delay_ms(10);
                  SUPPLY_ON;     // Enable instrument supply switch
                  delay_ms(300);
                  DP_ON;         // Power DP sensor
                  delay_ms(50);
                  AP_ON;         // Power AP sensor
                  delay_ms(100);
                  LOGGING_ON;
                  psuState = LOG;
               }
               else
               {
                  delay_ms(250);
                  if (loopCount2 > 3)
                  {
                     /* Switch off all supplies except PIC supply, enable
                     interrupt at PIC RB0 pin and enter wait state */
                     PROCESSOR_OFF;
          ext_int_edge(H_to_L);
                     enable_interrupts(INT_EXT);
                     psuState = DELAY_WAIT;
                  }
               }
               loopCount2++;
            }
            else
            {
               PROCESSOR_OFF;
               psuState = LOG_FAULT;
            }
            break;


      case DELAY_WAIT: // Holding state while waiting for RTC alarm

            break;


      case DELAY_BOOT:   // Boot power supplies following user delay
            delay_ms(500); // Delay to allow logic supplies to settle

            if ((PORTC & 0x07) == 0x07)
            {
               SUPPLY_ON;     // Enable instrument supply switch
               delay_ms(300);
               DP_ON;         // Power DP sensor
               delay_ms(50);
               AP_ON;         // Power AP sensor
               delay_ms(100);
               LOGGING_ON;
               psuState = LOG;
            }
            else
            {
               PROCESSOR_OFF;
               psuState = LOG_FAULT;
            }

            break;

      case LOG:   // Logging mode
            /* Check for system faults:
            1. If processor logic supply faulty, battery low or memory full,
            shutdown logging and supplies
            2. If overcurrent detected at DP sensor, remove power from DP sensor
            3. If overcurrent detected at AP sensor, remove power from AP sensor
            */
            if (((PORTC & 0x37) != 0x17) || ((PORTD & 0x01) != 0x01))
            {
               if ((PORTC & 0x27) != 0x07)
               {
                  LOGGING_OFF;
                  SUPPLY_OFF;
                  DP_OFF;
                  AP_OFF;
                  PROCESSOR_OFF;
                  disable_interrupts(GLOBAL);
                  disable_interrupts(INT_TIMER1);
                  setup_timer_1(T1_DISABLED);
                  psuState = LOG_FAULT;
               }

               if ((PORTC & 0x10) != 0x10)
                  DP_OFF;

               if ((PORTD & 0x01) != 0x01)
                  AP_OFF;
            }

            break;


         case USB_COMMS:      // USB (100mA)
             /* If USB cable connected, check USB regulated and processor
            supplies shutting down all supplies if fault(s) detected. If
            READ_ADC is selected by user, enable power to sensors */
            if ((PORTC & 0x08) != 0x08)
            {
               if ((PORTC & 0x07) != 0x07)
               {
                  PROCESSOR_OFF;
                  psuState = USB_FAULT;
               }
               else if ((PORTB & 0x04) != 0x04)
               {
                  USB_ON;        // Enable 500mA USB mode at DC-DC switcher
                  delay_ms(200);
                  SUPPLY_ON;     // Enable instrument supply switch
                  delay_ms(300);
                  DP_ON;         // Power DP sensor
                  delay_ms(50);
                  AP_ON;         // Power AP sensor
                  delay_ms(50);
                  psuState = READ_ADC;
               }
            }
            else
               psuState=SHUTDOWN;

            break;

         case READ_ADC:      // USB (500mA)
            /* Check for system faults:
            1. If overcurrent detected at DP sensor, remove power from sensor
            2. If overcurrent detected at AP sensor, remove power from sensor
            */
            if ((PORTC & 0x10) != 0x10)
               DP_OFF;

            if ((PORTD & 0x01) != 0x01)
               AP_OFF;

            /* If USB cable connected, check USB regulated and processor
            supplies shutting down all supplies if fault(s) detected. If
            READ_ADC is deselected by user, remove power from sensors */
            if ((PORTC & 0x08) != 0x08)
            {
               if ((PORTC & 0x07) != 0x07)
               {
                  SUPPLY_OFF;
                  DP_OFF;
                  AP_OFF;
                  USB_OFF;
                  PROCESSOR_OFF;
                  psuState = USB_FAULT;
               }
               else if ((PORTB & 0x04) == 0x04)
               {
                  SUPPLY_OFF;
                  DP_OFF;
                  AP_OFF;
                  delay_ms(50);
                  USB_OFF;
                  psuState = USB_COMMS;
               }
            }
            else
               psuState = SHUTDOWN;

            break;

         case LOG_FAULT:   // Fault trap - escape only by removing user cover
            break;

         case USB_FAULT:   // Fault trap - escape only by removing USB cable
            break;

         case SHUTDOWN:
            // Switch off 1s timer and sounder
            disable_interrupts(GLOBAL);
            disable_interrupts(INT_TIMER1);
            setup_timer_1(T1_DISABLED);
            SOUNDER_OFF;

            delay_ms(3500);         // Delay > power down time of processor
            psuState = START;       // Wait 3.5s and restart process loop

            break;

      }  // End switch

   }
}
/*-------------------------End of main()--------------------------------------*/
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 9:51 am     Reply with quote

Seriously, you need to learn how to debug problems. You trim away code, till you only have the parts causing the problem. You then have a minimum program showing he problem that can be posted if you still can't see it for yourself.
As it is, I doubt if anyone will even bother to look at a program this large, especially given that it is still incomplete. Things like the state values are not defined, etc. etc...
Separately, forget simulators. The only one that is reasonably 'worthwhile', is MPLAB, and this is slow, and still doen't handle quite a few peripherals. Get an ICE, or ICD.
Most likely thing is that the interrupt is being immediately called, and then cleared. _Read the data sheet_. What can happen when you change the interrupt edge?.

Best Wishes


Last edited by Ttelmah on Sun Apr 01, 2012 9:58 am; edited 1 time in total
neilelph



Joined: 01 Apr 2012
Posts: 5
Location: Edinburgh

View user's profile Send private message Visit poster's website

PostPosted: Sun Apr 01, 2012 9:58 am     Reply with quote

Seriously, if you've nothing helpful to post, then don't bother.

I only posted the whole code, because it was requested. I have been through various debug procedures and not found the problem. I have limited tools as I work for a tight fisted company.

I didn't just post on here as soon as I had a problem, I only post so I can get a second pair of eyes looking at the problem that may be staring me in the face.

But thanks for your comments.
jeremiah



Joined: 20 Jul 2010
Posts: 1328

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 11:25 am     Reply with quote

The MPLAB simulator he is speaking of is absolutely FREE. I would suggest the one with MPLAB 8.whatever IDE versus MPLAB X IDE, since MPLAB X is very new and still buggy.

Try the following program:

Code:


volatile unsigned int8 ext_isr_triggered = 0;

#INT_EXT
void ext_isr(void)
{
   ext_isr_triggered = 1;
}

void main(){

   unsigned int8 status = 0;

   //if you need to drive any lines to turn on hardware, do it here
   //but don't use TRIS junk.  Stick to output_high(PIN_B8) and
   //output_low(PIN_B8) or similar.

   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);

   while(TRUE){
      if(ext_isr_triggered){
         status = 1;
         //you can do output stuff here if you need to see output
      }
   }
}


If you need to do any output driving to turn on other hardware, do it where I specified to start with. See if the interrupt triggers. If it doesn't, try moving your hardware initialization to just below the enable_interrupt() calls and try again. Again, please don't use TRIS settings and such. Stick to CCS routines for this test.

Let us know what happens
Ttelmah



Joined: 11 Mar 2010
Posts: 19368

View user's profile Send private message

PostPosted: Sun Apr 01, 2012 12:23 pm     Reply with quote

It was 'requested', because what you posted originally was not enough to give even the faintest hint of what your problem might be. However Temtronic, like me, assumed you would have at least started to try to actually debug the problem yourself, and would therefore have a trimmed set of code.

Your postings are a bit like a person having trouble getting a car to track straight, who posts a picture of the steering wheel, and says "I can't get this to work", and then when asked to show some more information, instead of showing perhaps some details of the steering arms and geometry, instead shows a photo of the car....

My comment about looking in the data sheet, at what happens when you change the interrupt edge, still applies.

Best Wishes
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Help
PostPosted: Sun Apr 01, 2012 2:45 pm     Reply with quote

I fully endorse what the other guys are saying.

Read the CCS forum guide.

Amongst other things, it advises you to post MINIMUM compilable code which allows us to diagnose your problem.

I, for one, will not touch simulator issues, nor plough my way through mountains of irrelevant code.

The advice you get here is freely given by experts who normally charge $$$$/££££ for their services.

You need to make it easy for them to help you.

Mike
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Apr 02, 2012 1:13 am     Reply with quote

I agree with Ttelmah that the problem might be in how you enable the interrupt, an essential instruction is missing here. Check the datasheet.
A similar problem lures with the Timer1 interrupt enabling.

I normally don't like long code postings but nonetheless had a quick look at it:
1) I don't see code for initializing the variables. Perhaps this is done in the missing declaration code? At least loopCount2 has a problem as it is never reset again.
2)
Code:
   setup_spi(SPI_SS_DISABLED);
Disable SPI by giving the setup_spi call the parameter FALSE. Your code is invalid and might cause problems (an error in the CCS setup wizard created this line).

3)
Code:
   RC5:  /MEM_FULL         INPUT

...
               /* Has ATMEL uC flagged memory as not full? If so, enable
               sensor supply and logging */
               if ((PORTC & 0x20) != 0x20)
               {
                  ...
                  LOGGING_ON;
According to your comments the RC5 input being 0 indicates the memory to be full, but your implementation is inverted. Which is correct?

4)
Code:
            /* Check battery and logic supply levels */
            if ((PORTC & 0x07) == 0x07)
            {
               /* Has ATMEL uC flagged memory as not full? If so, enable
               sensor supply and logging */
               if ((PORTC & 0x20) != 0x20)
               {
                  ....
                  LOGGING_ON;
                  psuState = LOG;
               }
               else
               {
                    ...
                     psuState = DELAY_WAIT;
               }
               loopCount2++;
            }
            else
            {
               PROCESSOR_OFF;
               psuState = LOG_FAULT;
            }
            break;
This doesn't look right to me. When power is incorrect you now set LOG_FAULT. But when logging memory is full you don't set an error code? Seems mixed up.
Even worse mixed up as you now only start the delay_wait code in case there is a logging memory problem. Feels like a rewrite is required here.


As a generic remark: I'm missing a lot of debugging code. How did you do your debugging? You say the int_ext doesn't work but when I look at your code I have a strong feeling the int_ext is never enabled. This is so easy to check, even when you don't have an ICD tool. Just add little extra debugging code that activates an output in several parts of your code and connect an LED to these outputs.
I strongly recommend to you and your employer to buy an In Circuit Debugging tool. Even a cheap PicKit3 would suffice for a mere €35. As you are living in the UK that equals to less than 1 hour development time.
neilelph



Joined: 01 Apr 2012
Posts: 5
Location: Edinburgh

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 02, 2012 2:03 am     Reply with quote

Apologies if I seemed over-sensitive to criticism, but I was only responding to a request that I perhaps took too literally! I also clearly state the tools I have used in my first post (free or otherwise).

I accept constructive criticism openly, but there are ways of doing it without jumping down someones throat. I am also a professional who designs digital and analogue electronics along with developing firmware and software, but I can't apologise for not being an expert in all!

I thank you all for your feedback and input - it is very much appreciated. I also provide help to others on forums occasionally, so it's not a one way street with me.

Thanks again.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Apr 02, 2012 3:03 am     Reply with quote

Many of those who provide most of the help here are also professionals, myself included. I can only speak for myself: I post in my tea and lunch breaks. I do it because I want to help.

I have limited time. I cannot read through and understand more than a few tens of lines of code in an example. I can't wade through lines and lines of application specific code that's (probably) irrelevant to the problem.

What we want, and can deal with, is a complete but very short code example that will compile and show the problem. That means we expect the poster to have isolated the problem to a significant extent. It also gets round the problem of IP issues by not requiring the posting of proprietary code. It also means the "helped" needs to do some of the work. In return we give freely of our own time to help as much as we can. Sometimes though that's not good enough, as we can't know everything.

Only if that fails is it useful to cast the net wider.

That though is what we'd like to happen. What actually usually happens is that someone posts a very vague "my stuff doesn't work", then when requested for more information, gives a nearly complete info dump of their code, often missing out vital information such as fuse set-up, PIC type, compiler version and so on and expects us to work out what their problem is without even telling us the symptoms. Oh yes, and they've generally not bothered to read the CCS manual, which to be fair is not always correct or updated to reflect the current state of the tool set.

Do you still wonder why some of us are a more than a little twitchy and touchy about what goes on here?

RF Developer.

PS: My tea is now cold and I've been moaned at to get my timesheets for March done....
neilelph



Joined: 01 Apr 2012
Posts: 5
Location: Edinburgh

View user's profile Send private message Visit poster's website

PostPosted: Mon Apr 02, 2012 3:22 am     Reply with quote

Again, I apologise for any offence caused.

However, as mentioned already I have done all the work in debugging to the point where I needed help and my first post shows this. I only posted the whole code in response to a request. I don't expect anyone else to do my work for me.

I fully understand where you are coming from with regards to time etc., but I also work under pressured conditions and tight timelines but I don't shoot people down in flames for doing what was requested of them (albeit I accept I misinterpreted what was being asked).

Again, I thank and respect all comments and help provided, and have no bones to grind with anyone.

Thanks again.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Mon Jul 02, 2012 9:47 am     Reply with quote

From your post...

Code:

#INT_EXT
void ext_isr(void)
{
if (psuState == DELAY_WAIT)
{
   disable_interrupts(INT_EXT);  // Disable future interrupts on RB0

   PROCESSOR_ON;           // Enable logic supplies
   psuState = DELAY_BOOT;  // Move to next stage
}
   return;


Maybe its a copy/paste issue... but your missing a bracket ..."}"

Also, what are you returning? its void...
and is the right syntax not:
Code:
Return();


Just my two cents...


EDIT... i just realized this is an old thread... i side tracked... sorry...

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
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