Shop OBEX P1 Docs P2 Docs Learn Events
Cannot pass data between a cog running spin and a cog runnig pasm — Parallax Forums

Cannot pass data between a cog running spin and a cog runnig pasm

Hello everyone, I've been struggling with this problem for some time now and hopping that someone is able to lend a hand as I'm new to propeller. I'm struggling with passing data between a cog running spin and another cog running pasm. I'm writing a driver for an touchscreen display and have gotten basic functionality with it. The problem is that I cannot print even a small image (50x50 pixels) without it taking 2 seconds. To fix this I'm writing the function that sends data to the LCD in pasm in the hopes that I can print a large image almost instantly instead of a few seconds. The SPIN code sets a flag that indicates to the PASM code that it needs to draw an image and waits until it is cleared. The pasm code is currently able to realize that a flag is being set but nothing else. The pixel info and the flag is stored in Dat labeled datablock. If you have any ideas how to fix this issue or general ways to improve the code please let me know as I'm not yet familiar with proper propeller programming standards. Thanks in advance.

This is the slow spin code that is able to print an image which is what I'm trying to convert

pub LCD_Datawrite(Data)

pin.High(rd)
pin.Low(cs)
pin.Low(rs)
pin.Outs(dataend,datastart, data)
pin.Low(write)
pin.High(write)
pin.High(cs)
pin.Outs(dataend,datastart, $ff)
pin.High(rs)

This is what i have converted it into. The testloop is there only to check if i can write back to the datablock and will be removed later

DAT

org 0

asm_enter MOV memptr, PAR 'passing the first address of the data block to the counter
RDLONG flag, memptr 'passing the value that memptr points to into flag
TJZ flag, dataWrite 'if the flag is set then enter the loop


:testloop WRLONG lng, memptr 'loop to check if data can be written to the flag location
JMP :testloop

:skipflags add memptr, #4 'incrementing the counter past the flag, pointing to the first pixel in the dat blcok
WRLONG memptr, 0

:loop OR OUTA, ard 'set rd high
MOV pins, INA 'store the pin states in pins
AND pins, lowcs 'clear the bit that corresponds to the cs pin
MOV OUTA, pins 'output the new OUTA value
MOV pins, INA 'set rs low
AND pins, lowrs
MOV OUTA, pins

RDBYTE pixel, memptr 'accesing the PIC data block and storing the data in pixel
AND OUTA, pixel ' sending the data out. data bus is pins 0-7

MOV pins, INA 'set write low
AND pins, lowwrite
MOV OUTA, pins
OR pins, awrite 'set write high
OR OUTA, acs 'set cs high
OR OUTA, #$000FF 'set the data buss high
OR OUTA, ars ' set ars high
ADD memptr, #2 'the next memory location being accessed is one byte higher
djnz loopcount, #:loop 'jump back to loop

WRLONG memptr lng 'loop has finished clear the flag
JMP dataWrite 'start checking for the next image to draw

A sample of the datablock that PAR is pointing to is:
datablock long $ffffff byte $ff,$ff,$ff......(more pixel data)
the long is is the flag being checked in the pasm code and the bytes are pixels. I realize the flag could be just a byte however I'm not sure if the data block needed to be long aligned

