+ Reply to Thread
Results 1 to 24 of 24
  1. #1
    Join Date
    Feb 2013
    Posts
    545

    Default Is it possible to make LCDOUT asynchronous?

    There is tight main loop, which should not be interrupted. But there is also need to update 1602 LCD at specified moments of time. LCDOUT statement is very slow and nothing can be done while it is running. So is there a way to make it less time consuming? I've seen a lot of serial adapters for it, will they do the trick?

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,259

    Default Re: Is it possible to make LCDOUT asynchronous?

    It's not really the LCDOUT command that is "slow" but the HD44780 controller, not so much for data but quite so when sending commands and the timing requirement can differ quite a bit between manufacturers of "compatible" chipsets.

    What you have to do is determine how much time you have available for servicing the LCD each time thru the main loop and then only write as many bytes as you have time for during that period. Load an array with the data that should be written to the LCD (like a screen buffer) and index thru that array 2,3,4, whatever number of bytes per pass thru the main loop. You might look at the byte to be sent and determine if it's a command and then exit after just that byte while, if it's data, you might have time for 5-10 bytes.

    OR, if a lot of info on the display is static, make sure you only update what's actually changes instead of the whole display.

    Serial backbacks with buffers might exist, I don't know.

  3. #3
    Join Date
    Apr 2014
    Location
    Northeast
    Posts
    307

    Default Re: Is it possible to make LCDOUT asynchronous?

    I remember several years ago I was feeling quite confident with my PBP skills. I ran into an issue where the PBP command set was inadequate for my needs, sort of like LCDOUT is for you right now. The data sheets were telling me how the hardware functions worked, but it would take extra effort on my part to learn how to use them without the convenient PBP commands. Out of necessity, I started learning how to manipulate timers, interrupts, UART, ADC, and many other magnificent features, all within the confines of the PBP language.

    CuriousOne, in a different post I made a suggestion involving an interrupt. You said it would be too hard. However, you live up to your username and are trying your best to create new projects. Perhaps learning how to use the PIC peripherals may start serving you well as you try more complex things.

    As for this post, the PIC18FxxK42 platform has a feature called DMA that would allow you to shuffle out data to your LCD in hardware, or through interrupt routines. New things aren't "hard", you just haven't taken the time to learn them yet. Just a thought.
    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.

  4. #4
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    2,909

    Default Re: Is it possible to make LCDOUT asynchronous?

    You have to change your way of thinking.

    Give the timer example I posted on the other thread a chance and walk your way from there.

    What you ask for is time sharing and the best candidate is Interrupts.

    The second best is Finite States but I am not very fond of it. Have a look here http://emesystems.com/OLDSITE/BS2fsm.htm

    Ioannis
    Last edited by Ioannis; - 2nd August 2019 at 21:29.

  5. #5
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,259

    Default Re: Is it possible to make LCDOUT asynchronous?

    CuriousOne,
    There are likely several ways this can be handled but we know WAY to little about your code.

    * How often or fast does your main loop have to run?
    * How often does the LCD need to update? Is it "randomly" but not more often than once per second or is it more like a stopwatch where you want updates every 10ms?
    * Do you have any PAUSE statements in the Main loop and if so how many and how long are they?

    Perhaps you can attack the problem from another angle, like utilize the available hardware peripherals for the time critical stuff (if that's even possible, I don't know what your code does...) and use LCDOUT as normal. Or, as I suggested earlier, update the display in chunks of as many bytes as you have time for each pass thru the main loop. I churneds out a proof-of-concept but really, without more detailed requirements about timings etc all we can do is offer general advice like what you've received.

    /Henrik.

  6. #6
    Join Date
    Feb 2013
    Posts
    545

    Default Re: Is it possible to make LCDOUT asynchronous?

    Main loop generates pulses for two stepper motors control and their frequency can reach 2-3khz. Any disruption in speed should be avoided, since these motors drive camera slider and any speed change will be noticeable on video. LCD is used to display current position, update speed of 1fps will be fine.

    There are no pauses inside the loop, in fact, it looks like this (simplified here, I've skipped some code for simplicity)

    Code:
    mainloop:
    I=I+1
    if I>count then goto MENUSET 'count is variable calculated from longest path, i.e. if X axis travel is longer, it will be taken from it, if Y is longer - then from Y.
    IF I // XSTEP = 0 THEN GOSUB XPULSE 'give pulse to  X stepper, so it moves according to required speed
    IF I // YSTEP =0 THEN GOSUB YPULSE 'same for Y axis
    ADCREAD: 'read current position on both axis
    CPOINT:  'checks ADC readings and determines whenever control points were reached and there's time to stop, or to change STEP variable values or direction, etc.
    INTERACT: 'check buttons for user input, like stopping action, increasing speed, etc.
    LCDSHOW: 'display current speed, position, track being read.
    goto mainloop
    Regarding the hardware use, I wanted to use HPWM, but it can't go too low, and I need frequency in 30Hz-3Khz range.
    Another solution is to replace LCD with MAX7219 module, which can work much faster, but the drawback is, it is hard to display text on 7 segment display. Currently I'm using PIC16F886 at 8 mhz.

    For the interrupts and DMA, I have general knowledge what these are and how they do work In fact, I used to code a lot of Z80 ASM in 80s, on ZX Spectrum But things on Spectrum were really simpler compared to PIC

  7. #7
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    using a different display may help, but your snippets tell nothing at all about timing.

    using my code and a frame buffer i can refresh an entire nokia lcd in less time than a 1602 lcd takes to home the cursor
    its < 1.3 mS (1.298 on the salea), such a scheme can allow interleaved screen writes and background refreshing

    but there is no substitute to
    1 identifying tasks
    2 timing tasks
    3 prioritising and sequencing tasks to achieve result
    This is more entertaining than Free to Air TV

  8. #8
    Join Date
    Sep 2009
    Posts
    769

    Default Re: Is it possible to make LCDOUT asynchronous?

    LCDOUT can be quick. If you just update values that was changed, not whole display.

  9. #9
    Join Date
    Feb 2013
    Posts
    545

    Default Re: Is it possible to make LCDOUT asynchronous?

    Well I thought I outlined it straight.

    There are two pulses, each is 5 microseconds, generated during one turnaround of the loop. The loop is slowed according to requirements, however, shortest and maintainable loop turnaround is 300 microseconds, which can be extended to 30 milliseconds.

  10. #10
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    Well I thought I outlined it straight.
    outlined what

    IF I // XSTEP = 0 THEN GOSUB XPULSE 'give pulse to X stepper, so it moves according to required speed
    takes ? uS



    IF I // YSTEP =0 THEN GOSUB YPULSE 'same for Y axis
    takes ? uS


    ADCREAD: 'read current position on both axis
    takes ? uS


    CPOINT: 'checks ADC readings and determines whenever control points were reached and there's time to stop, or to change STEP variable values or direction, etc.
    takes ? uS
    INTERACT: check buttons for user input, like stopping action, increasing speed, etc.
    takes ? uS
    LCDSHOW: 'display current speed, position, track being read.
    takes ? mS displays what where ?

    shortest and maintainable loop turnaround is 300 microseconds
    which is not enough time for 1 lcdcmd
    This is more entertaining than Free to Air TV

  11. #11
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,259

    Default Re: Is it possible to make LCDOUT asynchronous?

    Right, good thing I didn't spend too much time on my example because if you can't allow more than 300us it wouldn't work anyway.

    Three alternatives (not the ONLY three of course):

    1) Use timer interrupt(s) to create the pulses. Update the LCD using LCDOUT in the main loop.

    2) Ditch LCDOUT with its blocking timing and instead write to it "manually" and use the main loop as the timebase for the needed delays.

    3) Switch to a display with a serial interface, use the UART or MSSP peripheral and hit the display with one byte per pass thru the main loop. Obviously you can't have the main loop take 300ms so you can't have any blocking delays in there and, depending on if there's a buffer in the LCD or not, you may have to consider what to do when the byte you're sending requires longer processing time (clear screen etc) than what it takes before the next byte is sent. If the selected baudrate is kept low(ish) that might not be a problem.

    /Henrik.

  12. #12
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    perhaps if in this thread
    http://www.picbasic.co.uk/forum/show...ht=#post146121
    you explained it was for driving steppers at speed somebody would have pointed out that
    Bresenham's line algorithm could do the job at least 20 times faster without any nasty time consuming
    divides and multiplies once the move is "planned"

    @8mhz this loop
    Code:
    mainloop:
    led=!led
    if I>counter then goto MENUSET 'count is variable calculated from longest path, i.e. if X axis travel is longer, it will be taken from it, if Y is longer - then from Y.
    
    I=I+1
    IF I // XSTEP = 0 THEN GOSUB XPULSE 'give pulse to  X stepper, so it moves according to required speed
    IF I // YSTEP = 0 THEN GOSUB YPULSE 'same for Y axis
    
    
    goto mainloop
    alone takes over 300uS

    this little C prog executes the run loop in about 5uS / easily adaptable to pbp

    Code:
    #include "mcc_generated_files/mcc.h"
    void mydel(int d);
    char plan_move(int x0, int x1, int y0, int y1);
    char move(void);
    int speed;
    int stepsX, stepsY, dx, dy, D;
    char f;
    
    /*
                             Main application
     */
    void main(void) {
        // initialize the device
        int x0 = 55, x1 = 0, y1 = 147, y0 = 0, del;
        char running;
        speed = 3300; //steps/sec
        SYSTEM_Initialize();
        del = 200000l / speed;
        while (1) {
            running = plan_move(x0, x1, y0, y1);
            while (running) {
                led_SetHigh();     // the runloop
                running = move();
                led_SetLow();
                mydel(del - 6);  //we delay about 295uS here to slow to 3300 steps per sec
            }
            __delay_ms(1000);
        }
    }
    
    void mydel(int d) {
        while (d--) {
            __delay_us(5);
        }
    }
    
    char move() {
        if (f) {
            if (stepsY--) {
                Yout_SetHigh();
                asm("NOP");
                Yout_SetLow();
                if (D > 0) {
                    if (stepsX){
                    stepsX--;
                    Xout_SetHigh();
                    asm("NOP");
                    Xout_SetLow();
                    }
                    D = D - dx;
                }
                D = D + dy;
                return 1;
            }
        } else {
            if (stepsX--) {
                Xout_SetHigh();
                asm("NOP");
                Xout_SetLow();
                if (D > 0) {
                    if (stepsY){
                    stepsY--;
                    Yout_SetHigh();
                    asm("NOP");
                    Yout_SetLow();
                    }
                    D = D - dx;
                }
                D = D + dy;
                return 1;
            }
        }
        return 0;
    }
    
    char plan_move(int x0, int x1, int y0, int y1) {
        stepsX = x1 - x0;
        stepsY = y1 - y0;
    
        if (stepsX < 0) {
            stepsX = ~stepsX + 1;
            //dirX=1;
        }
        if (stepsY < 0) {
            stepsY = ~stepsY + 1;
            //dirY=1;
        }
        if (stepsX + stepsY) {
            if (stepsX > stepsY) {
                D = stepsY * 2 - stepsX;
                dx = stepsX * 2;
                dy = stepsY * 2;
                f = 0;
            } else {
                D = stepsX * 2 - stepsY;
                dy = stepsX * 2;
                dx = stepsY * 2;
                f = 1;
            }
            return 1;
        }
        return 0;
    }
    This is more entertaining than Free to Air TV

  13. #13
    Join Date
    Feb 2013
    Posts
    545

    Default Re: Is it possible to make LCDOUT asynchronous?

    Thanks a lot, but I don't know C syntax and all these different brackets make code unreadable for me.

  14. #14
    Join Date
    Apr 2014
    Location
    Northeast
    Posts
    307

    Default Re: Is it possible to make LCDOUT asynchronous?

    In C, most every line of code is terminated with a semicolon( ; ). Clauses are grouped between curly brackets ({ }) Let's look at one of the clauses:
    Code:
    while (running) {
                led_SetHigh();     // the runloop
                running = move();
                led_SetLow();
                mydel(del - 6);  //we delay about 295uS here to slow to 3300 steps per sec
            }
    Starting with the first line, "while (running) {":
    - "while" is similar to PBP's DO/WHILE commands. So, the above = "DO WHILE running = 1". In PBP, you have IF/ENDIF, DO/WHILE, etc where at the top of the clause is a DO/IF or whatever. At the end of the clause is "ENDIF/WHILE" or something like that. In C, the clause is started with "{" and ended with "}" (an end bracket). You'll notice the 6th line is "}".

    The second line: "led_SetHigh(); // the runloop":
    - "led_SetHigh();" is the same as "GOSUB led_SetHigh". Again, this line of code is terminated with a " ; ". The double parentheses "()" denote a function (in C, subroutine in PBP). The double slashes "//" is how you denote comments in C. In PBP you typically use the hyphen (') or semicolon ( ; ). In ASM you use the semicolon ( ; ) to denote start of comments.

    Third line: "running = move();"
    - This one is a bit different than PBP Basic. There is a "subroutine" called "move". In "move" some calculations or Boolean logic would be performed that nets a result. The result is then put into the variable "running". With PBP, if you declare a variable "running VAR BYTE" then call a subroutine called "move", the desired result should be calculate and put into the variable "running".

    The next line, "led_SetLow();" is pretty much the same as PBP "GOSUB led_SetLow".

    The last line (not counting the end bracket): "mydel(del - 6); //we delay about 295uS here to slow to 3300 steps per sec"
    - [Bear with me as there is no correlation in PBP]
    - "mydel" is a subroutine (as denoted by the double parentheses). In C, you can use a generic variable without declaring it. In the above line of C code, "(del-6)" is such a case. In PBP you might declare "del1 VAR BYTE" and do something like this:
    Code:
    del1 = del - 6
    GOSUB mydel
    I know this is far more confusing than some of the proficient "C" programmers would have a PBP guy to believe, but I hope it helps.
    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.

  15. #15
    Join Date
    Sep 2009
    Posts
    769

    Default Re: Is it possible to make LCDOUT asynchronous?

    Actually you don't need C. Just google Bresenham's line algorithm...
    https://en.wikipedia.org/wiki/Bresen...line_algorithm
    Also I want to point that you do stuff totally opposite as it should be done.
    Timing critical stuff should be interrupt driven, using timer. Speed is easily adjustable, just set different preload to timer.
    Display stuff, user input etc should be free running in main code.

  16. #16

    Default Re: Is it possible to make LCDOUT asynchronous?

    Bear in mind there is no point in updating the LCD faster than the brain can grasp, do a double buffer. In one buffer you have an image of what the LCD looks like now, you write to the other buffer (in the appropriate position). Either by utilizing spare time or by timer cyclically compare input buffer with image buffer and if they are different write to LCD (directly, not using Picbasic commands which I assume have builtin delays).
    George

  17. #17
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    Also I want to point that you do stuff totally opposite as it should be done.
    Timing critical stuff should be interrupt driven, using timer. Speed is easily adjustable, just set different preload to timer.
    Display stuff, user input etc should be free running in main code.
    i agree but to match this you need asm isr in pbp, dt ints would slow it bigtime
    code here steps at 40 to 3333 steps/sec with disp @10mS
    osc timebase 50uS/div
    Name:  STEPS.jpg
Views: 47
Size:  387.7 KB
    Code:
    #include "mcc_generated_files/mcc.h"
    #include <stdlib.h>
    #include "lcd.h"
    char *itoa(int value);
    char plan_move(int x0, int x1, int y0, int y1);
    void move(void);
    int speed; //40 to 3333 sps
    int stepsX, stepsY, dx, dy, D;
    char running, f;
    volatile int x, y;
    
    /*
                             Main application
     */
    void main(void) {
        // initialize the device
        int x1 = 553, x0 = 0, y1 = 1407, y0 = 0;
        speed = 3000; //steps/sec
        SYSTEM_Initialize();
        TMR4_SetInterruptHandler(move);
        INTERRUPT_GlobalInterruptEnable();
        INTERRUPT_PeripheralInterruptEnable();
        lcd_init();
        PR4 = 10000 / speed;
        lcd_goto(1, 0);
        lcd_puts("Speed ");
        lcd_puts(itoa(speed));
        while (1) {
            rst_Toggle(); //DEBUG RESET  COUNTERS
            rst_Toggle(); //DEBUG RESET  COUNTERS
            x = x0;//SET START CONDITIONS
            y = y0;
            lcd_goto(2, 0);
            lcd_puts("X ");
            lcd_goto(2, 8);
            lcd_puts("Y ");
            running = plan_move(x0, x1, y0, y1);
            TMR4_StartTimer(); //ENGAGE ISR
            while (running) {
                lcd_goto(2, 1);
                lcd_puts(itoa(x));
                lcd_goto(2, 9);
                lcd_puts(itoa(y));
                __delay_ms(10);
            }
            lcd_goto(2, 1);
            lcd_puts(itoa(x));
            lcd_goto(2, 9);
            lcd_puts(itoa(y));
            __delay_ms(1000);
        }
    }
    
    
    void move() {
        led_SetHigh(); //DEBUG TIME ISR
        if (f) {
            if (stepsY--) {
                Yout_SetHigh();
                asm("NOP");
                Yout_SetLow();
                y++;
                if (D > 0) {
                    if (stepsX) {
                        stepsX--;
                        Xout_SetHigh();
                        asm("NOP");
                        Xout_SetLow();
                        x++;
                    }
                    D = D - dx;
                }
                D = D + dy;
                led_SetLow(); //DEBUG TIME ISR
                return;
            }
        } else {
            if (stepsX--) {
                Xout_SetHigh();
                asm("NOP");
                Xout_SetLow();
                x++;
                if (D > 0) {
                    if (stepsY) {
                        stepsY--;
                        Yout_SetHigh();
                        asm("NOP");
                        Yout_SetLow();
                        y++;
                    }
                    D = D - dx;
                }
                D = D + dy;
                led_SetLow(); //DEBUG TIME ISR
                return;
            }
        }
        running = 0;
        TMR4_StopTimer();
        led_SetLow();
    }
    
    char plan_move(int x0, int x1, int y0, int y1) {
        stepsX = x1 - x0;
        stepsY = y1 - y0;
        if (stepsX < 0) {
            stepsX = ~stepsX + 1;
            //dirX=1;
        }
        if (stepsY < 0) {
            stepsY = ~stepsY + 1;
            //dirY=1;
        }
        if (stepsX + stepsY) {
            if (stepsX > stepsY) {
                D = stepsY * 2 - stepsX;
                dx = stepsX * 2;
                dy = stepsY * 2;
                f = 0;
            } else {
                D = stepsX * 2 - stepsY;
                dy = stepsX * 2;
                dx = stepsY * 2;
                f = 1;
            }
            return 1;
        }
        return 0;
    }
    
    char *itoa(int value) {//CUSTOM FIXED LENGTH OF 4DIG + SIGN
        static char buffer[6]; // 7 bytes is REALLY  NEEDED for an INT 
        int original = value; // save original value
        int c = sizeof (buffer) - 1;
        buffer[c] = 0; // write trailing null in last byte of buffer 
        if (value < 0) // if it's negative, note that and take the absolute value
            value = -value;
        do // write least significant digit of value that's left
        {
            buffer[--c] = (value % 10) + '0';
            value /= 10;
        } while (value);
        if (original < 0)
            buffer[--c] = '-';
        while (c)//fixed width
            buffer[--c] = 0x20;
        return buffer;
    }
    This is more entertaining than Free to Air TV

  18. #18
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    I just tried it in pbp using pbp dt ints , its much better than i thought it would be.
    with few tweaks its a match if not a little better
    since pbp doesn't do signed int math not sure how it will go with overflows


    isr

    Code:
    move:
        led=1
        if f then
            if (stepsY) then
                stepsY=stepsY-1
                youtp=1
                @ NOP  
                youtp=0
                y=y+1
                 if (D.15==0) then
                    if (stepsX)then
                    stepsX=stepsX-1
                    Xoutp=1
                    @ NOP 
                    Xoutp=0
                    x=x+1
                    endif
                    D = D - dx;
                endif
                D = D + dy
                led=0
             @   INT_RETURN
            endif
         else 
            if (stepsX) then
                stepsx=stepsx-1
                xoutp=1
                @ NOP 
                xoutp=0
                x=x+1
                if (D.15 ==0) then
                    if (stepsY)then
                    stepsY = stepsY-1
                    Youtp=1 
                    @ NOP 
                    Youtp=0
                    y=y+1
                    endif
                D = D - dx;
                endif
                D = D + dy;
                led=0
            @    INT_RETURN
            endif
        endif
        T4CON.2=0
        running = 0
        led=0
    @ INT_RETURN
    This is more entertaining than Free to Air TV

  19. #19
    Join Date
    Sep 2009
    Posts
    769

    Default Re: Is it possible to make LCDOUT asynchronous?

    I'm really glad that you tried it. I didn't have time to do it, but wanted...
    I don't know why everyone assumes always that PBP is slower than C. In my experience it was opposite.
    Speed of DT int depends on how much internal variables is used. If you have complicated condition for IF, While etc it will use bunch.
    But if you keep it simple, as you should, it will use none.

  20. #20
    Join Date
    May 2013
    Location
    australia
    Posts
    1,715

    Default Re: Is it possible to make LCDOUT asynchronous?

    I just tried it in pbp using pbp dt ints , its much better than i thought it would be.
    with few tweaks its a match if not a little better
    oops forgot to add reenterpbp into the timing , it 9 uS C to 30uS pbp , still not too shabby

  21. #21
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,259

    Default Re: Is it possible to make LCDOUT asynchronous?

    But if you keep it simple, as you should, it will use none.
    Unfortunately DT-Ints will always save all the "default" system variables. There are some additional variables that gets defined only when needed and they are only saved (obviously) if they are indeed defined (by the compiler that is). Unfortunately (again) it has nothing to do with which or how many variables the code in the actual ISR uses.

    I've been toying with the idea of writing some sort of "code analyzer" where you could compile your ISR alone and it would tell you which system vars it's actually using, then you could save/restore those variables and those variables only. But I don't think my PC programming skills are up to it to be honest.

  22. #22
    Join Date
    Sep 2009
    Posts
    769

    Default Re: Is it possible to make LCDOUT asynchronous?

    This is off topic, but...
    Default vars are must to save. Because those are internal PBP vars inside compiler subroutines.
    That what you want is great, but require too much work if you ask me.
    You will need to find every call and jump in your ISR, then follow every possible call/jump from other routines.
    I use 99,9% ASM interrupt, and leave PBP outside...
    This give me very efficient code where it is count, especially for battery powered devices. And fast developing main stuff.

  23. #23
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,259

    Default Re: Is it possible to make LCDOUT asynchronous?

    Exactly. I've done it manually a couple of times but it's tedious and prone to errors and you have to redo it whenever you change the ISR...
    Good for you that you're that good at ASM, I bought PBP because I'm not :-)

  24. #24
    Join Date
    Sep 2009
    Posts
    769

    Default Re: Is it possible to make LCDOUT asynchronous?

    I'm not that good in asm. But You can always look at disassembly window in MPLAB X to see how PBP compiler done it.
    Also Step by step debugging helps a lot.

Similar Threads

  1. Replies: 3
    Last Post: - 15th September 2015, 01:36
  2. Replies: 7
    Last Post: - 6th February 2008, 05:38
  3. 8bit LCDout vs 4bit LCDout
    By keithdoxey in forum mel PIC BASIC Pro
    Replies: 2
    Last Post: - 24th May 2006, 12:16
  4. Asynchronous counter mode on TMR1
    By micro in forum General
    Replies: 1
    Last Post: - 8th April 2006, 15:42
  5. Replies: 3
    Last Post: - 23rd February 2005, 17:59

Members who have read this thread : 16

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts