Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Help with bootloader please...

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR
View previous topic :: View next topic  
Author Message
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Wed Aug 05, 2015 9:41 pm    Post subject: Help with bootloader please... Reply with quote

Hello all,

I am using an ATMEGA1281, 16Mhz xtal and COM1 to communicate with a PC over serial at 9600bps. My application program uses 8% of the programming space available - according to BASCOM. The application works perfectly without a bootloader. However, once I install a bootloader, which is based on Marks example the main application will not run.

The bootloader does work, it does accept the upload from the MCS bootloader windows application but the main app never starts.

I have the fuses set as:
BOOTSZ 1024 words start address = $FC00
BOOTRST is checked.


The bootloader.hex file appears to work, talking and receiving the data from the MCS Bootloader Windows app - here are some highlights:
Code:

$hwstack = 40
$swstack = 40
$framesize = 40

$crystal = 16000000                                         '16MHz crystal
$baud1 = 9600                                               '38400                                              'this loader uses serial com
 


Code:

$regfile = "m1281def.dat"
Const Loaderchip = 1281
 


Code:

#if Loaderchip = 1281                                       ' Mega128
   $loader = &HFC00                                        ' 1024 words
   '$loader = &H7C00                                        ' 1024 words
   '$loader = &H7800                                        ' 2048 words
   Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
   Open "COM2:" For Binary As #1
   Config Com2 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif
 


The application code has nothing special in it for bootloading - did I forget something?

If anyone has any suggestions, I would really appreciate the feedback!
Thank you all,
Tim

(BASCOM-AVR version : 2.0.7.8 )
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 2262

blank.gif
PostPosted: Thu Aug 06, 2015 9:21 am    Post subject: Re: Help with bootloader please... Reply with quote

TSEYFARTH wrote:
If anyone has any suggestions, I would really appreciate the feedback!

Is this a modified bootloader?
As often said and I may sound like a prayer mill: don't expect someone to find a bug in your code, without actually having your code, i.e. bootloader. Evil or Very Mad
Quote:
The bootloader does work, it does accept the upload from the MCS bootloader windows application but the main app never starts.

If it would work, your application would run.
How the reset is achieved? A jump to &h0000, or via watchdog timeout?
Only a watchdog reset brings the µC into pristine condition, a jump to &h0000 leaves registers in the condition, as they were written by the bootloader.
If you have written unclean code in your application, which relies on the µC to be in pristine condition, it may fail.
A first test is to have the bootloader upload the application code and after uncheck BOOTRST.
If your application works after re-powering, you have a reset issue, if it still does not work, the bootloader did not correctly load up the application code.
Back to top
View user's profile
AndersL

Bascom Member



Joined: 25 Jan 2010
Posts: 92
Location: Kragerø,Norway

norway.gif
PostPosted: Thu Aug 06, 2015 3:18 pm    Post subject: Reply with quote

Hi TSEYFARTH,
One thing to check is:
from MCS bootloader
Code:
$baud = 128000                                              'this loader uses serial com
'It is VERY IMPORTANT that the baud rate matches the one of the boot loader
'do not try to use buffered com as we can not use interrupts

I use 128k baudrate and in the:
Code:
#if Loaderchip = 1280                                       ' Mega1280
    $loader = &HFC00                                        ' 1024 words
    Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif


This is all for com1 and you have to use 128k baud in your code as well.

_________________
Anders
Back to top
View user's profile
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Thu Aug 06, 2015 6:22 pm    Post subject: Reply with quote

Hi and thanks for the replies!

The Baud rate is 9600, on COM2 as shown in the original post. The bootloader does talk to the Windows MCS bootloader app, both within the IDE and the stand alone.

@MWS -
Quote:
Is this a modified bootloader?

It is modified to the extent that the M1281 was added, and the Baud rate was changed to 9600. I also tried 38400. Nothing else has been changed. The bootloader code replies to the MCS Bootloader IDE and standone with a completed successfully code.

I have not been able to call the bootloader from within the application code, since the app code never seems to be launched. What I have done is using the AVRISPII:
1. Erase the chip
2. Set fuses for size and reset vector as shown in the original post
3. Program the compiled bootloader.hex app
4. Use either the MCS IDE Bootloader, or the MCS Standalone bootloader to communicate with the bootloader.hex code programmed on chip in step 3 above.
5. Power cycle the board. If LED indicators from the bootloader blink. App code never runs.

**There are no bootloader errors**