Comments


  • Welcome to the forum.
    Insert the # symbol for immediate addresses as follows
    TJZ flag, #dataWrite 'if the flag is set then enter the loop
    
    JMP #dataWrite 'start checking for the next image to draw
    
  • It would be helpful if you posted the entire program.

    I see code for setting pins high using "or outa" but I don't see where the I/O pins have been set as outputs.

    When you post your code, it would help a lot if you use code tags. If you quote ozpropdev's post, you'll see the code tags used. You can either manually add code tags or you can click the "C" icon in the text editor to add code tags.

    You can archive your program by, after compiling your program, selecting File\Archive "MyProgram"\Project..." This will produce a zip file with all the object used in the program. If you attach the archive then we can take a look of your code.
  • So the # symbol is used to access the value that is stored at the location that the pointer points to? If that is the case I'm curious as to why is was able to enter the testloop based on the value that I had stored in my datablock? It would however explain why I am unable to clear the flag.
    I've attached the full code below, most of it is commented out because they are working functions that print text and simple shapes. Thanks for the help :)
  • Duane DegnDuane Degn Posts: 10,588
    edited 2016-07-25 07:10
    All your "jmp" commands should use the "#" symbol.
                    TJZ flag, asm_enter 'if the flag is set then enter the loop
    

    Should be:
                    TJZ flag, #asm_enter 'if the flag is set then enter the loop
    

    The line:
                    JMP asm_enter 'start checking for the next image to draw
    

    Should be:
                    JMP #asm_enter 'start checking for the next image to draw
    

    The following line is correct:
                    djnz loopcount, #:loop 'jump back to loop
    

    As I mentioned earlier, your "or outa, ..." commands in your PASM code will not set any of the I/O pins high. The pins must be set as outputs using "dira" somewhere in your PASM code in order drive the I/O pins with the "outa" command.

    The direction of the I/O pins need to be set from the same cog as the one setting the I/O pins high or low.

    The object "Input Output Pins" will set pin states in the cog calling the methods in the object. You can't use this object to set the direction of I/O pins for a cog running PASM code.

    For example, in order for the line below to set any I/O pin high you must first set the I/O pin as an output from within your PASM code.
    :loop           OR OUTA, ard 'set rd high
    

    Somewhere early in your PASM code use the following line to set "ard" as an output:
                    OR DIRA, ard 'set rd as output
    

    BTW, the following code will set "ard" low.
                    ANDN OUTA, ard 'set rd low
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2016-07-25 07:43
    The # is normally required in a JMP/CALL/DJNZ/TJNZ instruction because this is the register/code address that the program will jump to. If you leave out the # the contents of that address will be used as an address to jump to (ie indirection).
            jmp     #here
            jmp     there
    
    here    mov     .....
            .....
    
    there   long    @here
    

    In the above examples, both jumps will go to the label "here". In the first, the instruction stores the address of "here" and sets the immediate bit (#). In the second jump, the instruction stores the address of "there" without the immediate bit. When it executes, it fetches the contents of the long "there" which stores the 9-bit address of "here", and used that ("here") as the jump to address.

    If you make a mistake and leave out the "#" in the first jump, then the program will go to wherever the lower 9-bits of "here" points to. That means your program will go somewhere you didn't mean it to go!!!
  • I just noticed another possible problem.

    It looks like your test loop correctly uses the hub address of your flag but other places in your code you have the data and address reversed.

    I think you have this line correct:
    :testloop       WRLONG lng, memptr 'loop to check if data can be written to the flag location
    

    However other places you have the address located in the destination field like this line.
                    WRLONG memptr, lng 'loop has finished clear the flag
    

    I'm pretty sure you want to write the value "lng" to the address "memptr". Right?

    If so, you should use:
                    WRLONG lng, memptr  'loop has finished clear the flag
    

    Both reads and writes require the address to be located in the source field.

    It would seem like the hub address should be the destination with a write but this is not the case. The data to be written is the destination and the address to write the data is the source. Apparently there are hardware reasons why these fields are used this way.
  • vettervetter Posts: 8
    edited 2016-07-25 18:18
    I implemented the corrections that have been suggested and it makes sense as to why some things weren't working. I'm still having some issues changing the state of the pins. I'm testing the first couple lines to see if any pins can actually change state. Unless I have missed a line the spin code has set all the pins low which would allow the pasm code to set them to any state it needs, however the pin outputs are still high.

    This is what I currently have in the assembly program
    DAT
    
                    org 0
            
    asm_enter       OR DIRA, #pindirection
                    MOV memptr, PAR  'passing the first addres of the data block to the counter
                    RDLONG flag, memptr 'passing the value that memptr points to into flag
                    TJZ flag, #asm_enter 'if the flag is set then enter the loop
                    JMP #:skipflag
    
    :testloop       JMP #:testloop
                           
    :skipflag       add memptr, #4  'incrementing the counter past the drawflag, pointing to the first pixel in the dat blcok 
                    OR OUTA, #$000FF 'set the data buss high
                    'JMP #:testloop
                    
    :loop           OR OUTA, ard 'set rd high                              
                    ANDN OUTA, acs 'clear the bit that corresponds to the cs pin
    
                    ANDN OUTA, ars 'set rs low
                    
                    'JMP #:testloop
                    RDBYTE pixel, memptr 'accesing the PIC data block and storing the data in pixel
                    OR  OUTA, pixel ' sending the data out. data bus is pins 0-7
                    
                    ANDN OUTA, awrite 'set rs low
                               
                    OR OUTA, awrite 'set write high
                    OR OUTA, acs 'set cs high 
                    OR OUTA, #$000FF 'set the data buss high
                    OR OUTA, ars ' set ars high
                    
                    ADD memptr, #1 'the next memory location being accesed is one byte higher
                    djnz loopcount, #:loop 'jump back to loop 
                     
                    
                    WRLONG lng, PAR 'loop has finished clear the flag
                    MOV loopcount, loopreset 
                    JMP #asm_enter 'start checking for the next image to draw
                    
                    
    {:loop          MOV loopcount, #500 'repeat 500 times
                    MUXC OUTA, ard  'set rd high
                    MUXNC OUTA, acs 'set cs low
                    MUXNC OUTA, ars 'set rs low
                    MOV pixel, count 'accesing the PIC data block and storing the data in pixel
                    XOR pixel, #$FF 'inverts the data creatign a mask for the MUXC command
                    MUXC OUTA, pixel 'send the data out 
                    MUXNC OUTA, awrite 'set write low
                    MUXC OUTA, awrite ' set write high
                    MUXC OUTA, #$FF 'set the data buss high
                    ADD count, #2 'the next memory location being accesed is one byte higher
                    djnz loopcount, #:loop 'jump back to the loop label
    
                    WRBYTE PAR, #$00 'loop has finished clear the flag
                    JMP dataWrite 'start checking for the next image to draw
     }
          
    
    
    
    
    lng long $00000000
    pindirection long $0FFF
    loopreset long 5000
    
    'constants used to set the pins low in OUTA
    'lowcs long %11111111111111111111101111111111
    'lowrs long %11111111111111111111110111111111
    'lowwrite long %11111111111111111111011111111111
     
    ard long |< rd 'encodes pins into a 32 bit value
    acs long |< 10
    ars long |< 9
    awrite long |< write
    
    
    loopcount long 5000 'controls how many times the loop executes
    
    
     {code to copy into assembler
        repeat 5000        
             LCD_DataWrite(pic2[i++])'  //write black data
        pin.High(rd)
        pin.Low(cs)
        pin.Low(rs)
        pin.Outs(dataend,datastart, data)
        pin.Low(write)
        pin.High(write)
        pin.High(cs)
       pin.Outs(dataend,datastart, $ff)
        pin.High(rs)
     }
    
    
    flag long 1
    pins res 1 'Temp OUTA registry storage
    pixel res 1 'individual pixel info
    memptr res 2
    

    This is the current spin code
        pin.High(rd)
        pin.High(cs)
        pin.High(rs)
        pin.High(write)
        pin.Dir(nxt,0)
        pin.High(15)
        time.Pause(500)
      'vp.config(string("start:terminal::terminal:1"))
      'vp.share(@OutP,@InP)
      '  vp.str(string("Hello World!",13))
    
         
         'vp.share(@datablock,@datablock)
         
    
         
            pst.STR(String("Startup: ")) 
          
          
    
          LCD_Initial
          
          write_Dir($01,$80)'//display on
             Text_Background_Color1(color_green)'//Background color setting
            write_Dir($8E,$80)'//Began to clear the screen (display window)
            nxtStep
            
            cognew(@asm_enter,@datablock)
    
            Active_Window(250,300,250,300)
            MemoryWrite_Position(0,200)   '//cursor position 
             Graphic_Mode
            LCD_CmdWrite($02)';//set CMD02 to  prepare data write
             pin.Outs(dataend,clearporta, $00) 'clearing the port so the pasm code can set the pins low. clearporta has the value 12, so pins 0-12 should be cleared
            datablock[0] := 1 'flag indicates that pasm should draw the image
                repeat while datablock[0] ==1 'wait for pasm to clear the flag
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2016-07-25 18:22
    :testloop       WRLONG lng, memptr 'loop to check if data can be written to the flag location
                    JMP #:testloop
                 
    

    Do you realize the program never exits the above loop?

    I think you are using "DIRA" incorrectly. You set the dira states the same way you do with outa states, using a mask. I provided an example earlier using your "ard" mask. It looks like you're setting the masks correctly already, you just need to treat dira statements with the same syntax as the outa statements.

    When I first learned to use the Propeller I was terribly confused about pointers and PASM. It was thanks to many forum members such as Cluso99 that I eventually understood how things worked.

    I have a list of links to Propeller related tutorials in my (non-alphabetical) "index." Here's a link to the post with this list of links.

    JonnyMac's SpinZone articles were a big help with my attempt to understand PASM and DeSilva's PASM tutorial was also a big help. I had to come back to DeSilva's tutorial several different times. Each time I read it, I understood more of what he was saying. (I never interacted with DeSilva but I sure miss his input around here.)

    I thought Cluso99 explained things better than I could but I'll attempt to add what I understand about pointers in PASM. The "#" symbol indicates the value stored in the "source" section of the PASM line should be acted on directly. When "#4" is used, the value four is used as the source field. If instead of "#4", one used "4" then the value located in cog memory position 4 would be used as the source field.

    As I learned from DeSilva's tutorial, each line of PASM is also a 32 bit register. These registers can either contain data or instructions. The Propeller doesn't care if the information in each memory slot (register) is an instruction or a numeric value used in calculations. When a memory slot is used as an instruction, it's broken into multiple fields. The last nine bits is the "source" field. One of the remaining 23 bits (32-9 = 23) is a bit indicating if the value in the source field should be treated as value (as in the case of "#4") or if the field should be used to indicate which memory position should be used as the source of the PASM instruction. I don't recall the correct terms for the direct rather than indirect source field. DeSilva's tutorial uses the correct terminology.

    I have a feeling what I just wrote didn't make any sense. I encourage you to read DeSilva's tutorial (a couple of times). There's also a tutorial by Graham Stabler which I have heard good things about. I haven't read Graham's tutorial myself because by the time I learned it existed, I felt like I understood how PASM worked reasonably well.

    I'm going to make sure these links I suggest following are still good.

  • Thanks for those links they seem to contain a lot of the information I've been searching for, so I will be going through those soon. Your explanation along with Cluso99 make sense now thank you. I realize that the loop was never being broken that was just my attempts of debugging the code, it has since been removed (see the code in my previous post) because it is now working.
Sign In or Register to comment.