Shop OBEX P1 Docs P2 Docs Learn Events
Help Accessing Single LCD with multiple Cogs — Parallax Forums

Help Accessing Single LCD with multiple Cogs

jaws369jaws369 Posts: 6
edited 2014-11-14 12:08 in Propeller 1
I have been reading the forum and manual for about 5 hours trying to get a few cogs to run some simple code and each control a line in a 4x20 LCD. However, I have found I cannot seem to do it. I can get 1 line to work, but never more than that. I have simplified the code down for easy reading. Could someone please review it and let me know where I am going wrong. LINE 1 is Main Cog, Line 2 - 3 are the other cogs launched that just make some timing up and increment an integer.
{Object_LCDTest.spin}

CON
        _clkmode = xtal1 + pll16x   'Standard clock mode * crystal frequency = 80 MHz
        _xinfreq = 5_000_000
        LCD_Baud   = 19_200    ' LCD Baud Rate
        LCD_Lines  = 4         ' Parallax 4X20 Serial LCD (#27979) 
        LCD_Pin    = 0
VAR
  long  LockNum
  long  cog1
  long  cog2
  long  cog3
  long  StackSp1[20]
  long  StackSp2[20]
  long  StackSp3[20]
 
OBJ
  LCD       : "debug_lcd"
PUB Main | x, Success
  lcd.init(LCD_Pin, LCD_Baud, LCD_Lines)
  lcd.backlight(1)
  lcd.cls
  lcd.str(string("Starting Test"))
  waitcnt(clkfreq + cnt)
  lcd.cls
  
  lcd.gotoxy(0,0)
  lcd.str(String("COG 1:"))
  lcd.gotoxy(8, 0)
  lcd.str(string("Get Lock"))
  ' Setup and Sign out a new LOCK ID....
  LockNum := locknew
  waitcnt(clkfreq + cnt)
  
  lcd.gotoxy(8, 0)
  lcd.str(string("Locked         "))
  lcd.gotoxy(15, 0)
  lcd.dec(LockNum)
  waitcnt(clkfreq / 2 + cnt)
  ' *************  START THE NEW COGS FOR LCD TESTING  **********
 
  cog1 := Cognew(LCDTest(1, @LockNum), @StackSp1)
  cog2 := Cognew(LCDTest(2, @LockNum), @StackSp2)
 
  cog3 := Cognew(LCDTest(3, @LockNum), @StackSp3)  

  repeat
    x++
    repeat until not lockset(LockNum) 'wait until we lock the resource 
    lcd.gotoxy(18, 0)
    lcd.dec(x)
    lockclr(LockNum) 'unlock the resource
    waitcnt(clkfreq / 5 + cnt)
    if x == 50
      x :=0  
 
PRI LCDTest(LCDBase, _LockNum) | x
  x := 0
  lcd.init(LCD_Pin, LCD_Baud, LCD_Lines) 
  repeat until not lockset(long[_LockNum] -1)
  lcd.gotoxy(0,LCDBase)
  lcd.str(String("Start Cog "))
  lcd.dec(LCDBase)
  lockclr(long[_LockNum] -1)
  waitcnt(clkfreq / 2 + cnt)
  
  repeat
    x++ 
    repeat until not lockset(long[_LockNum] -1)
    lcd.gotoxy(18, LCDBase)
    lcd.dec(x)
    lockclr(long[_LockNum] -1) 'unlock the resource 
    waitcnt(clkfreq / LCDBase + cnt)
    if x == 300
      x :=0

Thanks so much for anyone that can spot the error of my ways with Locks.
Sean