I will try your test procedure to see what that shows.

BTW, the reset code from the bootloader, when it is completed receiving the data from the PC is
Code:
Goto _reset                                    ' start new program



This is the entire bootloader code:

Code:

'----------------------------------------------------------------
'                          (c) 1995-2005, MCS
'                        BootloaderM1281_COM2.bas
'  This sample demonstrates how you can write your own bootloader
'  in BASCOM BASIC
'  VERSION 2 of the BOOTLOADER. The waiting for the NAK is stretched
'-----------------------------------------------------------------
'This sample is a mod of the original loader and shows how to use COM2
$hwstack = 40
$swstack = 40
$framesize = 40

$crystal = 16000000                                         '16MHz crystal
$baud1 = 38400                                              'this loader uses serial com

'It is VERY IMPORTANT that the baud rate matches the one of the boot loader
'do not try to use buffered com as we can not use interrupts



'$regfile = "m8def.dat"
'Const Loaderchip = 8

'$regfile = "m168def.dat"
'Const Loaderchip = 168

'$regfile = "m16def.dat"
'Const Loaderchip = 16

'$regfile = "m32def.dat"
'Const Loaderchip = 32

'$regfile = "m88def.dat"
'Const Loaderchip = 88

'$regfile = "m162def.dat"
'Const Loaderchip = 162

'$regfile = "m128def.dat"
'Const Loaderchip = 128

$regfile = "m1281def.dat"
Const Loaderchip = 1281


'$regfile = "m64def.dat"
'Const Loaderchip = 64

'$regfile = "m2561def.dat"
'Const Loaderchip = 2561


'#if Loaderchip = 88                                         'Mega88
'    $loader = $c00                                          'this address you can find in the datasheet
'    'the loader address is the same as the boot vector address
'    Const Maxwordbit = 5
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif

'#if Loaderchip = 168                                        'Mega168
'    $loader = $1c00                                         'this address you can find in the datasheet
'    'the loader address is the same as the boot vector address
'    Const Maxwordbit = 6
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif

'#if Loaderchip = 32                                         ' Mega32
'    $loader = $3c00                                         ' 1024 words
'    Const Maxwordbit = 6                                    'Z6 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif
'#if Loaderchip = 8                                          ' Mega8
'    $loader = $c00                                          ' 1024 words
'    Const Maxwordbit = 5                                    'Z5 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif
'#if Loaderchip = 161                                        ' Mega161
'    $loader = $1e00                                         ' 1024 words
'    Const Maxwordbit = 6                                    'Z6 is maximum bit                                   '
'#endif
'#if Loaderchip = 162                                        ' Mega162
'    $loader = $1c00                                         ' 1024 words
'    Const Maxwordbit = 6                                    'Z6 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif

'#if Loaderchip = 64                                         ' Mega64
'    $loader = $7c00                                         ' 1024 words
'    Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif

'#if Loaderchip = 128                                        ' Mega128
'    $loader = &HFC00                                        ' 1024 words
'    Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
'    Open "COM2:" For Binary As #1
'    Config Com2 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif


#if Loaderchip = 1281                                       ' Mega128
    $loader = &HFC00                                        ' 1024 words
    '$loader = &HF800                                        ' 2048 words
   Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
   Config Com2 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
   Open "COM2:" For Binary As #1
#endif


'#if Loaderchip = 2561                                       ' Mega2561
'    $loader = &H1FC00                                       ' 1024 words
'    Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif

'#if Loaderchip = 16                                         ' Mega16
'    $loader = $1c00                                         ' 1024 words
'    Const Maxwordbit = 6                                    'Z6 is maximum bit                                   '
'    Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'#endif



Const Maxword =(2 ^ Maxwordbit) * 2                         '128
Const Maxwordshift = Maxwordbit + 1
Const Cdebug = 0                                            ' leave this to 0

#if Cdebug
   Print #1 , Maxword
   Print #1 , Maxwordshift
#endif

'we use some leds as indication in this sample , you might want to remove it

Tx_d_led Alias Porte.5
Config Tx_d_led = Output                                 'Input
Set Tx_d_led                                             'Set = High

Rx_d_led Alias Porte.4
Config Rx_d_led = Output                                 'Input
Set Rx_d_led                                             'Set = High

Config Print1 = Portd.6 , Mode = Set
Coma_rts Alias Portd.6                                   'UART1 RTS
Config Coma_rts = Output                                 'Input
'Set Coma_rts                                             'Set = High
'Coma_RTS = 0




'Dim the used variables
Dim Bstatus As Byte , Bretries As Byte , Bblock As Byte , Bblocklocal As Byte
Dim Bcsum1 As Byte , Bcsum2 As Byte , Buf(128) As Byte , Csum As Byte
Dim J As Byte , Spmcrval As Byte                            ' self program command byte value

Dim Z As Long                                               'this is the Z pointer word
Dim Vl As Byte , Vh As Byte                                 ' these bytes are used for the data values
Dim Wrd As Word , Page As Word                              'these vars contain the page and word address
Dim Bkind As Byte , Bstarted As Byte
'Mega 88 : 32 words, 128 pages

Disable Interrupts                                          'we do not use ints


'Waitms 100                                                  'wait 100 msec sec
'We start with receiving a file. The PC must send this binary file

'some constants used in serial com
Const Nak = &H15
Const Ack = &H06
Const Can = &H18


$timeout = 200000                                           'we use a timeout
'When you get LOADER errors during the upload, increase the timeout value
'for example at 16 Mhz, use 200000

Bretries = 5                                                'we try 5 times
Testfor123:
#if Cdebug
    Print "Try " ; Bretries
    Print "Wait"
#endif
Bstatus = Waitkey(#1)                                       'wait for the loader to send a byte
#if Cdebug
   Print #1 , "Got "
#endif

'Waitms 1
Print #1 , Chr(bstatus);
'Waitms 3

If Bstatus = 123 Then                                       'did we received value 123 ?
   Rx_d_led = 0
   Bkind = 0                                              'normal flash loader
   Goto Loader

Elseif Bstatus = 124 Then                                   ' EEPROM
   Bkind = 1                                              ' EEPROM loader
   Goto Loader

Elseif Bstatus <> 0 Then
   Decr Bretries
   If Bretries <> 0 Then
      Goto Testfor123                  'we test again
   Else
      Close #1
   End If
End If

For J = 1 To 10                                             'this is a simple indication that we start the normal reset vector
    Toggle Tx_d_led : Waitms 50 '100
Next

#if Cdebug
     Print #1 , "RESET"
#endif
Goto _reset                                                 'goto the normal reset vector at address 0


'this is the loader routine. It is a Xmodem-checksum reception routine
Loader:
  #if Cdebug
      Print #1 , "Clear buffer"
  #endif

  Do
          Bstatus = Waitkey(#1)
  Loop Until Bstatus = 0


   For J = 1 To 4                                            'this is a simple indication that we start the normal reset vector
      Toggle Tx_d_led : Waitms 50
   Next

   If Bkind = 0 Then
          Spmcrval = 3 : Gosub Do_spm                       ' erase  the first page
          Spmcrval = 17 : Gosub Do_spm                      ' re-enable page
   End If


Bretries = 10                                               'number of retries

Do
      Bstarted = 0                                         ' we were not started yet
      Csum = 0                                             'checksum is 0 when we start
      Print #1 , Chr(nak);                                ' firt time send a nack

       Do
              Bstatus = Waitkey(#1)                         'wait for statuse byte
               Rx_d_led = 0

              Select Case Bstatus
                 Case 1:                                    ' start of heading, PC is ready to send
                      Incr Bblocklocal                      'increase local block count
                      Csum = 1                              'checksum is 1
                      Bblock = Waitkey(#1) : Csum = Csum + Bblock       'get block
                      Bcsum1 = Waitkey(#1) : Csum = Csum + Bcsum1       'get checksum first byte
                      For J = 1 To 128                      'get 128 bytes
                        Buf(j) = Waitkey(#1) : Csum = Csum + Buf(j)
                      Next
                      Bcsum2 = Waitkey(#1)                  'get second checksum byte
                      If Bblocklocal = Bblock Then          'are the blocks the same?

                         Rx_d_led = 1                        'turn off led
                         If Bcsum2 = Csum Then              'is the checksum the same?
                            Gosub Writepage                 'yes go write the page
                            Print #1 , Chr(ack);            'acknowledge
                         Else                               'no match so send nak
                            Print #1 , Chr(nak);
                         End If
                      Else
                         Print #1 , Chr(nak);               'blocks do not match
                     End If
                 Case 4:                                    ' end of transmission , file is transmitted
                       If Wrd > 0 Then                      'if there was something left in the page
                           Wrd = 0                          'Z pointer needs wrd to be 0
                           Spmcrval = 5 : Gosub Do_spm      'write page
                           Spmcrval = 17 : Gosub Do_spm     ' re-enable page
                       End If
                       Print #1 , Chr(ack);                 ' send ack and ready
                       Rx_d_led = 1                        'turn off led

                       Tx_d_led = 0                          ' simple indication that we are finished and ok
                       Waitms 20
                       Tx_d_led = 1                  'turn OFF the LED
                       Goto _reset                          ' start new program

                 Case &H18:                                 ' PC aborts transmission
                       Goto _reset                          ' ready
                 Case 123 : Exit Do                         'was probably still in the buffer
                 Case 124 : Exit Do
                 Case Else
                    Exit Do                                 ' no valid data
              End Select
       Loop

       If Bretries > 0 Then                                 'attempte left?
               Waitms 1000
               Decr Bretries                                'decrease attempts
       Else
               Goto _reset                                  'reset chip
       End If
Loop



'write one or more pages
Writepage:
 If Bkind = 0 Then
   For J = 1 To 128 Step 2                                  'we write 2 bytes into a page
      Vl = Buf(j) : Vh = Buf(j + 1)                         'get Low and High bytes
      lds r0, {vl}                                          'store them into r0 and r1 registers
      lds r1, {vh}
      Spmcrval = 1 : Gosub Do_spm                           'write value into page at word address
      Wrd = Wrd + 2                                         ' word address increases with 2 because LS bit of Z is not used
      If Wrd = Maxword Then                                 ' page is full
          Wrd = 0                                           'Z pointer needs wrd to be 0
          Spmcrval = 5 : Gosub Do_spm                       'write page
          Spmcrval = 17 : Gosub Do_spm                      ' re-enable page

          Page = Page + 1                                   'next page
          Spmcrval = 3 : Gosub Do_spm                       ' erase  next page
          Spmcrval = 17 : Gosub Do_spm                      ' re-enable page
      End If
   Next

 Else                                                       'eeprom
     For J = 1 To 128
       Writeeeprom Buf(j) , Wrd
       Wrd = Wrd + 1
     Next
 End If
' Toggle Portb.2 : Waitms 10 : Toggle Portb.2                'indication that we write
Return


Do_spm:
  Bitwait Spmcsr.0 , Reset                                  ' check for previous SPM complete
  Bitwait Eecr.1 , Reset                                    'wait for eeprom

  Z = Page                                                  'make equal to page
  Shift Z , Left , Maxwordshift                             'shift to proper place
  Z = Z + Wrd                                               'add word
  lds r30,{Z}
  lds r31,{Z+1}

  #if(loaderchip = 128) Or(loaderchip = 2561)
      lds r24,{Z+2}
      sts rampz,r24                                         ' we need to set rampz also for the M128
  #endif

  Spmcsr = Spmcrval                                         'assign register
  spm                                                       'this is an asm instruction
  nop
  nop
Return


'How you need to use this program:
'1- compile this program
'2- program into chip with sample elctronics programmer
'3- select MCS Bootloader from programmers
'4- compile a new program for example M88.bas
'5- press F4 and reset your micro
' the program will now be uploaded into the chip with Xmodem Checksum
' you can write your own loader.too
'A stand alone command line loader is also available


'How to call the bootloader from your program without a reset ???
'Do
'   Print "test"
'   Waitms 1000
'   If Inkey() = 27 Then
'      Print "boot"
'      Goto &H1C00
'   End If
'Loop

'The GOTO will do the work, you need to specify the correct bootloader address
'this is the same as the $LOADER statement
 


Thanks again for your responses and help.
Tim
Back to top
View user's profile
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Thu Aug 06, 2015 7:48 pm    Post subject: Reply with quote

MWS,

Quote:
A first test is to have the bootloader upload the application code and after uncheck BOOTRST.
If your application works after re-powering, you have a reset issue, if it still does not work, the bootloader did not correctly load up the application code.


The application did NOT work following your proposed procedure. But again, the bootloader did not throw any errors either.

Any other ideas?
Thanks,

Tim
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 2262

blank.gif
PostPosted: Thu Aug 06, 2015 8:02 pm    Post subject: Reply with quote

TSEYFARTH wrote:
It is modified to the extent that the M1281 was added, and the Baud rate was changed to 9600.

Assumed only these two mods, I was not able to match any of the Bascom sample bootloader codes to your code. Where you did derive the modified code from?
It would have been helpful, if you would have left a reference to the original code in the header.
Quote:
The application did NOT work following your proposed procedure. But again, the bootloader did not throw any errors either.

Then your bootloader code is faulty, doesn't matter if it reports errors or not.
Sending back some ACK or ERR bytes over the serial is one thing, correctly writing the flash another.
As your test did prove, the latter doesn't work.
Disabling the BOOTRST fuse sets the bootloader out of bussiness, if the bootloader would have previously loaded a valid application into the flash, the application would have been started from the reset vector &h0000.
As this does not work, the bootloader did not load a valid application.
Back to top
View user's profile
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Thu Aug 06, 2015 8:44 pm    Post subject: Reply with quote

MWS,

Agreed - it does not work... I got it from the samples. Maybe the problem lies with using COM2 instead of COM1. Will have another look.

Thank you,
Tim
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 2262

blank.gif
PostPosted: Thu Aug 06, 2015 9:10 pm    Post subject: Reply with quote

TSEYFARTH wrote:
Agreed - it does not work...

Sure enough. But one has to find the reason.
Do you need this Com1/2 stuff?
I'd do a restart, use a proven working bootloader sample and set it up for the 1281.
For double checking: is the app working on the 1281, if flashed via ISP?
Back to top
View user's profile
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Thu Aug 06, 2015 9:24 pm    Post subject: Reply with quote

I MWS,

Yes, I need it to work on COM2. That is the com port that connects to the PC.

The app works perfectly when programmed with an AVRMKII.

The bootloader came from the MCS samples.

Am reviewing it again.
Tim
Back to top
View user's profile
TSEYFARTH

Bascom Member



Joined: 01 Jul 2006
Posts: 1054

usa.gif
PostPosted: Thu Aug 06, 2015 9:34 pm    Post subject: Reply with quote

Found it... I think.

Your statement of

Quote:

Disabling the BOOTRST fuse sets the bootloader out of bussiness, if the bootloader would have previously loaded a valid application into the flash, the application would have been started from the reset vector &h0000.
As this does not work, the bootloader did not load a valid application.


led me to look at that part of the bootloader app.

The original had this:
Code:

  #if(loaderchip = 128) Or (loaderchip = 2561)
      lds r24,{Z+2}
      sts rampz,r24                                         ' we need to set rampz also for the M128
  #endif

 


I changed it to this:
Code:

  #if(loaderchip = 128) Or (loaderchip = 2561)  Or (loaderchip = 1281)
      lds r24,{Z+2}
      sts rampz,r24                                         ' we need to set rampz also for the M128
  #endif
 


Now it works. Confused

I did also notice that the code in the Help did not have this part at all. Instead it has this:
Code:

#if _romsize > 65536
    lds r24,{Z+2}
    sts rampz,r24                                         ' we need to set rampz also for the M128
#endif
 


Maybe the help is even newer than the samples. If so, and the help code works, that would be better since it is more generic.

Thoughts?

Tim
Back to top
View user's profile
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 971

poland.gif
PostPosted: Thu Aug 06, 2015 9:48 pm    Post subject: Reply with quote

Also please look that Sample Code configure pins.

Code:
'we use some leds as indication in this sample , you might want to remove it

Tx_d_led Alias Porte.5
Config Tx_d_led = Output                                 'Input
Set Tx_d_led                                             'Set = High

Rx_d_led Alias Porte.4
Config Rx_d_led = Output                                 'Input
Set Rx_d_led                                             'Set = High

Config Print1 = Portd.6 , Mode = Set
Coma_rts Alias Portd.6                                   'UART1 RTS
Config Coma_rts = Output                                 'Input
'Set Coma_rts                                             'Set = High
'Coma_RTS = 0


State of microcontroller AFTER BOOTLOADER IS NOT STATE AFTER RESET.
So I must once use option "Init LCD".. It depends pins You use
Back to top
View user's profile Visit poster's website
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 2262

blank.gif
PostPosted: Thu Aug 06, 2015 9:53 pm    Post subject: Reply with quote

That's why I've asked for the origin of the bootloader, saw no sense of looking through the bootloader code, without knowing its origin. I'd say the latter block for setting RAMPZ is more universal, as it gets _romsize from the dat-file, so no extra inclusion of the chip in question is necessary.
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR All times are GMT + 1 Hour
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
You cannot attach files in this forum
You cannot download files in this forum