Comments

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-11-13 21:19
    I had a similar need so all I did was write a simple access method where the cogs would write to a hub variable if it was non-zero, or else wait. The LCD cog would just sit in a loop checking that hub variable and read it as if it were a character or control code then zero the hub variable. Since my LCD driver is designed for I/O streams this is easy to do but many objects require you to call the various methods however your polling loop can still implement a control character detection scheme to call these various methods. For instance to clear the screen I write a $0C and of course $0D returns to the left of the current line, $0A feeds down one line etc.

    Alternatively you could just have all access to the very lowest I/O level stuff doing something similar. You could have two registers, data and control, except they are hub variables. You write what you want to them and the cog dedicated to the LCD I/O can read them and perform the low-level I/O write. Also there is never any need to read the busy flag, never, so simplify the code and cut it out, the Prop I/O and Spin are never faster then the LCD. Just observe the delays during initialization, that's all.
  • T ChapT Chap Posts: 4,223
    edited 2014-11-14 04:27
    The stack size may be small?

    Can you test this.
    VAR
       Byte  LCDlock
    OBJ
         ser          :"FullDuplexSerial4Port"
    
    
    PUB Testline0    'from cog 0
            Repeat while LCDlock == 1
            LCDlock := 1
            Go(0,0)
            ser.str(3, string("Line0"))
           ' Go(1,0)
           ' ser.str(3, string("Line1"))    
            LCDlock~
    
    PUB Testline1    'from cog 1
            Repeat while LCDlock == 1
            LCDlock := 1
            'Go(0,0)
           ' ser.str(3, string("Line0"))
            Go(1,0)
            ser.str(3, string("Line1"))    
            LCDlock~ 
    
    
    PUB go(line,col) | lcdline
        if line == 0
          lcdline := $80  'verify this for the 4 line LCD,  it works on 2 line for sure
        elseif line == 1
          lcdline := $94   'verify
        ser.putc(3,lcdline + col)
    PUB StartSerial   '(port,rxpin,txpin,ctspin,rtspin,rtsthreshold,mode,baudrate)
         Ser.init
         ser.addport(3, -1, 7, -1, -1, 0,0, 19200) 'LCD display  this has pin 7 set,   change for your LCD
         Ser.Start
    
    
    
  • ValeTValeT Posts: 308
    edited 2014-11-14 05:30
    I had a similar need so all I did was write a simple access method where the cogs would write to a hub variable if it was non-zero, or else wait. The LCD cog would just sit in a loop checking that hub variable and read it as if it were a character or control code then zero the hub variable. Since my LCD driver is designed for I/O streams this is easy to do but many objects require you to call the various methods however your polling loop can still implement a control character detection scheme to call these various methods. For instance to clear the screen I write a $0C and of course $0D returns to the left of the current line, $0A feeds down one line etc.

    Alternatively you could just have all access to the very lowest I/O level stuff doing something similar. You could have two registers, data and control, except they are hub variables. You write what you want to them and the cog dedicated to the LCD I/O can read them and perform the low-level I/O write. Also there is never any need to read the busy flag, never, so simplify the code and cut it out, the Prop I/O and Spin are never faster then the LCD. Just observe the delays during initialization, that's all.

    I have also been wondering about this. Thanks for a solution!
  • dbpagedbpage Posts: 217
    edited 2014-11-14 07:16
    Try using lockset/lockclr instead, to set and clear the semaphores in one hub operation.. You can expect continued difficulty using your existing lock code.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-11-14 07:40
    dbpage wrote: »
    Try using lockset/lockclr instead, to set and clear the semaphores in one hub operation.. You can expect continued difficulty using your existing lock code.

    This is simply a matter of each cog having it's own direction and output registers which is always a problem when trying to access the same I/O from different cogs as they end up as 8 sets of outputs being OR'ed together. If cog 4 had set the I/O high then there is nothing another cog can do to bring it low. But you can have pullups on the pins to keep them high and let each cog release the "high" level once it's done but this doesn't stop more than one cog trying to access it at the same time. The second method is simply to have a cog handle this I/O (and maybe others) and pass "commands" to the cog to do the work for you. In the case of an LCD you can pass characters and commands without touching any I/O but which the LCD cog then proceeds to handle.
  • jaws369jaws369 Posts: 6
    edited 2014-11-14 08:07
    dbpage - I assume you are talking to Peter or T as I am "attempting" to use those freaking commands and failing miserably.

    I have tried it with small and large stack spaces, passing references and also passing the variable directly. Nothing seems to allow different cogs to gain control and start writing. I'm suspecting that the objects I am using do not support this and will have to check that next too.

    IF ANYONE has a working multi-cog set of code that writes to a single LCD (you can strip it down to it's bare essentials) and are willing to share the code, I'd seriously appreciate it. I'd rather solve the issue and learn rather than create a master cog running the LCD as a work around personally. Any help is appreciated!!!

    S.
  • jaws369jaws369 Posts: 6
    edited 2014-11-14 08:10
    Ok Peter - if that turns out to be the only method, I can implement that, but I find it very difficult to believe that they didn't take that into account designing the chip. I feel it's very possible to do this, just need a nudge from someone that has implemented it successfully.
    Thanks however for your thoughts on it,I'll have the control cog as my backup plan...
    S.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2014-11-14 08:16
    jaws369 wrote: »
    dbpage - I assume you are talking to Peter or T as I am "attempting" to use those freaking commands and failing miserably.

    I have tried it with small and large stack spaces, passing references and also passing the variable directly. Nothing seems to allow different cogs to gain control and start writing. I'm suspecting that the objects I am using do not support this and will have to check that next too.

    IF ANYONE has a working multi-cog set of code that writes to a single LCD (you can strip it down to it's bare essentials) and are willing to share the code, I'd seriously appreciate it. I'd rather solve the issue and learn rather than create a master cog running the LCD as a work around personally. Any help is appreciated!!!

    S.

    As I mentioned, it's all in the I/O and it's hard to share because of the OR'd nature of the cogs, so let one cog do the work. Look, at it's bare basics you should only really have one function that writes the data to the LCD I/O pins after setting up the RS. It's this function that really just needs to sniff for input from a hub variable and if set then it writes. The higher level code can be shared with multiple cogs but none of them should attempt to access the I/O pins themselves.

    If you need some detail on how to do this then zip/archive up your project files and attach them to your post so I can see exactly what you've got as I'm not going to go searching for them and guessing. I will mod it for you (with improvements of course).

    P.S. The next generation Prop chip P2 has much more flexible I/O in this regard.
  • jaws369jaws369 Posts: 6
    edited 2014-11-14 08:32
    Ok thanks. I'll make the mods to the code now and test it out. Appreciate the feedback.
    S
  • T ChapT Chap Posts: 4,223
    edited 2014-11-14 09:00
    Jaws, did you test the code I posted? I use this all the time with multicogs accessing the LCD.
  • StefanL38StefanL38 Posts: 2,292
    edited 2014-11-14 12:08
    another aproach ist to have a buffer for each character on the LCD.
    all cogs that want to display something write into the buffer.

    then there is one cog who sends the buffer-content to the LCD.

    this makes sure that the data send to the LCD is not messed up at low-level.
    (or'ed IO-pins)

    it might happen that the content of the buffer is partly "crappy" because
    cogs and start overwrite the characters.


    two ideas about how to avoid this

    each cog has an exclusive area on the LCD where only this cog writes new characters in the buffer
    some kind of semaphores to avoid crosswriting into the buffer.

    best regards
    Stefan
Sign In or Register to comment.